From 1a60b63b7d9be96b890c7e59a77fd10504ab15ab Mon Sep 17 00:00:00 2001 From: eFini Date: Sat, 18 May 2024 00:17:22 +0800 Subject: [PATCH 001/220] Mutilang: update CHS/CHT translation (#32455) update translations for chinese --- selfdrive/ui/translations/main_zh-CHS.ts | 20 ++++----- selfdrive/ui/translations/main_zh-CHT.ts | 56 ++++++++++++------------ 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 306678363..32119ee10 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -299,11 +299,11 @@ Pair Device - + 配对设备 PAIR - + 配对 @@ -487,23 +487,23 @@ OnroadAlerts openpilot Unavailable - + 无法使用 openpilot Waiting for controls to start - + 等待控制服务啟動 TAKE CONTROL IMMEDIATELY - + 立即接管 Controls Unresponsive - + 控制服务无响应 Reboot Device - + 重启设备 @@ -628,7 +628,7 @@ now - + 现在 @@ -1152,11 +1152,11 @@ This may take up to a minute. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - + 推荐使用标准模式。在积极模式下,openpilot 会更靠近前方车辆,并在油门和刹车方面更加激进。在放松模式下,openpilot 会与前方车辆保持更远距离。在支持的车型上,你可以使用方向盘上的距离按钮来循环切换这些驾驶风格。 The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - + 在低速时,驾驶可视化将转换为道路朝向的广角摄像头,以更好地展示某些转弯。测试模式标志也将显示在右上角。 Always-On Driver Monitoring diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 8d0df30f9..9d1c16db9 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -247,11 +247,11 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot 需要將設備固定在左右偏差 4° 以內,朝上偏差 5° 以內或朝下偏差 9° 以內。鏡頭在後台會持續自動校準,很少有需要重設的情況。 + openpilot 需要將裝置固定在左右偏差 4° 以內,朝上偏差 5° 以內或朝下偏差 9° 以內。鏡頭在後台會持續自動校準,很少有需要重置的情況。 Your device is pointed %1° %2 and %3° %4. - 你的設備目前朝%2 %1° 以及朝%4 %3° 。 + 你的裝置目前朝%2 %1° 以及朝%4 %3° 。 down @@ -295,15 +295,15 @@ Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - 將您的設備與 comma connect (connect.comma.ai) 配對並領取您的 comma 高級會員優惠。 + 將您的裝置與 comma connect (connect.comma.ai) 配對並領取您的 comma 高級會員優惠。 Pair Device - + 配對裝置 PAIR - + 配對 @@ -437,11 +437,11 @@ An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - 一個給您設備的操作系統的更新正在後台下載中。當更新準備好安裝時,您將收到提示進行更新。 + 一個有關操作系統的更新正在後台下載中。當更新準備好安裝時,您將收到提示進行更新。 Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - 設備註冊失敗。它將無法連接或上傳至 comma.ai 伺服器,並且無法獲得 comma.ai 的支援。如果這是一個官方設備,請訪問 https://comma.ai/support 。 + 裝置註冊失敗。它將無法連接或上傳至 comma.ai 伺服器,並且無法獲得 comma.ai 的支援。如果這是一個官方裝置,請訪問 https://comma.ai/support 。 NVMe drive not mounted. @@ -449,7 +449,7 @@ Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - 檢測到不支援的 NVMe 固態硬碟。您的設備因為使用了不支援的 NVMe 固態硬碟可能會消耗更多電力並更易過熱。 + 檢測到不支援的 NVMe 固態硬碟。您的裝置因為使用了不支援的 NVMe 固態硬碟可能會消耗更多電力並更易過熱。 openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. @@ -461,11 +461,11 @@ openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - openpilot 偵測到設備的安裝位置發生變化。請確保設備完全安裝在支架上,並確保支架牢固地固定在擋風玻璃上。 + openpilot 偵測到裝置的安裝位置發生變化。請確保裝置完全安裝在支架上,並確保支架牢固地固定在擋風玻璃上。 Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - 設備溫度過高。系統正在冷卻中,等冷卻完畢後才會啟動。目前內部組件溫度:%1 + 裝置溫度過高。系統正在冷卻中,等冷卻完畢後才會啟動。目前內部組件溫度:%1 @@ -487,30 +487,30 @@ OnroadAlerts openpilot Unavailable - + 無法使用 openpilot Waiting for controls to start - + 等待操控服務開始 TAKE CONTROL IMMEDIATELY - + 立即接管 Controls Unresponsive - + 操控服務沒有反應 Reboot Device - + 請重新啟裝置 PairingPopup Pair your device to your comma account - 將設備與您的 comma 帳號配對 + 將裝置與您的 comma 帳號配對 Go to https://connect.comma.ai on your phone @@ -628,7 +628,7 @@ now - + 現在 @@ -639,7 +639,7 @@ Are you sure you want to reset your device? - 您確定要重設你的設備嗎? + 您確定要重設你的裝置嗎? System Reset @@ -659,12 +659,12 @@ Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - 無法掛載資料分割區。分割區可能已經毀損。請確認是否要刪除並重新設定。 + 無法掛載資料分割區。分割區可能已經毀損。請確認是否要刪除並重置。 Resetting device... This may take up to a minute. - 設備重設中… + 重置中… 這可能需要一分鐘的時間。 @@ -680,7 +680,7 @@ This may take up to a minute. Device - 設備 + 裝置 Network @@ -755,7 +755,7 @@ This may take up to a minute. Ensure the entered URL is valid, and the device’s internet connection is good. - 請確定您輸入的是有效的安裝網址,並且確定設備的網路連線狀態良好。 + 請確定您輸入的是有效的安裝網址,並且確定裝置的網路連線狀態良好。 Reboot device @@ -771,7 +771,7 @@ This may take up to a minute. Something went wrong. Reboot the device. - 發生了一些錯誤。請重新啟動您的設備。 + 發生了一些錯誤。請重新啟動您的裝置。 Select a language @@ -798,11 +798,11 @@ This may take up to a minute. Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - 將您的設備與 comma connect (connect.comma.ai) 配對並領取您的 comma 高級會員優惠。 + 將您的裝置與 comma connect (connect.comma.ai) 配對並領取您的 comma 高級會員優惠。 Pair device - 配對設備 + 配對裝置 @@ -1152,11 +1152,11 @@ This may take up to a minute. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - + 建議使用標準模式。在積極模式下,openpilot 會更接近前車並更積極地使用油門和剎車。在輕鬆模式下,openpilot 會與前車保持較遠距離。對於支援的汽車,您可以使用方向盤上的距離按鈕來切換這些駕駛風格。 The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - + 在低速時,駕駛可視化將切換至道路朝向的廣角攝影機,以更好地顯示某些彎道。在右上角還會顯示「實驗模式」的標誌。 Always-On Driver Monitoring @@ -1175,7 +1175,7 @@ This may take up to a minute. An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - 設備的操作系統需要更新。請將您的設備連接到 Wi-Fi 以獲得最快的更新體驗。下載大小約為 1GB。 + 需要進行作業系統更新。建議將您的裝置連接上 Wi-Fi 獲得更快的更新下載。下載大小約為 1GB。 Connect to Wi-Fi From f5bca9c08c549e502f5684c112ce9b02b9d33420 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 10:45:04 -0700 Subject: [PATCH 002/220] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 2cf3b84c7..cade0d5e7 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 2cf3b84c77f6ba541619d53edc291b5b94033821 +Subproject commit cade0d5e75cdd6a659e1ded21a45d8f3c6c62c18 From dd9d5d4528ff0a61c7699abc1b63ba8fd282632f Mon Sep 17 00:00:00 2001 From: cl0cks4fe <108313040+cl0cks4fe@users.noreply.github.com> Date: Fri, 17 May 2024 11:01:44 -0700 Subject: [PATCH 003/220] Unittest to pytest (#32366) * add pytest-asyncio * switch common * switch selfdrive * switch system * switch tools * small fixes * fix setUp and valgrind pytest * switch to setup * fix random * switch mock * switch test_lateral_limits * revert test_ui * fix poetry.lock * add unittest to banned-api * add inline ignores to remaining unittest imports * revert test_models * revert check_can_parser_performance * one more skip --------- Co-authored-by: Adeeb Shihadeh --- .github/workflows/selfdrive_tests.yaml | 2 +- common/tests/test_file_helpers.py | 9 +- common/tests/test_numpy_fast.py | 7 +- common/tests/test_params.py | 28 +-- common/tests/test_simple_kalman.py | 14 +- .../transformations/tests/test_coordinates.py | 13 +- .../transformations/tests/test_orientation.py | 7 +- opendbc | 2 +- poetry.lock | 39 ++- pyproject.toml | 3 + selfdrive/athena/tests/test_athenad.py | 184 +++++++------- selfdrive/athena/tests/test_athenad_ping.py | 39 ++- selfdrive/athena/tests/test_registration.py | 68 +++-- .../boardd/tests/test_boardd_loopback.py | 5 - selfdrive/boardd/tests/test_pandad.py | 16 +- selfdrive/car/ford/tests/test_ford.py | 37 ++- selfdrive/car/gm/tests/test_gm.py | 13 +- selfdrive/car/honda/tests/test_honda.py | 9 +- selfdrive/car/hyundai/tests/test_hyundai.py | 85 +++---- selfdrive/car/subaru/tests/test_subaru.py | 8 +- selfdrive/car/tests/test_can_fingerprint.py | 23 +- selfdrive/car/tests/test_car_interfaces.py | 45 ++-- selfdrive/car/tests/test_docs.py | 67 +++-- selfdrive/car/tests/test_fw_fingerprint.py | 145 ++++++----- selfdrive/car/tests/test_lateral_limits.py | 37 +-- selfdrive/car/tests/test_models.py | 2 +- selfdrive/car/tests/test_platform_configs.py | 22 +- selfdrive/car/toyota/tests/test_toyota.py | 73 +++--- .../car/volkswagen/tests/test_volkswagen.py | 35 ++- .../controls/lib/tests/test_alertmanager.py | 9 +- .../controls/lib/tests/test_latcontrol.py | 10 +- .../controls/lib/tests/test_vehicle_model.py | 15 +- selfdrive/controls/tests/test_alerts.py | 38 ++- selfdrive/controls/tests/test_cruise_speed.py | 28 +-- .../controls/tests/test_following_distance.py | 10 +- selfdrive/controls/tests/test_lateral_mpc.py | 24 +- selfdrive/controls/tests/test_leads.py | 10 +- .../controls/tests/test_state_machine.py | 25 +- selfdrive/locationd/test/test_calibrationd.py | 36 ++- selfdrive/locationd/test/test_locationd.py | 21 +- .../test/test_locationd_scenarios.py | 63 +++-- selfdrive/manager/test/test_manager.py | 27 +- selfdrive/modeld/tests/test_modeld.py | 35 ++- selfdrive/monitoring/test_monitoring.py | 110 ++++---- selfdrive/navd/tests/test_map_renderer.py | 18 +- selfdrive/navd/tests/test_navd.py | 11 +- selfdrive/test/helpers.py | 7 +- .../test_longitudinal.py | 13 +- selfdrive/test/process_replay/test_fuzzy.py | 6 +- selfdrive/test/process_replay/test_regen.py | 10 +- selfdrive/test/test_onroad.py | 51 ++-- selfdrive/test/test_updated.py | 35 ++- selfdrive/test/test_valgrind_replay.py | 9 +- .../thermald/tests/test_fan_controller.py | 57 ++--- .../thermald/tests/test_power_monitoring.py | 236 +++++++++--------- selfdrive/ui/tests/test_soundd.py | 10 +- selfdrive/ui/tests/test_translations.py | 44 ++-- selfdrive/ui/tests/test_ui/run.py | 2 +- selfdrive/updated/tests/test_base.py | 53 ++-- system/camerad/test/test_exposure.py | 10 +- .../hardware/tici/tests/test_agnos_updater.py | 9 +- system/hardware/tici/tests/test_amplifier.py | 18 +- system/hardware/tici/tests/test_hardware.py | 7 +- system/hardware/tici/tests/test_power_draw.py | 19 +- system/loggerd/tests/loggerd_tests_common.py | 5 +- system/loggerd/tests/test_deleter.py | 15 +- system/loggerd/tests/test_encoder.py | 39 ++- system/loggerd/tests/test_uploader.py | 55 ++-- system/qcomgpsd/tests/test_qcomgpsd.py | 24 +- system/sensord/tests/test_sensord.py | 22 +- system/tests/test_logmessaged.py | 10 +- system/ubloxd/tests/test_pigeond.py | 9 +- system/updated/casync/tests/test_casync.py | 86 +++---- system/webrtc/tests/test_stream_session.py | 74 +++--- system/webrtc/tests/test_webrtcd.py | 26 +- tools/car_porting/test_car_model.py | 2 +- tools/lib/tests/test_caching.py | 47 ++-- tools/lib/tests/test_comma_car_segments.py | 11 +- tools/lib/tests/test_logreader.py | 136 +++++----- tools/lib/tests/test_readers.py | 23 +- tools/lib/tests/test_route_library.py | 12 +- tools/plotjuggler/test_plotjuggler.py | 15 +- tools/sim/tests/test_metadrive_bridge.py | 5 - tools/sim/tests/test_sim_bridge.py | 24 +- 84 files changed, 1215 insertions(+), 1548 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 2be83b165..85c407307 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -147,7 +147,7 @@ jobs: - name: Run valgrind timeout-minutes: 1 run: | - ${{ env.RUN }} "python selfdrive/test/test_valgrind_replay.py" + ${{ env.RUN }} "pytest selfdrive/test/test_valgrind_replay.py" - name: Print logs if: always() run: cat selfdrive/test/valgrind_logs.txt diff --git a/common/tests/test_file_helpers.py b/common/tests/test_file_helpers.py index 1817f77cd..a9977c236 100644 --- a/common/tests/test_file_helpers.py +++ b/common/tests/test_file_helpers.py @@ -1,11 +1,10 @@ import os -import unittest from uuid import uuid4 from openpilot.common.file_helpers import atomic_write_in_dir -class TestFileHelpers(unittest.TestCase): +class TestFileHelpers: def run_atomic_write_func(self, atomic_write_func): path = f"/tmp/tmp{uuid4()}" with atomic_write_func(path) as f: @@ -13,12 +12,8 @@ class TestFileHelpers(unittest.TestCase): assert not os.path.exists(path) with open(path) as f: - self.assertEqual(f.read(), "test") + assert f.read() == "test" os.remove(path) def test_atomic_write_in_dir(self): self.run_atomic_write_func(atomic_write_in_dir) - - -if __name__ == "__main__": - unittest.main() diff --git a/common/tests/test_numpy_fast.py b/common/tests/test_numpy_fast.py index de7bb972e..aa53851db 100644 --- a/common/tests/test_numpy_fast.py +++ b/common/tests/test_numpy_fast.py @@ -1,10 +1,9 @@ import numpy as np -import unittest from openpilot.common.numpy_fast import interp -class InterpTest(unittest.TestCase): +class TestInterp: def test_correctness_controls(self): _A_CRUISE_MIN_BP = np.asarray([0., 5., 10., 20., 40.]) _A_CRUISE_MIN_V = np.asarray([-1.0, -.8, -.67, -.5, -.30]) @@ -20,7 +19,3 @@ class InterpTest(unittest.TestCase): expected = np.interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V) actual = interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V) np.testing.assert_equal(actual, expected) - - -if __name__ == "__main__": - unittest.main() diff --git a/common/tests/test_params.py b/common/tests/test_params.py index 490ee122b..16cbc4529 100644 --- a/common/tests/test_params.py +++ b/common/tests/test_params.py @@ -1,13 +1,13 @@ +import pytest import os import threading import time import uuid -import unittest from openpilot.common.params import Params, ParamKeyType, UnknownKeyName -class TestParams(unittest.TestCase): - def setUp(self): +class TestParams: + def setup_method(self): self.params = Params() def test_params_put_and_get(self): @@ -49,16 +49,16 @@ class TestParams(unittest.TestCase): assert self.params.get("CarParams", True) == b"test" def test_params_unknown_key_fails(self): - with self.assertRaises(UnknownKeyName): + with pytest.raises(UnknownKeyName): self.params.get("swag") - with self.assertRaises(UnknownKeyName): + with pytest.raises(UnknownKeyName): self.params.get_bool("swag") - with self.assertRaises(UnknownKeyName): + with pytest.raises(UnknownKeyName): self.params.put("swag", "abc") - with self.assertRaises(UnknownKeyName): + with pytest.raises(UnknownKeyName): self.params.put_bool("swag", True) def test_remove_not_there(self): @@ -68,19 +68,19 @@ class TestParams(unittest.TestCase): def test_get_bool(self): self.params.remove("IsMetric") - self.assertFalse(self.params.get_bool("IsMetric")) + assert not self.params.get_bool("IsMetric") self.params.put_bool("IsMetric", True) - self.assertTrue(self.params.get_bool("IsMetric")) + assert self.params.get_bool("IsMetric") self.params.put_bool("IsMetric", False) - self.assertFalse(self.params.get_bool("IsMetric")) + assert not self.params.get_bool("IsMetric") self.params.put("IsMetric", "1") - self.assertTrue(self.params.get_bool("IsMetric")) + assert self.params.get_bool("IsMetric") self.params.put("IsMetric", "0") - self.assertFalse(self.params.get_bool("IsMetric")) + assert not self.params.get_bool("IsMetric") def test_put_non_blocking_with_get_block(self): q = Params() @@ -107,7 +107,3 @@ class TestParams(unittest.TestCase): assert len(keys) > 20 assert len(keys) == len(set(keys)) assert b"CarParams" in keys - - -if __name__ == "__main__": - unittest.main() diff --git a/common/tests/test_simple_kalman.py b/common/tests/test_simple_kalman.py index f641cd19e..f4a967e58 100644 --- a/common/tests/test_simple_kalman.py +++ b/common/tests/test_simple_kalman.py @@ -1,10 +1,8 @@ -import unittest - from openpilot.common.simple_kalman import KF1D -class TestSimpleKalman(unittest.TestCase): - def setUp(self): +class TestSimpleKalman: + def setup_method(self): dt = 0.01 x0_0 = 0.0 x1_0 = 0.0 @@ -24,12 +22,8 @@ class TestSimpleKalman(unittest.TestCase): def test_getter_setter(self): self.kf.set_x([[1.0], [1.0]]) - self.assertEqual(self.kf.x, [[1.0], [1.0]]) + assert self.kf.x == [[1.0], [1.0]] def update_returns_state(self): x = self.kf.update(100) - self.assertEqual(x, self.kf.x) - - -if __name__ == "__main__": - unittest.main() + assert x == self.kf.x diff --git a/common/transformations/tests/test_coordinates.py b/common/transformations/tests/test_coordinates.py index 7ae79403b..41076d9b3 100755 --- a/common/transformations/tests/test_coordinates.py +++ b/common/transformations/tests/test_coordinates.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import numpy as np -import unittest import openpilot.common.transformations.coordinates as coord @@ -44,7 +43,7 @@ ned_offsets_batch = np.array([[ 53.88103168, 43.83445935, -46.27488057], [ 78.56272609, 18.53100158, -43.25290759]]) -class TestNED(unittest.TestCase): +class TestNED: def test_small_distances(self): start_geodetic = np.array([33.8042184, -117.888593, 0.0]) local_coord = coord.LocalCoord.from_geodetic(start_geodetic) @@ -54,13 +53,13 @@ class TestNED(unittest.TestCase): west_geodetic = start_geodetic + [0, -0.0005, 0] west_ned = local_coord.geodetic2ned(west_geodetic) - self.assertLess(np.abs(west_ned[0]), 1e-3) - self.assertLess(west_ned[1], 0) + assert np.abs(west_ned[0]) < 1e-3 + assert west_ned[1] < 0 southwest_geodetic = start_geodetic + [-0.0005, -0.002, 0] southwest_ned = local_coord.geodetic2ned(southwest_geodetic) - self.assertLess(southwest_ned[0], 0) - self.assertLess(southwest_ned[1], 0) + assert southwest_ned[0] < 0 + assert southwest_ned[1] < 0 def test_ecef_geodetic(self): # testing single @@ -105,5 +104,3 @@ class TestNED(unittest.TestCase): np.testing.assert_allclose(converter.ned2ecef(ned_offsets_batch), ecef_positions_offset_batch, rtol=1e-9, atol=1e-7) -if __name__ == "__main__": - unittest.main() diff --git a/common/transformations/tests/test_orientation.py b/common/transformations/tests/test_orientation.py index f77827d2f..695642774 100755 --- a/common/transformations/tests/test_orientation.py +++ b/common/transformations/tests/test_orientation.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import numpy as np -import unittest from openpilot.common.transformations.orientation import euler2quat, quat2euler, euler2rot, rot2euler, \ rot2quat, quat2rot, \ @@ -32,7 +31,7 @@ ned_eulers = np.array([[ 0.46806039, -0.4881889 , 1.65697808], [ 2.50450101, 0.36304151, 0.33136365]]) -class TestOrientation(unittest.TestCase): +class TestOrientation: def test_quat_euler(self): for i, eul in enumerate(eulers): np.testing.assert_allclose(quats[i], euler2quat(eul), rtol=1e-7) @@ -62,7 +61,3 @@ class TestOrientation(unittest.TestCase): np.testing.assert_allclose(ned_eulers[i], ned_euler_from_ecef(ecef_positions[i], eulers[i]), rtol=1e-7) #np.testing.assert_allclose(eulers[i], ecef_euler_from_ned(ecef_positions[i], ned_eulers[i]), rtol=1e-7) # np.testing.assert_allclose(ned_eulers, ned_euler_from_ecef(ecef_positions, eulers), rtol=1e-7) - - -if __name__ == "__main__": - unittest.main() diff --git a/opendbc b/opendbc index 91a9bb482..e2408cb27 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 91a9bb4824381c39b8a15b443d5b265ec550b62b +Subproject commit e2408cb2725671ad63e827e02f37e0f1739b68c6 diff --git a/poetry.lock b/poetry.lock index 978574a1e..f1f8d9f51 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohttp" @@ -6641,6 +6641,24 @@ pluggy = ">=1.5,<2.0" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-asyncio" +version = "0.23.6" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, + {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, +] + +[package.dependencies] +pytest = ">=7.0.0,<9" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + [[package]] name = "pytest-cov" version = "5.0.0" @@ -6674,6 +6692,23 @@ files = [ colorama = "*" pytest = ">=7.0" +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + [[package]] name = "pytest-randomly" version = "3.15.0" @@ -7987,4 +8022,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "5f0a1b6f26faa3effeaa5393b73d9188be385a72c1d3b9befb3f03df3b38c86d" +content-hash = "9f69dc7862f33f61e94e960f0ead2cbcd306b4502163d1934381d476143344f4" diff --git a/pyproject.toml b/pyproject.toml index a25fcc164..a4e31145d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,6 +154,8 @@ pytest-subtests = "*" pytest-xdist = "*" pytest-timeout = "*" pytest-randomly = "*" +pytest-asyncio = "*" +pytest-mock = "*" ruff = "*" sphinx = "*" sphinx-rtd-theme = "*" @@ -197,6 +199,7 @@ lint.flake8-implicit-str-concat.allow-multiline=false "third_party".msg = "Use openpilot.third_party" "tools".msg = "Use openpilot.tools" "pytest.main".msg = "pytest.main requires special handling that is easy to mess up!" +"unittest".msg = "Use pytest" [tool.coverage.run] concurrency = ["multiprocessing", "thread"] diff --git a/selfdrive/athena/tests/test_athenad.py b/selfdrive/athena/tests/test_athenad.py index 4850ab9a3..bdce3dcce 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/selfdrive/athena/tests/test_athenad.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -from functools import partial, wraps +import pytest +from functools import wraps import json import multiprocessing import os @@ -8,12 +9,9 @@ import shutil import time import threading import queue -import unittest from dataclasses import asdict, replace from datetime import datetime, timedelta -from parameterized import parameterized -from unittest import mock from websocket import ABNF from websocket._exceptions import WebSocketConnectionClosedException @@ -24,7 +22,7 @@ from openpilot.common.timeout import Timeout from openpilot.selfdrive.athena import athenad from openpilot.selfdrive.athena.athenad import MAX_RETRY_COUNT, dispatcher from openpilot.selfdrive.athena.tests.helpers import HTTPRequestHandler, MockWebsocket, MockApi, EchoSocket -from openpilot.selfdrive.test.helpers import with_http_server +from openpilot.selfdrive.test.helpers import http_server_context from openpilot.system.hardware.hw import Paths @@ -37,10 +35,6 @@ def seed_athena_server(host, port): except requests.exceptions.ConnectionError: time.sleep(0.1) - -with_mock_athena = partial(with_http_server, handler=HTTPRequestHandler, setup=seed_athena_server) - - def with_upload_handler(func): @wraps(func) def wrapper(*args, **kwargs): @@ -54,15 +48,23 @@ def with_upload_handler(func): thread.join() return wrapper +@pytest.fixture +def mock_create_connection(mocker): + return mocker.patch('openpilot.selfdrive.athena.athenad.create_connection') -class TestAthenadMethods(unittest.TestCase): +@pytest.fixture +def host(): + with http_server_context(handler=HTTPRequestHandler, setup=seed_athena_server) as (host, port): + yield f"http://{host}:{port}" + +class TestAthenadMethods: @classmethod - def setUpClass(cls): + def setup_class(cls): cls.SOCKET_PORT = 45454 athenad.Api = MockApi athenad.LOCAL_PORT_WHITELIST = {cls.SOCKET_PORT} - def setUp(self): + def setup_method(self): self.default_params = { "DongleId": "0000000000000000", "GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private", # noqa: E501 @@ -109,8 +111,8 @@ class TestAthenadMethods(unittest.TestCase): def test_echo(self): assert dispatcher["echo"]("bob") == "bob" - def test_getMessage(self): - with self.assertRaises(TimeoutError) as _: + def test_get_message(self): + with pytest.raises(TimeoutError) as _: dispatcher["getMessage"]("controlsState") end_event = multiprocessing.Event() @@ -133,7 +135,7 @@ class TestAthenadMethods(unittest.TestCase): end_event.set() p.join() - def test_listDataDirectory(self): + def test_list_data_directory(self): route = '2021-03-29--13-32-47' segments = [0, 1, 2, 3, 11] @@ -143,69 +145,66 @@ class TestAthenadMethods(unittest.TestCase): self._create_file(file) resp = dispatcher["listDataDirectory"]() - self.assertTrue(resp, 'list empty!') - self.assertCountEqual(resp, files) + assert resp, 'list empty!' + assert len(resp) == len(files) resp = dispatcher["listDataDirectory"](f'{route}--123') - self.assertCountEqual(resp, []) + assert len(resp) == 0 prefix = f'{route}' - expected = filter(lambda f: f.startswith(prefix), files) + expected = list(filter(lambda f: f.startswith(prefix), files)) resp = dispatcher["listDataDirectory"](prefix) - self.assertTrue(resp, 'list empty!') - self.assertCountEqual(resp, expected) + assert resp, 'list empty!' + assert len(resp) == len(expected) prefix = f'{route}--1' - expected = filter(lambda f: f.startswith(prefix), files) + expected = list(filter(lambda f: f.startswith(prefix), files)) resp = dispatcher["listDataDirectory"](prefix) - self.assertTrue(resp, 'list empty!') - self.assertCountEqual(resp, expected) + assert resp, 'list empty!' + assert len(resp) == len(expected) prefix = f'{route}--1/' - expected = filter(lambda f: f.startswith(prefix), files) + expected = list(filter(lambda f: f.startswith(prefix), files)) resp = dispatcher["listDataDirectory"](prefix) - self.assertTrue(resp, 'list empty!') - self.assertCountEqual(resp, expected) + assert resp, 'list empty!' + assert len(resp) == len(expected) prefix = f'{route}--1/q' - expected = filter(lambda f: f.startswith(prefix), files) + expected = list(filter(lambda f: f.startswith(prefix), files)) resp = dispatcher["listDataDirectory"](prefix) - self.assertTrue(resp, 'list empty!') - self.assertCountEqual(resp, expected) + assert resp, 'list empty!' + assert len(resp) == len(expected) def test_strip_bz2_extension(self): fn = self._create_file('qlog.bz2') if fn.endswith('.bz2'): - self.assertEqual(athenad.strip_bz2_extension(fn), fn[:-4]) + assert athenad.strip_bz2_extension(fn) == fn[:-4] - @parameterized.expand([(True,), (False,)]) - @with_mock_athena - def test_do_upload(self, compress, host): + @pytest.mark.parametrize("compress", [True, False]) + def test_do_upload(self, host, compress): # random bytes to ensure rather large object post-compression fn = self._create_file('qlog', data=os.urandom(10000 * 1024)) upload_fn = fn + ('.bz2' if compress else '') item = athenad.UploadItem(path=upload_fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='') - with self.assertRaises(requests.exceptions.ConnectionError): + with pytest.raises(requests.exceptions.ConnectionError): athenad._do_upload(item) item = athenad.UploadItem(path=upload_fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='') resp = athenad._do_upload(item) - self.assertEqual(resp.status_code, 201) + assert resp.status_code == 201 - @with_mock_athena - def test_uploadFileToUrl(self, host): + def test_upload_file_to_url(self, host): fn = self._create_file('qlog.bz2') resp = dispatcher["uploadFileToUrl"]("qlog.bz2", f"{host}/qlog.bz2", {}) - self.assertEqual(resp['enqueued'], 1) - self.assertNotIn('failed', resp) - self.assertLessEqual({"path": fn, "url": f"{host}/qlog.bz2", "headers": {}}.items(), resp['items'][0].items()) - self.assertIsNotNone(resp['items'][0].get('id')) - self.assertEqual(athenad.upload_queue.qsize(), 1) + assert resp['enqueued'] == 1 + assert 'failed' not in resp + assert {"path": fn, "url": f"{host}/qlog.bz2", "headers": {}}.items() <= resp['items'][0].items() + assert resp['items'][0].get('id') is not None + assert athenad.upload_queue.qsize() == 1 - @with_mock_athena - def test_uploadFileToUrl_duplicate(self, host): + def test_upload_file_to_url_duplicate(self, host): self._create_file('qlog.bz2') url1 = f"{host}/qlog.bz2?sig=sig1" @@ -214,14 +213,12 @@ class TestAthenadMethods(unittest.TestCase): # Upload same file again, but with different signature url2 = f"{host}/qlog.bz2?sig=sig2" resp = dispatcher["uploadFileToUrl"]("qlog.bz2", url2, {}) - self.assertEqual(resp, {'enqueued': 0, 'items': []}) + assert resp == {'enqueued': 0, 'items': []} - @with_mock_athena - def test_uploadFileToUrl_does_not_exist(self, host): + def test_upload_file_to_url_does_not_exist(self, host): not_exists_resp = dispatcher["uploadFileToUrl"]("does_not_exist.bz2", "http://localhost:1238", {}) - self.assertEqual(not_exists_resp, {'enqueued': 0, 'items': [], 'failed': ['does_not_exist.bz2']}) + assert not_exists_resp == {'enqueued': 0, 'items': [], 'failed': ['does_not_exist.bz2']} - @with_mock_athena @with_upload_handler def test_upload_handler(self, host): fn = self._create_file('qlog.bz2') @@ -233,13 +230,12 @@ class TestAthenadMethods(unittest.TestCase): # TODO: verify that upload actually succeeded # TODO: also check that end_event and metered network raises AbortTransferException - self.assertEqual(athenad.upload_queue.qsize(), 0) + assert athenad.upload_queue.qsize() == 0 - @parameterized.expand([(500, True), (412, False)]) - @with_mock_athena - @mock.patch('requests.put') + @pytest.mark.parametrize("status,retry", [(500,True), (412,False)]) @with_upload_handler - def test_upload_handler_retry(self, status, retry, mock_put, host): + def test_upload_handler_retry(self, mocker, host, status, retry): + mock_put = mocker.patch('requests.put') mock_put.return_value.status_code = status fn = self._create_file('qlog.bz2') item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) @@ -248,10 +244,10 @@ class TestAthenadMethods(unittest.TestCase): self._wait_for_upload() time.sleep(0.1) - self.assertEqual(athenad.upload_queue.qsize(), 1 if retry else 0) + assert athenad.upload_queue.qsize() == (1 if retry else 0) if retry: - self.assertEqual(athenad.upload_queue.get().retry_count, 1) + assert athenad.upload_queue.get().retry_count == 1 @with_upload_handler def test_upload_handler_timeout(self): @@ -265,33 +261,33 @@ class TestAthenadMethods(unittest.TestCase): time.sleep(0.1) # Check that upload with retry count exceeded is not put back - self.assertEqual(athenad.upload_queue.qsize(), 0) + assert athenad.upload_queue.qsize() == 0 athenad.upload_queue.put_nowait(item) self._wait_for_upload() time.sleep(0.1) # Check that upload item was put back in the queue with incremented retry count - self.assertEqual(athenad.upload_queue.qsize(), 1) - self.assertEqual(athenad.upload_queue.get().retry_count, 1) + assert athenad.upload_queue.qsize() == 1 + assert athenad.upload_queue.get().retry_count == 1 @with_upload_handler - def test_cancelUpload(self): + def test_cancel_upload(self): item = athenad.UploadItem(path="qlog.bz2", url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='id', allow_cellular=True) athenad.upload_queue.put_nowait(item) dispatcher["cancelUpload"](item.id) - self.assertIn(item.id, athenad.cancelled_uploads) + assert item.id in athenad.cancelled_uploads self._wait_for_upload() time.sleep(0.1) - self.assertEqual(athenad.upload_queue.qsize(), 0) - self.assertEqual(len(athenad.cancelled_uploads), 0) + assert athenad.upload_queue.qsize() == 0 + assert len(athenad.cancelled_uploads) == 0 @with_upload_handler - def test_cancelExpiry(self): + def test_cancel_expiry(self): t_future = datetime.now() - timedelta(days=40) ts = int(t_future.strftime("%s")) * 1000 @@ -303,15 +299,14 @@ class TestAthenadMethods(unittest.TestCase): self._wait_for_upload() time.sleep(0.1) - self.assertEqual(athenad.upload_queue.qsize(), 0) + assert athenad.upload_queue.qsize() == 0 - def test_listUploadQueueEmpty(self): + def test_list_upload_queue_empty(self): items = dispatcher["listUploadQueue"]() - self.assertEqual(len(items), 0) + assert len(items) == 0 - @with_http_server @with_upload_handler - def test_listUploadQueueCurrent(self, host: str): + def test_list_upload_queue_current(self, host: str): fn = self._create_file('qlog.bz2') item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) @@ -319,22 +314,22 @@ class TestAthenadMethods(unittest.TestCase): self._wait_for_upload() items = dispatcher["listUploadQueue"]() - self.assertEqual(len(items), 1) - self.assertTrue(items[0]['current']) + assert len(items) == 1 + assert items[0]['current'] - def test_listUploadQueue(self): + def test_list_upload_queue(self): item = athenad.UploadItem(path="qlog.bz2", url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='id', allow_cellular=True) athenad.upload_queue.put_nowait(item) items = dispatcher["listUploadQueue"]() - self.assertEqual(len(items), 1) - self.assertDictEqual(items[0], asdict(item)) - self.assertFalse(items[0]['current']) + assert len(items) == 1 + assert items[0] == asdict(item) + assert not items[0]['current'] athenad.cancelled_uploads.add(item.id) items = dispatcher["listUploadQueue"]() - self.assertEqual(len(items), 0) + assert len(items) == 0 def test_upload_queue_persistence(self): item1 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id1') @@ -353,11 +348,10 @@ class TestAthenadMethods(unittest.TestCase): athenad.upload_queue.queue.clear() athenad.UploadQueueCache.initialize(athenad.upload_queue) - self.assertEqual(athenad.upload_queue.qsize(), 1) - self.assertDictEqual(asdict(athenad.upload_queue.queue[-1]), asdict(item1)) + assert athenad.upload_queue.qsize() == 1 + assert asdict(athenad.upload_queue.queue[-1]) == asdict(item1) - @mock.patch('openpilot.selfdrive.athena.athenad.create_connection') - def test_startLocalProxy(self, mock_create_connection): + def test_start_local_proxy(self, mock_create_connection): end_event = threading.Event() ws_recv = queue.Queue() @@ -380,21 +374,21 @@ class TestAthenadMethods(unittest.TestCase): ws_recv.put_nowait(WebSocketConnectionClosedException()) socket_thread.join() - def test_getSshAuthorizedKeys(self): + def test_get_ssh_authorized_keys(self): keys = dispatcher["getSshAuthorizedKeys"]() - self.assertEqual(keys, self.default_params["GithubSshKeys"].decode('utf-8')) + assert keys == self.default_params["GithubSshKeys"].decode('utf-8') - def test_getGithubUsername(self): + def test_get_github_username(self): keys = dispatcher["getGithubUsername"]() - self.assertEqual(keys, self.default_params["GithubUsername"].decode('utf-8')) + assert keys == self.default_params["GithubUsername"].decode('utf-8') - def test_getVersion(self): + def test_get_version(self): resp = dispatcher["getVersion"]() keys = ["version", "remote", "branch", "commit"] - self.assertEqual(list(resp.keys()), keys) + assert list(resp.keys()) == keys for k in keys: - self.assertIsInstance(resp[k], str, f"{k} is not a string") - self.assertTrue(len(resp[k]) > 0, f"{k} has no value") + assert isinstance(resp[k], str), f"{k} is not a string" + assert len(resp[k]) > 0, f"{k} has no value" def test_jsonrpc_handler(self): end_event = threading.Event() @@ -405,15 +399,15 @@ class TestAthenadMethods(unittest.TestCase): # with params athenad.recv_queue.put_nowait(json.dumps({"method": "echo", "params": ["hello"], "jsonrpc": "2.0", "id": 0})) resp = athenad.send_queue.get(timeout=3) - self.assertDictEqual(json.loads(resp), {'result': 'hello', 'id': 0, 'jsonrpc': '2.0'}) + assert json.loads(resp) == {'result': 'hello', 'id': 0, 'jsonrpc': '2.0'} # without params athenad.recv_queue.put_nowait(json.dumps({"method": "getNetworkType", "jsonrpc": "2.0", "id": 0})) resp = athenad.send_queue.get(timeout=3) - self.assertDictEqual(json.loads(resp), {'result': 1, 'id': 0, 'jsonrpc': '2.0'}) + assert json.loads(resp) == {'result': 1, 'id': 0, 'jsonrpc': '2.0'} # log forwarding athenad.recv_queue.put_nowait(json.dumps({'result': {'success': 1}, 'id': 0, 'jsonrpc': '2.0'})) resp = athenad.log_recv_queue.get(timeout=3) - self.assertDictEqual(json.loads(resp), {'result': {'success': 1}, 'id': 0, 'jsonrpc': '2.0'}) + assert json.loads(resp) == {'result': {'success': 1}, 'id': 0, 'jsonrpc': '2.0'} finally: end_event.set() thread.join() @@ -427,8 +421,4 @@ class TestAthenadMethods(unittest.TestCase): # ensure the list is all logs except most recent sl = athenad.get_logs_to_send_sorted() - self.assertListEqual(sl, fl[:-1]) - - -if __name__ == '__main__': - unittest.main() + assert sl == fl[:-1] diff --git a/selfdrive/athena/tests/test_athenad_ping.py b/selfdrive/athena/tests/test_athenad_ping.py index f56fcac8b..44fa0b848 100755 --- a/selfdrive/athena/tests/test_athenad_ping.py +++ b/selfdrive/athena/tests/test_athenad_ping.py @@ -1,10 +1,9 @@ #!/usr/bin/env python3 +import pytest import subprocess import threading import time -import unittest from typing import cast -from unittest import mock from openpilot.common.params import Params from openpilot.common.timeout import Timeout @@ -22,7 +21,7 @@ def wifi_radio(on: bool) -> None: subprocess.run(["nmcli", "radio", "wifi", "on" if on else "off"], check=True) -class TestAthenadPing(unittest.TestCase): +class TestAthenadPing: params: Params dongle_id: str @@ -39,10 +38,10 @@ class TestAthenadPing(unittest.TestCase): return self._get_ping_time() is not None @classmethod - def tearDownClass(cls) -> None: + def teardown_class(cls) -> None: wifi_radio(True) - def setUp(self) -> None: + def setup_method(self) -> None: self.params = Params() self.dongle_id = self.params.get("DongleId", encoding="utf-8") @@ -52,21 +51,23 @@ class TestAthenadPing(unittest.TestCase): self.exit_event = threading.Event() self.athenad = threading.Thread(target=athenad.main, args=(self.exit_event,)) - def tearDown(self) -> None: + def teardown_method(self) -> None: if self.athenad.is_alive(): self.exit_event.set() self.athenad.join() - @mock.patch('openpilot.selfdrive.athena.athenad.create_connection', new_callable=lambda: mock.MagicMock(wraps=athenad.create_connection)) - def assertTimeout(self, reconnect_time: float, mock_create_connection: mock.MagicMock) -> None: + def assertTimeout(self, reconnect_time: float, subtests, mocker) -> None: self.athenad.start() + mock_create_connection = mocker.patch('openpilot.selfdrive.athena.athenad.create_connection', + new_callable=lambda: mocker.MagicMock(wraps=athenad.create_connection)) + time.sleep(1) mock_create_connection.assert_called_once() mock_create_connection.reset_mock() # check normal behaviour, server pings on connection - with self.subTest("Wi-Fi: receives ping"), Timeout(70, "no ping received"): + with subtests.test("Wi-Fi: receives ping"), Timeout(70, "no ping received"): while not self._received_ping(): time.sleep(0.1) print("ping received") @@ -74,7 +75,7 @@ class TestAthenadPing(unittest.TestCase): mock_create_connection.assert_not_called() # websocket should attempt reconnect after short time - with self.subTest("LTE: attempt reconnect"): + with subtests.test("LTE: attempt reconnect"): wifi_radio(False) print("waiting for reconnect attempt") start_time = time.monotonic() @@ -86,21 +87,17 @@ class TestAthenadPing(unittest.TestCase): self._clear_ping_time() # check ping received after reconnect - with self.subTest("LTE: receives ping"), Timeout(70, "no ping received"): + with subtests.test("LTE: receives ping"), Timeout(70, "no ping received"): while not self._received_ping(): time.sleep(0.1) print("ping received") - @unittest.skipIf(not TICI, "only run on desk") - def test_offroad(self) -> None: + @pytest.mark.skipif(not TICI, reason="only run on desk") + def test_offroad(self, subtests, mocker) -> None: write_onroad_params(False, self.params) - self.assertTimeout(60 + TIMEOUT_TOLERANCE) # based using TCP keepalive settings + self.assertTimeout(60 + TIMEOUT_TOLERANCE, subtests, mocker) # based using TCP keepalive settings - @unittest.skipIf(not TICI, "only run on desk") - def test_onroad(self) -> None: + @pytest.mark.skipif(not TICI, reason="only run on desk") + def test_onroad(self, subtests, mocker) -> None: write_onroad_params(True, self.params) - self.assertTimeout(21 + TIMEOUT_TOLERANCE) - - -if __name__ == "__main__": - unittest.main() + self.assertTimeout(21 + TIMEOUT_TOLERANCE, subtests, mocker) diff --git a/selfdrive/athena/tests/test_registration.py b/selfdrive/athena/tests/test_registration.py index e7ad63a37..a808dd566 100755 --- a/selfdrive/athena/tests/test_registration.py +++ b/selfdrive/athena/tests/test_registration.py @@ -1,9 +1,7 @@ #!/usr/bin/env python3 import json -import unittest from Crypto.PublicKey import RSA from pathlib import Path -from unittest import mock from openpilot.common.params import Params from openpilot.selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID @@ -11,9 +9,9 @@ from openpilot.selfdrive.athena.tests.helpers import MockResponse from openpilot.system.hardware.hw import Paths -class TestRegistration(unittest.TestCase): +class TestRegistration: - def setUp(self): + def setup_method(self): # clear params and setup key paths self.params = Params() self.params.clear_all() @@ -32,50 +30,46 @@ class TestRegistration(unittest.TestCase): with open(self.pub_key, "wb") as f: f.write(k.publickey().export_key()) - def test_valid_cache(self): + def test_valid_cache(self, mocker): # if all params are written, return the cached dongle id self.params.put("IMEI", "imei") self.params.put("HardwareSerial", "serial") self._generate_keys() - with mock.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) as m: - dongle = "DONGLE_ID_123" - self.params.put("DongleId", dongle) - self.assertEqual(register(), dongle) - self.assertFalse(m.called) + m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) + dongle = "DONGLE_ID_123" + self.params.put("DongleId", dongle) + assert register() == dongle + assert not m.called - def test_no_keys(self): + def test_no_keys(self, mocker): # missing pubkey - with mock.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) as m: - dongle = register() - self.assertEqual(m.call_count, 0) - self.assertEqual(dongle, UNREGISTERED_DONGLE_ID) - self.assertEqual(self.params.get("DongleId", encoding='utf-8'), dongle) + m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) + dongle = register() + assert m.call_count == 0 + assert dongle == UNREGISTERED_DONGLE_ID + assert self.params.get("DongleId", encoding='utf-8') == dongle - def test_missing_cache(self): + def test_missing_cache(self, mocker): # keys exist but no dongle id self._generate_keys() - with mock.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) as m: - dongle = "DONGLE_ID_123" - m.return_value = MockResponse(json.dumps({'dongle_id': dongle}), 200) - self.assertEqual(register(), dongle) - self.assertEqual(m.call_count, 1) + m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) + dongle = "DONGLE_ID_123" + m.return_value = MockResponse(json.dumps({'dongle_id': dongle}), 200) + assert register() == dongle + assert m.call_count == 1 - # call again, shouldn't hit the API this time - self.assertEqual(register(), dongle) - self.assertEqual(m.call_count, 1) - self.assertEqual(self.params.get("DongleId", encoding='utf-8'), dongle) + # call again, shouldn't hit the API this time + assert register() == dongle + assert m.call_count == 1 + assert self.params.get("DongleId", encoding='utf-8') == dongle - def test_unregistered(self): + def test_unregistered(self, mocker): # keys exist, but unregistered self._generate_keys() - with mock.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) as m: - m.return_value = MockResponse(None, 402) - dongle = register() - self.assertEqual(m.call_count, 1) - self.assertEqual(dongle, UNREGISTERED_DONGLE_ID) - self.assertEqual(self.params.get("DongleId", encoding='utf-8'), dongle) - - -if __name__ == "__main__": - unittest.main() + m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) + m.return_value = MockResponse(None, 402) + dongle = register() + assert m.call_count == 1 + assert dongle == UNREGISTERED_DONGLE_ID + assert self.params.get("DongleId", encoding='utf-8') == dongle diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index 3ab3a9c5b..fa9eb957c 100755 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -4,7 +4,6 @@ import copy import random import time import pytest -import unittest from collections import defaultdict from pprint import pprint @@ -107,7 +106,3 @@ class TestBoarddLoopback: pprint(sm['pandaStates']) # may drop messages due to RX buffer overflow for bus in sent_loopback.keys(): assert not len(sent_loopback[bus]), f"loop {i}: bus {bus} missing {len(sent_loopback[bus])} out of {sent_total[bus]} messages" - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/boardd/tests/test_pandad.py b/selfdrive/boardd/tests/test_pandad.py index 3434be3fe..65f3ad657 100755 --- a/selfdrive/boardd/tests/test_pandad.py +++ b/selfdrive/boardd/tests/test_pandad.py @@ -2,7 +2,6 @@ import os import pytest import time -import unittest import cereal.messaging as messaging from cereal import log @@ -16,16 +15,16 @@ HERE = os.path.dirname(os.path.realpath(__file__)) @pytest.mark.tici -class TestPandad(unittest.TestCase): +class TestPandad: - def setUp(self): + def setup_method(self): # ensure panda is up if len(Panda.list()) == 0: self._run_test(60) self.spi = HARDWARE.get_device_type() != 'tici' - def tearDown(self): + def teardown_method(self): managed_processes['pandad'].stop() def _run_test(self, timeout=30) -> float: @@ -65,7 +64,7 @@ class TestPandad(unittest.TestCase): assert Panda.wait_for_panda(None, 10) if expect_mismatch: - with self.assertRaises(PandaProtocolMismatch): + with pytest.raises(PandaProtocolMismatch): Panda() else: with Panda() as p: @@ -108,9 +107,10 @@ class TestPandad(unittest.TestCase): assert 0.1 < (sum(ts)/len(ts)) < (0.5 if self.spi else 5.0) print("startup times", ts, sum(ts) / len(ts)) + def test_protocol_version_check(self): if not self.spi: - raise unittest.SkipTest("SPI test") + pytest.skip("SPI test") # flash old fw fn = os.path.join(HERE, "bootstub.panda_h7_spiv0.bin") self._flash_bootstub_and_test(fn, expect_mismatch=True) @@ -127,7 +127,3 @@ class TestPandad(unittest.TestCase): self._assert_no_panda() self._run_test(60) - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/car/ford/tests/test_ford.py b/selfdrive/car/ford/tests/test_ford.py index 5d7b2c333..72dd69980 100755 --- a/selfdrive/car/ford/tests/test_ford.py +++ b/selfdrive/car/ford/tests/test_ford.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import random -import unittest from collections.abc import Iterable import capnp @@ -43,31 +42,31 @@ ECU_PART_NUMBER = { } -class TestFordFW(unittest.TestCase): +class TestFordFW: def test_fw_query_config(self): for (ecu, addr, subaddr) in FW_QUERY_CONFIG.extra_ecus: - self.assertIn(ecu, ECU_ADDRESSES, "Unknown ECU") - self.assertEqual(addr, ECU_ADDRESSES[ecu], "ECU address mismatch") - self.assertIsNone(subaddr, "Unexpected ECU subaddress") + assert ecu in ECU_ADDRESSES, "Unknown ECU" + assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch" + assert subaddr is None, "Unexpected ECU subaddress" @parameterized.expand(FW_VERSIONS.items()) def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[capnp.lib.capnp._EnumModule, int, int | None], Iterable[bytes]]): for (ecu, addr, subaddr), fws in fw_versions.items(): - self.assertIn(ecu, ECU_PART_NUMBER, "Unexpected ECU") - self.assertEqual(addr, ECU_ADDRESSES[ecu], "ECU address mismatch") - self.assertIsNone(subaddr, "Unexpected ECU subaddress") + assert ecu in ECU_PART_NUMBER, "Unexpected ECU" + assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch" + assert subaddr is None, "Unexpected ECU subaddress" for fw in fws: - self.assertEqual(len(fw), 24, "Expected ECU response to be 24 bytes") + assert len(fw) == 24, "Expected ECU response to be 24 bytes" match = FW_PATTERN.match(fw) - self.assertIsNotNone(match, f"Unable to parse FW: {fw!r}") + assert match is not None, f"Unable to parse FW: {fw!r}" if match: part_number = match.group("part_number") - self.assertIn(part_number, ECU_PART_NUMBER[ecu], f"Unexpected part number for {fw!r}") + assert part_number in ECU_PART_NUMBER[ecu], f"Unexpected part number for {fw!r}" codes = get_platform_codes([fw]) - self.assertEqual(1, len(codes), f"Unable to parse FW: {fw!r}") + assert 1 == len(codes), f"Unable to parse FW: {fw!r}" @settings(max_examples=100) @given(data=st.data()) @@ -85,7 +84,7 @@ class TestFordFW(unittest.TestCase): b"PJ6T-14H102-ABJ\x00\x00\x00\x00\x00\x00\x00\x00\x00", b"LB5A-14C204-EAC\x00\x00\x00\x00\x00\x00\x00\x00\x00", ]) - self.assertEqual(results, {(b"X6A", b"J"), (b"Z6T", b"N"), (b"J6T", b"P"), (b"B5A", b"L")}) + assert results == {(b"X6A", b"J"), (b"Z6T", b"N"), (b"J6T", b"P"), (b"B5A", b"L")} def test_fuzzy_match(self): for platform, fw_by_addr in FW_VERSIONS.items(): @@ -100,7 +99,7 @@ class TestFordFW(unittest.TestCase): CP = car.CarParams.new_message(carFw=car_fw) matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS) - self.assertEqual(matches, {platform}) + assert matches == {platform} def test_match_fw_fuzzy(self): offline_fw = { @@ -132,18 +131,14 @@ class TestFordFW(unittest.TestCase): (0x706, None): {b"LB5T-14F397-XX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}, } candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw}) - self.assertEqual(candidates, {expected_fingerprint}) + assert candidates == {expected_fingerprint} # model year hint in between the range should match live_fw[(0x706, None)] = {b"MB5T-14F397-XX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"} candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw,}) - self.assertEqual(candidates, {expected_fingerprint}) + assert candidates == {expected_fingerprint} # unseen model year hint should not match live_fw[(0x760, None)] = {b"M1MC-2D053-XX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"} candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw}) - self.assertEqual(len(candidates), 0, "Should not match new model year hint") - - -if __name__ == "__main__": - unittest.main() + assert len(candidates) == 0, "Should not match new model year hint" diff --git a/selfdrive/car/gm/tests/test_gm.py b/selfdrive/car/gm/tests/test_gm.py index 01ec8533b..389d0636c 100755 --- a/selfdrive/car/gm/tests/test_gm.py +++ b/selfdrive/car/gm/tests/test_gm.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 from parameterized import parameterized -import unittest from openpilot.selfdrive.car.gm.fingerprints import FINGERPRINTS from openpilot.selfdrive.car.gm.values import CAMERA_ACC_CAR, GM_RX_OFFSET @@ -8,19 +7,15 @@ from openpilot.selfdrive.car.gm.values import CAMERA_ACC_CAR, GM_RX_OFFSET CAMERA_DIAGNOSTIC_ADDRESS = 0x24b -class TestGMFingerprint(unittest.TestCase): +class TestGMFingerprint: @parameterized.expand(FINGERPRINTS.items()) def test_can_fingerprints(self, car_model, fingerprints): - self.assertGreater(len(fingerprints), 0) + assert len(fingerprints) > 0 - self.assertTrue(all(len(finger) for finger in fingerprints)) + assert all(len(finger) for finger in fingerprints) # The camera can sometimes be communicating on startup if car_model in CAMERA_ACC_CAR: for finger in fingerprints: for required_addr in (CAMERA_DIAGNOSTIC_ADDRESS, CAMERA_DIAGNOSTIC_ADDRESS + GM_RX_OFFSET): - self.assertEqual(finger.get(required_addr), 8, required_addr) - - -if __name__ == "__main__": - unittest.main() + assert finger.get(required_addr) == 8, required_addr diff --git a/selfdrive/car/honda/tests/test_honda.py b/selfdrive/car/honda/tests/test_honda.py index 60d91b84a..54d177d2e 100755 --- a/selfdrive/car/honda/tests/test_honda.py +++ b/selfdrive/car/honda/tests/test_honda.py @@ -1,20 +1,15 @@ #!/usr/bin/env python3 import re -import unittest from openpilot.selfdrive.car.honda.fingerprints import FW_VERSIONS HONDA_FW_VERSION_RE = br"[A-Z0-9]{5}-[A-Z0-9]{3}(-|,)[A-Z0-9]{4}(\x00){2}$" -class TestHondaFingerprint(unittest.TestCase): +class TestHondaFingerprint: def test_fw_version_format(self): # Asserts all FW versions follow an expected format for fw_by_ecu in FW_VERSIONS.values(): for fws in fw_by_ecu.values(): for fw in fws: - self.assertTrue(re.match(HONDA_FW_VERSION_RE, fw) is not None, fw) - - -if __name__ == "__main__": - unittest.main() + assert re.match(HONDA_FW_VERSION_RE, fw) is not None, fw diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index 0753b372e..db2110b0d 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from hypothesis import settings, given, strategies as st -import unittest + +import pytest from cereal import car from openpilot.selfdrive.car.fw_versions import build_fw_dict @@ -39,19 +40,19 @@ NO_DATES_PLATFORMS = { CANFD_EXPECTED_ECUS = {Ecu.fwdCamera, Ecu.fwdRadar} -class TestHyundaiFingerprint(unittest.TestCase): +class TestHyundaiFingerprint: def test_can_features(self): # Test no EV/HEV in any gear lists (should all use ELECT_GEAR) - self.assertEqual(set.union(*CAN_GEARS.values()) & (HYBRID_CAR | EV_CAR), set()) + assert set.union(*CAN_GEARS.values()) & (HYBRID_CAR | EV_CAR) == set() # Test CAN FD car not in CAN feature lists can_specific_feature_list = set.union(*CAN_GEARS.values(), *CHECKSUM.values(), LEGACY_SAFETY_MODE_CAR, UNSUPPORTED_LONGITUDINAL_CAR, CAMERA_SCC_CAR) for car_model in CANFD_CAR: - self.assertNotIn(car_model, can_specific_feature_list, "CAN FD car unexpectedly found in a CAN feature list") + assert car_model not in can_specific_feature_list, "CAN FD car unexpectedly found in a CAN feature list" def test_hybrid_ev_sets(self): - self.assertEqual(HYBRID_CAR & EV_CAR, set(), "Shared cars between hybrid and EV") - self.assertEqual(CANFD_CAR & HYBRID_CAR, set(), "Hard coding CAN FD cars as hybrid is no longer supported") + assert HYBRID_CAR & EV_CAR == set(), "Shared cars between hybrid and EV" + assert CANFD_CAR & HYBRID_CAR == set(), "Hard coding CAN FD cars as hybrid is no longer supported" def test_canfd_ecu_whitelist(self): # Asserts only expected Ecus can exist in database for CAN-FD cars @@ -59,34 +60,34 @@ class TestHyundaiFingerprint(unittest.TestCase): ecus = {fw[0] for fw in FW_VERSIONS[car_model].keys()} ecus_not_in_whitelist = ecus - CANFD_EXPECTED_ECUS ecu_strings = ", ".join([f"Ecu.{ECU_NAME[ecu]}" for ecu in ecus_not_in_whitelist]) - self.assertEqual(len(ecus_not_in_whitelist), 0, - f"{car_model}: Car model has unexpected ECUs: {ecu_strings}") + assert len(ecus_not_in_whitelist) == 0, \ + f"{car_model}: Car model has unexpected ECUs: {ecu_strings}" - def test_blacklisted_parts(self): + def test_blacklisted_parts(self, subtests): # Asserts no ECUs known to be shared across platforms exist in the database. # Tucson having Santa Cruz camera and EPS for example for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): if car_model == CAR.HYUNDAI_SANTA_CRUZ_1ST_GEN: - raise unittest.SkipTest("Skip checking Santa Cruz for its parts") + pytest.skip("Skip checking Santa Cruz for its parts") for code, _ in get_platform_codes(ecus[(Ecu.fwdCamera, 0x7c4, None)]): if b"-" not in code: continue part = code.split(b"-")[1] - self.assertFalse(part.startswith(b'CW'), "Car has bad part number") + assert not part.startswith(b'CW'), "Car has bad part number" - def test_correct_ecu_response_database(self): + def test_correct_ecu_response_database(self, subtests): """ Assert standard responses for certain ECUs, since they can respond to multiple queries with different data """ expected_fw_prefix = HYUNDAI_VERSION_REQUEST_LONG[1:] for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): for ecu, fws in ecus.items(): - self.assertTrue(all(fw.startswith(expected_fw_prefix) for fw in fws), - f"FW from unexpected request in database: {(ecu, fws)}") + assert all(fw.startswith(expected_fw_prefix) for fw in fws), \ + f"FW from unexpected request in database: {(ecu, fws)}" @settings(max_examples=100) @given(data=st.data()) @@ -96,10 +97,10 @@ class TestHyundaiFingerprint(unittest.TestCase): fws = data.draw(fw_strategy) get_platform_codes(fws) - def test_expected_platform_codes(self): + def test_expected_platform_codes(self, subtests): # Ensures we don't accidentally add multiple platform codes for a car unless it is intentional for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): for ecu, fws in ecus.items(): if ecu[0] not in PLATFORM_CODE_ECUS: continue @@ -107,37 +108,37 @@ class TestHyundaiFingerprint(unittest.TestCase): # Third and fourth character are usually EV/hybrid identifiers codes = {code.split(b"-")[0][:2] for code, _ in get_platform_codes(fws)} if car_model == CAR.HYUNDAI_PALISADE: - self.assertEqual(codes, {b"LX", b"ON"}, f"Car has unexpected platform codes: {car_model} {codes}") + assert codes == {b"LX", b"ON"}, f"Car has unexpected platform codes: {car_model} {codes}" elif car_model == CAR.HYUNDAI_KONA_EV and ecu[0] == Ecu.fwdCamera: - self.assertEqual(codes, {b"OE", b"OS"}, f"Car has unexpected platform codes: {car_model} {codes}") + assert codes == {b"OE", b"OS"}, f"Car has unexpected platform codes: {car_model} {codes}" else: - self.assertEqual(len(codes), 1, f"Car has multiple platform codes: {car_model} {codes}") + assert len(codes) == 1, f"Car has multiple platform codes: {car_model} {codes}" # Tests for platform codes, part numbers, and FW dates which Hyundai will use to fuzzy # fingerprint in the absence of full FW matches: - def test_platform_code_ecus_available(self): + def test_platform_code_ecus_available(self, subtests): # TODO: add queries for these non-CAN FD cars to get EPS no_eps_platforms = CANFD_CAR | {CAR.KIA_SORENTO, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL, CAR.HYUNDAI_SONATA_LF, CAR.HYUNDAI_TUCSON, CAR.GENESIS_G90, CAR.GENESIS_G80, CAR.HYUNDAI_ELANTRA} # Asserts ECU keys essential for fuzzy fingerprinting are available on all platforms for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): for platform_code_ecu in PLATFORM_CODE_ECUS: if platform_code_ecu in (Ecu.fwdRadar, Ecu.eps) and car_model == CAR.HYUNDAI_GENESIS: continue if platform_code_ecu == Ecu.eps and car_model in no_eps_platforms: continue - self.assertIn(platform_code_ecu, [e[0] for e in ecus]) + assert platform_code_ecu in [e[0] for e in ecus] - def test_fw_format(self): + def test_fw_format(self, subtests): # Asserts: # - every supported ECU FW version returns one platform code # - every supported ECU FW version has a part number # - expected parsing of ECU FW dates for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): for ecu, fws in ecus.items(): if ecu[0] not in PLATFORM_CODE_ECUS: continue @@ -145,40 +146,40 @@ class TestHyundaiFingerprint(unittest.TestCase): codes = set() for fw in fws: result = get_platform_codes([fw]) - self.assertEqual(1, len(result), f"Unable to parse FW: {fw}") + assert 1 == len(result), f"Unable to parse FW: {fw}" codes |= result if ecu[0] not in DATE_FW_ECUS or car_model in NO_DATES_PLATFORMS: - self.assertTrue(all(date is None for _, date in codes)) + assert all(date is None for _, date in codes) else: - self.assertTrue(all(date is not None for _, date in codes)) + assert all(date is not None for _, date in codes) if car_model == CAR.HYUNDAI_GENESIS: - raise unittest.SkipTest("No part numbers for car model") + pytest.skip("No part numbers for car model") # Hyundai places the ECU part number in their FW versions, assert all parsable # Some examples of valid formats: b"56310-L0010", b"56310L0010", b"56310/M6300" - self.assertTrue(all(b"-" in code for code, _ in codes), - f"FW does not have part number: {fw}") + assert all(b"-" in code for code, _ in codes), \ + f"FW does not have part number: {fw}" def test_platform_codes_spot_check(self): # Asserts basic platform code parsing behavior for a few cases results = get_platform_codes([b"\xf1\x00DH LKAS 1.1 -150210"]) - self.assertEqual(results, {(b"DH", b"150210")}) + assert results == {(b"DH", b"150210")} # Some cameras and all radars do not have dates results = get_platform_codes([b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 "]) - self.assertEqual(results, {(b"AEhe-G2000", None)}) + assert results == {(b"AEhe-G2000", None)} results = get_platform_codes([b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 "]) - self.assertEqual(results, {(b"CV1-CV000", None)}) + assert results == {(b"CV1-CV000", None)} results = get_platform_codes([ b"\xf1\x00DH LKAS 1.1 -150210", b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ", b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ", ]) - self.assertEqual(results, {(b"DH", b"150210"), (b"AEhe-G2000", None), (b"CV1-CV000", None)}) + assert results == {(b"DH", b"150210"), (b"AEhe-G2000", None), (b"CV1-CV000", None)} results = get_platform_codes([ b"\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222", @@ -186,8 +187,8 @@ class TestHyundaiFingerprint(unittest.TestCase): b"\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405", b"\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 190720", ]) - self.assertEqual(results, {(b"LX2-S8100", b"220222"), (b"LX2-S8100", b"211103"), - (b"ON-S9100", b"190405"), (b"ON-S9100", b"190720")}) + assert results == {(b"LX2-S8100", b"220222"), (b"LX2-S8100", b"211103"), + (b"ON-S9100", b"190405"), (b"ON-S9100", b"190720")} def test_fuzzy_excluded_platforms(self): # Asserts a list of platforms that will not fuzzy fingerprint with platform codes due to them being shared. @@ -211,12 +212,8 @@ class TestHyundaiFingerprint(unittest.TestCase): CP = car.CarParams.new_message(carFw=car_fw) matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS) if len(matches) == 1: - self.assertEqual(list(matches)[0], platform) + assert list(matches)[0] == platform else: platforms_with_shared_codes.add(platform) - self.assertEqual(platforms_with_shared_codes, excluded_platforms) - - -if __name__ == "__main__": - unittest.main() + assert platforms_with_shared_codes == excluded_platforms diff --git a/selfdrive/car/subaru/tests/test_subaru.py b/selfdrive/car/subaru/tests/test_subaru.py index c8cdf6606..33040442b 100644 --- a/selfdrive/car/subaru/tests/test_subaru.py +++ b/selfdrive/car/subaru/tests/test_subaru.py @@ -1,5 +1,4 @@ from cereal import car -import unittest from openpilot.selfdrive.car.subaru.fingerprints import FW_VERSIONS Ecu = car.CarParams.Ecu @@ -7,14 +6,11 @@ Ecu = car.CarParams.Ecu ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} -class TestSubaruFingerprint(unittest.TestCase): +class TestSubaruFingerprint: def test_fw_version_format(self): for platform, fws_per_ecu in FW_VERSIONS.items(): for (ecu, _, _), fws in fws_per_ecu.items(): fw_size = len(fws[0]) for fw in fws: - self.assertEqual(len(fw), fw_size, f"{platform} {ecu}: {len(fw)} {fw_size}") + assert len(fw) == fw_size, f"{platform} {ecu}: {len(fw)} {fw_size}" - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/car/tests/test_can_fingerprint.py b/selfdrive/car/tests/test_can_fingerprint.py index 8df700733..bb585d567 100755 --- a/selfdrive/car/tests/test_can_fingerprint.py +++ b/selfdrive/car/tests/test_can_fingerprint.py @@ -1,13 +1,12 @@ #!/usr/bin/env python3 from parameterized import parameterized -import unittest from cereal import log, messaging from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, can_fingerprint from openpilot.selfdrive.car.fingerprints import _FINGERPRINTS as FINGERPRINTS -class TestCanFingerprint(unittest.TestCase): +class TestCanFingerprint: @parameterized.expand(list(FINGERPRINTS.items())) def test_can_fingerprint(self, car_model, fingerprints): """Tests online fingerprinting function on offline fingerprints""" @@ -21,12 +20,12 @@ class TestCanFingerprint(unittest.TestCase): empty_can = messaging.new_message('can', 0) car_fingerprint, finger = can_fingerprint(lambda: next(fingerprint_iter, empty_can)) # noqa: B023 - self.assertEqual(car_fingerprint, car_model) - self.assertEqual(finger[0], fingerprint) - self.assertEqual(finger[1], fingerprint) - self.assertEqual(finger[2], {}) + assert car_fingerprint == car_model + assert finger[0] == fingerprint + assert finger[1] == fingerprint + assert finger[2] == {} - def test_timing(self): + def test_timing(self, subtests): # just pick any CAN fingerprinting car car_model = "CHEVROLET_BOLT_EUV" fingerprint = FINGERPRINTS[car_model][0] @@ -50,7 +49,7 @@ class TestCanFingerprint(unittest.TestCase): cases.append((FRAME_FINGERPRINT * 2, None, can)) for expected_frames, car_model, can in cases: - with self.subTest(expected_frames=expected_frames, car_model=car_model): + with subtests.test(expected_frames=expected_frames, car_model=car_model): frames = 0 def test(): @@ -59,9 +58,5 @@ class TestCanFingerprint(unittest.TestCase): return can # noqa: B023 car_fingerprint, _ = can_fingerprint(test) - self.assertEqual(car_fingerprint, car_model) - self.assertEqual(frames, expected_frames + 2) # TODO: fix extra frames - - -if __name__ == "__main__": - unittest.main() + assert car_fingerprint == car_model + assert frames == expected_frames + 2# TODO: fix extra frames diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index dfcd9b052..4bbecd99f 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import os import math -import unittest import hypothesis.strategies as st from hypothesis import Phase, given, settings import importlib @@ -45,7 +44,7 @@ def get_fuzzy_car_interface_args(draw: DrawType) -> dict: return params -class TestCarInterfaces(unittest.TestCase): +class TestCarInterfaces: # FIXME: Due to the lists used in carParams, Phase.target is very slow and will cause # many generated examples to overrun when max_examples > ~20, don't use it @parameterized.expand([(car,) for car in sorted(all_known_cars())]) @@ -63,28 +62,28 @@ class TestCarInterfaces(unittest.TestCase): assert car_params assert car_interface - self.assertGreater(car_params.mass, 1) - self.assertGreater(car_params.wheelbase, 0) + assert car_params.mass > 1 + assert car_params.wheelbase > 0 # centerToFront is center of gravity to front wheels, assert a reasonable range - self.assertTrue(car_params.wheelbase * 0.3 < car_params.centerToFront < car_params.wheelbase * 0.7) - self.assertGreater(car_params.maxLateralAccel, 0) + assert car_params.wheelbase * 0.3 < car_params.centerToFront < car_params.wheelbase * 0.7 + assert car_params.maxLateralAccel > 0 # Longitudinal sanity checks - self.assertEqual(len(car_params.longitudinalTuning.kpV), len(car_params.longitudinalTuning.kpBP)) - self.assertEqual(len(car_params.longitudinalTuning.kiV), len(car_params.longitudinalTuning.kiBP)) - self.assertEqual(len(car_params.longitudinalTuning.deadzoneV), len(car_params.longitudinalTuning.deadzoneBP)) + assert len(car_params.longitudinalTuning.kpV) == len(car_params.longitudinalTuning.kpBP) + assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP) + assert len(car_params.longitudinalTuning.deadzoneV) == len(car_params.longitudinalTuning.deadzoneBP) # Lateral sanity checks if car_params.steerControlType != car.CarParams.SteerControlType.angle: tune = car_params.lateralTuning if tune.which() == 'pid': - self.assertTrue(not math.isnan(tune.pid.kf) and tune.pid.kf > 0) - self.assertTrue(len(tune.pid.kpV) > 0 and len(tune.pid.kpV) == len(tune.pid.kpBP)) - self.assertTrue(len(tune.pid.kiV) > 0 and len(tune.pid.kiV) == len(tune.pid.kiBP)) + assert not math.isnan(tune.pid.kf) and tune.pid.kf > 0 + assert len(tune.pid.kpV) > 0 and len(tune.pid.kpV) == len(tune.pid.kpBP) + assert len(tune.pid.kiV) > 0 and len(tune.pid.kiV) == len(tune.pid.kiBP) elif tune.which() == 'torque': - self.assertTrue(not math.isnan(tune.torque.kf) and tune.torque.kf > 0) - self.assertTrue(not math.isnan(tune.torque.friction) and tune.torque.friction > 0) + assert not math.isnan(tune.torque.kf) and tune.torque.kf > 0 + assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0 cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True) # Run car interface @@ -128,33 +127,29 @@ class TestCarInterfaces(unittest.TestCase): if not car_params.radarUnavailable and radar_interface.rcp is not None: cans = [messaging.new_message('can', 1).to_bytes() for _ in range(5)] rr = radar_interface.update(cans) - self.assertTrue(rr is None or len(rr.errors) > 0) + assert rr is None or len(rr.errors) > 0 def test_interface_attrs(self): """Asserts basic behavior of interface attribute getter""" num_brands = len(get_interface_attr('CAR')) - self.assertGreaterEqual(num_brands, 13) + assert num_brands >= 13 # Should return value for all brands when not combining, even if attribute doesn't exist ret = get_interface_attr('FAKE_ATTR') - self.assertEqual(len(ret), num_brands) + assert len(ret) == num_brands # Make sure we can combine dicts ret = get_interface_attr('DBC', combine_brands=True) - self.assertGreaterEqual(len(ret), 160) + assert len(ret) >= 160 # We don't support combining non-dicts ret = get_interface_attr('CAR', combine_brands=True) - self.assertEqual(len(ret), 0) + assert len(ret) == 0 # If brand has None value, it shouldn't return when ignore_none=True is specified none_brands = {b for b, v in get_interface_attr('FINGERPRINTS').items() if v is None} - self.assertGreaterEqual(len(none_brands), 1) + assert len(none_brands) >= 1 ret = get_interface_attr('FINGERPRINTS', ignore_none=True) none_brands_in_ret = none_brands.intersection(ret) - self.assertEqual(len(none_brands_in_ret), 0, f'Brands with None values in ignore_none=True result: {none_brands_in_ret}') - - -if __name__ == "__main__": - unittest.main() + assert len(none_brands_in_ret) == 0, f'Brands with None values in ignore_none=True result: {none_brands_in_ret}' diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py index 143b402d5..0ed95e18f 100755 --- a/selfdrive/car/tests/test_docs.py +++ b/selfdrive/car/tests/test_docs.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 from collections import defaultdict import os +import pytest import re -import unittest from openpilot.common.basedir import BASEDIR from openpilot.selfdrive.car.car_helpers import interfaces @@ -14,9 +14,9 @@ from openpilot.selfdrive.debug.dump_car_docs import dump_car_docs from openpilot.selfdrive.debug.print_docs_diff import print_car_docs_diff -class TestCarDocs(unittest.TestCase): +class TestCarDocs: @classmethod - def setUpClass(cls): + def setup_class(cls): cls.all_cars = get_all_car_docs() def test_generator(self): @@ -24,8 +24,7 @@ class TestCarDocs(unittest.TestCase): with open(CARS_MD_OUT) as f: current_cars_md = f.read() - self.assertEqual(generated_cars_md, current_cars_md, - "Run selfdrive/car/docs.py to update the compatibility documentation") + assert generated_cars_md == current_cars_md, "Run selfdrive/car/docs.py to update the compatibility documentation" def test_docs_diff(self): dump_path = os.path.join(BASEDIR, "selfdrive", "car", "tests", "cars_dump") @@ -33,65 +32,61 @@ class TestCarDocs(unittest.TestCase): print_car_docs_diff(dump_path) os.remove(dump_path) - def test_duplicate_years(self): + def test_duplicate_years(self, subtests): make_model_years = defaultdict(list) for car in self.all_cars: - with self.subTest(car_docs_name=car.name): + with subtests.test(car_docs_name=car.name): make_model = (car.make, car.model) for year in car.year_list: - self.assertNotIn(year, make_model_years[make_model], f"{car.name}: Duplicate model year") + assert year not in make_model_years[make_model], f"{car.name}: Duplicate model year" make_model_years[make_model].append(year) - def test_missing_car_docs(self): + def test_missing_car_docs(self, subtests): all_car_docs_platforms = [name for name, config in PLATFORMS.items()] for platform in sorted(interfaces.keys()): - with self.subTest(platform=platform): - self.assertTrue(platform in all_car_docs_platforms, f"Platform: {platform} doesn't have a CarDocs entry") + with subtests.test(platform=platform): + assert platform in all_car_docs_platforms, f"Platform: {platform} doesn't have a CarDocs entry" - def test_naming_conventions(self): + def test_naming_conventions(self, subtests): # Asserts market-standard car naming conventions by brand for car in self.all_cars: - with self.subTest(car=car): + with subtests.test(car=car.name): tokens = car.model.lower().split(" ") if car.car_name == "hyundai": - self.assertNotIn("phev", tokens, "Use `Plug-in Hybrid`") - self.assertNotIn("hev", tokens, "Use `Hybrid`") + assert "phev" not in tokens, "Use `Plug-in Hybrid`" + assert "hev" not in tokens, "Use `Hybrid`" if "plug-in hybrid" in car.model.lower(): - self.assertIn("Plug-in Hybrid", car.model, "Use correct capitalization") + assert "Plug-in Hybrid" in car.model, "Use correct capitalization" if car.make != "Kia": - self.assertNotIn("ev", tokens, "Use `Electric`") + assert "ev" not in tokens, "Use `Electric`" elif car.car_name == "toyota": if "rav4" in tokens: - self.assertIn("RAV4", car.model, "Use correct capitalization") + assert "RAV4" in car.model, "Use correct capitalization" - def test_torque_star(self): + def test_torque_star(self, subtests): # Asserts brand-specific assumptions around steering torque star for car in self.all_cars: - with self.subTest(car=car): + 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): - self.assertEqual(car.row[Column.STEERING_TORQUE], Star.EMPTY, f"{car.name} has full torque star") + assert car.row[Column.STEERING_TORQUE] == Star.EMPTY, f"{car.name} has full torque star" elif car.car_name in ("toyota", "hyundai"): - self.assertNotEqual(car.row[Column.STEERING_TORQUE], Star.EMPTY, f"{car.name} has no torque star") + assert car.row[Column.STEERING_TORQUE] != Star.EMPTY, f"{car.name} has no torque star" - def test_year_format(self): + def test_year_format(self, subtests): for car in self.all_cars: - with self.subTest(car=car): - self.assertIsNone(re.search(r"\d{4}-\d{4}", car.name), f"Format years correctly: {car.name}") + with subtests.test(car=car.name): + assert re.search(r"\d{4}-\d{4}", car.name) is None, f"Format years correctly: {car.name}" - def test_harnesses(self): + def test_harnesses(self, subtests): for car in self.all_cars: - with self.subTest(car=car): + with subtests.test(car=car.name): if car.name == "comma body": - raise unittest.SkipTest + pytest.skip() car_part_type = [p.part_type for p in car.car_parts.all_parts()] car_parts = list(car.car_parts.all_parts()) - self.assertTrue(len(car_parts) > 0, f"Need to specify car parts: {car.name}") - self.assertTrue(car_part_type.count(PartType.connector) == 1, f"Need to specify one harness connector: {car.name}") - self.assertTrue(car_part_type.count(PartType.mount) == 1, f"Need to specify one mount: {car.name}") - self.assertTrue(Cable.right_angle_obd_c_cable_1_5ft in car_parts, f"Need to specify a right angle OBD-C cable (1.5ft): {car.name}") - - -if __name__ == "__main__": - unittest.main() + assert len(car_parts) > 0, f"Need to specify car parts: {car.name}" + assert car_part_type.count(PartType.connector) == 1, f"Need to specify one harness connector: {car.name}" + assert car_part_type.count(PartType.mount) == 1, f"Need to specify one mount: {car.name}" + assert Cable.right_angle_obd_c_cable_1_5ft in car_parts, f"Need to specify a right angle OBD-C cable (1.5ft): {car.name}" diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index ed5edbef3..230e6f10e 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -1,10 +1,9 @@ #!/usr/bin/env python3 +import pytest import random import time -import unittest from collections import defaultdict from parameterized import parameterized -from unittest import mock from cereal import car from openpilot.selfdrive.car.car_helpers import interfaces @@ -27,11 +26,11 @@ class FakeSocket: pass -class TestFwFingerprint(unittest.TestCase): +class TestFwFingerprint: def assertFingerprints(self, candidates, expected): candidates = list(candidates) - self.assertEqual(len(candidates), 1, f"got more than one candidate: {candidates}") - self.assertEqual(candidates[0], expected) + assert len(candidates) == 1, f"got more than one candidate: {candidates}" + assert candidates[0] == expected @parameterized.expand([(b, c, e[c], n) for b, e in VERSIONS.items() for c in e for n in (True, False)]) def test_exact_match(self, brand, car_model, ecus, test_non_essential): @@ -62,7 +61,7 @@ class TestFwFingerprint(unittest.TestCase): # Assert brand-specific fuzzy fingerprinting function doesn't disagree with standard fuzzy function config = FW_QUERY_CONFIGS[brand] if config.match_fw_to_car_fuzzy is None: - raise unittest.SkipTest("Brand does not implement custom fuzzy fingerprinting function") + pytest.skip("Brand does not implement custom fuzzy fingerprinting function") CP = car.CarParams.new_message() for _ in range(5): @@ -77,14 +76,14 @@ class TestFwFingerprint(unittest.TestCase): # If both have matches, they must agree if len(matches) == 1 and len(brand_matches) == 1: - self.assertEqual(matches, brand_matches) + assert matches == brand_matches @parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e]) def test_fuzzy_match_ecu_count(self, brand, car_model, ecus): # Asserts that fuzzy matching does not count matching FW, but ECU address keys valid_ecus = [e for e in ecus if e[0] not in FUZZY_EXCLUDE_ECUS] if not len(valid_ecus): - raise unittest.SkipTest("Car model has no compatible ECUs for fuzzy matching") + pytest.skip("Car model has no compatible ECUs for fuzzy matching") fw = [] for ecu in valid_ecus: @@ -99,19 +98,19 @@ class TestFwFingerprint(unittest.TestCase): # Assert no match if there are not enough unique ECUs unique_ecus = {(f['address'], f['subAddress']) for f in fw} if len(unique_ecus) < 2: - self.assertEqual(len(matches), 0, car_model) + assert len(matches) == 0, car_model # There won't always be a match due to shared FW, but if there is it should be correct elif len(matches): self.assertFingerprints(matches, car_model) - def test_fw_version_lists(self): + def test_fw_version_lists(self, subtests): for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): for ecu, ecu_fw in ecus.items(): - with self.subTest(ecu): + with subtests.test(ecu): duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1} - self.assertFalse(len(duplicates), f'{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}') - self.assertGreater(len(ecu_fw), 0, f'{car_model}: No FW versions: Ecu.{ECU_NAME[ecu[0]]}') + assert not len(duplicates), f'{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}' + assert len(ecu_fw) > 0, f'{car_model}: No FW versions: Ecu.{ECU_NAME[ecu[0]]}' def test_all_addrs_map_to_one_ecu(self): for brand, cars in VERSIONS.items(): @@ -121,59 +120,59 @@ class TestFwFingerprint(unittest.TestCase): addr_to_ecu[(addr, sub_addr)].add(ecu_type) ecus_for_addr = addr_to_ecu[(addr, sub_addr)] ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_for_addr]) - self.assertLessEqual(len(ecus_for_addr), 1, f"{brand} has multiple ECUs that map to one address: {ecu_strings} -> ({hex(addr)}, {sub_addr})") + assert len(ecus_for_addr) <= 1, f"{brand} has multiple ECUs that map to one address: {ecu_strings} -> ({hex(addr)}, {sub_addr})" - def test_data_collection_ecus(self): + def test_data_collection_ecus(self, subtests): # Asserts no extra ECUs are in the fingerprinting database for brand, config in FW_QUERY_CONFIGS.items(): for car_model, ecus in VERSIONS[brand].items(): bad_ecus = set(ecus).intersection(config.extra_ecus) - with self.subTest(car_model=car_model.value): - self.assertFalse(len(bad_ecus), f'{car_model}: Fingerprints contain ECUs added for data collection: {bad_ecus}') + with subtests.test(car_model=car_model.value): + assert not len(bad_ecus), f'{car_model}: Fingerprints contain ECUs added for data collection: {bad_ecus}' - def test_blacklisted_ecus(self): + def test_blacklisted_ecus(self, subtests): blacklisted_addrs = (0x7c4, 0x7d0) # includes A/C ecu and an unknown ecu for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): CP = interfaces[car_model][0].get_non_essential_params(car_model) if CP.carName == 'subaru': for ecu in ecus.keys(): - self.assertNotIn(ecu[1], blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})') + assert ecu[1] not in blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})' elif CP.carName == "chrysler": # Some HD trucks have a combined TCM and ECM if CP.carFingerprint.startswith("RAM HD"): for ecu in ecus.keys(): - self.assertNotEqual(ecu[0], Ecu.transmission, f"{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})") + assert ecu[0] != Ecu.transmission, f"{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})" - def test_non_essential_ecus(self): + def test_non_essential_ecus(self, subtests): for brand, config in FW_QUERY_CONFIGS.items(): - with self.subTest(brand): + with subtests.test(brand): # These ECUs are already not in ESSENTIAL_ECUS which the fingerprint functions give a pass if missing unnecessary_non_essential_ecus = set(config.non_essential_ecus) - set(ESSENTIAL_ECUS) - self.assertEqual(unnecessary_non_essential_ecus, set(), "Declaring non-essential ECUs non-essential is not required: " + - f"{', '.join([f'Ecu.{ECU_NAME[ecu]}' for ecu in unnecessary_non_essential_ecus])}") + assert unnecessary_non_essential_ecus == set(), "Declaring non-essential ECUs non-essential is not required: " + \ + f"{', '.join([f'Ecu.{ECU_NAME[ecu]}' for ecu in unnecessary_non_essential_ecus])}" - def test_missing_versions_and_configs(self): + def test_missing_versions_and_configs(self, subtests): brand_versions = set(VERSIONS.keys()) brand_configs = set(FW_QUERY_CONFIGS.keys()) if len(brand_configs - brand_versions): - with self.subTest(): - self.fail(f"Brands do not implement FW_VERSIONS: {brand_configs - brand_versions}") + with subtests.test(): + pytest.fail(f"Brands do not implement FW_VERSIONS: {brand_configs - brand_versions}") if len(brand_versions - brand_configs): - with self.subTest(): - self.fail(f"Brands do not implement FW_QUERY_CONFIG: {brand_versions - brand_configs}") + with subtests.test(): + pytest.fail(f"Brands do not implement FW_QUERY_CONFIG: {brand_versions - brand_configs}") # Ensure each brand has at least 1 ECU to query, and extra ECU retrieval for brand, config in FW_QUERY_CONFIGS.items(): - self.assertEqual(len(config.get_all_ecus({}, include_extra_ecus=False)), 0) - self.assertEqual(config.get_all_ecus({}), set(config.extra_ecus)) - self.assertGreater(len(config.get_all_ecus(VERSIONS[brand])), 0) + assert len(config.get_all_ecus({}, include_extra_ecus=False)) == 0 + assert config.get_all_ecus({}) == set(config.extra_ecus) + assert len(config.get_all_ecus(VERSIONS[brand])) > 0 - def test_fw_request_ecu_whitelist(self): + def test_fw_request_ecu_whitelist(self, subtests): for brand, config in FW_QUERY_CONFIGS.items(): - with self.subTest(brand=brand): + with subtests.test(brand=brand): whitelisted_ecus = {ecu for r in config.requests for ecu in r.whitelist_ecus} brand_ecus = {fw[0] for car_fw in VERSIONS[brand].values() for fw in car_fw} brand_ecus |= {ecu[0] for ecu in config.extra_ecus} @@ -182,30 +181,30 @@ class TestFwFingerprint(unittest.TestCase): ecus_not_whitelisted = brand_ecus - whitelisted_ecus ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_whitelisted]) - self.assertFalse(len(whitelisted_ecus) and len(ecus_not_whitelisted), - f'{brand.title()}: ECUs not in any FW query whitelists: {ecu_strings}') + assert not (len(whitelisted_ecus) and len(ecus_not_whitelisted)), \ + f'{brand.title()}: ECUs not in any FW query whitelists: {ecu_strings}' - def test_fw_requests(self): + def test_fw_requests(self, subtests): # Asserts equal length request and response lists for brand, config in FW_QUERY_CONFIGS.items(): - with self.subTest(brand=brand): + with subtests.test(brand=brand): for request_obj in config.requests: - self.assertEqual(len(request_obj.request), len(request_obj.response)) + assert len(request_obj.request) == len(request_obj.response) # No request on the OBD port (bus 1, multiplexed) should be run on an aux panda - self.assertFalse(request_obj.auxiliary and request_obj.bus == 1 and request_obj.obd_multiplexing, - f"{brand.title()}: OBD multiplexed request is marked auxiliary: {request_obj}") + assert not (request_obj.auxiliary and request_obj.bus == 1 and request_obj.obd_multiplexing), \ + f"{brand.title()}: OBD multiplexed request is marked auxiliary: {request_obj}" def test_brand_ecu_matches(self): empty_response = {brand: set() for brand in FW_QUERY_CONFIGS} - self.assertEqual(get_brand_ecu_matches(set()), empty_response) + assert get_brand_ecu_matches(set()) == empty_response # we ignore bus expected_response = empty_response | {'toyota': {(0x750, 0xf)}} - self.assertEqual(get_brand_ecu_matches({(0x758, 0xf, 99)}), expected_response) + assert get_brand_ecu_matches({(0x758, 0xf, 99)}) == expected_response -class TestFwFingerprintTiming(unittest.TestCase): +class TestFwFingerprintTiming: N: int = 5 TOL: float = 0.05 @@ -223,26 +222,26 @@ class TestFwFingerprintTiming(unittest.TestCase): self.total_time += timeout return {} - def _benchmark_brand(self, brand, num_pandas): + def _benchmark_brand(self, brand, num_pandas, mocker): fake_socket = FakeSocket() self.total_time = 0 - with (mock.patch("openpilot.selfdrive.car.fw_versions.set_obd_multiplexing", self.fake_set_obd_multiplexing), - mock.patch("openpilot.selfdrive.car.isotp_parallel_query.IsoTpParallelQuery.get_data", self.fake_get_data)): - for _ in range(self.N): - # Treat each brand as the most likely (aka, the first) brand with OBD multiplexing initially on - self.current_obd_multiplexing = True + mocker.patch("openpilot.selfdrive.car.fw_versions.set_obd_multiplexing", self.fake_set_obd_multiplexing) + mocker.patch("openpilot.selfdrive.car.isotp_parallel_query.IsoTpParallelQuery.get_data", self.fake_get_data) + for _ in range(self.N): + # Treat each brand as the most likely (aka, the first) brand with OBD multiplexing initially on + self.current_obd_multiplexing = True - t = time.perf_counter() - get_fw_versions(fake_socket, fake_socket, brand, num_pandas=num_pandas) - self.total_time += time.perf_counter() - t + t = time.perf_counter() + get_fw_versions(fake_socket, fake_socket, brand, num_pandas=num_pandas) + self.total_time += time.perf_counter() - t return self.total_time / self.N def _assert_timing(self, avg_time, ref_time): - self.assertLess(avg_time, ref_time + self.TOL) - self.assertGreater(avg_time, ref_time - self.TOL, "Performance seems to have improved, update test refs.") + assert avg_time < ref_time + self.TOL + assert avg_time > ref_time - self.TOL, "Performance seems to have improved, update test refs." - def test_startup_timing(self): + def test_startup_timing(self, subtests, mocker): # Tests worse-case VIN query time and typical present ECU query time vin_ref_times = {'worst': 1.4, 'best': 0.7} # best assumes we go through all queries to get a match present_ecu_ref_time = 0.45 @@ -253,24 +252,24 @@ class TestFwFingerprintTiming(unittest.TestCase): fake_socket = FakeSocket() self.total_time = 0.0 - with (mock.patch("openpilot.selfdrive.car.fw_versions.set_obd_multiplexing", self.fake_set_obd_multiplexing), - mock.patch("openpilot.selfdrive.car.fw_versions.get_ecu_addrs", fake_get_ecu_addrs)): - for _ in range(self.N): - self.current_obd_multiplexing = True - get_present_ecus(fake_socket, fake_socket, num_pandas=2) + mocker.patch("openpilot.selfdrive.car.fw_versions.set_obd_multiplexing", self.fake_set_obd_multiplexing) + mocker.patch("openpilot.selfdrive.car.fw_versions.get_ecu_addrs", fake_get_ecu_addrs) + for _ in range(self.N): + self.current_obd_multiplexing = True + get_present_ecus(fake_socket, fake_socket, num_pandas=2) self._assert_timing(self.total_time / self.N, present_ecu_ref_time) print(f'get_present_ecus, query time={self.total_time / self.N} seconds') for name, args in (('worst', {}), ('best', {'retry': 1})): - with self.subTest(name=name): + with subtests.test(name=name): self.total_time = 0.0 - with (mock.patch("openpilot.selfdrive.car.isotp_parallel_query.IsoTpParallelQuery.get_data", self.fake_get_data)): - for _ in range(self.N): - get_vin(fake_socket, fake_socket, (0, 1), **args) + mocker.patch("openpilot.selfdrive.car.isotp_parallel_query.IsoTpParallelQuery.get_data", self.fake_get_data) + for _ in range(self.N): + get_vin(fake_socket, fake_socket, (0, 1), **args) self._assert_timing(self.total_time / self.N, vin_ref_times[name]) print(f'get_vin {name} case, query time={self.total_time / self.N} seconds') - def test_fw_query_timing(self): + def test_fw_query_timing(self, subtests, mocker): total_ref_time = {1: 7.2, 2: 7.8} brand_ref_times = { 1: { @@ -297,8 +296,8 @@ class TestFwFingerprintTiming(unittest.TestCase): total_times = {1: 0.0, 2: 0.0} for num_pandas in (1, 2): for brand, config in FW_QUERY_CONFIGS.items(): - with self.subTest(brand=brand, num_pandas=num_pandas): - avg_time = self._benchmark_brand(brand, num_pandas) + with subtests.test(brand=brand, num_pandas=num_pandas): + avg_time = self._benchmark_brand(brand, num_pandas, mocker) total_times[num_pandas] += avg_time avg_time = round(avg_time, 2) @@ -311,11 +310,7 @@ class TestFwFingerprintTiming(unittest.TestCase): print(f'{brand=}, {num_pandas=}, {len(config.requests)=}, avg FW query time={avg_time} seconds') for num_pandas in (1, 2): - with self.subTest(brand='all_brands', num_pandas=num_pandas): + with subtests.test(brand='all_brands', num_pandas=num_pandas): total_time = round(total_times[num_pandas], 2) self._assert_timing(total_time, total_ref_time[num_pandas]) print(f'all brands, total FW query time={total_time} seconds') - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py index e5cfd972b..a478bc601 100755 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -2,8 +2,7 @@ from collections import defaultdict import importlib from parameterized import parameterized_class -import sys -import unittest +import pytest from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car.car_helpers import interfaces @@ -25,23 +24,23 @@ car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict) @parameterized_class('car_model', [(c,) for c in sorted(CAR_MODELS)]) -class TestLateralLimits(unittest.TestCase): +class TestLateralLimits: car_model: str @classmethod - def setUpClass(cls): + def setup_class(cls): CarInterface, _, _ = interfaces[cls.car_model] CP = CarInterface.get_non_essential_params(cls.car_model) if CP.dashcamOnly: - raise unittest.SkipTest("Platform is behind dashcamOnly") + pytest.skip("Platform is behind dashcamOnly") # TODO: test all platforms if CP.lateralTuning.which() != 'torque': - raise unittest.SkipTest + pytest.skip() if CP.notCar: - raise unittest.SkipTest + pytest.skip() CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams cls.control_params = CarControllerParams(CP) @@ -66,26 +65,8 @@ class TestLateralLimits(unittest.TestCase): def test_jerk_limits(self): up_jerk, down_jerk = self.calculate_0_5s_jerk(self.control_params, self.torque_params) car_model_jerks[self.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk} - self.assertLessEqual(up_jerk, MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE) - self.assertLessEqual(down_jerk, MAX_LAT_JERK_DOWN) + assert up_jerk <= MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE + assert down_jerk <= MAX_LAT_JERK_DOWN def test_max_lateral_accel(self): - self.assertLessEqual(self.torque_params["MAX_LAT_ACCEL_MEASURED"], MAX_LAT_ACCEL) - - -if __name__ == "__main__": - result = unittest.main(exit=False) - - print(f"\n\n---- Lateral limit report ({len(CAR_MODELS)} cars) ----\n") - - max_car_model_len = max([len(car_model) for car_model in car_model_jerks]) - for car_model, _jerks in sorted(car_model_jerks.items(), key=lambda i: i[1]['up_jerk'], reverse=True): - violation = _jerks["up_jerk"] > MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE or \ - _jerks["down_jerk"] > MAX_LAT_JERK_DOWN - violation_str = " - VIOLATION" if violation else "" - - print(f"{car_model:{max_car_model_len}} - up jerk: {round(_jerks['up_jerk'], 2):5} " + - f"m/s^3, down jerk: {round(_jerks['down_jerk'], 2):5} m/s^3{violation_str}") - - # exit with test result - sys.exit(not result.result.wasSuccessful()) + assert self.torque_params["MAX_LAT_ACCEL_MEASURED"] <= MAX_LAT_ACCEL diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index dc3d4256a..026693bdc 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -4,7 +4,7 @@ import os import importlib import pytest import random -import unittest +import unittest # noqa: TID251 from collections import defaultdict, Counter import hypothesis.strategies as st from hypothesis import Phase, given, settings diff --git a/selfdrive/car/tests/test_platform_configs.py b/selfdrive/car/tests/test_platform_configs.py index 523c331b9..217189255 100755 --- a/selfdrive/car/tests/test_platform_configs.py +++ b/selfdrive/car/tests/test_platform_configs.py @@ -1,25 +1,19 @@ #!/usr/bin/env python3 -import unittest - from openpilot.selfdrive.car.values import PLATFORMS -class TestPlatformConfigs(unittest.TestCase): - def test_configs(self): +class TestPlatformConfigs: + def test_configs(self, subtests): for name, platform in PLATFORMS.items(): - with self.subTest(platform=str(platform)): - self.assertTrue(platform.config._frozen) + with subtests.test(platform=str(platform)): + assert platform.config._frozen if platform != "MOCK": - self.assertIn("pt", platform.config.dbc_dict) - self.assertTrue(len(platform.config.platform_str) > 0) + assert "pt" in platform.config.dbc_dict + assert len(platform.config.platform_str) > 0 - self.assertEqual(name, platform.config.platform_str) + assert name == platform.config.platform_str - self.assertIsNotNone(platform.config.specs) - - -if __name__ == "__main__": - unittest.main() + assert platform.config.specs is not None diff --git a/selfdrive/car/toyota/tests/test_toyota.py b/selfdrive/car/toyota/tests/test_toyota.py index e2a9b46eb..ef49e0055 100755 --- a/selfdrive/car/toyota/tests/test_toyota.py +++ b/selfdrive/car/toyota/tests/test_toyota.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 from hypothesis import given, settings, strategies as st -import unittest from cereal import car from openpilot.selfdrive.car.fw_versions import build_fw_dict @@ -17,59 +16,58 @@ def check_fw_version(fw_version: bytes) -> bool: return b'?' not in fw_version -class TestToyotaInterfaces(unittest.TestCase): +class TestToyotaInterfaces: def test_car_sets(self): - self.assertTrue(len(ANGLE_CONTROL_CAR - TSS2_CAR) == 0) - self.assertTrue(len(RADAR_ACC_CAR - TSS2_CAR) == 0) + assert len(ANGLE_CONTROL_CAR - TSS2_CAR) == 0 + assert len(RADAR_ACC_CAR - TSS2_CAR) == 0 def test_lta_platforms(self): # At this time, only RAV4 2023 is expected to use LTA/angle control - self.assertEqual(ANGLE_CONTROL_CAR, {CAR.TOYOTA_RAV4_TSS2_2023}) + assert ANGLE_CONTROL_CAR == {CAR.TOYOTA_RAV4_TSS2_2023} def test_tss2_dbc(self): # We make some assumptions about TSS2 platforms, # like looking up certain signals only in this DBC for car_model, dbc in DBC.items(): if car_model in TSS2_CAR: - self.assertEqual(dbc["pt"], "toyota_nodsu_pt_generated") + assert dbc["pt"] == "toyota_nodsu_pt_generated" - def test_essential_ecus(self): + def test_essential_ecus(self, subtests): # Asserts standard ECUs exist for each platform common_ecus = {Ecu.fwdRadar, Ecu.fwdCamera} for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): present_ecus = {ecu[0] for ecu in ecus} missing_ecus = common_ecus - present_ecus - self.assertEqual(len(missing_ecus), 0) + assert len(missing_ecus) == 0 # Some exceptions for other common ECUs if car_model not in (CAR.TOYOTA_ALPHARD_TSS2,): - self.assertIn(Ecu.abs, present_ecus) + assert Ecu.abs in present_ecus if car_model not in (CAR.TOYOTA_MIRAI,): - self.assertIn(Ecu.engine, present_ecus) + assert Ecu.engine in present_ecus if car_model not in (CAR.TOYOTA_PRIUS_V, CAR.LEXUS_CTH): - self.assertIn(Ecu.eps, present_ecus) + assert Ecu.eps in present_ecus -class TestToyotaFingerprint(unittest.TestCase): - def test_non_essential_ecus(self): +class TestToyotaFingerprint: + def test_non_essential_ecus(self, subtests): # Ensures only the cars that have multiple engine ECUs are in the engine non-essential ECU list for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): engine_ecus = {ecu for ecu in ecus if ecu[0] == Ecu.engine} - self.assertEqual(len(engine_ecus) > 1, - car_model in FW_QUERY_CONFIG.non_essential_ecus[Ecu.engine], - f"Car model unexpectedly {'not ' if len(engine_ecus) > 1 else ''}in non-essential list") + assert (len(engine_ecus) > 1) == (car_model in FW_QUERY_CONFIG.non_essential_ecus[Ecu.engine]), \ + f"Car model unexpectedly {'not ' if len(engine_ecus) > 1 else ''}in non-essential list" - def test_valid_fw_versions(self): + def test_valid_fw_versions(self, subtests): # Asserts all FW versions are valid for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): for fws in ecus.values(): for fw in fws: - self.assertTrue(check_fw_version(fw), fw) + assert check_fw_version(fw), fw # Tests for part numbers, platform codes, and sub-versions which Toyota will use to fuzzy # fingerprint in the absence of full FW matches: @@ -80,25 +78,25 @@ class TestToyotaFingerprint(unittest.TestCase): fws = data.draw(fw_strategy) get_platform_codes(fws) - def test_platform_code_ecus_available(self): + def test_platform_code_ecus_available(self, subtests): # Asserts ECU keys essential for fuzzy fingerprinting are available on all platforms for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): for platform_code_ecu in PLATFORM_CODE_ECUS: if platform_code_ecu == Ecu.eps and car_model in (CAR.TOYOTA_PRIUS_V, CAR.LEXUS_CTH,): continue if platform_code_ecu == Ecu.abs and car_model in (CAR.TOYOTA_ALPHARD_TSS2,): continue - self.assertIn(platform_code_ecu, [e[0] for e in ecus]) + assert platform_code_ecu in [e[0] for e in ecus] - def test_fw_format(self): + def test_fw_format(self, subtests): # Asserts: # - every supported ECU FW version returns one platform code # - every supported ECU FW version has a part number # - expected parsing of ECU sub-versions for car_model, ecus in FW_VERSIONS.items(): - with self.subTest(car_model=car_model.value): + with subtests.test(car_model=car_model.value): for ecu, fws in ecus.items(): if ecu[0] not in PLATFORM_CODE_ECUS: continue @@ -107,15 +105,14 @@ class TestToyotaFingerprint(unittest.TestCase): for fw in fws: result = get_platform_codes([fw]) # Check only one platform code and sub-version - self.assertEqual(1, len(result), f"Unable to parse FW: {fw}") - self.assertEqual(1, len(list(result.values())[0]), f"Unable to parse FW: {fw}") + assert 1 == len(result), f"Unable to parse FW: {fw}" + assert 1 == len(list(result.values())[0]), f"Unable to parse FW: {fw}" codes |= result # Toyota places the ECU part number in their FW versions, assert all parsable # Note that there is only one unique part number per ECU across the fleet, so this # is not important for identification, just a sanity check. - self.assertTrue(all(code.count(b"-") > 1 for code in codes), - f"FW does not have part number: {fw} {codes}") + assert all(code.count(b"-") > 1 for code in codes), f"FW does not have part number: {fw} {codes}" def test_platform_codes_spot_check(self): # Asserts basic platform code parsing behavior for a few cases @@ -125,20 +122,20 @@ class TestToyotaFingerprint(unittest.TestCase): b"F152607110\x00\x00\x00\x00\x00\x00", b"F152607180\x00\x00\x00\x00\x00\x00", ]) - self.assertEqual(results, {b"F1526-07-1": {b"10", b"40", b"71", b"80"}}) + assert results == {b"F1526-07-1": {b"10", b"40", b"71", b"80"}} results = get_platform_codes([ b"\x028646F4104100\x00\x00\x00\x008646G5301200\x00\x00\x00\x00", b"\x028646F4104100\x00\x00\x00\x008646G3304000\x00\x00\x00\x00", ]) - self.assertEqual(results, {b"8646F-41-04": {b"100"}}) + assert results == {b"8646F-41-04": {b"100"}} # Short version has no part number results = get_platform_codes([ b"\x0235870000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00", b"\x0235883000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00", ]) - self.assertEqual(results, {b"58-70": {b"000"}, b"58-83": {b"000"}}) + assert results == {b"58-70": {b"000"}, b"58-83": {b"000"}} results = get_platform_codes([ b"F152607110\x00\x00\x00\x00\x00\x00", @@ -146,7 +143,7 @@ class TestToyotaFingerprint(unittest.TestCase): b"\x028646F4104100\x00\x00\x00\x008646G5301200\x00\x00\x00\x00", b"\x0235879000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00", ]) - self.assertEqual(results, {b"F1526-07-1": {b"10", b"40"}, b"8646F-41-04": {b"100"}, b"58-79": {b"000"}}) + assert results == {b"F1526-07-1": {b"10", b"40"}, b"8646F-41-04": {b"100"}, b"58-79": {b"000"}} def test_fuzzy_excluded_platforms(self): # Asserts a list of platforms that will not fuzzy fingerprint with platform codes due to them being shared. @@ -162,13 +159,9 @@ class TestToyotaFingerprint(unittest.TestCase): CP = car.CarParams.new_message(carFw=car_fw) matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS) if len(matches) == 1: - self.assertEqual(list(matches)[0], platform) + assert list(matches)[0] == platform else: # If a platform has multiple matches, add it and its matches platforms_with_shared_codes |= {str(platform), *matches} - self.assertEqual(platforms_with_shared_codes, FUZZY_EXCLUDED_PLATFORMS, (len(platforms_with_shared_codes), len(FW_VERSIONS))) - - -if __name__ == "__main__": - unittest.main() + assert platforms_with_shared_codes == FUZZY_EXCLUDED_PLATFORMS, (len(platforms_with_shared_codes), len(FW_VERSIONS)) diff --git a/selfdrive/car/volkswagen/tests/test_volkswagen.py b/selfdrive/car/volkswagen/tests/test_volkswagen.py index 17331203b..561d28b9f 100755 --- a/selfdrive/car/volkswagen/tests/test_volkswagen.py +++ b/selfdrive/car/volkswagen/tests/test_volkswagen.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import random import re -import unittest from cereal import car from openpilot.selfdrive.car.volkswagen.values import CAR, FW_QUERY_CONFIG, WMI @@ -14,35 +13,35 @@ CHASSIS_CODE_PATTERN = re.compile('[A-Z0-9]{2}') SPARE_PART_FW_PATTERN = re.compile(b'\xf1\x87(?P[0-9][0-9A-Z]{2})(?P[0-9][0-9A-Z][0-9])(?P[0-9A-Z]{2}[0-9])([A-Z0-9]| )') -class TestVolkswagenPlatformConfigs(unittest.TestCase): - def test_spare_part_fw_pattern(self): +class TestVolkswagenPlatformConfigs: + def test_spare_part_fw_pattern(self, subtests): # Relied on for determining if a FW is likely VW for platform, ecus in FW_VERSIONS.items(): - with self.subTest(platform=platform): + with subtests.test(platform=platform.value): for fws in ecus.values(): for fw in fws: - self.assertNotEqual(SPARE_PART_FW_PATTERN.match(fw), None, f"Bad FW: {fw}") + assert SPARE_PART_FW_PATTERN.match(fw) is not None, f"Bad FW: {fw}" - def test_chassis_codes(self): + def test_chassis_codes(self, subtests): for platform in CAR: - with self.subTest(platform=platform): - self.assertTrue(len(platform.config.wmis) > 0, "WMIs not set") - self.assertTrue(len(platform.config.chassis_codes) > 0, "Chassis codes not set") - self.assertTrue(all(CHASSIS_CODE_PATTERN.match(cc) for cc in - platform.config.chassis_codes), "Bad chassis codes") + with subtests.test(platform=platform.value): + assert len(platform.config.wmis) > 0, "WMIs not set" + assert len(platform.config.chassis_codes) > 0, "Chassis codes not set" + assert all(CHASSIS_CODE_PATTERN.match(cc) for cc in \ + platform.config.chassis_codes), "Bad chassis codes" # No two platforms should share chassis codes for comp in CAR: if platform == comp: continue - self.assertEqual(set(), platform.config.chassis_codes & comp.config.chassis_codes, - f"Shared chassis codes: {comp}") + assert set() == platform.config.chassis_codes & comp.config.chassis_codes, \ + f"Shared chassis codes: {comp}" - def test_custom_fuzzy_fingerprinting(self): + def test_custom_fuzzy_fingerprinting(self, subtests): all_radar_fw = list({fw for ecus in FW_VERSIONS.values() for fw in ecus[Ecu.fwdRadar, 0x757, None]}) for platform in CAR: - with self.subTest(platform=platform): + with subtests.test(platform=platform.name): for wmi in WMI: for chassis_code in platform.config.chassis_codes | {"00"}: vin = ["0"] * 17 @@ -59,8 +58,4 @@ class TestVolkswagenPlatformConfigs(unittest.TestCase): matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fws, vin, FW_VERSIONS) expected_matches = {platform} if should_match else set() - self.assertEqual(expected_matches, matches, "Bad match") - - -if __name__ == "__main__": - unittest.main() + assert expected_matches == matches, "Bad match" diff --git a/selfdrive/controls/lib/tests/test_alertmanager.py b/selfdrive/controls/lib/tests/test_alertmanager.py index dbd42858a..c234cc49d 100755 --- a/selfdrive/controls/lib/tests/test_alertmanager.py +++ b/selfdrive/controls/lib/tests/test_alertmanager.py @@ -1,12 +1,11 @@ #!/usr/bin/env python3 import random -import unittest from openpilot.selfdrive.controls.lib.events import Alert, EVENTS from openpilot.selfdrive.controls.lib.alertmanager import AlertManager -class TestAlertManager(unittest.TestCase): +class TestAlertManager: def test_duration(self): """ @@ -38,8 +37,4 @@ class TestAlertManager(unittest.TestCase): shown = current_alert is not None should_show = frame <= show_duration - self.assertEqual(shown, should_show, msg=f"{frame=} {add_duration=} {duration=}") - - -if __name__ == "__main__": - unittest.main() + assert shown == should_show, f"{frame=} {add_duration=} {duration=}" diff --git a/selfdrive/controls/lib/tests/test_latcontrol.py b/selfdrive/controls/lib/tests/test_latcontrol.py index 838023af7..b731bbd95 100755 --- a/selfdrive/controls/lib/tests/test_latcontrol.py +++ b/selfdrive/controls/lib/tests/test_latcontrol.py @@ -1,6 +1,4 @@ #!/usr/bin/env python3 -import unittest - from parameterized import parameterized from cereal import car, log @@ -15,7 +13,7 @@ from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel from openpilot.common.mock.generators import generate_liveLocationKalman -class TestLatControl(unittest.TestCase): +class TestLatControl: @parameterized.expand([(HONDA.HONDA_CIVIC, LatControlPID), (TOYOTA.TOYOTA_RAV4, LatControlTorque), (NISSAN.NISSAN_LEAF, LatControlAngle)]) def test_saturation(self, car_name, controller): @@ -36,8 +34,4 @@ class TestLatControl(unittest.TestCase): for _ in range(1000): _, _, lac_log = controller.update(True, CS, VM, params, False, 1, llk) - self.assertTrue(lac_log.saturated) - - -if __name__ == "__main__": - unittest.main() + assert lac_log.saturated diff --git a/selfdrive/controls/lib/tests/test_vehicle_model.py b/selfdrive/controls/lib/tests/test_vehicle_model.py index c3997afdf..2efcf2fbb 100755 --- a/selfdrive/controls/lib/tests/test_vehicle_model.py +++ b/selfdrive/controls/lib/tests/test_vehicle_model.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 +import pytest import math -import unittest import numpy as np from control import StateSpace @@ -10,8 +10,8 @@ from openpilot.selfdrive.car.honda.values import CAR from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel, dyn_ss_sol, create_dyn_state_matrices -class TestVehicleModel(unittest.TestCase): - def setUp(self): +class TestVehicleModel: + def setup_method(self): CP = CarInterface.get_non_essential_params(CAR.HONDA_CIVIC) self.VM = VehicleModel(CP) @@ -23,7 +23,7 @@ class TestVehicleModel(unittest.TestCase): yr = self.VM.yaw_rate(sa, u, roll) new_sa = self.VM.get_steer_from_yaw_rate(yr, u, roll) - self.assertAlmostEqual(sa, new_sa) + assert sa == pytest.approx(new_sa) def test_dyn_ss_sol_against_yaw_rate(self): """Verify that the yaw_rate helper function matches the results @@ -38,7 +38,7 @@ class TestVehicleModel(unittest.TestCase): # Compute yaw rate using direct computations yr2 = self.VM.yaw_rate(sa, u, roll) - self.assertAlmostEqual(float(yr1[0]), yr2) + assert float(yr1[0]) == pytest.approx(yr2) def test_syn_ss_sol_simulate(self): """Verifies that dyn_ss_sol matches a simulation""" @@ -63,8 +63,3 @@ class TestVehicleModel(unittest.TestCase): x2 = dyn_ss_sol(sa, u, roll, self.VM) np.testing.assert_almost_equal(x1, x2, decimal=3) - - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/controls/tests/test_alerts.py b/selfdrive/controls/tests/test_alerts.py index 7b4fba0dc..e29a6322a 100755 --- a/selfdrive/controls/tests/test_alerts.py +++ b/selfdrive/controls/tests/test_alerts.py @@ -2,7 +2,6 @@ import copy import json import os -import unittest import random from PIL import Image, ImageDraw, ImageFont @@ -25,10 +24,10 @@ for event_types in EVENTS.values(): ALERTS.append(alert) -class TestAlerts(unittest.TestCase): +class TestAlerts: @classmethod - def setUpClass(cls): + def setup_class(cls): with open(OFFROAD_ALERTS_PATH) as f: cls.offroad_alerts = json.loads(f.read()) @@ -45,7 +44,7 @@ class TestAlerts(unittest.TestCase): for name, e in events.items(): if not name.endswith("DEPRECATED"): fail_msg = "%s @%d not in EVENTS" % (name, e) - self.assertTrue(e in EVENTS.keys(), msg=fail_msg) + assert e in EVENTS.keys(), fail_msg # ensure alert text doesn't exceed allowed width def test_alert_text_length(self): @@ -80,7 +79,7 @@ class TestAlerts(unittest.TestCase): left, _, right, _ = draw.textbbox((0, 0), txt, font) width = right - left msg = f"type: {alert.alert_type} msg: {txt}" - self.assertLessEqual(width, max_text_width, msg=msg) + assert width <= max_text_width, msg def test_alert_sanity_check(self): for event_types in EVENTS.values(): @@ -90,21 +89,21 @@ class TestAlerts(unittest.TestCase): continue if a.alert_size == AlertSize.none: - self.assertEqual(len(a.alert_text_1), 0) - self.assertEqual(len(a.alert_text_2), 0) + assert len(a.alert_text_1) == 0 + assert len(a.alert_text_2) == 0 elif a.alert_size == AlertSize.small: - self.assertGreater(len(a.alert_text_1), 0) - self.assertEqual(len(a.alert_text_2), 0) + assert len(a.alert_text_1) > 0 + assert len(a.alert_text_2) == 0 elif a.alert_size == AlertSize.mid: - self.assertGreater(len(a.alert_text_1), 0) - self.assertGreater(len(a.alert_text_2), 0) + assert len(a.alert_text_1) > 0 + assert len(a.alert_text_2) > 0 else: - self.assertGreater(len(a.alert_text_1), 0) + assert len(a.alert_text_1) > 0 - self.assertGreaterEqual(a.duration, 0.) + assert a.duration >= 0. if event_type not in (ET.WARNING, ET.PERMANENT, ET.PRE_ENABLE): - self.assertEqual(a.creation_delay, 0.) + assert a.creation_delay == 0. def test_offroad_alerts(self): params = Params() @@ -113,11 +112,11 @@ class TestAlerts(unittest.TestCase): alert = copy.copy(self.offroad_alerts[a]) set_offroad_alert(a, True) alert['extra'] = '' - self.assertTrue(json.dumps(alert) == params.get(a, encoding='utf8')) + assert json.dumps(alert) == params.get(a, encoding='utf8') # then delete it set_offroad_alert(a, False) - self.assertTrue(params.get(a) is None) + assert params.get(a) is None def test_offroad_alerts_extra_text(self): params = Params() @@ -128,8 +127,5 @@ class TestAlerts(unittest.TestCase): set_offroad_alert(a, True, extra_text="a"*i) written_alert = json.loads(params.get(a, encoding='utf8')) - self.assertTrue("a"*i == written_alert['extra']) - self.assertTrue(alert["text"] == written_alert['text']) - -if __name__ == "__main__": - unittest.main() + assert "a"*i == written_alert['extra'] + assert alert["text"] == written_alert['text'] diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py index c46d03ad1..6c46285e8 100755 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 +import pytest import itertools import numpy as np -import unittest from parameterized import parameterized_class from cereal import log @@ -36,19 +36,19 @@ def run_cruise_simulation(cruise, e2e, personality, t_end=20.): [True, False], # e2e log.LongitudinalPersonality.schema.enumerants, # personality [5,35])) # speed -class TestCruiseSpeed(unittest.TestCase): +class TestCruiseSpeed: def test_cruise_speed(self): print(f'Testing {self.speed} m/s') cruise_speed = float(self.speed) simulation_steady_state = run_cruise_simulation(cruise_speed, self.e2e, self.personality) - self.assertAlmostEqual(simulation_steady_state, cruise_speed, delta=.01, msg=f'Did not reach {self.speed} m/s') + assert simulation_steady_state == pytest.approx(cruise_speed, abs=.01), f'Did not reach {self.speed} m/s' # TODO: test pcmCruise @parameterized_class(('pcm_cruise',), [(False,)]) -class TestVCruiseHelper(unittest.TestCase): - def setUp(self): +class TestVCruiseHelper: + def setup_method(self): self.CP = car.CarParams(pcmCruise=self.pcm_cruise) self.v_cruise_helper = VCruiseHelper(self.CP) self.reset_cruise_speed_state() @@ -75,7 +75,7 @@ class TestVCruiseHelper(unittest.TestCase): CS.buttonEvents = [ButtonEvent(type=btn, pressed=pressed)] self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=False) - self.assertEqual(pressed, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) + assert pressed == (self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) def test_rising_edge_enable(self): """ @@ -94,7 +94,7 @@ class TestVCruiseHelper(unittest.TestCase): self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False) # Expected diff on enabling. Speed should not change on falling edge of pressed - self.assertEqual(not pressed, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) + assert not pressed == self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last def test_resume_in_standstill(self): """ @@ -111,7 +111,7 @@ class TestVCruiseHelper(unittest.TestCase): # speed should only update if not at standstill and button falling edge should_equal = standstill or pressed - self.assertEqual(should_equal, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) + assert should_equal == (self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) def test_set_gas_pressed(self): """ @@ -135,7 +135,7 @@ class TestVCruiseHelper(unittest.TestCase): # TODO: fix skipping first run due to enabled on rising edge exception if v_ego == 0.0: continue - self.assertEqual(expected_v_cruise_kph, self.v_cruise_helper.v_cruise_kph) + assert expected_v_cruise_kph == self.v_cruise_helper.v_cruise_kph def test_initialize_v_cruise(self): """ @@ -145,12 +145,8 @@ class TestVCruiseHelper(unittest.TestCase): for experimental_mode in (True, False): for v_ego in np.linspace(0, 100, 101): self.reset_cruise_speed_state() - self.assertFalse(self.v_cruise_helper.v_cruise_initialized) + assert not self.v_cruise_helper.v_cruise_initialized self.enable(float(v_ego), experimental_mode) - self.assertTrue(V_CRUISE_INITIAL <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX) - self.assertTrue(self.v_cruise_helper.v_cruise_initialized) - - -if __name__ == "__main__": - unittest.main() + assert V_CRUISE_INITIAL <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX + assert self.v_cruise_helper.v_cruise_initialized diff --git a/selfdrive/controls/tests/test_following_distance.py b/selfdrive/controls/tests/test_following_distance.py index f58e6383c..5d6091180 100755 --- a/selfdrive/controls/tests/test_following_distance.py +++ b/selfdrive/controls/tests/test_following_distance.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import unittest +import pytest import itertools from parameterized import parameterized_class @@ -32,14 +32,10 @@ def run_following_distance_simulation(v_lead, t_end=100.0, e2e=False, personalit log.LongitudinalPersonality.standard, log.LongitudinalPersonality.aggressive], [0,10,35])) # speed -class TestFollowingDistance(unittest.TestCase): +class TestFollowingDistance(): def test_following_distance(self): v_lead = float(self.speed) simulation_steady_state = run_following_distance_simulation(v_lead, e2e=self.e2e, personality=self.personality) correct_steady_state = desired_follow_distance(v_lead, v_lead, get_T_FOLLOW(self.personality)) err_ratio = 0.2 if self.e2e else 0.1 - self.assertAlmostEqual(simulation_steady_state, correct_steady_state, delta=(err_ratio * correct_steady_state + .5)) - - -if __name__ == "__main__": - unittest.main() + assert simulation_steady_state == pytest.approx(correct_steady_state, abs=err_ratio * correct_steady_state + .5) diff --git a/selfdrive/controls/tests/test_lateral_mpc.py b/selfdrive/controls/tests/test_lateral_mpc.py index 8c09f46b6..3aa0fd1bc 100644 --- a/selfdrive/controls/tests/test_lateral_mpc.py +++ b/selfdrive/controls/tests/test_lateral_mpc.py @@ -1,4 +1,4 @@ -import unittest +import pytest import numpy as np from openpilot.selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc from openpilot.selfdrive.controls.lib.drive_helpers import CAR_ROTATION_RADIUS @@ -27,20 +27,20 @@ def run_mpc(lat_mpc=None, v_ref=30., x_init=0., y_init=0., psi_init=0., curvatur return lat_mpc.x_sol -class TestLateralMpc(unittest.TestCase): +class TestLateralMpc: def _assert_null(self, sol, curvature=1e-6): for i in range(len(sol)): - self.assertAlmostEqual(sol[0,i,1], 0., delta=curvature) - self.assertAlmostEqual(sol[0,i,2], 0., delta=curvature) - self.assertAlmostEqual(sol[0,i,3], 0., delta=curvature) + assert sol[0,i,1] == pytest.approx(0, abs=curvature) + assert sol[0,i,2] == pytest.approx(0, abs=curvature) + assert sol[0,i,3] == pytest.approx(0, abs=curvature) def _assert_simmetry(self, sol, curvature=1e-6): for i in range(len(sol)): - self.assertAlmostEqual(sol[0,i,1], -sol[1,i,1], delta=curvature) - self.assertAlmostEqual(sol[0,i,2], -sol[1,i,2], delta=curvature) - self.assertAlmostEqual(sol[0,i,3], -sol[1,i,3], delta=curvature) - self.assertAlmostEqual(sol[0,i,0], sol[1,i,0], delta=curvature) + assert sol[0,i,1] == pytest.approx(-sol[1,i,1], abs=curvature) + assert sol[0,i,2] == pytest.approx(-sol[1,i,2], abs=curvature) + assert sol[0,i,3] == pytest.approx(-sol[1,i,3], abs=curvature) + assert sol[0,i,0] == pytest.approx(sol[1,i,0], abs=curvature) def test_straight(self): sol = run_mpc() @@ -74,7 +74,7 @@ class TestLateralMpc(unittest.TestCase): y_init = 1. sol = run_mpc(y_init=y_init) for y in list(sol[:,1]): - self.assertGreaterEqual(y_init, abs(y)) + assert y_init >= abs(y) def test_switch_convergence(self): lat_mpc = LateralMpc() @@ -83,7 +83,3 @@ class TestLateralMpc(unittest.TestCase): sol = run_mpc(lat_mpc=lat_mpc, poly_shift=-3.0, v_ref=7.0) left_psi_deg = np.degrees(sol[:,2]) np.testing.assert_almost_equal(right_psi_deg, -left_psi_deg, decimal=3) - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/controls/tests/test_leads.py b/selfdrive/controls/tests/test_leads.py index a06387a08..f4e97725f 100755 --- a/selfdrive/controls/tests/test_leads.py +++ b/selfdrive/controls/tests/test_leads.py @@ -1,13 +1,11 @@ #!/usr/bin/env python3 -import unittest - import cereal.messaging as messaging from openpilot.selfdrive.test.process_replay import replay_process_with_name from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA -class TestLeads(unittest.TestCase): +class TestLeads: def test_radar_fault(self): # if there's no radar-related can traffic, radard should either not respond or respond with an error # this is tightly coupled with underlying car radar_interface implementation, but it's a good sanity check @@ -29,8 +27,4 @@ class TestLeads(unittest.TestCase): states = [m for m in out if m.which() == "radarState"] failures = [not state.valid and len(state.radarState.radarErrors) for state in states] - self.assertTrue(len(states) == 0 or all(failures)) - - -if __name__ == "__main__": - unittest.main() + assert len(states) == 0 or all(failures) diff --git a/selfdrive/controls/tests/test_state_machine.py b/selfdrive/controls/tests/test_state_machine.py index d49111752..b92724ce4 100755 --- a/selfdrive/controls/tests/test_state_machine.py +++ b/selfdrive/controls/tests/test_state_machine.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import unittest from cereal import car, log from openpilot.common.realtime import DT_CTRL @@ -28,9 +27,9 @@ def make_event(event_types): return 0 -class TestStateMachine(unittest.TestCase): +class TestStateMachine: - def setUp(self): + def setup_method(self): CarInterface, CarController, CarState = interfaces[MOCK.MOCK] CP = CarInterface.get_non_essential_params(MOCK.MOCK) CI = CarInterface(CP, CarController, CarState) @@ -46,7 +45,7 @@ class TestStateMachine(unittest.TestCase): self.controlsd.events.add(make_event([et, ET.IMMEDIATE_DISABLE])) self.controlsd.state = state self.controlsd.state_transition(self.CS) - self.assertEqual(State.disabled, self.controlsd.state) + assert State.disabled == self.controlsd.state self.controlsd.events.clear() def test_user_disable(self): @@ -55,7 +54,7 @@ class TestStateMachine(unittest.TestCase): self.controlsd.events.add(make_event([et, ET.USER_DISABLE])) self.controlsd.state = state self.controlsd.state_transition(self.CS) - self.assertEqual(State.disabled, self.controlsd.state) + assert State.disabled == self.controlsd.state self.controlsd.events.clear() def test_soft_disable(self): @@ -66,7 +65,7 @@ class TestStateMachine(unittest.TestCase): self.controlsd.events.add(make_event([et, ET.SOFT_DISABLE])) self.controlsd.state = state self.controlsd.state_transition(self.CS) - self.assertEqual(self.controlsd.state, State.disabled if state == State.disabled else State.softDisabling) + assert self.controlsd.state == State.disabled if state == State.disabled else State.softDisabling self.controlsd.events.clear() def test_soft_disable_timer(self): @@ -74,17 +73,17 @@ class TestStateMachine(unittest.TestCase): self.controlsd.events.add(make_event([ET.SOFT_DISABLE])) self.controlsd.state_transition(self.CS) for _ in range(int(SOFT_DISABLE_TIME / DT_CTRL)): - self.assertEqual(self.controlsd.state, State.softDisabling) + assert self.controlsd.state == State.softDisabling self.controlsd.state_transition(self.CS) - self.assertEqual(self.controlsd.state, State.disabled) + assert self.controlsd.state == State.disabled def test_no_entry(self): # Make sure noEntry keeps us disabled for et in ENABLE_EVENT_TYPES: self.controlsd.events.add(make_event([ET.NO_ENTRY, et])) self.controlsd.state_transition(self.CS) - self.assertEqual(self.controlsd.state, State.disabled) + assert self.controlsd.state == State.disabled self.controlsd.events.clear() def test_no_entry_pre_enable(self): @@ -92,7 +91,7 @@ class TestStateMachine(unittest.TestCase): self.controlsd.state = State.preEnabled self.controlsd.events.add(make_event([ET.NO_ENTRY, ET.PRE_ENABLE])) self.controlsd.state_transition(self.CS) - self.assertEqual(self.controlsd.state, State.preEnabled) + assert self.controlsd.state == State.preEnabled def test_maintain_states(self): # Given current state's event type, we should maintain state @@ -101,9 +100,5 @@ class TestStateMachine(unittest.TestCase): self.controlsd.state = state self.controlsd.events.add(make_event([et])) self.controlsd.state_transition(self.CS) - self.assertEqual(self.controlsd.state, state) + assert self.controlsd.state == state self.controlsd.events.clear() - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/locationd/test/test_calibrationd.py b/selfdrive/locationd/test/test_calibrationd.py index e2db09439..598d5d2d5 100755 --- a/selfdrive/locationd/test/test_calibrationd.py +++ b/selfdrive/locationd/test/test_calibrationd.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import random -import unittest import numpy as np @@ -31,7 +30,7 @@ def process_messages(c, cam_odo_calib, cycles, [0.0, 0.0, HEIGHT_INIT.item()], [cam_odo_height_std, cam_odo_height_std, cam_odo_height_std]) -class TestCalibrationd(unittest.TestCase): +class TestCalibrationd: def test_read_saved_params(self): msg = messaging.new_message('liveCalibration') @@ -43,13 +42,13 @@ class TestCalibrationd(unittest.TestCase): np.testing.assert_allclose(msg.liveCalibration.rpyCalib, c.rpy) np.testing.assert_allclose(msg.liveCalibration.height, c.height) - self.assertEqual(msg.liveCalibration.validBlocks, c.valid_blocks) + assert msg.liveCalibration.validBlocks == c.valid_blocks def test_calibration_basics(self): c = Calibrator(param_put=False) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_WANTED) - self.assertEqual(c.valid_blocks, INPUTS_WANTED) + assert c.valid_blocks == INPUTS_WANTED np.testing.assert_allclose(c.rpy, np.zeros(3)) np.testing.assert_allclose(c.height, HEIGHT_INIT) c.reset() @@ -59,7 +58,7 @@ class TestCalibrationd(unittest.TestCase): c = Calibrator(param_put=False) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_WANTED, cam_odo_speed=MIN_SPEED_FILTER - 1) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_WANTED, carstate_speed=MIN_SPEED_FILTER - 1) - self.assertEqual(c.valid_blocks, 0) + assert c.valid_blocks == 0 np.testing.assert_allclose(c.rpy, np.zeros(3)) np.testing.assert_allclose(c.height, HEIGHT_INIT) @@ -67,7 +66,7 @@ class TestCalibrationd(unittest.TestCase): def test_calibration_yaw_rate_reject(self): c = Calibrator(param_put=False) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_WANTED, cam_odo_yr=MAX_YAW_RATE_FILTER) - self.assertEqual(c.valid_blocks, 0) + assert c.valid_blocks == 0 np.testing.assert_allclose(c.rpy, np.zeros(3)) np.testing.assert_allclose(c.height, HEIGHT_INIT) @@ -75,43 +74,40 @@ class TestCalibrationd(unittest.TestCase): def test_calibration_speed_std_reject(self): c = Calibrator(param_put=False) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_WANTED, cam_odo_speed_std=1e3) - self.assertEqual(c.valid_blocks, INPUTS_NEEDED) + assert c.valid_blocks == INPUTS_NEEDED np.testing.assert_allclose(c.rpy, np.zeros(3)) def test_calibration_speed_std_height_reject(self): c = Calibrator(param_put=False) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_WANTED, cam_odo_height_std=1e3) - self.assertEqual(c.valid_blocks, INPUTS_NEEDED) + assert c.valid_blocks == INPUTS_NEEDED np.testing.assert_allclose(c.rpy, np.zeros(3)) def test_calibration_auto_reset(self): c = Calibrator(param_put=False) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_NEEDED) - self.assertEqual(c.valid_blocks, INPUTS_NEEDED) + assert c.valid_blocks == INPUTS_NEEDED np.testing.assert_allclose(c.rpy, [0.0, 0.0, 0.0], atol=1e-3) process_messages(c, [0.0, MAX_ALLOWED_PITCH_SPREAD*0.9, MAX_ALLOWED_YAW_SPREAD*0.9], BLOCK_SIZE + 10) - self.assertEqual(c.valid_blocks, INPUTS_NEEDED + 1) - self.assertEqual(c.cal_status, log.LiveCalibrationData.Status.calibrated) + assert c.valid_blocks == INPUTS_NEEDED + 1 + assert c.cal_status == log.LiveCalibrationData.Status.calibrated c = Calibrator(param_put=False) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_NEEDED) - self.assertEqual(c.valid_blocks, INPUTS_NEEDED) + assert c.valid_blocks == INPUTS_NEEDED np.testing.assert_allclose(c.rpy, [0.0, 0.0, 0.0]) process_messages(c, [0.0, MAX_ALLOWED_PITCH_SPREAD*1.1, 0.0], BLOCK_SIZE + 10) - self.assertEqual(c.valid_blocks, 1) - self.assertEqual(c.cal_status, log.LiveCalibrationData.Status.recalibrating) + assert c.valid_blocks == 1 + assert c.cal_status == log.LiveCalibrationData.Status.recalibrating np.testing.assert_allclose(c.rpy, [0.0, MAX_ALLOWED_PITCH_SPREAD*1.1, 0.0], atol=1e-2) c = Calibrator(param_put=False) process_messages(c, [0.0, 0.0, 0.0], BLOCK_SIZE * INPUTS_NEEDED) - self.assertEqual(c.valid_blocks, INPUTS_NEEDED) + assert c.valid_blocks == INPUTS_NEEDED np.testing.assert_allclose(c.rpy, [0.0, 0.0, 0.0]) process_messages(c, [0.0, 0.0, MAX_ALLOWED_YAW_SPREAD*1.1], BLOCK_SIZE + 10) - self.assertEqual(c.valid_blocks, 1) - self.assertEqual(c.cal_status, log.LiveCalibrationData.Status.recalibrating) + assert c.valid_blocks == 1 + assert c.cal_status == log.LiveCalibrationData.Status.recalibrating np.testing.assert_allclose(c.rpy, [0.0, 0.0, MAX_ALLOWED_YAW_SPREAD*1.1], atol=1e-2) - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/locationd/test/test_locationd.py b/selfdrive/locationd/test/test_locationd.py index cd032dbaf..bac824bad 100755 --- a/selfdrive/locationd/test/test_locationd.py +++ b/selfdrive/locationd/test/test_locationd.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 +import pytest import json import random -import unittest import time import capnp @@ -13,13 +13,11 @@ from openpilot.common.transformations.coordinates import ecef2geodetic from openpilot.selfdrive.manager.process_config import managed_processes -class TestLocationdProc(unittest.TestCase): +class TestLocationdProc: LLD_MSGS = ['gpsLocationExternal', 'cameraOdometry', 'carState', 'liveCalibration', 'accelerometer', 'gyroscope', 'magnetometer'] - def setUp(self): - random.seed(123489234) - + def setup_method(self): self.pm = messaging.PubMaster(self.LLD_MSGS) self.params = Params() @@ -27,7 +25,7 @@ class TestLocationdProc(unittest.TestCase): managed_processes['locationd'].prepare() managed_processes['locationd'].start() - def tearDown(self): + def teardown_method(self): managed_processes['locationd'].stop() def get_msg(self, name, t): @@ -65,6 +63,7 @@ class TestLocationdProc(unittest.TestCase): return msg def test_params_gps(self): + random.seed(123489234) self.params.remove('LastGPSPosition') self.x = -2710700 + (random.random() * 1e5) @@ -86,10 +85,6 @@ class TestLocationdProc(unittest.TestCase): time.sleep(1) # wait for async params write lastGPS = json.loads(self.params.get('LastGPSPosition')) - self.assertAlmostEqual(lastGPS['latitude'], self.lat, places=3) - self.assertAlmostEqual(lastGPS['longitude'], self.lon, places=3) - self.assertAlmostEqual(lastGPS['altitude'], self.alt, places=3) - - -if __name__ == "__main__": - unittest.main() + assert lastGPS['latitude'] == pytest.approx(self.lat, abs=0.001) + assert lastGPS['longitude'] == pytest.approx(self.lon, abs=0.001) + assert lastGPS['altitude'] == pytest.approx(self.alt, abs=0.001) diff --git a/selfdrive/locationd/test/test_locationd_scenarios.py b/selfdrive/locationd/test/test_locationd_scenarios.py index 3fdd47275..be95c6fff 100755 --- a/selfdrive/locationd/test/test_locationd_scenarios.py +++ b/selfdrive/locationd/test/test_locationd_scenarios.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import pytest -import unittest import numpy as np from collections import defaultdict from enum import Enum @@ -99,7 +98,7 @@ def run_scenarios(scenario, logs): @pytest.mark.xdist_group("test_locationd_scenarios") @pytest.mark.shared_download_cache -class TestLocationdScenarios(unittest.TestCase): +class TestLocationdScenarios: """ Test locationd with different scenarios. In all these scenarios, we expect the following: - locationd kalman filter should never go unstable (we care mostly about yaw_rate, roll, gpsOK, inputsOK, sensorsOK) @@ -107,7 +106,7 @@ class TestLocationdScenarios(unittest.TestCase): """ @classmethod - def setUpClass(cls): + def setup_class(cls): cls.logs = migrate_all(LogReader(TEST_ROUTE)) def test_base(self): @@ -118,8 +117,8 @@ class TestLocationdScenarios(unittest.TestCase): - roll: unchanged """ orig_data, replayed_data = run_scenarios(Scenario.BASE, self.logs) - self.assertTrue(np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2))) - self.assertTrue(np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5))) + assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2)) + assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5)) def test_gps_off(self): """ @@ -130,9 +129,9 @@ class TestLocationdScenarios(unittest.TestCase): - gpsOK: False """ orig_data, replayed_data = run_scenarios(Scenario.GPS_OFF, self.logs) - self.assertTrue(np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2))) - self.assertTrue(np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5))) - self.assertTrue(np.all(replayed_data['gps_flag'] == 0.0)) + assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2)) + assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5)) + assert np.all(replayed_data['gps_flag'] == 0.0) def test_gps_off_midway(self): """ @@ -143,9 +142,9 @@ class TestLocationdScenarios(unittest.TestCase): - gpsOK: True for the first half, False for the second half """ orig_data, replayed_data = run_scenarios(Scenario.GPS_OFF_MIDWAY, self.logs) - self.assertTrue(np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2))) - self.assertTrue(np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5))) - self.assertTrue(np.diff(replayed_data['gps_flag'])[512] == -1.0) + assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2)) + assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5)) + assert np.diff(replayed_data['gps_flag'])[512] == -1.0 def test_gps_on_midway(self): """ @@ -156,9 +155,9 @@ class TestLocationdScenarios(unittest.TestCase): - gpsOK: False for the first half, True for the second half """ orig_data, replayed_data = run_scenarios(Scenario.GPS_ON_MIDWAY, self.logs) - self.assertTrue(np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2))) - self.assertTrue(np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(1.5))) - self.assertTrue(np.diff(replayed_data['gps_flag'])[505] == 1.0) + assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2)) + assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(1.5)) + assert np.diff(replayed_data['gps_flag'])[505] == 1.0 def test_gps_tunnel(self): """ @@ -169,10 +168,10 @@ class TestLocationdScenarios(unittest.TestCase): - gpsOK: False for the middle section, True for the rest """ orig_data, replayed_data = run_scenarios(Scenario.GPS_TUNNEL, self.logs) - self.assertTrue(np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2))) - self.assertTrue(np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5))) - self.assertTrue(np.diff(replayed_data['gps_flag'])[213] == -1.0) - self.assertTrue(np.diff(replayed_data['gps_flag'])[805] == 1.0) + assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2)) + assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5)) + assert np.diff(replayed_data['gps_flag'])[213] == -1.0 + assert np.diff(replayed_data['gps_flag'])[805] == 1.0 def test_gyro_off(self): """ @@ -183,9 +182,9 @@ class TestLocationdScenarios(unittest.TestCase): - sensorsOK: False """ _, replayed_data = run_scenarios(Scenario.GYRO_OFF, self.logs) - self.assertTrue(np.allclose(replayed_data['yaw_rate'], 0.0)) - self.assertTrue(np.allclose(replayed_data['roll'], 0.0)) - self.assertTrue(np.all(replayed_data['sensors_flag'] == 0.0)) + assert np.allclose(replayed_data['yaw_rate'], 0.0) + assert np.allclose(replayed_data['roll'], 0.0) + assert np.all(replayed_data['sensors_flag'] == 0.0) def test_gyro_spikes(self): """ @@ -196,10 +195,10 @@ class TestLocationdScenarios(unittest.TestCase): - inputsOK: False for some time after the spike, True for the rest """ orig_data, replayed_data = run_scenarios(Scenario.GYRO_SPIKE_MIDWAY, self.logs) - self.assertTrue(np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2))) - self.assertTrue(np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5))) - self.assertTrue(np.diff(replayed_data['inputs_flag'])[500] == -1.0) - self.assertTrue(np.diff(replayed_data['inputs_flag'])[694] == 1.0) + assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2)) + assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5)) + assert np.diff(replayed_data['inputs_flag'])[500] == -1.0 + assert np.diff(replayed_data['inputs_flag'])[694] == 1.0 def test_accel_off(self): """ @@ -210,9 +209,9 @@ class TestLocationdScenarios(unittest.TestCase): - sensorsOK: False """ _, replayed_data = run_scenarios(Scenario.ACCEL_OFF, self.logs) - self.assertTrue(np.allclose(replayed_data['yaw_rate'], 0.0)) - self.assertTrue(np.allclose(replayed_data['roll'], 0.0)) - self.assertTrue(np.all(replayed_data['sensors_flag'] == 0.0)) + assert np.allclose(replayed_data['yaw_rate'], 0.0) + assert np.allclose(replayed_data['roll'], 0.0) + assert np.all(replayed_data['sensors_flag'] == 0.0) def test_accel_spikes(self): """ @@ -221,9 +220,5 @@ class TestLocationdScenarios(unittest.TestCase): Expected Result: Right now, the kalman filter is not robust to small spikes like it is to gyroscope spikes. """ orig_data, replayed_data = run_scenarios(Scenario.ACCEL_SPIKE_MIDWAY, self.logs) - self.assertTrue(np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2))) - self.assertTrue(np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5))) - - -if __name__ == "__main__": - unittest.main() + assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.2)) + assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.5)) diff --git a/selfdrive/manager/test/test_manager.py b/selfdrive/manager/test/test_manager.py index 1ae94b26a..4cdc99c24 100755 --- a/selfdrive/manager/test/test_manager.py +++ b/selfdrive/manager/test/test_manager.py @@ -3,7 +3,6 @@ import os import pytest import signal import time -import unittest from parameterized import parameterized @@ -21,15 +20,15 @@ BLACKLIST_PROCS = ['manage_athenad', 'pandad', 'pigeond'] @pytest.mark.tici -class TestManager(unittest.TestCase): - def setUp(self): +class TestManager: + def setup_method(self): HARDWARE.set_power_save(False) # ensure clean CarParams params = Params() params.clear_all() - def tearDown(self): + def teardown_method(self): manager.manager_cleanup() def test_manager_prepare(self): @@ -38,7 +37,7 @@ class TestManager(unittest.TestCase): def test_blacklisted_procs(self): # TODO: ensure there are blacklisted procs until we have a dedicated test - self.assertTrue(len(BLACKLIST_PROCS), "No blacklisted procs to test not_run") + assert len(BLACKLIST_PROCS), "No blacklisted procs to test not_run" @parameterized.expand([(i,) for i in range(10)]) def test_startup_time(self, index): @@ -48,8 +47,8 @@ class TestManager(unittest.TestCase): t = time.monotonic() - start assert t < MAX_STARTUP_TIME, f"startup took {t}s, expected <{MAX_STARTUP_TIME}s" - @unittest.skip("this test is flaky the way it's currently written, should be moved to test_onroad") - def test_clean_exit(self): + @pytest.mark.skip("this test is flaky the way it's currently written, should be moved to test_onroad") + def test_clean_exit(self, subtests): """ Ensure all processes exit cleanly when stopped. """ @@ -62,21 +61,17 @@ class TestManager(unittest.TestCase): time.sleep(10) for p in procs: - with self.subTest(proc=p.name): + with subtests.test(proc=p.name): state = p.get_process_state_msg() - self.assertTrue(state.running, f"{p.name} not running") + assert state.running, f"{p.name} not running" exit_code = p.stop(retry=False) - self.assertNotIn(p.name, BLACKLIST_PROCS, f"{p.name} was started") + assert p.name not in BLACKLIST_PROCS, f"{p.name} was started" - self.assertTrue(exit_code is not None, f"{p.name} failed to exit") + assert exit_code is not None, f"{p.name} failed to exit" # TODO: interrupted blocking read exits with 1 in cereal. use a more unique return code exit_codes = [0, 1] if p.sigkill: exit_codes = [-signal.SIGKILL] - self.assertIn(exit_code, exit_codes, f"{p.name} died with {exit_code}") - - -if __name__ == "__main__": - unittest.main() + assert exit_code in exit_codes, f"{p.name} died with {exit_code}" diff --git a/selfdrive/modeld/tests/test_modeld.py b/selfdrive/modeld/tests/test_modeld.py index 67c6f7103..a18ce8fa4 100755 --- a/selfdrive/modeld/tests/test_modeld.py +++ b/selfdrive/modeld/tests/test_modeld.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import unittest import numpy as np import random @@ -16,9 +15,9 @@ IMG = np.zeros(int(CAM.width*CAM.height*(3/2)), dtype=np.uint8) IMG_BYTES = IMG.flatten().tobytes() -class TestModeld(unittest.TestCase): +class TestModeld: - def setUp(self): + def setup_method(self): self.vipc_server = VisionIpcServer("camerad") self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_ROAD, 40, False, CAM.width, CAM.height) self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_DRIVER, 40, False, CAM.width, CAM.height) @@ -32,7 +31,7 @@ class TestModeld(unittest.TestCase): managed_processes['modeld'].start() self.pm.wait_for_readers_to_update("roadCameraState", 10) - def tearDown(self): + def teardown_method(self): managed_processes['modeld'].stop() del self.vipc_server @@ -65,15 +64,15 @@ class TestModeld(unittest.TestCase): self._wait() mdl = self.sm['modelV2'] - self.assertEqual(mdl.frameId, n) - self.assertEqual(mdl.frameIdExtra, n) - self.assertEqual(mdl.timestampEof, cs.timestampEof) - self.assertEqual(mdl.frameAge, 0) - self.assertEqual(mdl.frameDropPerc, 0) + assert mdl.frameId == n + assert mdl.frameIdExtra == n + assert mdl.timestampEof == cs.timestampEof + assert mdl.frameAge == 0 + assert mdl.frameDropPerc == 0 odo = self.sm['cameraOdometry'] - self.assertEqual(odo.frameId, n) - self.assertEqual(odo.timestampEof, cs.timestampEof) + assert odo.frameId == n + assert odo.timestampEof == cs.timestampEof def test_dropped_frames(self): """ @@ -95,13 +94,9 @@ class TestModeld(unittest.TestCase): mdl = self.sm['modelV2'] odo = self.sm['cameraOdometry'] - self.assertEqual(mdl.frameId, frame_id) - self.assertEqual(mdl.frameIdExtra, frame_id) - self.assertEqual(odo.frameId, frame_id) + assert mdl.frameId == frame_id + assert mdl.frameIdExtra == frame_id + assert odo.frameId == frame_id if n != frame_id: - self.assertFalse(self.sm.updated['modelV2']) - self.assertFalse(self.sm.updated['cameraOdometry']) - - -if __name__ == "__main__": - unittest.main() + assert not self.sm.updated['modelV2'] + assert not self.sm.updated['cameraOdometry'] diff --git a/selfdrive/monitoring/test_monitoring.py b/selfdrive/monitoring/test_monitoring.py index 50b2746e2..9395960b6 100755 --- a/selfdrive/monitoring/test_monitoring.py +++ b/selfdrive/monitoring/test_monitoring.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import unittest import numpy as np from cereal import car, log @@ -53,7 +52,7 @@ always_true = [True] * int(TEST_TIMESPAN / DT_DMON) always_false = [False] * int(TEST_TIMESPAN / DT_DMON) # TODO: this only tests DriverStatus -class TestMonitoring(unittest.TestCase): +class TestMonitoring: def _run_seq(self, msgs, interaction, engaged, standstill): DS = DriverStatus() events = [] @@ -69,7 +68,7 @@ class TestMonitoring(unittest.TestCase): return events, DS def _assert_no_events(self, events): - self.assertTrue(all(not len(e) for e in events)) + assert all(not len(e) for e in events) # engaged, driver is attentive all the time def test_fully_aware_driver(self): @@ -79,27 +78,27 @@ class TestMonitoring(unittest.TestCase): # engaged, driver is distracted and does nothing def test_fully_distracted_driver(self): events, d_status = self._run_seq(always_distracted, always_false, always_true, always_false) - self.assertEqual(len(events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)]), 0) - self.assertEqual(events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL + - ((d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL-d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0], - EventName.preDriverDistracted) - self.assertEqual(events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL + - ((d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertEqual(events[int((d_status.settings._DISTRACTED_TIME + - ((TEST_TIMESPAN-10-d_status.settings._DISTRACTED_TIME)/2))/DT_DMON)].names[0], EventName.driverDistracted) - self.assertIs(type(d_status.awareness), float) + assert len(events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)]) == 0 + assert events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL + \ + ((d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL-d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == \ + EventName.preDriverDistracted + assert events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL + \ + ((d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == EventName.promptDriverDistracted + assert events[int((d_status.settings._DISTRACTED_TIME + \ + ((TEST_TIMESPAN-10-d_status.settings._DISTRACTED_TIME)/2))/DT_DMON)].names[0] == EventName.driverDistracted + assert isinstance(d_status.awareness, float) # engaged, no face detected the whole time, no action def test_fully_invisible_driver(self): events, d_status = self._run_seq(always_no_face, always_false, always_true, always_false) - self.assertTrue(len(events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)]) == 0) - self.assertEqual(events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL + - ((d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL-d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0], - EventName.preDriverUnresponsive) - self.assertEqual(events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL + - ((d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0], EventName.promptDriverUnresponsive) - self.assertEqual(events[int((d_status.settings._AWARENESS_TIME + - ((TEST_TIMESPAN-10-d_status.settings._AWARENESS_TIME)/2))/DT_DMON)].names[0], EventName.driverUnresponsive) + assert len(events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)]) == 0 + assert events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL + \ + ((d_status.settings._AWARENESS_PRE_TIME_TILL_TERMINAL-d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == \ + EventName.preDriverUnresponsive + assert events[int((d_status.settings._AWARENESS_TIME-d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL + \ + ((d_status.settings._AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0] == EventName.promptDriverUnresponsive + assert events[int((d_status.settings._AWARENESS_TIME + \ + ((TEST_TIMESPAN-10-d_status.settings._AWARENESS_TIME)/2))/DT_DMON)].names[0] == EventName.driverUnresponsive # engaged, down to orange, driver pays attention, back to normal; then down to orange, driver touches wheel # - should have short orange recovery time and no green afterwards; wheel touch only recovers when paying attention @@ -111,12 +110,12 @@ class TestMonitoring(unittest.TestCase): interaction_vector = [car_interaction_NOT_DETECTED] * int(DISTRACTED_SECONDS_TO_ORANGE*3/DT_DMON) + \ [car_interaction_DETECTED] * (int(TEST_TIMESPAN/DT_DMON)-int(DISTRACTED_SECONDS_TO_ORANGE*3/DT_DMON)) events, _ = self._run_seq(ds_vector, interaction_vector, always_true, always_false) - self.assertEqual(len(events[int(DISTRACTED_SECONDS_TO_ORANGE*0.5/DT_DMON)]), 0) - self.assertEqual(events[int((DISTRACTED_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertEqual(len(events[int(DISTRACTED_SECONDS_TO_ORANGE*1.5/DT_DMON)]), 0) - self.assertEqual(events[int((DISTRACTED_SECONDS_TO_ORANGE*3-0.1)/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertEqual(events[int((DISTRACTED_SECONDS_TO_ORANGE*3+0.1)/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertEqual(len(events[int((DISTRACTED_SECONDS_TO_ORANGE*3+2.5)/DT_DMON)]), 0) + assert len(events[int(DISTRACTED_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0 + assert events[int((DISTRACTED_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.promptDriverDistracted + assert len(events[int(DISTRACTED_SECONDS_TO_ORANGE*1.5/DT_DMON)]) == 0 + assert events[int((DISTRACTED_SECONDS_TO_ORANGE*3-0.1)/DT_DMON)].names[0] == EventName.promptDriverDistracted + assert events[int((DISTRACTED_SECONDS_TO_ORANGE*3+0.1)/DT_DMON)].names[0] == EventName.promptDriverDistracted + assert len(events[int((DISTRACTED_SECONDS_TO_ORANGE*3+2.5)/DT_DMON)]) == 0 # engaged, down to orange, driver dodges camera, then comes back still distracted, down to red, \ # driver dodges, and then touches wheel to no avail, disengages and reengages @@ -135,10 +134,10 @@ class TestMonitoring(unittest.TestCase): op_vector[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+2.5)/DT_DMON):int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+3)/DT_DMON)] \ = [False] * int(0.5/DT_DMON) events, _ = self._run_seq(ds_vector, interaction_vector, op_vector, always_false) - self.assertEqual(events[int((DISTRACTED_SECONDS_TO_ORANGE+0.5*_invisible_time)/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertEqual(events[int((DISTRACTED_SECONDS_TO_RED+1.5*_invisible_time)/DT_DMON)].names[0], EventName.driverDistracted) - self.assertEqual(events[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+1.5)/DT_DMON)].names[0], EventName.driverDistracted) - self.assertTrue(len(events[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+3.5)/DT_DMON)]) == 0) + assert events[int((DISTRACTED_SECONDS_TO_ORANGE+0.5*_invisible_time)/DT_DMON)].names[0] == EventName.promptDriverDistracted + assert events[int((DISTRACTED_SECONDS_TO_RED+1.5*_invisible_time)/DT_DMON)].names[0] == EventName.driverDistracted + assert events[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+1.5)/DT_DMON)].names[0] == EventName.driverDistracted + assert len(events[int((DISTRACTED_SECONDS_TO_RED+2*_invisible_time+3.5)/DT_DMON)]) == 0 # engaged, invisible driver, down to orange, driver touches wheel; then down to orange again, driver appears # - both actions should clear the alert, but momentary appearance should not @@ -150,15 +149,15 @@ class TestMonitoring(unittest.TestCase): [msg_ATTENTIVE] * int(_visible_time/DT_DMON) interaction_vector[int((INVISIBLE_SECONDS_TO_ORANGE)/DT_DMON):int((INVISIBLE_SECONDS_TO_ORANGE+1)/DT_DMON)] = [True] * int(1/DT_DMON) events, _ = self._run_seq(ds_vector, interaction_vector, 2*always_true, 2*always_false) - self.assertTrue(len(events[int(INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0) - self.assertEqual(events[int((INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0], EventName.promptDriverUnresponsive) - self.assertTrue(len(events[int((INVISIBLE_SECONDS_TO_ORANGE+0.1)/DT_DMON)]) == 0) + assert len(events[int(INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0 + assert events[int((INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.promptDriverUnresponsive + assert len(events[int((INVISIBLE_SECONDS_TO_ORANGE+0.1)/DT_DMON)]) == 0 if _visible_time == 0.5: - self.assertEqual(events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0], EventName.promptDriverUnresponsive) - self.assertEqual(events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)].names[0], EventName.preDriverUnresponsive) + assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0] == EventName.promptDriverUnresponsive + assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)].names[0] == EventName.preDriverUnresponsive elif _visible_time == 10: - self.assertEqual(events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0], EventName.promptDriverUnresponsive) - self.assertTrue(len(events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)]) == 0) + assert events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0] == EventName.promptDriverUnresponsive + assert len(events[int((INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)]) == 0 # engaged, invisible driver, down to red, driver appears and then touches wheel, then disengages/reengages # - only disengage will clear the alert @@ -171,18 +170,18 @@ class TestMonitoring(unittest.TestCase): interaction_vector[int((INVISIBLE_SECONDS_TO_RED+_visible_time)/DT_DMON):int((INVISIBLE_SECONDS_TO_RED+_visible_time+1)/DT_DMON)] = [True] * int(1/DT_DMON) op_vector[int((INVISIBLE_SECONDS_TO_RED+_visible_time+1)/DT_DMON):int((INVISIBLE_SECONDS_TO_RED+_visible_time+0.5)/DT_DMON)] = [False] * int(0.5/DT_DMON) events, _ = self._run_seq(ds_vector, interaction_vector, op_vector, always_false) - self.assertTrue(len(events[int(INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0) - self.assertEqual(events[int((INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0], EventName.promptDriverUnresponsive) - self.assertEqual(events[int((INVISIBLE_SECONDS_TO_RED-0.1)/DT_DMON)].names[0], EventName.driverUnresponsive) - self.assertEqual(events[int((INVISIBLE_SECONDS_TO_RED+0.5*_visible_time)/DT_DMON)].names[0], EventName.driverUnresponsive) - self.assertEqual(events[int((INVISIBLE_SECONDS_TO_RED+_visible_time+0.5)/DT_DMON)].names[0], EventName.driverUnresponsive) - self.assertTrue(len(events[int((INVISIBLE_SECONDS_TO_RED+_visible_time+1+0.1)/DT_DMON)]) == 0) + assert len(events[int(INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0 + assert events[int((INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0] == EventName.promptDriverUnresponsive + assert events[int((INVISIBLE_SECONDS_TO_RED-0.1)/DT_DMON)].names[0] == EventName.driverUnresponsive + assert events[int((INVISIBLE_SECONDS_TO_RED+0.5*_visible_time)/DT_DMON)].names[0] == EventName.driverUnresponsive + assert events[int((INVISIBLE_SECONDS_TO_RED+_visible_time+0.5)/DT_DMON)].names[0] == EventName.driverUnresponsive + assert len(events[int((INVISIBLE_SECONDS_TO_RED+_visible_time+1+0.1)/DT_DMON)]) == 0 # disengaged, always distracted driver # - dm should stay quiet when not engaged def test_pure_dashcam_user(self): events, _ = self._run_seq(always_distracted, always_false, always_false, always_false) - self.assertTrue(sum(len(event) for event in events) == 0) + assert sum(len(event) for event in events) == 0 # engaged, car stops at traffic light, down to orange, no action, then car starts moving # - should only reach green when stopped, but continues counting down on launch @@ -191,10 +190,10 @@ class TestMonitoring(unittest.TestCase): standstill_vector = always_true[:] standstill_vector[int(_redlight_time/DT_DMON):] = [False] * int((TEST_TIMESPAN-_redlight_time)/DT_DMON) events, d_status = self._run_seq(always_distracted, always_false, always_true, standstill_vector) - self.assertEqual(events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL+1)/DT_DMON)].names[0], - EventName.preDriverDistracted) - self.assertEqual(events[int((_redlight_time-0.1)/DT_DMON)].names[0], EventName.preDriverDistracted) - self.assertEqual(events[int((_redlight_time+0.5)/DT_DMON)].names[0], EventName.promptDriverDistracted) + assert events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL+1)/DT_DMON)].names[0] == \ + EventName.preDriverDistracted + assert events[int((_redlight_time-0.1)/DT_DMON)].names[0] == EventName.preDriverDistracted + assert events[int((_redlight_time+0.5)/DT_DMON)].names[0] == EventName.promptDriverDistracted # engaged, model is somehow uncertain and driver is distracted # - should fall back to wheel touch after uncertain alert @@ -202,13 +201,10 @@ class TestMonitoring(unittest.TestCase): ds_vector = [msg_DISTRACTED_BUT_SOMEHOW_UNCERTAIN] * int(TEST_TIMESPAN/DT_DMON) interaction_vector = always_false[:] events, d_status = self._run_seq(ds_vector, interaction_vector, always_true, always_false) - self.assertTrue(EventName.preDriverUnresponsive in - events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME-0.1)/DT_DMON)].names) - self.assertTrue(EventName.promptDriverUnresponsive in - events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names) - self.assertTrue(EventName.driverUnresponsive in - events[int((INVISIBLE_SECONDS_TO_RED-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names) + assert EventName.preDriverUnresponsive in \ + events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME-0.1)/DT_DMON)].names + assert EventName.promptDriverUnresponsive in \ + events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names + assert EventName.driverUnresponsive in \ + events[int((INVISIBLE_SECONDS_TO_RED-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/navd/tests/test_map_renderer.py b/selfdrive/navd/tests/test_map_renderer.py index 832e0d1ea..52b594a57 100755 --- a/selfdrive/navd/tests/test_map_renderer.py +++ b/selfdrive/navd/tests/test_map_renderer.py @@ -3,7 +3,6 @@ import time import numpy as np import os import pytest -import unittest import requests import threading import http.server @@ -66,11 +65,11 @@ class MapBoxInternetDisabledServer(threading.Thread): @pytest.mark.skip(reason="not used") -class TestMapRenderer(unittest.TestCase): +class TestMapRenderer: server: MapBoxInternetDisabledServer @classmethod - def setUpClass(cls): + def setup_class(cls): assert "MAPBOX_TOKEN" in os.environ cls.original_token = os.environ["MAPBOX_TOKEN"] cls.server = MapBoxInternetDisabledServer() @@ -78,10 +77,10 @@ class TestMapRenderer(unittest.TestCase): time.sleep(0.5) # wait for server to startup @classmethod - def tearDownClass(cls) -> None: + def teardown_class(cls) -> None: cls.server.stop() - def setUp(self): + def setup_method(self): self.server.enable_internet() os.environ['MAPS_HOST'] = f'http://localhost:{self.server.port}' @@ -203,15 +202,12 @@ class TestMapRenderer(unittest.TestCase): def assert_stat(stat, nominal, tol=0.3): tol = (nominal / (1+tol)), (nominal * (1+tol)) - self.assertTrue(tol[0] < stat < tol[1], f"{stat} not in tolerance {tol}") + assert tol[0] < stat < tol[1], f"{stat} not in tolerance {tol}" assert_stat(_mean, 0.030) assert_stat(_median, 0.027) assert_stat(_stddev, 0.0078) - self.assertLess(_max, 0.065) - self.assertGreater(_min, 0.015) + assert _max < 0.065 + assert _min > 0.015 - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/navd/tests/test_navd.py b/selfdrive/navd/tests/test_navd.py index 61be6cc38..07f930365 100755 --- a/selfdrive/navd/tests/test_navd.py +++ b/selfdrive/navd/tests/test_navd.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import json import random -import unittest import numpy as np from parameterized import parameterized @@ -11,12 +10,12 @@ from openpilot.common.params import Params from openpilot.selfdrive.manager.process_config import managed_processes -class TestNavd(unittest.TestCase): - def setUp(self): +class TestNavd: + def setup_method(self): self.params = Params() self.sm = messaging.SubMaster(['navRoute', 'navInstruction']) - def tearDown(self): + def teardown_method(self): managed_processes['navd'].stop() def _check_route(self, start, end, check_coords=True): @@ -57,7 +56,3 @@ class TestNavd(unittest.TestCase): start = {"latitude": random.uniform(-90, 90), "longitude": random.uniform(-180, 180)} end = {"latitude": random.uniform(-90, 90), "longitude": random.uniform(-180, 180)} self._check_route(start, end, check_coords=False) - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/test/helpers.py b/selfdrive/test/helpers.py index ce8918aec..148d142bb 100644 --- a/selfdrive/test/helpers.py +++ b/selfdrive/test/helpers.py @@ -3,6 +3,7 @@ import http.server import os import threading import time +import pytest from functools import wraps @@ -32,15 +33,15 @@ def phone_only(f): @wraps(f) def wrap(self, *args, **kwargs): if PC: - self.skipTest("This test is not meant to run on PC") - f(self, *args, **kwargs) + pytest.skip("This test is not meant to run on PC") + return f(self, *args, **kwargs) return wrap def release_only(f): @wraps(f) def wrap(self, *args, **kwargs): if "RELEASE" not in os.environ: - self.skipTest("This test is only for release branches") + pytest.skip("This test is only for release branches") f(self, *args, **kwargs) return wrap diff --git a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py index 713b7801f..0ad6d6d4f 100755 --- a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py +++ b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import itertools -import unittest from parameterized import parameterized_class from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import STOP_DISTANCE @@ -144,17 +143,13 @@ def create_maneuvers(kwargs): @parameterized_class(("e2e", "force_decel"), itertools.product([True, False], repeat=2)) -class LongitudinalControl(unittest.TestCase): +class TestLongitudinalControl: e2e: bool force_decel: bool - def test_maneuver(self): + def test_maneuver(self, subtests): for maneuver in create_maneuvers({"e2e": self.e2e, "force_decel": self.force_decel}): - with self.subTest(title=maneuver.title, e2e=maneuver.e2e, force_decel=maneuver.force_decel): + with subtests.test(title=maneuver.title, e2e=maneuver.e2e, force_decel=maneuver.force_decel): print(maneuver.title, f'in {"e2e" if maneuver.e2e else "acc"} mode') valid, _ = maneuver.evaluate() - self.assertTrue(valid) - - -if __name__ == "__main__": - unittest.main(failfast=True) + assert valid diff --git a/selfdrive/test/process_replay/test_fuzzy.py b/selfdrive/test/process_replay/test_fuzzy.py index 6c81119fb..d295092b2 100755 --- a/selfdrive/test/process_replay/test_fuzzy.py +++ b/selfdrive/test/process_replay/test_fuzzy.py @@ -3,7 +3,6 @@ import copy from hypothesis import given, HealthCheck, Phase, settings import hypothesis.strategies as st from parameterized import parameterized -import unittest from cereal import log from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA @@ -17,7 +16,7 @@ NOT_TESTED = ['controlsd', 'plannerd', 'calibrationd', 'dmonitoringd', 'paramsd' TEST_CASES = [(cfg.proc_name, copy.deepcopy(cfg)) for cfg in pr.CONFIGS if cfg.proc_name not in NOT_TESTED] -class TestFuzzProcesses(unittest.TestCase): +class TestFuzzProcesses: # TODO: make this faster and increase examples @parameterized.expand(TEST_CASES) @@ -28,6 +27,3 @@ class TestFuzzProcesses(unittest.TestCase): lr = [log.Event.new_message(**m).as_reader() for m in msgs] cfg.timeout = 5 pr.replay_process(cfg, lr, fingerprint=TOYOTA.TOYOTA_COROLLA_TSS2, disable_progress=True) - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/test/process_replay/test_regen.py b/selfdrive/test/process_replay/test_regen.py index d98963549..c27d9e8f7 100755 --- a/selfdrive/test/process_replay/test_regen.py +++ b/selfdrive/test/process_replay/test_regen.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -import unittest - from parameterized import parameterized from openpilot.selfdrive.test.process_replay.regen import regen_segment, DummyFrameReader @@ -30,7 +28,7 @@ def ci_setup_data_readers(route, sidx): return lr, frs -class TestRegen(unittest.TestCase): +class TestRegen: @parameterized.expand(TESTED_SEGMENTS) def test_engaged(self, case_name, segment): route, sidx = segment.rsplit("--", 1) @@ -38,8 +36,4 @@ class TestRegen(unittest.TestCase): output_logs = regen_segment(lr, frs, disable_tqdm=True) engaged = check_openpilot_enabled(output_logs) - self.assertTrue(engaged, f"openpilot not engaged in {case_name}") - - -if __name__=='__main__': - unittest.main() + assert engaged, f"openpilot not engaged in {case_name}" diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index cd0846c89..9aca9afcd 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -10,7 +10,6 @@ import shutil import subprocess import time import numpy as np -import unittest from collections import Counter, defaultdict from functools import cached_property from pathlib import Path @@ -102,10 +101,10 @@ def cputime_total(ct): @pytest.mark.tici -class TestOnroad(unittest.TestCase): +class TestOnroad: @classmethod - def setUpClass(cls): + def setup_class(cls): if "DEBUG" in os.environ: segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog")), Path(Paths.log_root()).iterdir()) segs = sorted(segs, key=lambda x: x.stat().st_mtime) @@ -181,7 +180,7 @@ class TestOnroad(unittest.TestCase): msgs[m.which()].append(m) return msgs - def test_service_frequencies(self): + def test_service_frequencies(self, subtests): for s, msgs in self.service_msgs.items(): if s in ('initData', 'sentinel'): continue @@ -190,18 +189,18 @@ class TestOnroad(unittest.TestCase): if s in ('ubloxGnss', 'ubloxRaw', 'gnssMeasurements', 'gpsLocation', 'gpsLocationExternal', 'qcomGnss'): continue - with self.subTest(service=s): + with subtests.test(service=s): assert len(msgs) >= math.floor(SERVICE_LIST[s].frequency*55) def test_cloudlog_size(self): msgs = [m for m in self.lr if m.which() == 'logMessage'] total_size = sum(len(m.as_builder().to_bytes()) for m in msgs) - self.assertLess(total_size, 3.5e5) + assert total_size < 3.5e5 cnt = Counter(json.loads(m.logMessage)['filename'] for m in msgs) big_logs = [f for f, n in cnt.most_common(3) if n / sum(cnt.values()) > 30.] - self.assertEqual(len(big_logs), 0, f"Log spam: {big_logs}") + assert len(big_logs) == 0, f"Log spam: {big_logs}" def test_log_sizes(self): for f, sz in self.log_sizes.items(): @@ -230,15 +229,15 @@ class TestOnroad(unittest.TestCase): result += "------------------------------------------------\n" print(result) - self.assertLess(max(ts), 250.) - self.assertLess(np.mean(ts), 10.) + assert max(ts) < 250. + assert np.mean(ts) < 10. #self.assertLess(np.std(ts), 5.) # some slow frames are expected since camerad/modeld can preempt ui veryslow = [x for x in ts if x > 40.] assert len(veryslow) < 5, f"Too many slow frame draw times: {veryslow}" - def test_cpu_usage(self): + def test_cpu_usage(self, subtests): result = "\n" result += "------------------------------------------------\n" result += "------------------ CPU Usage -------------------\n" @@ -286,12 +285,12 @@ class TestOnroad(unittest.TestCase): # Ensure there's no missing procs all_procs = {p.name for p in self.service_msgs['managerState'][0].managerState.processes if p.shouldBeRunning} for p in all_procs: - with self.subTest(proc=p): + with subtests.test(proc=p): assert any(p in pp for pp in PROCS.keys()), f"Expected CPU usage missing for {p}" # total CPU check procs_tot = sum([(max(x) if isinstance(x, tuple) else x) for x in PROCS.values()]) - with self.subTest(name="total CPU"): + with subtests.test(name="total CPU"): assert procs_tot < MAX_TOTAL_CPU, "Total CPU budget exceeded" result += "------------------------------------------------\n" result += f"Total allocated CPU usage is {procs_tot}%, budget is {MAX_TOTAL_CPU}%, {MAX_TOTAL_CPU-procs_tot:.1f}% left\n" @@ -299,7 +298,7 @@ class TestOnroad(unittest.TestCase): print(result) - self.assertTrue(cpu_ok) + assert cpu_ok def test_memory_usage(self): mems = [m.deviceState.memoryUsagePercent for m in self.service_msgs['deviceState']] @@ -307,10 +306,10 @@ class TestOnroad(unittest.TestCase): # check for big leaks. note that memory usage is # expected to go up while the MSGQ buffers fill up - self.assertLessEqual(max(mems) - min(mems), 3.0) + assert max(mems) - min(mems) <= 3.0 def test_gpu_usage(self): - self.assertEqual(self.gpu_procs, {"weston", "ui", "camerad", "selfdrive.modeld.modeld"}) + assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.modeld.modeld"} def test_camera_processing_time(self): result = "\n" @@ -319,14 +318,14 @@ class TestOnroad(unittest.TestCase): result += "------------------------------------------------\n" ts = [getattr(m, m.which()).processingTime for m in self.lr if 'CameraState' in m.which()] - self.assertLess(min(ts), 0.025, f"high execution time: {min(ts)}") + assert min(ts) < 0.025, f"high execution time: {min(ts)}" result += f"execution time: min {min(ts):.5f}s\n" result += f"execution time: max {max(ts):.5f}s\n" result += f"execution time: mean {np.mean(ts):.5f}s\n" result += "------------------------------------------------\n" print(result) - @unittest.skip("TODO: enable once timings are fixed") + @pytest.mark.skip("TODO: enable once timings are fixed") def test_camera_frame_timings(self): result = "\n" result += "------------------------------------------------\n" @@ -336,7 +335,7 @@ class TestOnroad(unittest.TestCase): ts = [getattr(m, m.which()).timestampSof for m in self.lr if name in m.which()] d_ms = np.diff(ts) / 1e6 d50 = np.abs(d_ms-50) - self.assertLess(max(d50), 1.0, f"high sof delta vs 50ms: {max(d50)}") + assert max(d50) < 1.0, f"high sof delta vs 50ms: {max(d50)}" result += f"{name} sof delta vs 50ms: min {min(d50):.5f}s\n" result += f"{name} sof delta vs 50ms: max {max(d50):.5f}s\n" result += f"{name} sof delta vs 50ms: mean {d50.mean():.5f}s\n" @@ -352,8 +351,8 @@ class TestOnroad(unittest.TestCase): cfgs = [("longitudinalPlan", 0.05, 0.05),] for (s, instant_max, avg_max) in cfgs: ts = [getattr(m, s).solverExecutionTime for m in self.service_msgs[s]] - self.assertLess(max(ts), instant_max, f"high '{s}' execution time: {max(ts)}") - self.assertLess(np.mean(ts), avg_max, f"high avg '{s}' execution time: {np.mean(ts)}") + assert max(ts) < instant_max, f"high '{s}' execution time: {max(ts)}" + assert np.mean(ts) < avg_max, f"high avg '{s}' execution time: {np.mean(ts)}" result += f"'{s}' execution time: min {min(ts):.5f}s\n" result += f"'{s}' execution time: max {max(ts):.5f}s\n" result += f"'{s}' execution time: mean {np.mean(ts):.5f}s\n" @@ -372,8 +371,8 @@ class TestOnroad(unittest.TestCase): ] for (s, instant_max, avg_max) in cfgs: ts = [getattr(m, s).modelExecutionTime for m in self.service_msgs[s]] - self.assertLess(max(ts), instant_max, f"high '{s}' execution time: {max(ts)}") - self.assertLess(np.mean(ts), avg_max, f"high avg '{s}' execution time: {np.mean(ts)}") + assert max(ts) < instant_max, f"high '{s}' execution time: {max(ts)}" + assert np.mean(ts) < avg_max, f"high avg '{s}' execution time: {np.mean(ts)}" result += f"'{s}' execution time: min {min(ts):.5f}s\n" result += f"'{s}' execution time: max {max(ts):.5f}s\n" result += f"'{s}' execution time: mean {np.mean(ts):.5f}s\n" @@ -409,7 +408,7 @@ class TestOnroad(unittest.TestCase): result += f"{''.ljust(40)} {np.max(np.absolute([np.max(ts)/dt, np.min(ts)/dt]))} {np.std(ts)/dt}\n" result += "="*67 print(result) - self.assertTrue(passed) + assert passed @release_only def test_startup(self): @@ -420,7 +419,7 @@ class TestOnroad(unittest.TestCase): startup_alert = msg.controlsState.alertText1 break expected = EVENTS[car.CarEvent.EventName.startup][ET.PERMANENT].alert_text_1 - self.assertEqual(startup_alert, expected, "wrong startup alert") + assert startup_alert == expected, "wrong startup alert" def test_engagable(self): no_entries = Counter() @@ -432,7 +431,3 @@ class TestOnroad(unittest.TestCase): eng = [m.controlsState.engageable for m in self.service_msgs['controlsState']] assert all(eng), \ f"Not engageable for whole segment:\n- controlsState.engageable: {Counter(eng)}\n- No entry events: {no_entries}" - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/test/test_updated.py b/selfdrive/test/test_updated.py index dd79e03de..5220cfb28 100755 --- a/selfdrive/test/test_updated.py +++ b/selfdrive/test/test_updated.py @@ -4,7 +4,6 @@ import os import pytest import time import tempfile -import unittest import shutil import signal import subprocess @@ -15,9 +14,9 @@ from openpilot.common.params import Params @pytest.mark.tici -class TestUpdated(unittest.TestCase): +class TestUpdated: - def setUp(self): + def setup_method(self): self.updated_proc = None self.tmp_dir = tempfile.TemporaryDirectory() @@ -59,7 +58,7 @@ class TestUpdated(unittest.TestCase): self.params.clear_all() os.sync() - def tearDown(self): + def teardown_method(self): try: if self.updated_proc is not None: self.updated_proc.terminate() @@ -167,7 +166,7 @@ class TestUpdated(unittest.TestCase): t = self._read_param("LastUpdateTime") last_update_time = datetime.datetime.fromisoformat(t) td = datetime.datetime.utcnow() - last_update_time - self.assertLess(td.total_seconds(), 10) + assert td.total_seconds() < 10 self.params.remove("LastUpdateTime") # wait a bit for the rest of the params to be written @@ -175,13 +174,13 @@ class TestUpdated(unittest.TestCase): # check params update = self._read_param("UpdateAvailable") - self.assertEqual(update == "1", update_available, f"UpdateAvailable: {repr(update)}") - self.assertEqual(self._read_param("UpdateFailedCount"), "0") + assert update == "1" == update_available, f"UpdateAvailable: {repr(update)}" + assert self._read_param("UpdateFailedCount") == "0" # TODO: check that the finalized update actually matches remote # check the .overlay_init and .overlay_consistent flags - self.assertTrue(os.path.isfile(os.path.join(self.basedir, ".overlay_init"))) - self.assertEqual(os.path.isfile(os.path.join(self.finalized_dir, ".overlay_consistent")), update_available) + assert os.path.isfile(os.path.join(self.basedir, ".overlay_init")) + assert os.path.isfile(os.path.join(self.finalized_dir, ".overlay_consistent")) == update_available # *** test cases *** @@ -214,7 +213,7 @@ class TestUpdated(unittest.TestCase): self._check_update_state(True) # Let the updater run for 10 cycles, and write an update every cycle - @unittest.skip("need to make this faster") + @pytest.mark.skip("need to make this faster") def test_update_loop(self): self._start_updater() @@ -243,12 +242,12 @@ class TestUpdated(unittest.TestCase): # run another cycle, should have a new mtime self._wait_for_update(clear_param=True) second_mtime = os.path.getmtime(overlay_init_fn) - self.assertTrue(first_mtime != second_mtime) + assert first_mtime != second_mtime # run another cycle, mtime should be same as last cycle self._wait_for_update(clear_param=True) new_mtime = os.path.getmtime(overlay_init_fn) - self.assertTrue(second_mtime == new_mtime) + assert second_mtime == new_mtime # Make sure updated exits if another instance is running def test_multiple_instances(self): @@ -260,7 +259,7 @@ class TestUpdated(unittest.TestCase): # start another instance second_updated = self._get_updated_proc() ret_code = second_updated.wait(timeout=5) - self.assertTrue(ret_code is not None) + assert ret_code is not None # *** test cases with NEOS updates *** @@ -277,10 +276,10 @@ class TestUpdated(unittest.TestCase): self._start_updater() self._wait_for_update(clear_param=True) self._check_update_state(False) - self.assertFalse(os.path.isdir(self.neosupdate_dir)) + assert not os.path.isdir(self.neosupdate_dir) # Let the updater run with no update for a cycle, then write an update - @unittest.skip("TODO: only runs on device") + @pytest.mark.skip("TODO: only runs on device") def test_update_with_neos_update(self): # bump the NEOS version and commit it self._run([ @@ -295,8 +294,4 @@ class TestUpdated(unittest.TestCase): self._check_update_state(True) # TODO: more comprehensive check - self.assertTrue(os.path.isdir(self.neosupdate_dir)) - - -if __name__ == "__main__": - unittest.main() + assert os.path.isdir(self.neosupdate_dir) diff --git a/selfdrive/test/test_valgrind_replay.py b/selfdrive/test/test_valgrind_replay.py index 75520df91..dffd60df9 100755 --- a/selfdrive/test/test_valgrind_replay.py +++ b/selfdrive/test/test_valgrind_replay.py @@ -2,7 +2,6 @@ import os import threading import time -import unittest import subprocess import signal @@ -35,7 +34,7 @@ CONFIGS = [ ] -class TestValgrind(unittest.TestCase): +class TestValgrind: def extract_leak_sizes(self, log): if "All heap blocks were freed -- no leaks are possible" in log: return (0,0,0) @@ -110,8 +109,4 @@ class TestValgrind(unittest.TestCase): while self.leak is None: time.sleep(0.1) # Wait for the valgrind to finish - self.assertFalse(self.leak) - - -if __name__ == "__main__": - unittest.main() + assert not self.leak diff --git a/selfdrive/thermald/tests/test_fan_controller.py b/selfdrive/thermald/tests/test_fan_controller.py index 7081e1353..c2b1a6450 100755 --- a/selfdrive/thermald/tests/test_fan_controller.py +++ b/selfdrive/thermald/tests/test_fan_controller.py @@ -1,17 +1,15 @@ #!/usr/bin/env python3 -import unittest -from unittest.mock import Mock, patch -from parameterized import parameterized +import pytest from openpilot.selfdrive.thermald.fan_controller import TiciFanController -ALL_CONTROLLERS = [(TiciFanController,)] +ALL_CONTROLLERS = [TiciFanController] -def patched_controller(controller_class): - with patch("os.system", new=Mock()): - return controller_class() +def patched_controller(mocker, controller_class): + mocker.patch("os.system", new=mocker.Mock()) + return controller_class() -class TestFanController(unittest.TestCase): +class TestFanController: def wind_up(self, controller, ignition=True): for _ in range(1000): controller.update(100, ignition) @@ -20,37 +18,34 @@ class TestFanController(unittest.TestCase): for _ in range(1000): controller.update(10, ignition) - @parameterized.expand(ALL_CONTROLLERS) - def test_hot_onroad(self, controller_class): - controller = patched_controller(controller_class) + @pytest.mark.parametrize("controller_class", ALL_CONTROLLERS) + def test_hot_onroad(self, mocker, controller_class): + controller = patched_controller(mocker, controller_class) self.wind_up(controller) - self.assertGreaterEqual(controller.update(100, True), 70) + assert controller.update(100, True) >= 70 - @parameterized.expand(ALL_CONTROLLERS) - def test_offroad_limits(self, controller_class): - controller = patched_controller(controller_class) + @pytest.mark.parametrize("controller_class", ALL_CONTROLLERS) + def test_offroad_limits(self, mocker, controller_class): + controller = patched_controller(mocker, controller_class) self.wind_up(controller) - self.assertLessEqual(controller.update(100, False), 30) + assert controller.update(100, False) <= 30 - @parameterized.expand(ALL_CONTROLLERS) - def test_no_fan_wear(self, controller_class): - controller = patched_controller(controller_class) + @pytest.mark.parametrize("controller_class", ALL_CONTROLLERS) + def test_no_fan_wear(self, mocker, controller_class): + controller = patched_controller(mocker, controller_class) self.wind_down(controller) - self.assertEqual(controller.update(10, False), 0) + assert controller.update(10, False) == 0 - @parameterized.expand(ALL_CONTROLLERS) - def test_limited(self, controller_class): - controller = patched_controller(controller_class) + @pytest.mark.parametrize("controller_class", ALL_CONTROLLERS) + def test_limited(self, mocker, controller_class): + controller = patched_controller(mocker, controller_class) self.wind_up(controller, True) - self.assertEqual(controller.update(100, True), 100) + assert controller.update(100, True) == 100 - @parameterized.expand(ALL_CONTROLLERS) - def test_windup_speed(self, controller_class): - controller = patched_controller(controller_class) + @pytest.mark.parametrize("controller_class", ALL_CONTROLLERS) + def test_windup_speed(self, mocker, controller_class): + controller = patched_controller(mocker, controller_class) self.wind_down(controller, True) for _ in range(10): controller.update(90, True) - self.assertGreaterEqual(controller.update(90, True), 60) - -if __name__ == "__main__": - unittest.main() + assert controller.update(90, True) >= 60 diff --git a/selfdrive/thermald/tests/test_power_monitoring.py b/selfdrive/thermald/tests/test_power_monitoring.py index c3a890f06..f68191475 100755 --- a/selfdrive/thermald/tests/test_power_monitoring.py +++ b/selfdrive/thermald/tests/test_power_monitoring.py @@ -1,12 +1,10 @@ #!/usr/bin/env python3 -import unittest -from unittest.mock import patch +import pytest from openpilot.common.params import Params from openpilot.selfdrive.thermald.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \ CAR_CHARGING_RATE_W, VBATT_PAUSE_CHARGING, DELAY_SHUTDOWN_TIME_S - # Create fake time ssb = 0. def mock_time_monotonic(): @@ -18,163 +16,169 @@ TEST_DURATION_S = 50 GOOD_VOLTAGE = 12 * 1e3 VOLTAGE_BELOW_PAUSE_CHARGING = (VBATT_PAUSE_CHARGING - 1) * 1e3 -def pm_patch(name, value, constant=False): +def pm_patch(mocker, name, value, constant=False): if constant: - return patch(f"openpilot.selfdrive.thermald.power_monitoring.{name}", value) - return patch(f"openpilot.selfdrive.thermald.power_monitoring.{name}", return_value=value) + mocker.patch(f"openpilot.selfdrive.thermald.power_monitoring.{name}", value) + else: + mocker.patch(f"openpilot.selfdrive.thermald.power_monitoring.{name}", return_value=value) -@patch("time.monotonic", new=mock_time_monotonic) -class TestPowerMonitoring(unittest.TestCase): - def setUp(self): +@pytest.fixture(autouse=True) +def mock_time(mocker): + mocker.patch("time.monotonic", mock_time_monotonic) + + +class TestPowerMonitoring: + def setup_method(self): self.params = Params() # Test to see that it doesn't do anything when pandaState is None - def test_pandaState_present(self): + def test_panda_state_present(self): pm = PowerMonitoring() for _ in range(10): pm.calculate(None, None) - self.assertEqual(pm.get_power_used(), 0) - self.assertEqual(pm.get_car_battery_capacity(), (CAR_BATTERY_CAPACITY_uWh / 10)) + assert pm.get_power_used() == 0 + assert pm.get_car_battery_capacity() == (CAR_BATTERY_CAPACITY_uWh / 10) # Test to see that it doesn't integrate offroad when ignition is True def test_offroad_ignition(self): pm = PowerMonitoring() for _ in range(10): pm.calculate(GOOD_VOLTAGE, True) - self.assertEqual(pm.get_power_used(), 0) + assert pm.get_power_used() == 0 # Test to see that it integrates with discharging battery - def test_offroad_integration_discharging(self): + def test_offroad_integration_discharging(self, mocker): POWER_DRAW = 4 - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - for _ in range(TEST_DURATION_S + 1): - pm.calculate(GOOD_VOLTAGE, False) - expected_power_usage = ((TEST_DURATION_S/3600) * POWER_DRAW * 1e6) - self.assertLess(abs(pm.get_power_used() - expected_power_usage), 10) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + for _ in range(TEST_DURATION_S + 1): + pm.calculate(GOOD_VOLTAGE, False) + expected_power_usage = ((TEST_DURATION_S/3600) * POWER_DRAW * 1e6) + assert abs(pm.get_power_used() - expected_power_usage) < 10 # Test to check positive integration of car_battery_capacity - def test_car_battery_integration_onroad(self): + def test_car_battery_integration_onroad(self, mocker): POWER_DRAW = 4 - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = 0 - for _ in range(TEST_DURATION_S + 1): - pm.calculate(GOOD_VOLTAGE, True) - expected_capacity = ((TEST_DURATION_S/3600) * CAR_CHARGING_RATE_W * 1e6) - self.assertLess(abs(pm.get_car_battery_capacity() - expected_capacity), 10) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = 0 + for _ in range(TEST_DURATION_S + 1): + pm.calculate(GOOD_VOLTAGE, True) + expected_capacity = ((TEST_DURATION_S/3600) * CAR_CHARGING_RATE_W * 1e6) + assert abs(pm.get_car_battery_capacity() - expected_capacity) < 10 # Test to check positive integration upper limit - def test_car_battery_integration_upper_limit(self): + def test_car_battery_integration_upper_limit(self, mocker): POWER_DRAW = 4 - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - 1000 - for _ in range(TEST_DURATION_S + 1): - pm.calculate(GOOD_VOLTAGE, True) - estimated_capacity = CAR_BATTERY_CAPACITY_uWh + (CAR_CHARGING_RATE_W / 3600 * 1e6) - self.assertLess(abs(pm.get_car_battery_capacity() - estimated_capacity), 10) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - 1000 + for _ in range(TEST_DURATION_S + 1): + pm.calculate(GOOD_VOLTAGE, True) + estimated_capacity = CAR_BATTERY_CAPACITY_uWh + (CAR_CHARGING_RATE_W / 3600 * 1e6) + assert abs(pm.get_car_battery_capacity() - estimated_capacity) < 10 # Test to check negative integration of car_battery_capacity - def test_car_battery_integration_offroad(self): + def test_car_battery_integration_offroad(self, mocker): POWER_DRAW = 4 - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - for _ in range(TEST_DURATION_S + 1): - pm.calculate(GOOD_VOLTAGE, False) - expected_capacity = CAR_BATTERY_CAPACITY_uWh - ((TEST_DURATION_S/3600) * POWER_DRAW * 1e6) - self.assertLess(abs(pm.get_car_battery_capacity() - expected_capacity), 10) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + for _ in range(TEST_DURATION_S + 1): + pm.calculate(GOOD_VOLTAGE, False) + expected_capacity = CAR_BATTERY_CAPACITY_uWh - ((TEST_DURATION_S/3600) * POWER_DRAW * 1e6) + assert abs(pm.get_car_battery_capacity() - expected_capacity) < 10 # Test to check negative integration lower limit - def test_car_battery_integration_lower_limit(self): + def test_car_battery_integration_lower_limit(self, mocker): POWER_DRAW = 4 - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = 1000 - for _ in range(TEST_DURATION_S + 1): - pm.calculate(GOOD_VOLTAGE, False) - estimated_capacity = 0 - ((1/3600) * POWER_DRAW * 1e6) - self.assertLess(abs(pm.get_car_battery_capacity() - estimated_capacity), 10) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = 1000 + for _ in range(TEST_DURATION_S + 1): + pm.calculate(GOOD_VOLTAGE, False) + estimated_capacity = 0 - ((1/3600) * POWER_DRAW * 1e6) + assert abs(pm.get_car_battery_capacity() - estimated_capacity) < 10 # Test to check policy of stopping charging after MAX_TIME_OFFROAD_S - def test_max_time_offroad(self): + def test_max_time_offroad(self, mocker): MOCKED_MAX_OFFROAD_TIME = 3600 POWER_DRAW = 0 # To stop shutting down for other reasons - with pm_patch("MAX_TIME_OFFROAD_S", MOCKED_MAX_OFFROAD_TIME, constant=True), pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - start_time = ssb - ignition = False - while ssb <= start_time + MOCKED_MAX_OFFROAD_TIME: - pm.calculate(GOOD_VOLTAGE, ignition) - if (ssb - start_time) % 1000 == 0 and ssb < start_time + MOCKED_MAX_OFFROAD_TIME: - self.assertFalse(pm.should_shutdown(ignition, True, start_time, False)) - self.assertTrue(pm.should_shutdown(ignition, True, start_time, False)) + pm_patch(mocker, "MAX_TIME_OFFROAD_S", MOCKED_MAX_OFFROAD_TIME, constant=True) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + start_time = ssb + ignition = False + while ssb <= start_time + MOCKED_MAX_OFFROAD_TIME: + pm.calculate(GOOD_VOLTAGE, ignition) + if (ssb - start_time) % 1000 == 0 and ssb < start_time + MOCKED_MAX_OFFROAD_TIME: + assert not pm.should_shutdown(ignition, True, start_time, False) + assert pm.should_shutdown(ignition, True, start_time, False) - def test_car_voltage(self): + def test_car_voltage(self, mocker): POWER_DRAW = 0 # To stop shutting down for other reasons TEST_TIME = 350 VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S = 50 - with pm_patch("VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S", VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S, constant=True), \ - pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - ignition = False - start_time = ssb - for i in range(TEST_TIME): - pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) - if i % 10 == 0: - self.assertEqual(pm.should_shutdown(ignition, True, start_time, True), - (pm.car_voltage_mV < VBATT_PAUSE_CHARGING * 1e3 and - (ssb - start_time) > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S and - (ssb - start_time) > DELAY_SHUTDOWN_TIME_S)) - self.assertTrue(pm.should_shutdown(ignition, True, start_time, True)) + pm_patch(mocker, "VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S", VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S, constant=True) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + ignition = False + start_time = ssb + for i in range(TEST_TIME): + pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) + if i % 10 == 0: + assert pm.should_shutdown(ignition, True, start_time, True) == \ + (pm.car_voltage_mV < VBATT_PAUSE_CHARGING * 1e3 and \ + (ssb - start_time) > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S and \ + (ssb - start_time) > DELAY_SHUTDOWN_TIME_S) + assert pm.should_shutdown(ignition, True, start_time, True) # Test to check policy of not stopping charging when DisablePowerDown is set - def test_disable_power_down(self): + def test_disable_power_down(self, mocker): POWER_DRAW = 0 # To stop shutting down for other reasons TEST_TIME = 100 self.params.put_bool("DisablePowerDown", True) - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - ignition = False - for i in range(TEST_TIME): - pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) - if i % 10 == 0: - self.assertFalse(pm.should_shutdown(ignition, True, ssb, False)) - self.assertFalse(pm.should_shutdown(ignition, True, ssb, False)) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + ignition = False + for i in range(TEST_TIME): + pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) + if i % 10 == 0: + assert not pm.should_shutdown(ignition, True, ssb, False) + assert not pm.should_shutdown(ignition, True, ssb, False) # Test to check policy of not stopping charging when ignition - def test_ignition(self): + def test_ignition(self, mocker): POWER_DRAW = 0 # To stop shutting down for other reasons TEST_TIME = 100 - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - ignition = True - for i in range(TEST_TIME): - pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) - if i % 10 == 0: - self.assertFalse(pm.should_shutdown(ignition, True, ssb, False)) - self.assertFalse(pm.should_shutdown(ignition, True, ssb, False)) + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + ignition = True + for i in range(TEST_TIME): + pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) + if i % 10 == 0: + assert not pm.should_shutdown(ignition, True, ssb, False) + assert not pm.should_shutdown(ignition, True, ssb, False) # Test to check policy of not stopping charging when harness is not connected - def test_harness_connection(self): + def test_harness_connection(self, mocker): POWER_DRAW = 0 # To stop shutting down for other reasons TEST_TIME = 100 - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): - pm = PowerMonitoring() - pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + pm_patch(mocker, "HARDWARE.get_current_power_draw", POWER_DRAW) + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - ignition = False - for i in range(TEST_TIME): - pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) - if i % 10 == 0: - self.assertFalse(pm.should_shutdown(ignition, False, ssb, False)) - self.assertFalse(pm.should_shutdown(ignition, False, ssb, False)) + ignition = False + for i in range(TEST_TIME): + pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) + if i % 10 == 0: + assert not pm.should_shutdown(ignition, False, ssb, False) + assert not pm.should_shutdown(ignition, False, ssb, False) def test_delay_shutdown_time(self): pm = PowerMonitoring() @@ -186,15 +190,11 @@ class TestPowerMonitoring(unittest.TestCase): pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) while ssb < offroad_timestamp + DELAY_SHUTDOWN_TIME_S: - self.assertFalse(pm.should_shutdown(ignition, in_car, + assert not pm.should_shutdown(ignition, in_car, offroad_timestamp, - started_seen), - f"Should not shutdown before {DELAY_SHUTDOWN_TIME_S} seconds offroad time") - self.assertTrue(pm.should_shutdown(ignition, in_car, + started_seen), \ + f"Should not shutdown before {DELAY_SHUTDOWN_TIME_S} seconds offroad time" + assert pm.should_shutdown(ignition, in_car, offroad_timestamp, - started_seen), - f"Should shutdown after {DELAY_SHUTDOWN_TIME_S} seconds offroad time") - - -if __name__ == "__main__": - unittest.main() + started_seen), \ + f"Should shutdown after {DELAY_SHUTDOWN_TIME_S} seconds offroad time" diff --git a/selfdrive/ui/tests/test_soundd.py b/selfdrive/ui/tests/test_soundd.py index 94ce26eb4..d15a6c183 100755 --- a/selfdrive/ui/tests/test_soundd.py +++ b/selfdrive/ui/tests/test_soundd.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import unittest from cereal import car from cereal import messaging @@ -11,7 +10,7 @@ import time AudibleAlert = car.CarControl.HUDControl.AudibleAlert -class TestSoundd(unittest.TestCase): +class TestSoundd: def test_check_controls_timeout_alert(self): sm = SubMaster(['controlsState']) pm = PubMaster(['controlsState']) @@ -26,16 +25,13 @@ class TestSoundd(unittest.TestCase): sm.update(0) - self.assertFalse(check_controls_timeout_alert(sm)) + assert not check_controls_timeout_alert(sm) for _ in range(CONTROLS_TIMEOUT * 110): sm.update(0) time.sleep(0.01) - self.assertTrue(check_controls_timeout_alert(sm)) + assert check_controls_timeout_alert(sm) # TODO: add test with micd for checking that soundd actually outputs sounds - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/ui/tests/test_translations.py b/selfdrive/ui/tests/test_translations.py index 8e50695e7..57de069d0 100755 --- a/selfdrive/ui/tests/test_translations.py +++ b/selfdrive/ui/tests/test_translations.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 +import pytest import json import os import re -import unittest import shutil import tempfile import xml.etree.ElementTree as ET @@ -21,7 +21,7 @@ FORMAT_ARG = re.compile("%[0-9]+") @parameterized_class(("name", "file"), translation_files.items()) -class TestTranslations(unittest.TestCase): +class TestTranslations: name: str file: str @@ -32,8 +32,8 @@ class TestTranslations(unittest.TestCase): return f.read() def test_missing_translation_files(self): - self.assertTrue(os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{self.file}.ts")), - f"{self.name} has no XML translation file, run selfdrive/ui/update_translations.py") + assert os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{self.file}.ts")), \ + f"{self.name} has no XML translation file, run selfdrive/ui/update_translations.py" def test_translations_updated(self): with tempfile.TemporaryDirectory() as tmpdir: @@ -42,19 +42,19 @@ class TestTranslations(unittest.TestCase): cur_translations = self._read_translation_file(TRANSLATIONS_DIR, self.file) new_translations = self._read_translation_file(tmpdir, self.file) - self.assertEqual(cur_translations, new_translations, - f"{self.file} ({self.name}) XML translation file out of date. Run selfdrive/ui/update_translations.py to update the translation files") + assert cur_translations == new_translations, \ + f"{self.file} ({self.name}) XML translation file out of date. Run selfdrive/ui/update_translations.py to update the translation files" - @unittest.skip("Only test unfinished translations before going to release") + @pytest.mark.skip("Only test unfinished translations before going to release") def test_unfinished_translations(self): cur_translations = self._read_translation_file(TRANSLATIONS_DIR, self.file) - self.assertTrue(UNFINISHED_TRANSLATION_TAG not in cur_translations, - f"{self.file} ({self.name}) translation file has unfinished translations. Finish translations or mark them as completed in Qt Linguist") + assert UNFINISHED_TRANSLATION_TAG not in cur_translations, \ + f"{self.file} ({self.name}) translation file has unfinished translations. Finish translations or mark them as completed in Qt Linguist" def test_vanished_translations(self): cur_translations = self._read_translation_file(TRANSLATIONS_DIR, self.file) - self.assertTrue("" not in cur_translations, - f"{self.file} ({self.name}) translation file has obsolete translations. Run selfdrive/ui/update_translations.py --vanish to remove them") + assert "" not in cur_translations, \ + f"{self.file} ({self.name}) translation file has obsolete translations. Run selfdrive/ui/update_translations.py --vanish to remove them" def test_finished_translations(self): """ @@ -81,27 +81,27 @@ class TestTranslations(unittest.TestCase): numerusform = [t.text for t in translation.findall("numerusform")] for nf in numerusform: - self.assertIsNotNone(nf, f"Ensure all plural translation forms are completed: {source_text}") - self.assertIn("%n", nf, "Ensure numerus argument (%n) exists in translation.") - self.assertIsNone(FORMAT_ARG.search(nf), f"Plural translations must use %n, not %1, %2, etc.: {numerusform}") + assert nf is not None, f"Ensure all plural translation forms are completed: {source_text}" + assert "%n" in nf, "Ensure numerus argument (%n) exists in translation." + assert FORMAT_ARG.search(nf) is None, f"Plural translations must use %n, not %1, %2, etc.: {numerusform}" else: - self.assertIsNotNone(translation.text, f"Ensure translation is completed: {source_text}") + assert translation.text is not None, f"Ensure translation is completed: {source_text}" source_args = FORMAT_ARG.findall(source_text) translation_args = FORMAT_ARG.findall(translation.text) - self.assertEqual(sorted(source_args), sorted(translation_args), - f"Ensure format arguments are consistent: `{source_text}` vs. `{translation.text}`") + assert sorted(source_args) == sorted(translation_args), \ + f"Ensure format arguments are consistent: `{source_text}` vs. `{translation.text}`" def test_no_locations(self): for line in self._read_translation_file(TRANSLATIONS_DIR, self.file).splitlines(): - self.assertFalse(line.strip().startswith(LOCATION_TAG), - f"Line contains location tag: {line.strip()}, remove all line numbers.") + assert not line.strip().startswith(LOCATION_TAG), \ + f"Line contains location tag: {line.strip()}, remove all line numbers." def test_entities_error(self): cur_translations = self._read_translation_file(TRANSLATIONS_DIR, self.file) matches = re.findall(r'@(\w+);', cur_translations) - self.assertEqual(len(matches), 0, f"The string(s) {matches} were found with '@' instead of '&'") + assert len(matches) == 0, f"The string(s) {matches} were found with '@' instead of '&'" def test_bad_language(self): IGNORED_WORDS = {'pédale'} @@ -128,7 +128,3 @@ class TestTranslations(unittest.TestCase): words = set(translation_text.translate(str.maketrans('', '', string.punctuation + '%n')).lower().split()) bad_words_found = words & (banned_words - IGNORED_WORDS) assert not bad_words_found, f"Bad language found in {self.name}: '{translation_text}'. Bad word(s): {', '.join(bad_words_found)}" - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/ui/tests/test_ui/run.py b/selfdrive/ui/tests/test_ui/run.py index c83410778..79f30e79b 100644 --- a/selfdrive/ui/tests/test_ui/run.py +++ b/selfdrive/ui/tests/test_ui/run.py @@ -8,7 +8,7 @@ import numpy as np import os import pywinctl import time -import unittest +import unittest # noqa: TID251 from parameterized import parameterized from cereal import messaging, car, log diff --git a/selfdrive/updated/tests/test_base.py b/selfdrive/updated/tests/test_base.py index b59f03fe7..615d0de99 100644 --- a/selfdrive/updated/tests/test_base.py +++ b/selfdrive/updated/tests/test_base.py @@ -6,9 +6,6 @@ import stat import subprocess import tempfile import time -import unittest -from unittest import mock - import pytest from openpilot.common.params import Params @@ -52,13 +49,13 @@ def get_version(path: str) -> str: @pytest.mark.slow # TODO: can we test overlayfs in GHA? -class BaseUpdateTest(unittest.TestCase): +class TestBaseUpdate: @classmethod - def setUpClass(cls): + def setup_class(cls): if "Base" in cls.__name__: - raise unittest.SkipTest + pytest.skip() - def setUp(self): + def setup_method(self): self.tmpdir = tempfile.mkdtemp() run(["sudo", "mount", "-t", "tmpfs", "tmpfs", self.tmpdir]) # overlayfs doesn't work inside of docker unless this is a tmpfs @@ -76,8 +73,6 @@ class BaseUpdateTest(unittest.TestCase): self.remote_dir = self.mock_update_path / "remote" self.remote_dir.mkdir() - mock.patch("openpilot.common.basedir.BASEDIR", self.basedir).start() - os.environ["UPDATER_STAGING_ROOT"] = str(self.staging_root) os.environ["UPDATER_LOCK_FILE"] = str(self.mock_update_path / "safe_staging_overlay.lock") @@ -86,6 +81,10 @@ class BaseUpdateTest(unittest.TestCase): "master": ("0.1.3", "1.2", "0.1.3 release notes"), } + @pytest.fixture(autouse=True) + def mock_basedir(self, mocker): + mocker.patch("openpilot.common.basedir.BASEDIR", self.basedir) + def set_target_branch(self, branch): self.params.put("UpdaterTargetBranch", branch) @@ -102,8 +101,7 @@ class BaseUpdateTest(unittest.TestCase): def additional_context(self): raise NotImplementedError("") - def tearDown(self): - mock.patch.stopall() + def teardown_method(self): try: run(["sudo", "umount", "-l", str(self.staging_root / "merged")]) run(["sudo", "umount", "-l", self.tmpdir]) @@ -125,17 +123,17 @@ class BaseUpdateTest(unittest.TestCase): time.sleep(1) def _test_finalized_update(self, branch, version, agnos_version, release_notes): - self.assertEqual(get_version(str(self.staging_root / "finalized")), version) - self.assertEqual(get_consistent_flag(str(self.staging_root / "finalized")), True) - self.assertTrue(os.access(str(self.staging_root / "finalized" / "launch_env.sh"), os.X_OK)) + assert get_version(str(self.staging_root / "finalized")) == version + assert get_consistent_flag(str(self.staging_root / "finalized")) + assert os.access(str(self.staging_root / "finalized" / "launch_env.sh"), os.X_OK) with open(self.staging_root / "finalized" / "test_symlink") as f: - self.assertIn(version, f.read()) + assert version in f.read() -class ParamsBaseUpdateTest(BaseUpdateTest): +class ParamsBaseUpdateTest(TestBaseUpdate): def _test_finalized_update(self, branch, version, agnos_version, release_notes): - self.assertTrue(self.params.get("UpdaterNewDescription", encoding="utf-8").startswith(f"{version} / {branch}")) - self.assertEqual(self.params.get("UpdaterNewReleaseNotes", encoding="utf-8"), f"

{release_notes}

\n") + assert self.params.get("UpdaterNewDescription", encoding="utf-8").startswith(f"{version} / {branch}") + assert self.params.get("UpdaterNewReleaseNotes", encoding="utf-8") == f"

{release_notes}

\n" super()._test_finalized_update(branch, version, agnos_version, release_notes) def send_check_for_updates_signal(self, updated: ManagerProcess): @@ -145,9 +143,9 @@ class ParamsBaseUpdateTest(BaseUpdateTest): updated.signal(signal.SIGHUP.value) def _test_params(self, branch, fetch_available, update_available): - self.assertEqual(self.params.get("UpdaterTargetBranch", encoding="utf-8"), branch) - self.assertEqual(self.params.get_bool("UpdaterFetchAvailable"), fetch_available) - self.assertEqual(self.params.get_bool("UpdateAvailable"), update_available) + assert self.params.get("UpdaterTargetBranch", encoding="utf-8") == branch + assert self.params.get_bool("UpdaterFetchAvailable") == fetch_available + assert self.params.get_bool("UpdateAvailable") == update_available def wait_for_idle(self): self.wait_for_condition(lambda: self.params.get("UpdaterState", encoding="utf-8") == "idle") @@ -229,17 +227,16 @@ class ParamsBaseUpdateTest(BaseUpdateTest): self._test_params("master", False, True) self._test_finalized_update("master", *self.MOCK_RELEASES["master"]) - def test_agnos_update(self): + def test_agnos_update(self, mocker): # Start on release3, push an update with an agnos change self.setup_remote_release("release3") self.setup_basedir_release("release3") - with self.additional_context(), \ - mock.patch("openpilot.system.hardware.AGNOS", "True"), \ - mock.patch("openpilot.system.hardware.tici.hardware.Tici.get_os_version", "1.2"), \ - mock.patch("openpilot.system.hardware.tici.agnos.get_target_slot_number"), \ - mock.patch("openpilot.system.hardware.tici.agnos.flash_agnos_update"), \ - processes_context(["updated"]) as [updated]: + with self.additional_context(), processes_context(["updated"]) as [updated]: + mocker.patch("openpilot.system.hardware.AGNOS", "True") + mocker.patch("openpilot.system.hardware.tici.hardware.Tici.get_os_version", "1.2") + mocker.patch("openpilot.system.hardware.tici.agnos.get_target_slot_number") + mocker.patch("openpilot.system.hardware.tici.agnos.flash_agnos_update") self._test_params("release3", False, False) self.wait_for_idle() diff --git a/system/camerad/test/test_exposure.py b/system/camerad/test/test_exposure.py index 50467f9db..36e8522b1 100755 --- a/system/camerad/test/test_exposure.py +++ b/system/camerad/test/test_exposure.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import time -import unittest import numpy as np from openpilot.selfdrive.test.helpers import with_processes, phone_only @@ -9,9 +8,9 @@ from openpilot.system.camerad.snapshot.snapshot import get_snapshots TEST_TIME = 45 REPEAT = 5 -class TestCamerad(unittest.TestCase): +class TestCamerad: @classmethod - def setUpClass(cls): + def setup_class(cls): pass def _numpy_rgb2gray(self, im): @@ -49,7 +48,4 @@ class TestCamerad(unittest.TestCase): passed += int(res) time.sleep(2) - self.assertGreaterEqual(passed, REPEAT) - -if __name__ == "__main__": - unittest.main() + assert passed >= REPEAT diff --git a/system/hardware/tici/tests/test_agnos_updater.py b/system/hardware/tici/tests/test_agnos_updater.py index 86bc78881..462cf6cb5 100755 --- a/system/hardware/tici/tests/test_agnos_updater.py +++ b/system/hardware/tici/tests/test_agnos_updater.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 import json import os -import unittest import requests TEST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__))) MANIFEST = os.path.join(TEST_DIR, "../agnos.json") -class TestAgnosUpdater(unittest.TestCase): +class TestAgnosUpdater: def test_manifest(self): with open(MANIFEST) as f: @@ -17,10 +16,6 @@ class TestAgnosUpdater(unittest.TestCase): for img in m: r = requests.head(img['url'], timeout=10) r.raise_for_status() - self.assertEqual(r.headers['Content-Type'], "application/x-xz") + assert r.headers['Content-Type'] == "application/x-xz" if not img['sparse']: assert img['hash'] == img['hash_raw'] - - -if __name__ == "__main__": - unittest.main() diff --git a/system/hardware/tici/tests/test_amplifier.py b/system/hardware/tici/tests/test_amplifier.py index cd3b0f90f..dfba84b94 100755 --- a/system/hardware/tici/tests/test_amplifier.py +++ b/system/hardware/tici/tests/test_amplifier.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 +import pytest import time import random -import unittest import subprocess from panda import Panda @@ -10,14 +10,14 @@ from openpilot.system.hardware.tici.hardware import Tici from openpilot.system.hardware.tici.amplifier import Amplifier -class TestAmplifier(unittest.TestCase): +class TestAmplifier: @classmethod - def setUpClass(cls): + def setup_class(cls): if not TICI: - raise unittest.SkipTest + pytest.skip() - def setUp(self): + def setup_method(self): # clear dmesg subprocess.check_call("sudo dmesg -C", shell=True) @@ -25,7 +25,7 @@ class TestAmplifier(unittest.TestCase): Panda.wait_for_panda(None, 30) self.panda = Panda() - def tearDown(self): + def teardown_method(self): HARDWARE.reset_internal_panda() def _check_for_i2c_errors(self, expected): @@ -68,8 +68,4 @@ class TestAmplifier(unittest.TestCase): if self._check_for_i2c_errors(True): break else: - self.fail("didn't hit any i2c errors") - - -if __name__ == "__main__": - unittest.main() + pytest.fail("didn't hit any i2c errors") diff --git a/system/hardware/tici/tests/test_hardware.py b/system/hardware/tici/tests/test_hardware.py index 6c41c383a..49d4ac769 100755 --- a/system/hardware/tici/tests/test_hardware.py +++ b/system/hardware/tici/tests/test_hardware.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import pytest import time -import unittest import numpy as np from openpilot.system.hardware.tici.hardware import Tici @@ -10,7 +9,7 @@ HARDWARE = Tici() @pytest.mark.tici -class TestHardware(unittest.TestCase): +class TestHardware: def test_power_save_time(self): ts = [] @@ -22,7 +21,3 @@ class TestHardware(unittest.TestCase): assert 0.1 < np.mean(ts) < 0.25 assert max(ts) < 0.3 - - -if __name__ == "__main__": - unittest.main() diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index ba7e0a6d9..104329da4 100755 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 from collections import defaultdict, deque import pytest -import unittest import time import numpy as np from dataclasses import dataclass @@ -40,15 +39,15 @@ PROCS = [ @pytest.mark.tici -class TestPowerDraw(unittest.TestCase): +class TestPowerDraw: - def setUp(self): + def setup_method(self): write_car_param() # wait a bit for power save to disable time.sleep(5) - def tearDown(self): + def teardown_method(self): manager_cleanup() def get_expected_messages(self, proc): @@ -97,7 +96,7 @@ class TestPowerDraw(unittest.TestCase): return now, msg_counts, time.monotonic() - start_time - SAMPLE_TIME @mock_messages(['liveLocationKalman']) - def test_camera_procs(self): + def test_camera_procs(self, subtests): baseline = get_power() prev = baseline @@ -122,12 +121,8 @@ class TestPowerDraw(unittest.TestCase): expected = proc.power msgs_received = sum(msg_counts[msg] for msg in proc.msgs) tab.append([proc.name, round(expected, 2), round(cur, 2), self.get_expected_messages(proc), msgs_received, round(warmup_time[proc.name], 2)]) - with self.subTest(proc=proc.name): - self.assertTrue(self.valid_msg_count(proc, msg_counts), f"expected {self.get_expected_messages(proc)} msgs, got {msgs_received} msgs") - self.assertTrue(self.valid_power_draw(proc, cur), f"expected {expected:.2f}W, got {cur:.2f}W") + with subtests.test(proc=proc.name): + assert self.valid_msg_count(proc, msg_counts), f"expected {self.get_expected_messages(proc)} msgs, got {msgs_received} msgs" + assert self.valid_power_draw(proc, cur), f"expected {expected:.2f}W, got {cur:.2f}W" print(tabulate(tab)) print(f"Baseline {baseline:.2f}W\n") - - -if __name__ == "__main__": - unittest.main() diff --git a/system/loggerd/tests/loggerd_tests_common.py b/system/loggerd/tests/loggerd_tests_common.py index 877c872b6..e8a6d031c 100644 --- a/system/loggerd/tests/loggerd_tests_common.py +++ b/system/loggerd/tests/loggerd_tests_common.py @@ -1,6 +1,5 @@ import os import random -import unittest from pathlib import Path @@ -54,7 +53,7 @@ class MockApiIgnore(): def get_token(self): return "fake-token" -class UploaderTestCase(unittest.TestCase): +class UploaderTestCase: f_type = "UNKNOWN" root: Path @@ -66,7 +65,7 @@ class UploaderTestCase(unittest.TestCase): def set_ignore(self): uploader.Api = MockApiIgnore - def setUp(self): + def setup_method(self): uploader.Api = MockApi uploader.fake_upload = True uploader.force_wifi = True diff --git a/system/loggerd/tests/test_deleter.py b/system/loggerd/tests/test_deleter.py index 37d25507e..3ba6ad403 100755 --- a/system/loggerd/tests/test_deleter.py +++ b/system/loggerd/tests/test_deleter.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import time import threading -import unittest from collections import namedtuple from pathlib import Path from collections.abc import Sequence @@ -17,9 +16,9 @@ class TestDeleter(UploaderTestCase): def fake_statvfs(self, d): return self.fake_stats - def setUp(self): + def setup_method(self): self.f_type = "fcamera.hevc" - super().setUp() + super().setup_method() self.fake_stats = Stats(f_bavail=0, f_blocks=10, f_frsize=4096) deleter.os.statvfs = self.fake_statvfs @@ -64,7 +63,7 @@ class TestDeleter(UploaderTestCase): finally: self.join_thread() - self.assertEqual(deleted_order, f_paths, "Files not deleted in expected order") + assert deleted_order == f_paths, "Files not deleted in expected order" def test_delete_order(self): self.assertDeleteOrder([ @@ -105,7 +104,7 @@ class TestDeleter(UploaderTestCase): time.sleep(0.01) self.join_thread() - self.assertTrue(f_path.exists(), "File deleted with available space") + assert f_path.exists(), "File deleted with available space" def test_no_delete_with_lock_file(self): f_path = self.make_file_with_data(self.seg_dir, self.f_type, lock=True) @@ -116,8 +115,4 @@ class TestDeleter(UploaderTestCase): time.sleep(0.01) self.join_thread() - self.assertTrue(f_path.exists(), "File deleted when locked") - - -if __name__ == "__main__": - unittest.main() + assert f_path.exists(), "File deleted when locked" diff --git a/system/loggerd/tests/test_encoder.py b/system/loggerd/tests/test_encoder.py index bd076dc5f..f6eb9b901 100755 --- a/system/loggerd/tests/test_encoder.py +++ b/system/loggerd/tests/test_encoder.py @@ -6,7 +6,6 @@ import random import shutil import subprocess import time -import unittest from pathlib import Path from parameterized import parameterized @@ -33,14 +32,14 @@ FILE_SIZE_TOLERANCE = 0.5 @pytest.mark.tici # TODO: all of loggerd should work on PC -class TestEncoder(unittest.TestCase): +class TestEncoder: - def setUp(self): + def setup_method(self): self._clear_logs() os.environ["LOGGERD_TEST"] = "1" os.environ["LOGGERD_SEGMENT_LENGTH"] = str(SEGMENT_LENGTH) - def tearDown(self): + def teardown_method(self): self._clear_logs() def _clear_logs(self): @@ -85,7 +84,7 @@ class TestEncoder(unittest.TestCase): file_path = f"{route_prefix_path}--{i}/{camera}" # check file exists - self.assertTrue(os.path.exists(file_path), f"segment #{i}: '{file_path}' missing") + assert os.path.exists(file_path), f"segment #{i}: '{file_path}' missing" # TODO: this ffprobe call is really slow # check frame count @@ -98,13 +97,13 @@ class TestEncoder(unittest.TestCase): frame_count = int(probe.split('\n')[0].strip()) counts.append(frame_count) - self.assertEqual(frame_count, expected_frames, - f"segment #{i}: {camera} failed frame count check: expected {expected_frames}, got {frame_count}") + assert frame_count == expected_frames, \ + f"segment #{i}: {camera} failed frame count check: expected {expected_frames}, got {frame_count}" # sanity check file size file_size = os.path.getsize(file_path) - self.assertTrue(math.isclose(file_size, size, rel_tol=FILE_SIZE_TOLERANCE), - f"{file_path} size {file_size} isn't close to target size {size}") + assert math.isclose(file_size, size, rel_tol=FILE_SIZE_TOLERANCE), \ + f"{file_path} size {file_size} isn't close to target size {size}" # Check encodeIdx if encode_idx_name is not None: @@ -118,24 +117,24 @@ class TestEncoder(unittest.TestCase): frame_idxs = [m.frameId for m in encode_msgs] # Check frame count - self.assertEqual(frame_count, len(segment_idxs)) - self.assertEqual(frame_count, len(encode_idxs)) + assert frame_count == len(segment_idxs) + assert frame_count == len(encode_idxs) # Check for duplicates or skips - self.assertEqual(0, segment_idxs[0]) - self.assertEqual(len(set(segment_idxs)), len(segment_idxs)) + assert 0 == segment_idxs[0] + assert len(set(segment_idxs)) == len(segment_idxs) - self.assertTrue(all(valid)) + assert all(valid) - self.assertEqual(expected_frames * i, encode_idxs[0]) + assert expected_frames * i == encode_idxs[0] first_frames.append(frame_idxs[0]) - self.assertEqual(len(set(encode_idxs)), len(encode_idxs)) + assert len(set(encode_idxs)) == len(encode_idxs) - self.assertEqual(1, len(set(first_frames))) + assert 1 == len(set(first_frames)) if TICI: expected_frames = fps * SEGMENT_LENGTH - self.assertEqual(min(counts), expected_frames) + assert min(counts) == expected_frames shutil.rmtree(f"{route_prefix_path}--{i}") try: @@ -150,7 +149,3 @@ class TestEncoder(unittest.TestCase): managed_processes['encoderd'].stop() managed_processes['camerad'].stop() managed_processes['sensord'].stop() - - -if __name__ == "__main__": - unittest.main() diff --git a/system/loggerd/tests/test_uploader.py b/system/loggerd/tests/test_uploader.py index 73917a30c..c0a9770e5 100755 --- a/system/loggerd/tests/test_uploader.py +++ b/system/loggerd/tests/test_uploader.py @@ -2,7 +2,6 @@ import os import time import threading -import unittest import logging import json from pathlib import Path @@ -38,8 +37,8 @@ cloudlog.addHandler(log_handler) class TestUploader(UploaderTestCase): - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() log_handler.reset() def start_thread(self): @@ -80,13 +79,13 @@ class TestUploader(UploaderTestCase): exp_order = self.gen_order([self.seg_num], []) - self.assertTrue(len(log_handler.upload_ignored) == 0, "Some files were ignored") - self.assertFalse(len(log_handler.upload_order) < len(exp_order), "Some files failed to upload") - self.assertFalse(len(log_handler.upload_order) > len(exp_order), "Some files were uploaded twice") + assert len(log_handler.upload_ignored) == 0, "Some files were ignored" + assert not len(log_handler.upload_order) < len(exp_order), "Some files failed to upload" + assert not len(log_handler.upload_order) > len(exp_order), "Some files were uploaded twice" for f_path in exp_order: - self.assertEqual(os.getxattr((Path(Paths.log_root()) / f_path).with_suffix(""), UPLOAD_ATTR_NAME), UPLOAD_ATTR_VALUE, "All files not uploaded") + assert os.getxattr((Path(Paths.log_root()) / f_path).with_suffix(""), UPLOAD_ATTR_NAME) == UPLOAD_ATTR_VALUE, "All files not uploaded" - self.assertTrue(log_handler.upload_order == exp_order, "Files uploaded in wrong order") + assert log_handler.upload_order == exp_order, "Files uploaded in wrong order" def test_upload_with_wrong_xattr(self): self.gen_files(lock=False, xattr=b'0') @@ -98,13 +97,13 @@ class TestUploader(UploaderTestCase): exp_order = self.gen_order([self.seg_num], []) - self.assertTrue(len(log_handler.upload_ignored) == 0, "Some files were ignored") - self.assertFalse(len(log_handler.upload_order) < len(exp_order), "Some files failed to upload") - self.assertFalse(len(log_handler.upload_order) > len(exp_order), "Some files were uploaded twice") + assert len(log_handler.upload_ignored) == 0, "Some files were ignored" + assert not len(log_handler.upload_order) < len(exp_order), "Some files failed to upload" + assert not len(log_handler.upload_order) > len(exp_order), "Some files were uploaded twice" for f_path in exp_order: - self.assertEqual(os.getxattr((Path(Paths.log_root()) / f_path).with_suffix(""), UPLOAD_ATTR_NAME), UPLOAD_ATTR_VALUE, "All files not uploaded") + assert os.getxattr((Path(Paths.log_root()) / f_path).with_suffix(""), UPLOAD_ATTR_NAME) == UPLOAD_ATTR_VALUE, "All files not uploaded" - self.assertTrue(log_handler.upload_order == exp_order, "Files uploaded in wrong order") + assert log_handler.upload_order == exp_order, "Files uploaded in wrong order" def test_upload_ignored(self): self.set_ignore() @@ -117,13 +116,13 @@ class TestUploader(UploaderTestCase): exp_order = self.gen_order([self.seg_num], []) - self.assertTrue(len(log_handler.upload_order) == 0, "Some files were not ignored") - self.assertFalse(len(log_handler.upload_ignored) < len(exp_order), "Some files failed to ignore") - self.assertFalse(len(log_handler.upload_ignored) > len(exp_order), "Some files were ignored twice") + assert len(log_handler.upload_order) == 0, "Some files were not ignored" + assert not len(log_handler.upload_ignored) < len(exp_order), "Some files failed to ignore" + assert not len(log_handler.upload_ignored) > len(exp_order), "Some files were ignored twice" for f_path in exp_order: - self.assertEqual(os.getxattr((Path(Paths.log_root()) / f_path).with_suffix(""), UPLOAD_ATTR_NAME), UPLOAD_ATTR_VALUE, "All files not ignored") + assert os.getxattr((Path(Paths.log_root()) / f_path).with_suffix(""), UPLOAD_ATTR_NAME) == UPLOAD_ATTR_VALUE, "All files not ignored" - self.assertTrue(log_handler.upload_ignored == exp_order, "Files ignored in wrong order") + assert log_handler.upload_ignored == exp_order, "Files ignored in wrong order" def test_upload_files_in_create_order(self): seg1_nums = [0, 1, 2, 10, 20] @@ -142,13 +141,13 @@ class TestUploader(UploaderTestCase): time.sleep(5) self.join_thread() - self.assertTrue(len(log_handler.upload_ignored) == 0, "Some files were ignored") - self.assertFalse(len(log_handler.upload_order) < len(exp_order), "Some files failed to upload") - self.assertFalse(len(log_handler.upload_order) > len(exp_order), "Some files were uploaded twice") + assert len(log_handler.upload_ignored) == 0, "Some files were ignored" + assert not len(log_handler.upload_order) < len(exp_order), "Some files failed to upload" + assert not len(log_handler.upload_order) > len(exp_order), "Some files were uploaded twice" for f_path in exp_order: - self.assertEqual(os.getxattr((Path(Paths.log_root()) / f_path).with_suffix(""), UPLOAD_ATTR_NAME), UPLOAD_ATTR_VALUE, "All files not uploaded") + assert os.getxattr((Path(Paths.log_root()) / f_path).with_suffix(""), UPLOAD_ATTR_NAME) == UPLOAD_ATTR_VALUE, "All files not uploaded" - self.assertTrue(log_handler.upload_order == exp_order, "Files uploaded in wrong order") + assert log_handler.upload_order == exp_order, "Files uploaded in wrong order" def test_no_upload_with_lock_file(self): self.start_thread() @@ -163,7 +162,7 @@ class TestUploader(UploaderTestCase): for f_path in f_paths: fn = f_path.with_suffix(f_path.suffix.replace(".bz2", "")) uploaded = UPLOAD_ATTR_NAME in os.listxattr(fn) and os.getxattr(fn, UPLOAD_ATTR_NAME) == UPLOAD_ATTR_VALUE - self.assertFalse(uploaded, "File upload when locked") + assert not uploaded, "File upload when locked" def test_no_upload_with_xattr(self): self.gen_files(lock=False, xattr=UPLOAD_ATTR_VALUE) @@ -173,7 +172,7 @@ class TestUploader(UploaderTestCase): time.sleep(5) self.join_thread() - self.assertEqual(len(log_handler.upload_order), 0, "File uploaded again") + assert len(log_handler.upload_order) == 0, "File uploaded again" def test_clear_locks_on_startup(self): f_paths = self.gen_files(lock=True, boot=False) @@ -183,8 +182,4 @@ class TestUploader(UploaderTestCase): for f_path in f_paths: lock_path = f_path.with_suffix(f_path.suffix + ".lock") - self.assertFalse(lock_path.is_file(), "File lock not cleared on startup") - - -if __name__ == "__main__": - unittest.main() + assert not lock_path.is_file(), "File lock not cleared on startup" diff --git a/system/qcomgpsd/tests/test_qcomgpsd.py b/system/qcomgpsd/tests/test_qcomgpsd.py index 6c93f7dd9..d47ea5d63 100755 --- a/system/qcomgpsd/tests/test_qcomgpsd.py +++ b/system/qcomgpsd/tests/test_qcomgpsd.py @@ -4,7 +4,6 @@ import pytest import json import time import datetime -import unittest import subprocess import cereal.messaging as messaging @@ -15,24 +14,24 @@ GOOD_SIGNAL = bool(int(os.getenv("GOOD_SIGNAL", '0'))) @pytest.mark.tici -class TestRawgpsd(unittest.TestCase): +class TestRawgpsd: @classmethod - def setUpClass(cls): + def setup_class(cls): os.system("sudo systemctl start systemd-resolved") os.system("sudo systemctl restart ModemManager lte") wait_for_modem() @classmethod - def tearDownClass(cls): + def teardown_class(cls): managed_processes['qcomgpsd'].stop() os.system("sudo systemctl restart systemd-resolved") os.system("sudo systemctl restart ModemManager lte") - def setUp(self): + def setup_method(self): at_cmd("AT+QGPSDEL=0") self.sm = messaging.SubMaster(['qcomGnss', 'gpsLocation', 'gnssMeasurements']) - def tearDown(self): + def teardown_method(self): managed_processes['qcomgpsd'].stop() os.system("sudo systemctl restart systemd-resolved") @@ -57,18 +56,18 @@ class TestRawgpsd(unittest.TestCase): os.system("sudo systemctl restart ModemManager") assert self._wait_for_output(30) - def test_startup_time(self): + def test_startup_time(self, subtests): for internet in (True, False): if not internet: os.system("sudo systemctl stop systemd-resolved") - with self.subTest(internet=internet): + with subtests.test(internet=internet): managed_processes['qcomgpsd'].start() assert self._wait_for_output(7) managed_processes['qcomgpsd'].stop() - def test_turns_off_gnss(self): + def test_turns_off_gnss(self, subtests): for s in (0.1, 1, 5): - with self.subTest(runtime=s): + with subtests.test(runtime=s): managed_processes['qcomgpsd'].start() time.sleep(s) managed_processes['qcomgpsd'].stop() @@ -87,7 +86,7 @@ class TestRawgpsd(unittest.TestCase): if should_be_loaded: assert valid_duration == "10080" # should be max time injected_time = datetime.datetime.strptime(injected_time_str.replace("\"", ""), "%Y/%m/%d,%H:%M:%S") - self.assertLess(abs((datetime.datetime.utcnow() - injected_time).total_seconds()), 60*60*12) + assert abs((datetime.datetime.utcnow() - injected_time).total_seconds()) < 60*60*12 else: valid_duration, injected_time_str = out.split(",", 1) injected_time_str = injected_time_str.replace('\"', '').replace('\'', '') @@ -119,6 +118,3 @@ class TestRawgpsd(unittest.TestCase): time.sleep(15) managed_processes['qcomgpsd'].stop() self.check_assistance(True) - -if __name__ == "__main__": - unittest.main(failfast=True) diff --git a/system/sensord/tests/test_sensord.py b/system/sensord/tests/test_sensord.py index 3075c8a34..1b3b78da8 100755 --- a/system/sensord/tests/test_sensord.py +++ b/system/sensord/tests/test_sensord.py @@ -2,7 +2,6 @@ import os import pytest import time -import unittest import numpy as np from collections import namedtuple, defaultdict @@ -99,9 +98,9 @@ def read_sensor_events(duration_sec): return {k: v for k, v in events.items() if len(v) > 0} @pytest.mark.tici -class TestSensord(unittest.TestCase): +class TestSensord: @classmethod - def setUpClass(cls): + def setup_class(cls): # enable LSM self test os.environ["LSM_SELF_TEST"] = "1" @@ -119,10 +118,10 @@ class TestSensord(unittest.TestCase): managed_processes["sensord"].stop() @classmethod - def tearDownClass(cls): + def teardown_class(cls): managed_processes["sensord"].stop() - def tearDown(self): + def teardown_method(self): managed_processes["sensord"].stop() def test_sensors_present(self): @@ -133,9 +132,9 @@ class TestSensord(unittest.TestCase): m = getattr(measurement, measurement.which()) seen.add((str(m.source), m.which())) - self.assertIn(seen, SENSOR_CONFIGURATIONS) + assert seen in SENSOR_CONFIGURATIONS - def test_lsm6ds3_timing(self): + def test_lsm6ds3_timing(self, subtests): # verify measurements are sampled and published at 104Hz sensor_t = { @@ -152,7 +151,7 @@ class TestSensord(unittest.TestCase): sensor_t[m.sensor].append(m.timestamp) for s, vals in sensor_t.items(): - with self.subTest(sensor=s): + with subtests.test(sensor=s): assert len(vals) > 0 tdiffs = np.diff(vals) / 1e6 # millis @@ -166,9 +165,9 @@ class TestSensord(unittest.TestCase): stddev = np.std(tdiffs) assert stddev < 2.0, f"Standard-dev to big {stddev}" - def test_sensor_frequency(self): + def test_sensor_frequency(self, subtests): for s, msgs in self.events.items(): - with self.subTest(sensor=s): + with subtests.test(sensor=s): freq = len(msgs) / self.sample_secs ef = SERVICE_LIST[s].frequency assert ef*0.85 <= freq <= ef*1.15 @@ -246,6 +245,3 @@ class TestSensord(unittest.TestCase): state_two = get_irq_count(self.sensord_irq) assert state_one == state_two, "Interrupts received after sensord stop!" - -if __name__ == "__main__": - unittest.main() diff --git a/system/tests/test_logmessaged.py b/system/tests/test_logmessaged.py index d27dae46a..6d59bdcb0 100755 --- a/system/tests/test_logmessaged.py +++ b/system/tests/test_logmessaged.py @@ -2,7 +2,6 @@ import glob import os import time -import unittest import cereal.messaging as messaging from openpilot.selfdrive.manager.process_config import managed_processes @@ -10,8 +9,8 @@ from openpilot.system.hardware.hw import Paths from openpilot.common.swaglog import cloudlog, ipchandler -class TestLogmessaged(unittest.TestCase): - def setUp(self): +class TestLogmessaged: + def setup_method(self): # clear the IPC buffer in case some other tests used cloudlog and filled it ipchandler.close() ipchandler.connect() @@ -25,7 +24,7 @@ class TestLogmessaged(unittest.TestCase): messaging.drain_sock(self.sock) messaging.drain_sock(self.error_sock) - def tearDown(self): + def teardown_method(self): del self.sock del self.error_sock managed_processes['logmessaged'].stop(block=True) @@ -55,6 +54,3 @@ class TestLogmessaged(unittest.TestCase): logsize = sum([os.path.getsize(f) for f in self._get_log_files()]) assert (n*len(msg)) < logsize < (n*(len(msg)+1024)) - -if __name__ == "__main__": - unittest.main() diff --git a/system/ubloxd/tests/test_pigeond.py b/system/ubloxd/tests/test_pigeond.py index 742e20bb9..a24414466 100755 --- a/system/ubloxd/tests/test_pigeond.py +++ b/system/ubloxd/tests/test_pigeond.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import pytest import time -import unittest import cereal.messaging as messaging from cereal.services import SERVICE_LIST @@ -13,9 +12,9 @@ from openpilot.system.hardware.tici.pins import GPIO # TODO: test TTFF when we have good A-GNSS @pytest.mark.tici -class TestPigeond(unittest.TestCase): +class TestPigeond: - def tearDown(self): + def teardown_method(self): managed_processes['pigeond'].stop() @with_processes(['pigeond']) @@ -54,7 +53,3 @@ class TestPigeond(unittest.TestCase): assert gpio_read(GPIO.UBLOX_RST_N) == 0 assert gpio_read(GPIO.GNSS_PWR_EN) == 0 - - -if __name__ == "__main__": - unittest.main() diff --git a/system/updated/casync/tests/test_casync.py b/system/updated/casync/tests/test_casync.py index 34427d562..80c5d2705 100755 --- a/system/updated/casync/tests/test_casync.py +++ b/system/updated/casync/tests/test_casync.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 +import pytest import os import pathlib -import unittest import tempfile import subprocess @@ -14,9 +14,9 @@ from openpilot.system.updated.casync import tar LOOPBACK = os.environ.get('LOOPBACK', None) -class TestCasync(unittest.TestCase): +class TestCasync: @classmethod - def setUpClass(cls): + def setup_class(cls): cls.tmpdir = tempfile.TemporaryDirectory() # Build example contents @@ -43,7 +43,7 @@ class TestCasync(unittest.TestCase): # Ensure we have chunk reuse assert len(hashes) > len(set(hashes)) - def setUp(self): + def setup_method(self): # Clear target_lo if LOOPBACK is not None: self.target_lo = LOOPBACK @@ -53,7 +53,7 @@ class TestCasync(unittest.TestCase): self.target_fn = os.path.join(self.tmpdir.name, next(tempfile._get_candidate_names())) self.seed_fn = os.path.join(self.tmpdir.name, next(tempfile._get_candidate_names())) - def tearDown(self): + def teardown_method(self): for fn in [self.target_fn, self.seed_fn]: try: os.unlink(fn) @@ -67,9 +67,9 @@ class TestCasync(unittest.TestCase): stats = casync.extract(target, sources, self.target_fn) with open(self.target_fn, 'rb') as target_f: - self.assertEqual(target_f.read(), self.contents) + assert target_f.read() == self.contents - self.assertEqual(stats['remote'], len(self.contents)) + assert stats['remote'] == len(self.contents) def test_seed(self): target = casync.parse_caibx(self.manifest_fn) @@ -83,10 +83,10 @@ class TestCasync(unittest.TestCase): stats = casync.extract(target, sources, self.target_fn) with open(self.target_fn, 'rb') as target_f: - self.assertEqual(target_f.read(), self.contents) + assert target_f.read() == self.contents - self.assertGreater(stats['seed'], 0) - self.assertLess(stats['remote'], len(self.contents)) + assert stats['seed'] > 0 + assert stats['remote'] < len(self.contents) def test_already_done(self): """Test that an already flashed target doesn't download any chunks""" @@ -101,9 +101,9 @@ class TestCasync(unittest.TestCase): stats = casync.extract(target, sources, self.target_fn) with open(self.target_fn, 'rb') as f: - self.assertEqual(f.read(), self.contents) + assert f.read() == self.contents - self.assertEqual(stats['target'], len(self.contents)) + assert stats['target'] == len(self.contents) def test_chunk_reuse(self): """Test that chunks that are reused are only downloaded once""" @@ -119,11 +119,11 @@ class TestCasync(unittest.TestCase): stats = casync.extract(target, sources, self.target_fn) with open(self.target_fn, 'rb') as f: - self.assertEqual(f.read(), self.contents) + assert f.read() == self.contents - self.assertLess(stats['remote'], len(self.contents)) + assert stats['remote'] < len(self.contents) - @unittest.skipUnless(LOOPBACK, "requires loopback device") + @pytest.mark.skipif(not LOOPBACK, reason="requires loopback device") def test_lo_simple_extract(self): target = casync.parse_caibx(self.manifest_fn) sources = [('remote', casync.RemoteChunkReader(self.store_fn), casync.build_chunk_dict(target))] @@ -131,11 +131,11 @@ class TestCasync(unittest.TestCase): stats = casync.extract(target, sources, self.target_lo) with open(self.target_lo, 'rb') as target_f: - self.assertEqual(target_f.read(len(self.contents)), self.contents) + assert target_f.read(len(self.contents)) == self.contents - self.assertEqual(stats['remote'], len(self.contents)) + assert stats['remote'] == len(self.contents) - @unittest.skipUnless(LOOPBACK, "requires loopback device") + @pytest.mark.skipif(not LOOPBACK, reason="requires loopback device") def test_lo_chunk_reuse(self): """Test that chunks that are reused are only downloaded once""" target = casync.parse_caibx(self.manifest_fn) @@ -146,12 +146,12 @@ class TestCasync(unittest.TestCase): stats = casync.extract(target, sources, self.target_lo) with open(self.target_lo, 'rb') as f: - self.assertEqual(f.read(len(self.contents)), self.contents) + assert f.read(len(self.contents)) == self.contents - self.assertLess(stats['remote'], len(self.contents)) + assert stats['remote'] < len(self.contents) -class TestCasyncDirectory(unittest.TestCase): +class TestCasyncDirectory: """Tests extracting a directory stored as a casync tar archive""" NUM_FILES = 16 @@ -174,7 +174,7 @@ class TestCasyncDirectory(unittest.TestCase): os.symlink(f"file_{i}.txt", os.path.join(directory, f"link_{i}.txt")) @classmethod - def setUpClass(cls): + def setup_class(cls): cls.tmpdir = tempfile.TemporaryDirectory() # Create casync files @@ -190,16 +190,16 @@ class TestCasyncDirectory(unittest.TestCase): subprocess.check_output(["casync", "make", "--compression=xz", "--store", cls.store_fn, cls.manifest_fn, cls.orig_fn]) @classmethod - def tearDownClass(cls): + def teardown_class(cls): cls.tmpdir.cleanup() cls.directory_to_extract.cleanup() - def setUp(self): + def setup_method(self): self.cache_dir = tempfile.TemporaryDirectory() self.working_dir = tempfile.TemporaryDirectory() self.out_dir = tempfile.TemporaryDirectory() - def tearDown(self): + def teardown_method(self): self.cache_dir.cleanup() self.working_dir.cleanup() self.out_dir.cleanup() @@ -216,32 +216,32 @@ class TestCasyncDirectory(unittest.TestCase): stats = casync.extract_directory(target, sources, pathlib.Path(self.out_dir.name), tmp_filename) with open(os.path.join(self.out_dir.name, "file_0.txt"), "rb") as f: - self.assertEqual(f.read(), self.contents) + assert f.read() == self.contents with open(os.path.join(self.out_dir.name, "link_0.txt"), "rb") as f: - self.assertEqual(f.read(), self.contents) - self.assertEqual(os.readlink(os.path.join(self.out_dir.name, "link_0.txt")), "file_0.txt") + assert f.read() == self.contents + assert os.readlink(os.path.join(self.out_dir.name, "link_0.txt")) == "file_0.txt" return stats def test_no_cache(self): self.setup_cache(self.cache_dir.name, []) stats = self.run_test() - self.assertGreater(stats['remote'], 0) - self.assertEqual(stats['cache'], 0) + assert stats['remote'] > 0 + assert stats['cache'] == 0 def test_full_cache(self): self.setup_cache(self.cache_dir.name, range(self.NUM_FILES)) stats = self.run_test() - self.assertEqual(stats['remote'], 0) - self.assertGreater(stats['cache'], 0) + assert stats['remote'] == 0 + assert stats['cache'] > 0 def test_one_file_cache(self): self.setup_cache(self.cache_dir.name, range(1)) stats = self.run_test() - self.assertGreater(stats['remote'], 0) - self.assertGreater(stats['cache'], 0) - self.assertLess(stats['cache'], stats['remote']) + assert stats['remote'] > 0 + assert stats['cache'] > 0 + assert stats['cache'] < stats['remote'] def test_one_file_incorrect_cache(self): self.setup_cache(self.cache_dir.name, range(self.NUM_FILES)) @@ -249,19 +249,15 @@ class TestCasyncDirectory(unittest.TestCase): f.write(b"1234") stats = self.run_test() - self.assertGreater(stats['remote'], 0) - self.assertGreater(stats['cache'], 0) - self.assertGreater(stats['cache'], stats['remote']) + assert stats['remote'] > 0 + assert stats['cache'] > 0 + assert stats['cache'] > stats['remote'] def test_one_file_missing_cache(self): self.setup_cache(self.cache_dir.name, range(self.NUM_FILES)) os.unlink(os.path.join(self.cache_dir.name, "file_12.txt")) stats = self.run_test() - self.assertGreater(stats['remote'], 0) - self.assertGreater(stats['cache'], 0) - self.assertGreater(stats['cache'], stats['remote']) - - -if __name__ == "__main__": - unittest.main() + assert stats['remote'] > 0 + assert stats['cache'] > 0 + assert stats['cache'] > stats['remote'] diff --git a/system/webrtc/tests/test_stream_session.py b/system/webrtc/tests/test_stream_session.py index 2173c3806..d8defab13 100755 --- a/system/webrtc/tests/test_stream_session.py +++ b/system/webrtc/tests/test_stream_session.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 import asyncio -import unittest -from unittest.mock import Mock, MagicMock, patch import json # for aiortc and its dependencies import warnings @@ -20,15 +18,15 @@ from openpilot.system.webrtc.device.audio import AudioInputStreamTrack from openpilot.common.realtime import DT_DMON -class TestStreamSession(unittest.TestCase): - def setUp(self): +class TestStreamSession: + def setup_method(self): self.loop = asyncio.new_event_loop() - def tearDown(self): + def teardown_method(self): self.loop.stop() self.loop.close() - def test_outgoing_proxy(self): + def test_outgoing_proxy(self, mocker): test_msg = log.Event.new_message() test_msg.logMonoTime = 123 test_msg.valid = True @@ -36,27 +34,27 @@ class TestStreamSession(unittest.TestCase): expected_dict = {"type": "customReservedRawData0", "logMonoTime": 123, "valid": True, "data": "test"} expected_json = json.dumps(expected_dict).encode() - channel = Mock(spec=RTCDataChannel) + channel = mocker.Mock(spec=RTCDataChannel) mocked_submaster = messaging.SubMaster(["customReservedRawData0"]) def mocked_update(t): mocked_submaster.update_msgs(0, [test_msg]) - with patch.object(messaging.SubMaster, "update", side_effect=mocked_update): - proxy = CerealOutgoingMessageProxy(mocked_submaster) - proxy.add_channel(channel) + mocker.patch.object(messaging.SubMaster, "update", side_effect=mocked_update) + proxy = CerealOutgoingMessageProxy(mocked_submaster) + proxy.add_channel(channel) - proxy.update() + proxy.update() - channel.send.assert_called_once_with(expected_json) + channel.send.assert_called_once_with(expected_json) - def test_incoming_proxy(self): + def test_incoming_proxy(self, mocker): tested_msgs = [ {"type": "customReservedRawData0", "data": "test"}, # primitive {"type": "can", "data": [{"address": 0, "busTime": 0, "dat": "", "src": 0}]}, # list {"type": "testJoystick", "data": {"axes": [0, 0], "buttons": [False]}}, # dict ] - mocked_pubmaster = MagicMock(spec=messaging.PubMaster) + mocked_pubmaster = mocker.MagicMock(spec=messaging.PubMaster) proxy = CerealIncomingMessageProxy(mocked_pubmaster) @@ -65,44 +63,40 @@ class TestStreamSession(unittest.TestCase): mocked_pubmaster.send.assert_called_once() mt, md = mocked_pubmaster.send.call_args.args - self.assertEqual(mt, msg["type"]) - self.assertIsInstance(md, capnp._DynamicStructBuilder) - self.assertTrue(hasattr(md, msg["type"])) + assert mt == msg["type"] + assert isinstance(md, capnp._DynamicStructBuilder) + assert hasattr(md, msg["type"]) mocked_pubmaster.reset_mock() - def test_livestream_track(self): + def test_livestream_track(self, mocker): fake_msg = messaging.new_message("livestreamDriverEncodeData") config = {"receive.return_value": fake_msg.to_bytes()} - with patch("cereal.messaging.SubSocket", spec=True, **config): - track = LiveStreamVideoStreamTrack("driver") + mocker.patch("cereal.messaging.SubSocket", spec=True, **config) + track = LiveStreamVideoStreamTrack("driver") - self.assertTrue(track.id.startswith("driver")) - self.assertEqual(track.codec_preference(), "H264") + assert track.id.startswith("driver") + assert track.codec_preference() == "H264" - for i in range(5): - packet = self.loop.run_until_complete(track.recv()) - self.assertEqual(packet.time_base, VIDEO_TIME_BASE) - self.assertEqual(packet.pts, int(i * DT_DMON * VIDEO_CLOCK_RATE)) - self.assertEqual(packet.size, 0) + for i in range(5): + packet = self.loop.run_until_complete(track.recv()) + assert packet.time_base == VIDEO_TIME_BASE + assert packet.pts == int(i * DT_DMON * VIDEO_CLOCK_RATE) + assert packet.size == 0 - def test_input_audio_track(self): + def test_input_audio_track(self, mocker): packet_time, rate = 0.02, 16000 sample_count = int(packet_time * rate) - mocked_stream = MagicMock(spec=pyaudio.Stream) + mocked_stream = mocker.MagicMock(spec=pyaudio.Stream) mocked_stream.read.return_value = b"\x00" * 2 * sample_count config = {"open.side_effect": lambda *args, **kwargs: mocked_stream} - with patch("pyaudio.PyAudio", spec=True, **config): - track = AudioInputStreamTrack(audio_format=pyaudio.paInt16, packet_time=packet_time, rate=rate) + mocker.patch("pyaudio.PyAudio", spec=True, **config) + track = AudioInputStreamTrack(audio_format=pyaudio.paInt16, packet_time=packet_time, rate=rate) - for i in range(5): - frame = self.loop.run_until_complete(track.recv()) - self.assertEqual(frame.rate, rate) - self.assertEqual(frame.samples, sample_count) - self.assertEqual(frame.pts, i * sample_count) - - -if __name__ == "__main__": - unittest.main() + for i in range(5): + frame = self.loop.run_until_complete(track.recv()) + assert frame.rate == rate + assert frame.samples == sample_count + assert frame.pts == i * sample_count diff --git a/system/webrtc/tests/test_webrtcd.py b/system/webrtc/tests/test_webrtcd.py index e5742dba0..684c7cf35 100755 --- a/system/webrtc/tests/test_webrtcd.py +++ b/system/webrtc/tests/test_webrtcd.py @@ -1,8 +1,7 @@ #!/usr/bin/env python +import pytest import asyncio import json -import unittest -from unittest.mock import MagicMock, AsyncMock # for aiortc and its dependencies import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) @@ -20,19 +19,20 @@ from parameterized import parameterized_class (["testJoystick"], []), ([], []), ]) -class TestWebrtcdProc(unittest.IsolatedAsyncioTestCase): +@pytest.mark.asyncio +class TestWebrtcdProc(): async def assertCompletesWithTimeout(self, awaitable, timeout=1): try: async with asyncio.timeout(timeout): await awaitable except TimeoutError: - self.fail("Timeout while waiting for awaitable to complete") + pytest.fail("Timeout while waiting for awaitable to complete") - async def test_webrtcd(self): - mock_request = MagicMock() + async def test_webrtcd(self, mocker): + mock_request = mocker.MagicMock() async def connect(offer): body = {'sdp': offer.sdp, 'cameras': offer.video, 'bridge_services_in': self.in_services, 'bridge_services_out': self.out_services} - mock_request.json.side_effect = AsyncMock(return_value=body) + mock_request.json.side_effect = mocker.AsyncMock(return_value=body) response = await get_stream(mock_request) response_json = json.loads(response.text) return aiortc.RTCSessionDescription(**response_json) @@ -48,9 +48,9 @@ class TestWebrtcdProc(unittest.IsolatedAsyncioTestCase): await self.assertCompletesWithTimeout(stream.start()) await self.assertCompletesWithTimeout(stream.wait_for_connection()) - self.assertTrue(stream.has_incoming_video_track("road")) - self.assertTrue(stream.has_incoming_audio_track()) - self.assertEqual(stream.has_messaging_channel(), len(self.in_services) > 0 or len(self.out_services) > 0) + assert stream.has_incoming_video_track("road") + assert stream.has_incoming_audio_track() + assert stream.has_messaging_channel() == (len(self.in_services) > 0 or len(self.out_services) > 0) video_track, audio_track = stream.get_incoming_video_track("road"), stream.get_incoming_audio_track() await self.assertCompletesWithTimeout(video_track.recv()) @@ -59,10 +59,6 @@ class TestWebrtcdProc(unittest.IsolatedAsyncioTestCase): await self.assertCompletesWithTimeout(stream.stop()) # cleanup, very implementation specific, test may break if it changes - self.assertTrue(mock_request.app["streams"].__setitem__.called, "Implementation changed, please update this test") + assert mock_request.app["streams"].__setitem__.called, "Implementation changed, please update this test" _, session = mock_request.app["streams"].__setitem__.call_args.args await self.assertCompletesWithTimeout(session.post_run_cleanup()) - - -if __name__ == "__main__": - unittest.main() diff --git a/tools/car_porting/test_car_model.py b/tools/car_porting/test_car_model.py index 5f8294fd3..cf0be1a80 100755 --- a/tools/car_porting/test_car_model.py +++ b/tools/car_porting/test_car_model.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import argparse import sys -import unittest +import unittest # noqa: TID251 from openpilot.selfdrive.car.tests.routes import CarTestRoute from openpilot.selfdrive.car.tests.test_models import TestCarModel diff --git a/tools/lib/tests/test_caching.py b/tools/lib/tests/test_caching.py index 5d3dfeba4..32f55df5d 100755 --- a/tools/lib/tests/test_caching.py +++ b/tools/lib/tests/test_caching.py @@ -1,13 +1,11 @@ #!/usr/bin/env python3 -from functools import partial import http.server import os import shutil import socket -import unittest +import pytest -from parameterized import parameterized -from openpilot.selfdrive.test.helpers import with_http_server +from openpilot.selfdrive.test.helpers import http_server_context from openpilot.system.hardware.hw import Paths from openpilot.tools.lib.url_file import URLFile @@ -31,22 +29,23 @@ class CachingTestRequestHandler(http.server.BaseHTTPRequestHandler): self.end_headers() -with_caching_server = partial(with_http_server, handler=CachingTestRequestHandler) +@pytest.fixture +def host(): + with http_server_context(handler=CachingTestRequestHandler) as (host, port): + yield f"http://{host}:{port}" +class TestFileDownload: -class TestFileDownload(unittest.TestCase): - - @with_caching_server def test_pipeline_defaults(self, host): # TODO: parameterize the defaults so we don't rely on hard-coded values in xx - self.assertEqual(URLFile.pool_manager().pools._maxsize, 10) # PoolManager num_pools param + assert URLFile.pool_manager().pools._maxsize == 10# PoolManager num_pools param pool_manager_defaults = { "maxsize": 100, "socket_options": [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),], } for k, v in pool_manager_defaults.items(): - self.assertEqual(URLFile.pool_manager().connection_pool_kw.get(k), v) + assert URLFile.pool_manager().connection_pool_kw.get(k) == v retry_defaults = { "total": 5, @@ -54,7 +53,7 @@ class TestFileDownload(unittest.TestCase): "status_forcelist": [409, 429, 503, 504], } for k, v in retry_defaults.items(): - self.assertEqual(getattr(URLFile.pool_manager().connection_pool_kw["retries"], k), v) + assert getattr(URLFile.pool_manager().connection_pool_kw["retries"], k) == v # ensure caching off by default and cache dir doesn't get created os.environ.pop("FILEREADER_CACHE", None) @@ -62,7 +61,7 @@ class TestFileDownload(unittest.TestCase): shutil.rmtree(Paths.download_cache_root()) URLFile(f"{host}/test.txt").get_length() URLFile(f"{host}/test.txt").read() - self.assertEqual(os.path.exists(Paths.download_cache_root()), False) + assert not os.path.exists(Paths.download_cache_root()) def compare_loads(self, url, start=0, length=None): """Compares range between cached and non cached version""" @@ -72,21 +71,21 @@ class TestFileDownload(unittest.TestCase): file_cached.seek(start) file_downloaded.seek(start) - self.assertEqual(file_cached.get_length(), file_downloaded.get_length()) - self.assertLessEqual(length + start if length is not None else 0, file_downloaded.get_length()) + assert file_cached.get_length() == file_downloaded.get_length() + assert length + start if length is not None else 0 <= file_downloaded.get_length() response_cached = file_cached.read(ll=length) response_downloaded = file_downloaded.read(ll=length) - self.assertEqual(response_cached, response_downloaded) + assert response_cached == response_downloaded # Now test with cache in place file_cached = URLFile(url, cache=True) file_cached.seek(start) response_cached = file_cached.read(ll=length) - self.assertEqual(file_cached.get_length(), file_downloaded.get_length()) - self.assertEqual(response_cached, response_downloaded) + assert file_cached.get_length() == file_downloaded.get_length() + assert response_cached == response_downloaded def test_small_file(self): # Make sure we don't force cache @@ -117,22 +116,16 @@ class TestFileDownload(unittest.TestCase): self.compare_loads(large_file_url, length - 100, 100) self.compare_loads(large_file_url) - @parameterized.expand([(True, ), (False, )]) - @with_caching_server - def test_recover_from_missing_file(self, cache_enabled, host): + @pytest.mark.parametrize("cache_enabled", [True, False]) + def test_recover_from_missing_file(self, host, cache_enabled): os.environ["FILEREADER_CACHE"] = "1" if cache_enabled else "0" file_url = f"{host}/test.png" CachingTestRequestHandler.FILE_EXISTS = False length = URLFile(file_url).get_length() - self.assertEqual(length, -1) + assert length == -1 CachingTestRequestHandler.FILE_EXISTS = True length = URLFile(file_url).get_length() - self.assertEqual(length, 4) - - - -if __name__ == "__main__": - unittest.main() + assert length == 4 diff --git a/tools/lib/tests/test_comma_car_segments.py b/tools/lib/tests/test_comma_car_segments.py index 91bab9434..b9a4def75 100644 --- a/tools/lib/tests/test_comma_car_segments.py +++ b/tools/lib/tests/test_comma_car_segments.py @@ -1,5 +1,4 @@ import pytest -import unittest import requests from openpilot.selfdrive.car.fingerprints import MIGRATION from openpilot.tools.lib.comma_car_segments import get_comma_car_segments_database, get_url @@ -8,7 +7,7 @@ from openpilot.tools.lib.route import SegmentRange @pytest.mark.skip(reason="huggingface is flaky, run this test manually to check for issues") -class TestCommaCarSegments(unittest.TestCase): +class TestCommaCarSegments: def test_database(self): database = get_comma_car_segments_database() @@ -28,12 +27,8 @@ class TestCommaCarSegments(unittest.TestCase): url = get_url(sr.route_name, sr.slice) resp = requests.get(url) - self.assertEqual(resp.status_code, 200) + assert resp.status_code == 200 lr = LogReader(url) CP = lr.first("carParams") - self.assertEqual(MIGRATION.get(CP.carFingerprint, CP.carFingerprint), fp) - - -if __name__ == "__main__": - unittest.main() + assert MIGRATION.get(CP.carFingerprint, CP.carFingerprint) == fp diff --git a/tools/lib/tests/test_logreader.py b/tools/lib/tests/test_logreader.py index fc72202b2..58d22a07e 100755 --- a/tools/lib/tests/test_logreader.py +++ b/tools/lib/tests/test_logreader.py @@ -5,12 +5,10 @@ import io import shutil import tempfile import os -import unittest import pytest import requests from parameterized import parameterized -from unittest import mock from cereal import log as capnp_log from openpilot.tools.lib.logreader import LogIterable, LogReader, comma_api_source, parse_indirect, ReadMode, InternalUnavailableException @@ -28,24 +26,22 @@ def noop(segment: LogIterable): @contextlib.contextmanager -def setup_source_scenario(is_internal=False): - with ( - mock.patch("openpilot.tools.lib.logreader.internal_source") as internal_source_mock, - mock.patch("openpilot.tools.lib.logreader.openpilotci_source") as openpilotci_source_mock, - mock.patch("openpilot.tools.lib.logreader.comma_api_source") as comma_api_source_mock, - ): - if is_internal: - internal_source_mock.return_value = [QLOG_FILE] - else: - internal_source_mock.side_effect = InternalUnavailableException +def setup_source_scenario(mocker, is_internal=False): + internal_source_mock = mocker.patch("openpilot.tools.lib.logreader.internal_source") + openpilotci_source_mock = mocker.patch("openpilot.tools.lib.logreader.openpilotci_source") + comma_api_source_mock = mocker.patch("openpilot.tools.lib.logreader.comma_api_source") + if is_internal: + internal_source_mock.return_value = [QLOG_FILE] + else: + internal_source_mock.side_effect = InternalUnavailableException - openpilotci_source_mock.return_value = [None] - comma_api_source_mock.return_value = [QLOG_FILE] + openpilotci_source_mock.return_value = [None] + comma_api_source_mock.return_value = [QLOG_FILE] - yield + yield -class TestLogReader(unittest.TestCase): +class TestLogReader: @parameterized.expand([ (f"{TEST_ROUTE}", ALL_SEGS), (f"{TEST_ROUTE.replace('/', '|')}", ALL_SEGS), @@ -74,7 +70,7 @@ class TestLogReader(unittest.TestCase): def test_indirect_parsing(self, identifier, expected): parsed, _, _ = parse_indirect(identifier) sr = SegmentRange(parsed) - self.assertListEqual(list(sr.seg_idxs), expected, identifier) + assert list(sr.seg_idxs) == expected, identifier @parameterized.expand([ (f"{TEST_ROUTE}", f"{TEST_ROUTE}"), @@ -86,11 +82,11 @@ class TestLogReader(unittest.TestCase): ]) def test_canonical_name(self, identifier, expected): sr = SegmentRange(identifier) - self.assertEqual(str(sr), expected) + assert str(sr) == expected - @parameterized.expand([(True,), (False,)]) - @mock.patch("openpilot.tools.lib.logreader.file_exists") - def test_direct_parsing(self, cache_enabled, file_exists_mock): + @pytest.mark.parametrize("cache_enabled", [True, False]) + def test_direct_parsing(self, mocker, cache_enabled): + file_exists_mock = mocker.patch("openpilot.tools.lib.logreader.file_exists") os.environ["FILEREADER_CACHE"] = "1" if cache_enabled else "0" qlog = tempfile.NamedTemporaryFile(mode='wb', delete=False) @@ -100,13 +96,13 @@ class TestLogReader(unittest.TestCase): for f in [QLOG_FILE, qlog.name]: l = len(list(LogReader(f))) - self.assertGreater(l, 100) + assert l > 100 - with self.assertRaises(URLFileException) if not cache_enabled else self.assertRaises(AssertionError): + with pytest.raises(URLFileException) if not cache_enabled else pytest.raises(AssertionError): l = len(list(LogReader(QLOG_FILE.replace("/3/", "/200/")))) # file_exists should not be called for direct files - self.assertEqual(file_exists_mock.call_count, 0) + assert file_exists_mock.call_count == 0 @parameterized.expand([ (f"{TEST_ROUTE}///",), @@ -121,110 +117,110 @@ class TestLogReader(unittest.TestCase): (f"{TEST_ROUTE}--3a",), ]) def test_bad_ranges(self, segment_range): - with self.assertRaises(AssertionError): + with pytest.raises(AssertionError): _ = SegmentRange(segment_range).seg_idxs - @parameterized.expand([ + @pytest.mark.parametrize("segment_range, api_call", [ (f"{TEST_ROUTE}/0", False), (f"{TEST_ROUTE}/:2", False), (f"{TEST_ROUTE}/0:", True), (f"{TEST_ROUTE}/-1", True), (f"{TEST_ROUTE}", True), ]) - def test_slicing_api_call(self, segment_range, api_call): - with mock.patch("openpilot.tools.lib.route.get_max_seg_number_cached") as max_seg_mock: - max_seg_mock.return_value = NUM_SEGS - _ = SegmentRange(segment_range).seg_idxs - self.assertEqual(api_call, max_seg_mock.called) + def test_slicing_api_call(self, mocker, segment_range, api_call): + max_seg_mock = mocker.patch("openpilot.tools.lib.route.get_max_seg_number_cached") + max_seg_mock.return_value = NUM_SEGS + _ = SegmentRange(segment_range).seg_idxs + assert api_call == max_seg_mock.called @pytest.mark.slow def test_modes(self): qlog_len = len(list(LogReader(f"{TEST_ROUTE}/0", ReadMode.QLOG))) rlog_len = len(list(LogReader(f"{TEST_ROUTE}/0", ReadMode.RLOG))) - self.assertLess(qlog_len * 6, rlog_len) + assert qlog_len * 6 < rlog_len @pytest.mark.slow def test_modes_from_name(self): qlog_len = len(list(LogReader(f"{TEST_ROUTE}/0/q"))) rlog_len = len(list(LogReader(f"{TEST_ROUTE}/0/r"))) - self.assertLess(qlog_len * 6, rlog_len) + assert qlog_len * 6 < rlog_len @pytest.mark.slow def test_list(self): qlog_len = len(list(LogReader(f"{TEST_ROUTE}/0/q"))) qlog_len_2 = len(list(LogReader([f"{TEST_ROUTE}/0/q", f"{TEST_ROUTE}/0/q"]))) - self.assertEqual(qlog_len * 2, qlog_len_2) + assert qlog_len * 2 == qlog_len_2 @pytest.mark.slow - @mock.patch("openpilot.tools.lib.logreader._LogFileReader") - def test_multiple_iterations(self, init_mock): + def test_multiple_iterations(self, mocker): + init_mock = mocker.patch("openpilot.tools.lib.logreader._LogFileReader") lr = LogReader(f"{TEST_ROUTE}/0/q") qlog_len1 = len(list(lr)) qlog_len2 = len(list(lr)) # ensure we don't create multiple instances of _LogFileReader, which means downloading the files twice - self.assertEqual(init_mock.call_count, 1) + assert init_mock.call_count == 1 - self.assertEqual(qlog_len1, qlog_len2) + assert qlog_len1 == qlog_len2 @pytest.mark.slow def test_helpers(self): lr = LogReader(f"{TEST_ROUTE}/0/q") - self.assertEqual(lr.first("carParams").carFingerprint, "SUBARU OUTBACK 6TH GEN") - self.assertTrue(0 < len(list(lr.filter("carParams"))) < len(list(lr))) + assert lr.first("carParams").carFingerprint == "SUBARU OUTBACK 6TH GEN" + assert 0 < len(list(lr.filter("carParams"))) < len(list(lr)) @parameterized.expand([(True,), (False,)]) @pytest.mark.slow def test_run_across_segments(self, cache_enabled): os.environ["FILEREADER_CACHE"] = "1" if cache_enabled else "0" lr = LogReader(f"{TEST_ROUTE}/0:4") - self.assertEqual(len(lr.run_across_segments(4, noop)), len(list(lr))) + assert len(lr.run_across_segments(4, noop)) == len(list(lr)) @pytest.mark.slow - def test_auto_mode(self): + def test_auto_mode(self, subtests, mocker): lr = LogReader(f"{TEST_ROUTE}/0/q") qlog_len = len(list(lr)) - with mock.patch("openpilot.tools.lib.route.Route.log_paths") as log_paths_mock: - log_paths_mock.return_value = [None] * NUM_SEGS - # Should fall back to qlogs since rlogs are not available + log_paths_mock = mocker.patch("openpilot.tools.lib.route.Route.log_paths") + log_paths_mock.return_value = [None] * NUM_SEGS + # Should fall back to qlogs since rlogs are not available - with self.subTest("interactive_yes"): - with mock.patch("sys.stdin", new=io.StringIO("y\n")): - lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, default_source=comma_api_source) - log_len = len(list(lr)) - self.assertEqual(qlog_len, log_len) + with subtests.test("interactive_yes"): + mocker.patch("sys.stdin", new=io.StringIO("y\n")) + lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, default_source=comma_api_source) + log_len = len(list(lr)) + assert qlog_len == log_len - with self.subTest("interactive_no"): - with mock.patch("sys.stdin", new=io.StringIO("n\n")): - with self.assertRaises(AssertionError): - lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, default_source=comma_api_source) + with subtests.test("interactive_no"): + mocker.patch("sys.stdin", new=io.StringIO("n\n")) + with pytest.raises(AssertionError): + lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, default_source=comma_api_source) - with self.subTest("non_interactive"): - lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO, default_source=comma_api_source) - log_len = len(list(lr)) - self.assertEqual(qlog_len, log_len) + with subtests.test("non_interactive"): + lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO, default_source=comma_api_source) + log_len = len(list(lr)) + assert qlog_len == log_len - @parameterized.expand([(True,), (False,)]) + @pytest.mark.parametrize("is_internal", [True, False]) @pytest.mark.slow - def test_auto_source_scenarios(self, is_internal): + def test_auto_source_scenarios(self, mocker, is_internal): lr = LogReader(QLOG_FILE) qlog_len = len(list(lr)) - with setup_source_scenario(is_internal=is_internal): + with setup_source_scenario(mocker, is_internal=is_internal): lr = LogReader(f"{TEST_ROUTE}/0/q") log_len = len(list(lr)) - self.assertEqual(qlog_len, log_len) + assert qlog_len == log_len @pytest.mark.slow def test_sort_by_time(self): msgs = list(LogReader(f"{TEST_ROUTE}/0/q")) - self.assertNotEqual(msgs, sorted(msgs, key=lambda m: m.logMonoTime)) + assert msgs != sorted(msgs, key=lambda m: m.logMonoTime) msgs = list(LogReader(f"{TEST_ROUTE}/0/q", sort_by_time=True)) - self.assertEqual(msgs, sorted(msgs, key=lambda m: m.logMonoTime)) + assert msgs == sorted(msgs, key=lambda m: m.logMonoTime) def test_only_union_types(self): with tempfile.NamedTemporaryFile() as qlog: @@ -234,7 +230,7 @@ class TestLogReader(unittest.TestCase): f.write(b"".join(capnp_log.Event.new_message().to_bytes() for _ in range(num_msgs))) msgs = list(LogReader(qlog.name)) - self.assertEqual(len(msgs), num_msgs) + assert len(msgs) == num_msgs [m.which() for m in msgs] # append non-union Event message @@ -246,15 +242,11 @@ class TestLogReader(unittest.TestCase): # ensure new message is added, but is not a union type msgs = list(LogReader(qlog.name)) - self.assertEqual(len(msgs), num_msgs + 1) - with self.assertRaises(capnp.KjException): + assert len(msgs) == num_msgs + 1 + with pytest.raises(capnp.KjException): [m.which() for m in msgs] # should not be added when only_union_types=True msgs = list(LogReader(qlog.name, only_union_types=True)) - self.assertEqual(len(msgs), num_msgs) + assert len(msgs) == num_msgs [m.which() for m in msgs] - - -if __name__ == "__main__": - unittest.main() diff --git a/tools/lib/tests/test_readers.py b/tools/lib/tests/test_readers.py index 1f24ae5c8..f92554872 100755 --- a/tools/lib/tests/test_readers.py +++ b/tools/lib/tests/test_readers.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -import unittest +import pytest import requests import tempfile @@ -9,16 +9,16 @@ from openpilot.tools.lib.framereader import FrameReader from openpilot.tools.lib.logreader import LogReader -class TestReaders(unittest.TestCase): - @unittest.skip("skip for bandwidth reasons") +class TestReaders: + @pytest.mark.skip("skip for bandwidth reasons") def test_logreader(self): def _check_data(lr): hist = defaultdict(int) for l in lr: hist[l.which()] += 1 - self.assertEqual(hist['carControl'], 6000) - self.assertEqual(hist['logMessage'], 6857) + assert hist['carControl'] == 6000 + assert hist['logMessage'] == 6857 with tempfile.NamedTemporaryFile(suffix=".bz2") as fp: r = requests.get("https://github.com/commaai/comma2k19/blob/master/Example_1/b0c9d2329ad1606b%7C2018-08-02--08-34-47/40/raw_log.bz2?raw=true", timeout=10) @@ -31,15 +31,15 @@ class TestReaders(unittest.TestCase): lr_url = LogReader("https://github.com/commaai/comma2k19/blob/master/Example_1/b0c9d2329ad1606b%7C2018-08-02--08-34-47/40/raw_log.bz2?raw=true") _check_data(lr_url) - @unittest.skip("skip for bandwidth reasons") + @pytest.mark.skip("skip for bandwidth reasons") def test_framereader(self): def _check_data(f): - self.assertEqual(f.frame_count, 1200) - self.assertEqual(f.w, 1164) - self.assertEqual(f.h, 874) + assert f.frame_count == 1200 + assert f.w == 1164 + assert f.h == 874 frame_first_30 = f.get(0, 30) - self.assertEqual(len(frame_first_30), 30) + assert len(frame_first_30) == 30 print(frame_first_30[15]) @@ -62,6 +62,3 @@ class TestReaders(unittest.TestCase): fr_url = FrameReader("https://github.com/commaai/comma2k19/blob/master/Example_1/b0c9d2329ad1606b%7C2018-08-02--08-34-47/40/video.hevc?raw=true") _check_data(fr_url) - -if __name__ == "__main__": - unittest.main() diff --git a/tools/lib/tests/test_route_library.py b/tools/lib/tests/test_route_library.py index 7977f17be..8f75fa19c 100755 --- a/tools/lib/tests/test_route_library.py +++ b/tools/lib/tests/test_route_library.py @@ -1,10 +1,9 @@ #!/usr/bin/env python -import unittest from collections import namedtuple from openpilot.tools.lib.route import SegmentName -class TestRouteLibrary(unittest.TestCase): +class TestRouteLibrary: def test_segment_name_formats(self): Case = namedtuple('Case', ['input', 'expected_route', 'expected_segment_num', 'expected_data_dir']) @@ -21,12 +20,9 @@ class TestRouteLibrary(unittest.TestCase): s = SegmentName(route_or_segment_name, allow_route_name=True) - self.assertEqual(str(s.route_name), case.expected_route) - self.assertEqual(s.segment_num, case.expected_segment_num) - self.assertEqual(s.data_dir, case.expected_data_dir) + assert str(s.route_name) == case.expected_route + assert s.segment_num == case.expected_segment_num + assert s.data_dir == case.expected_data_dir for case in cases: _validate(case) - -if __name__ == "__main__": - unittest.main() diff --git a/tools/plotjuggler/test_plotjuggler.py b/tools/plotjuggler/test_plotjuggler.py index 17287fb80..8b811f484 100755 --- a/tools/plotjuggler/test_plotjuggler.py +++ b/tools/plotjuggler/test_plotjuggler.py @@ -4,7 +4,6 @@ import glob import signal import subprocess import time -import unittest from openpilot.common.basedir import BASEDIR from openpilot.common.timeout import Timeout @@ -12,7 +11,7 @@ from openpilot.tools.plotjuggler.juggle import DEMO_ROUTE, install PJ_DIR = os.path.join(BASEDIR, "tools/plotjuggler") -class TestPlotJuggler(unittest.TestCase): +class TestPlotJuggler: def test_demo(self): install() @@ -28,13 +27,13 @@ class TestPlotJuggler(unittest.TestCase): # ensure plotjuggler didn't crash after exiting the plugin time.sleep(15) - self.assertEqual(p.poll(), None) + assert p.poll() is None os.killpg(os.getpgid(p.pid), signal.SIGTERM) - self.assertNotIn("Raw file read failed", output) + assert "Raw file read failed" not in output # TODO: also test that layouts successfully load - def test_layouts(self): + def test_layouts(self, subtests): bad_strings = ( # if a previously loaded file is defined, # PJ will throw a warning when loading the layout @@ -43,12 +42,8 @@ class TestPlotJuggler(unittest.TestCase): ) for fn in glob.glob(os.path.join(PJ_DIR, "layouts/*")): name = os.path.basename(fn) - with self.subTest(layout=name): + with subtests.test(layout=name): with open(fn) as f: layout = f.read() violations = [s for s in bad_strings if s in layout] assert len(violations) == 0, f"These should be stripped out of the layout: {str(violations)}" - - -if __name__ == "__main__": - unittest.main() diff --git a/tools/sim/tests/test_metadrive_bridge.py b/tools/sim/tests/test_metadrive_bridge.py index 6cb8e1465..28fa462a1 100755 --- a/tools/sim/tests/test_metadrive_bridge.py +++ b/tools/sim/tests/test_metadrive_bridge.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import pytest -import unittest from openpilot.tools.sim.bridge.metadrive.metadrive_bridge import MetaDriveBridge from openpilot.tools.sim.tests.test_sim_bridge import TestSimBridgeBase @@ -9,7 +8,3 @@ from openpilot.tools.sim.tests.test_sim_bridge import TestSimBridgeBase class TestMetaDriveBridge(TestSimBridgeBase): def create_bridge(self): return MetaDriveBridge(False, False) - - -if __name__ == "__main__": - unittest.main() diff --git a/tools/sim/tests/test_sim_bridge.py b/tools/sim/tests/test_sim_bridge.py index d9653d5cf..6b8b811fb 100644 --- a/tools/sim/tests/test_sim_bridge.py +++ b/tools/sim/tests/test_sim_bridge.py @@ -1,7 +1,7 @@ import os import subprocess import time -import unittest +import pytest from multiprocessing import Queue @@ -10,13 +10,13 @@ from openpilot.common.basedir import BASEDIR SIM_DIR = os.path.join(BASEDIR, "tools/sim") -class TestSimBridgeBase(unittest.TestCase): +class TestSimBridgeBase: @classmethod - def setUpClass(cls): + def setup_class(cls): if cls is TestSimBridgeBase: - raise unittest.SkipTest("Don't run this base class, run test_metadrive_bridge.py instead") + raise pytest.skip("Don't run this base class, run test_metadrive_bridge.py instead") - def setUp(self): + def setup_method(self): self.processes = [] def test_engage(self): @@ -36,7 +36,7 @@ class TestSimBridgeBase(unittest.TestCase): start_waiting = time.monotonic() while not bridge.started.value and time.monotonic() < start_waiting + max_time_per_step: time.sleep(0.1) - self.assertEqual(p_bridge.exitcode, None, f"Bridge process should be running, but exited with code {p_bridge.exitcode}") + assert p_bridge.exitcode is None, f"Bridge process should be running, but exited with code {p_bridge.exitcode}" start_time = time.monotonic() no_car_events_issues_once = False @@ -52,8 +52,8 @@ class TestSimBridgeBase(unittest.TestCase): no_car_events_issues_once = True break - self.assertTrue(no_car_events_issues_once, - f"Failed because no messages received, or CarEvents '{car_event_issues}' or processes not running '{not_running}'") + assert no_car_events_issues_once, \ + f"Failed because no messages received, or CarEvents '{car_event_issues}' or processes not running '{not_running}'" start_time = time.monotonic() min_counts_control_active = 100 @@ -68,9 +68,9 @@ class TestSimBridgeBase(unittest.TestCase): if control_active == min_counts_control_active: break - self.assertEqual(min_counts_control_active, control_active, f"Simulator did not engage a minimal of {min_counts_control_active} steps was {control_active}") + assert min_counts_control_active == control_active, f"Simulator did not engage a minimal of {min_counts_control_active} steps was {control_active}" - def tearDown(self): + def teardown_method(self): print("Test shutting down. CommIssues are acceptable") for p in reversed(self.processes): p.terminate() @@ -80,7 +80,3 @@ class TestSimBridgeBase(unittest.TestCase): p.wait(15) else: p.join(15) - - -if __name__ == "__main__": - unittest.main() From 6303d42535cd57cc6e763bcc4d878f6517179ac3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 11:02:26 -0700 Subject: [PATCH 004/220] bump opendbc --- opendbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc b/opendbc index e2408cb27..d53c8f558 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit e2408cb2725671ad63e827e02f37e0f1739b68c6 +Subproject commit d53c8f558cc4861ce6563498a3663ee9b57daf4b From 5cfaae771d02846c273797795a737ac22e312ec1 Mon Sep 17 00:00:00 2001 From: Curtis Jiang Date: Fri, 17 May 2024 16:17:24 -0400 Subject: [PATCH 005/220] HKG: Add FW version for Canada Hyundai Tucson PHEV 2024 (#32440) * Car port for Hyundai Tucson PHEV 2024 * Fix doc --- docs/CARS.md | 3 ++- selfdrive/car/hyundai/fingerprints.py | 1 + selfdrive/car/hyundai/values.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CARS.md b/docs/CARS.md index de9320594..4364f10b0 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. -# 286 Supported Cars +# 287 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -120,6 +120,7 @@ A supported vehicle is one that just works when you install a comma device. All |Hyundai|Tucson 2023-24[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Tucson Hybrid 2022-24[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson Plug-in Hybrid 2024[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 0c43b8e34..b6318eb8f 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -1003,6 +1003,7 @@ FW_VERSIONS = { CAR.HYUNDAI_TUCSON_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.01 99211-N9100 14A', + b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N9260 14Y', b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9220 14K', b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 2.02 99211-N9000 14E', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9210 14G', diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index db9055970..1e752185e 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -323,6 +323,7 @@ class CAR(Platforms): HyundaiCarDocs("Hyundai Tucson 2022", car_parts=CarParts.common([CarHarness.hyundai_n])), HyundaiCarDocs("Hyundai Tucson 2023-24", "All", car_parts=CarParts.common([CarHarness.hyundai_n])), HyundaiCarDocs("Hyundai Tucson Hybrid 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_n])), + HyundaiCarDocs("Hyundai Tucson Plug-in Hybrid 2024", "All", car_parts=CarParts.common([CarHarness.hyundai_n])), ], CarSpecs(mass=1630, wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385), ) From 4388a2aa68a59cdcf7c7577a4ee38e71aac611bd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 19:20:18 -0700 Subject: [PATCH 006/220] CI: use less parallel jobs for cars (#32458) * CI: use less parallel jobs for cars * 2 --- .github/workflows/selfdrive_tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 85c407307..c94bcbb7c 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -298,7 +298,7 @@ jobs: strategy: fail-fast: false matrix: - job: [0, 1, 2, 3, 4] + job: [0, 1] steps: - uses: actions/checkout@v4 with: @@ -318,7 +318,7 @@ jobs: ${{ env.RUN }} "$PYTEST selfdrive/car/tests/test_models.py && \ chmod -R 777 /tmp/comma_download_cache" env: - NUM_JOBS: 5 + NUM_JOBS: 2 JOB_ID: ${{ matrix.job }} - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v4 From 27da6bd752817a2af5df86cf1366c083ff732ffe Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 19:31:55 -0700 Subject: [PATCH 007/220] CI: move model tests (#32459) --- .github/workflows/selfdrive_tests.yaml | 40 +++++--------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index c94bcbb7c..c4b0d33d2 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -225,6 +225,13 @@ jobs: if: ${{ failure() && steps.print-diff.outcome == 'success' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }} run: | ${{ env.RUN }} "unset PYTHONWARNINGS && AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only" + # PYTHONWARNINGS triggers a SyntaxError in onnxruntime + - name: Run model replay with ONNX + timeout-minutes: 4 + run: | + ${{ env.RUN }} "unset PYTHONWARNINGS && \ + ONNXCPU=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ + coverage combine && coverage xml" - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v4 with: @@ -257,39 +264,6 @@ jobs: ${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \ chmod -R 777 /tmp/comma_download_cache" - test_modeld: - name: model tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: Build base Docker image - run: eval "$BUILD" - - name: Build openpilot - run: | - ${{ env.RUN }} "scons -j$(nproc)" - # PYTHONWARNINGS triggers a SyntaxError in onnxruntime - - name: Run model replay with ONNX - timeout-minutes: 4 - run: | - ${{ env.RUN }} "unset PYTHONWARNINGS && \ - ONNXCPU=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ - coverage combine && \ - coverage xml" - - name: Run unit tests - timeout-minutes: 4 - run: | - ${{ env.RUN }} "unset PYTHONWARNINGS && \ - $PYTEST selfdrive/modeld" - - name: "Upload coverage to Codecov" - uses: codecov/codecov-action@v4 - with: - name: ${{ github.job }} - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - test_cars: name: cars runs-on: ${{ ((github.repository == 'commaai/openpilot') && From e1a697fee521eedad2210d8e01d668e2bb020ace Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 19:43:47 -0700 Subject: [PATCH 008/220] remove old valgrind replay test --- .github/workflows/selfdrive_tests.yaml | 18 ---- selfdrive/test/test_valgrind_replay.py | 112 ------------------------- tools/install_ubuntu_dependencies.sh | 3 +- 3 files changed, 1 insertion(+), 132 deletions(-) delete mode 100755 selfdrive/test/test_valgrind_replay.py diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index c4b0d33d2..af4a9e113 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -134,24 +134,6 @@ jobs: timeout-minutes: 4 run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all && chmod -R 777 /tmp/pre-commit" - valgrind: - name: valgrind - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: Build openpilot - run: ${{ env.RUN }} "scons -j$(nproc)" - - name: Run valgrind - timeout-minutes: 1 - run: | - ${{ env.RUN }} "pytest selfdrive/test/test_valgrind_replay.py" - - name: Print logs - if: always() - run: cat selfdrive/test/valgrind_logs.txt - unit_tests: name: unit tests runs-on: ${{ ((github.repository == 'commaai/openpilot') && diff --git a/selfdrive/test/test_valgrind_replay.py b/selfdrive/test/test_valgrind_replay.py deleted file mode 100755 index dffd60df9..000000000 --- a/selfdrive/test/test_valgrind_replay.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python3 -import os -import threading -import time -import subprocess -import signal - -if "CI" in os.environ: - def tqdm(x): - return x -else: - from tqdm import tqdm # type: ignore - -import cereal.messaging as messaging -from collections import namedtuple -from openpilot.tools.lib.logreader import LogReader -from openpilot.tools.lib.openpilotci import get_url -from openpilot.common.basedir import BASEDIR - -ProcessConfig = namedtuple('ProcessConfig', ['proc_name', 'pub_sub', 'ignore', 'command', 'path', 'segment', 'wait_for_response']) - -CONFIGS = [ - ProcessConfig( - proc_name="ubloxd", - pub_sub={ - "ubloxRaw": ["ubloxGnss", "gpsLocationExternal"], - }, - ignore=[], - command="./ubloxd", - path="system/ubloxd", - segment="0375fdf7b1ce594d|2019-06-13--08-32-25--3", - wait_for_response=True - ), -] - - -class TestValgrind: - def extract_leak_sizes(self, log): - if "All heap blocks were freed -- no leaks are possible" in log: - return (0,0,0) - - log = log.replace(",","") # fixes casting to int issue with large leaks - err_lost1 = log.split("definitely lost: ")[1] - err_lost2 = log.split("indirectly lost: ")[1] - err_lost3 = log.split("possibly lost: ")[1] - definitely_lost = int(err_lost1.split(" ")[0]) - indirectly_lost = int(err_lost2.split(" ")[0]) - possibly_lost = int(err_lost3.split(" ")[0]) - return (definitely_lost, indirectly_lost, possibly_lost) - - def valgrindlauncher(self, arg, cwd): - os.chdir(os.path.join(BASEDIR, cwd)) - # Run valgrind on a process - command = "valgrind --leak-check=full " + arg - p = subprocess.Popen(command, stderr=subprocess.PIPE, shell=True, preexec_fn=os.setsid) - - while not self.replay_done: - time.sleep(0.1) - - # Kill valgrind and extract leak output - os.killpg(os.getpgid(p.pid), signal.SIGINT) - _, err = p.communicate() - error_msg = str(err, encoding='utf-8') - with open(os.path.join(BASEDIR, "selfdrive/test/valgrind_logs.txt"), "a") as f: - f.write(error_msg) - f.write(5 * "\n") - definitely_lost, indirectly_lost, possibly_lost = self.extract_leak_sizes(error_msg) - if max(definitely_lost, indirectly_lost, possibly_lost) > 0: - self.leak = True - print("LEAKS from", arg, "\nDefinitely lost:", definitely_lost, "\nIndirectly lost", indirectly_lost, "\nPossibly lost", possibly_lost) - else: - self.leak = False - - def replay_process(self, config, logreader): - pub_sockets = list(config.pub_sub.keys()) # We dump data from logs here - sub_sockets = [s for _, sub in config.pub_sub.items() for s in sub] # We get responses here - pm = messaging.PubMaster(pub_sockets) - sm = messaging.SubMaster(sub_sockets) - - print("Sorting logs") - all_msgs = sorted(logreader, key=lambda msg: msg.logMonoTime) - pub_msgs = [msg for msg in all_msgs if msg.which() in list(config.pub_sub.keys())] - - thread = threading.Thread(target=self.valgrindlauncher, args=(config.command, config.path)) - thread.daemon = True - thread.start() - - while not all(pm.all_readers_updated(s) for s in config.pub_sub.keys()): - time.sleep(0) - - for msg in tqdm(pub_msgs): - pm.send(msg.which(), msg.as_builder()) - if config.wait_for_response: - sm.update(100) - - self.replay_done = True - - def test_config(self): - open(os.path.join(BASEDIR, "selfdrive/test/valgrind_logs.txt"), "w").close() - - for cfg in CONFIGS: - self.leak = None - self.replay_done = False - - r, n = cfg.segment.rsplit("--", 1) - lr = LogReader(get_url(r, n)) - self.replay_process(cfg, lr) - - while self.leak is None: - time.sleep(0.1) # Wait for the valgrind to finish - - assert not self.leak diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 75d19141b..70a7ff2ea 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -77,8 +77,7 @@ function install_ubuntu_common_requirements() { libqt5x11extras5-dev \ libqt5opengl5-dev \ libreadline-dev \ - libdw1 \ - valgrind + libdw1 } # Install Ubuntu 24.04 LTS packages From 57c8510a42b086bd2479f90f8d7a26b010454c89 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 19:48:14 -0700 Subject: [PATCH 009/220] CI: move regen into replay job (#32460) --- .github/workflows/selfdrive_tests.yaml | 32 +++++--------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index af4a9e113..e8c776642 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -182,7 +182,7 @@ jobs: uses: actions/cache@v4 with: path: .ci_cache/comma_download_cache - key: proc-replay-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/ref_commit') }} + key: proc-replay-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/ref_commit', 'selfdrive/test/process_replay/test_regen.py') }} - name: Build openpilot run: | ${{ env.RUN }} "scons -j$(nproc)" @@ -214,6 +214,11 @@ jobs: ${{ env.RUN }} "unset PYTHONWARNINGS && \ ONNXCPU=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ coverage combine && coverage xml" + - name: Run regen + timeout-minutes: 4 + run: | + ${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \ + chmod -R 777 /tmp/comma_download_cache" - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v4 with: @@ -221,31 +226,6 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - regen: - name: regen - runs-on: 'ubuntu-latest' - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: Cache test routes - id: dependency-cache - uses: actions/cache@v4 - with: - path: .ci_cache/comma_download_cache - key: regen-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/test_regen.py') }} - - name: Build base Docker image - run: eval "$BUILD" - - name: Build openpilot - run: | - ${{ env.RUN }} "scons -j$(nproc)" - - name: Run regen - timeout-minutes: 30 - run: | - ${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \ - chmod -R 777 /tmp/comma_download_cache" - test_cars: name: cars runs-on: ${{ ((github.repository == 'commaai/openpilot') && From 630e1529008ce0c996ba6a111df44877596acfea Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Fri, 17 May 2024 22:51:07 -0400 Subject: [PATCH 010/220] Simulator: standardize queue messages (#32313) * standardize queue messages * update control_command_gen * fix * fix logic * update closing type * qmessagetype -> enum * update type hint * old close() makes more sense * cleanup * fix * revert that * revert that * better name * actually this is better --- tools/sim/bridge/common.py | 71 +++++++++++-------- .../sim/bridge/metadrive/metadrive_bridge.py | 4 +- tools/sim/bridge/metadrive/metadrive_world.py | 17 ++--- tools/sim/lib/keyboard_ctrl.py | 31 ++++---- tools/sim/lib/manual_ctrl.py | 16 +++-- 5 files changed, 76 insertions(+), 63 deletions(-) diff --git a/tools/sim/bridge/common.py b/tools/sim/bridge/common.py index 46d09c7b9..275a9a764 100644 --- a/tools/sim/bridge/common.py +++ b/tools/sim/bridge/common.py @@ -2,6 +2,8 @@ import signal import threading import functools +from collections import namedtuple +from enum import Enum from multiprocessing import Process, Queue, Value from abc import ABC, abstractmethod @@ -14,6 +16,16 @@ from openpilot.tools.sim.lib.common import SimulatorState, World from openpilot.tools.sim.lib.simulated_car import SimulatedCar from openpilot.tools.sim.lib.simulated_sensors import SimulatedSensors +QueueMessage = namedtuple("QueueMessage", ["type", "info"], defaults=[None]) + +class QueueMessageType(Enum): + START_STATUS = 0 + CONTROL_COMMAND = 1 + TERMINATION_INFO = 2 + CLOSE_STATUS = 3 + +def control_cmd_gen(cmd: str): + return QueueMessage(QueueMessageType.CONTROL_COMMAND, cmd) def rk_loop(function, hz, exit_event: threading.Event): rk = Ratekeeper(hz, None) @@ -80,11 +92,11 @@ Ignition: {self.simulator_state.ignition} Engaged: {self.simulator_state.is_enga """) @abstractmethod - def spawn_world(self) -> World: + def spawn_world(self, q: Queue) -> World: pass def _run(self, q: Queue): - self.world = self.spawn_world() + self.world = self.spawn_world(q) self.simulated_car = SimulatedCar() self.simulated_sensors = SimulatedSensors(self.dual_camera) @@ -114,33 +126,34 @@ Ignition: {self.simulator_state.ignition} Engaged: {self.simulator_state.is_enga # Read manual controls if not q.empty(): message = q.get() - m = message.split('_') - if m[0] == "steer": - steer_manual = float(m[1]) - elif m[0] == "throttle": - throttle_manual = float(m[1]) - elif m[0] == "brake": - brake_manual = float(m[1]) - elif m[0] == "cruise": - if m[1] == "down": - self.simulator_state.cruise_button = CruiseButtons.DECEL_SET - elif m[1] == "up": - self.simulator_state.cruise_button = CruiseButtons.RES_ACCEL - elif m[1] == "cancel": - self.simulator_state.cruise_button = CruiseButtons.CANCEL - elif m[1] == "main": - self.simulator_state.cruise_button = CruiseButtons.MAIN - elif m[0] == "blinker": - if m[1] == "left": - self.simulator_state.left_blinker = True - elif m[1] == "right": - self.simulator_state.right_blinker = True - elif m[0] == "ignition": - self.simulator_state.ignition = not self.simulator_state.ignition - elif m[0] == "reset": - self.world.reset() - elif m[0] == "quit": - break + if message.type == QueueMessageType.CONTROL_COMMAND: + m = message.info.split('_') + if m[0] == "steer": + steer_manual = float(m[1]) + elif m[0] == "throttle": + throttle_manual = float(m[1]) + elif m[0] == "brake": + brake_manual = float(m[1]) + elif m[0] == "cruise": + if m[1] == "down": + self.simulator_state.cruise_button = CruiseButtons.DECEL_SET + elif m[1] == "up": + self.simulator_state.cruise_button = CruiseButtons.RES_ACCEL + elif m[1] == "cancel": + self.simulator_state.cruise_button = CruiseButtons.CANCEL + elif m[1] == "main": + self.simulator_state.cruise_button = CruiseButtons.MAIN + elif m[0] == "blinker": + if m[1] == "left": + self.simulator_state.left_blinker = True + elif m[1] == "right": + self.simulator_state.right_blinker = True + elif m[0] == "ignition": + self.simulator_state.ignition = not self.simulator_state.ignition + elif m[0] == "reset": + self.world.reset() + elif m[0] == "quit": + break self.simulator_state.user_brake = brake_manual self.simulator_state.user_gas = throttle_manual diff --git a/tools/sim/bridge/metadrive/metadrive_bridge.py b/tools/sim/bridge/metadrive/metadrive_bridge.py index 5c91238c5..cbac21509 100644 --- a/tools/sim/bridge/metadrive/metadrive_bridge.py +++ b/tools/sim/bridge/metadrive/metadrive_bridge.py @@ -53,7 +53,7 @@ class MetaDriveBridge(SimulatorBridge): super().__init__(dual_camera, high_quality) - def spawn_world(self): + def spawn_world(self, queue: Queue): sensors = { "rgb_road": (RGBCameraRoad, W, H, ) } @@ -83,4 +83,4 @@ class MetaDriveBridge(SimulatorBridge): preload_models=False ) - return MetaDriveWorld(Queue(), config, self.dual_camera) + return MetaDriveWorld(queue, config, self.dual_camera) diff --git a/tools/sim/bridge/metadrive/metadrive_world.py b/tools/sim/bridge/metadrive/metadrive_world.py index 357020506..35a828868 100644 --- a/tools/sim/bridge/metadrive/metadrive_world.py +++ b/tools/sim/bridge/metadrive/metadrive_world.py @@ -5,6 +5,8 @@ import numpy as np import time from multiprocessing import Pipe, Array + +from openpilot.tools.sim.bridge.common import QueueMessage, QueueMessageType from openpilot.tools.sim.bridge.metadrive.metadrive_process import (metadrive_process, metadrive_simulation_state, metadrive_vehicle_state) from openpilot.tools.sim.lib.common import SimulatorState, World @@ -35,14 +37,14 @@ class MetaDriveWorld(World): self.vehicle_state_send, self.exit_event)) self.metadrive_process.start() - self.status_q.put({"status": "starting"}) + self.status_q.put(QueueMessage(QueueMessageType.START_STATUS, "starting")) print("----------------------------------------------------------") print("---- Spawning Metadrive world, this might take awhile ----") print("----------------------------------------------------------") self.vehicle_state_recv.recv() # wait for a state message to ensure metadrive is launched - self.status_q.put({"status": "started"}) + self.status_q.put(QueueMessage(QueueMessageType.START_STATUS, "started")) self.steer_ratio = 15 self.vc = [0.0,0.0] @@ -68,11 +70,7 @@ class MetaDriveWorld(World): while self.simulation_state_recv.poll(0): md_state: metadrive_simulation_state = self.simulation_state_recv.recv() if md_state.done: - self.status_q.put({ - "status": "terminating", - "reason": "done", - "done_info": md_state.done_info - }) + self.status_q.put(QueueMessage(QueueMessageType.TERMINATION_INFO, md_state.done_info)) self.exit_event.set() def read_sensors(self, state: SimulatorState): @@ -94,9 +92,6 @@ class MetaDriveWorld(World): self.should_reset = True def close(self, reason: str): - self.status_q.put({ - "status": "terminating", - "reason": reason, - }) + self.status_q.put(QueueMessage(QueueMessageType.CLOSE_STATUS, reason)) self.exit_event.set() self.metadrive_process.join() diff --git a/tools/sim/lib/keyboard_ctrl.py b/tools/sim/lib/keyboard_ctrl.py index ea255d9ce..0a17f0ee8 100644 --- a/tools/sim/lib/keyboard_ctrl.py +++ b/tools/sim/lib/keyboard_ctrl.py @@ -2,10 +2,13 @@ import sys import termios import time +from multiprocessing import Queue from termios import (BRKINT, CS8, CSIZE, ECHO, ICANON, ICRNL, IEXTEN, INPCK, ISTRIP, IXON, PARENB, VMIN, VTIME) from typing import NoReturn +from openpilot.tools.sim.bridge.common import QueueMessage, control_cmd_gen + # Indexes for termios list. IFLAG = 0 OFLAG = 1 @@ -52,35 +55,35 @@ def getch() -> str: def print_keyboard_help(): print(f"Keyboard Commands:\n{KEYBOARD_HELP}") -def keyboard_poll_thread(q: 'Queue[str]'): +def keyboard_poll_thread(q: 'Queue[QueueMessage]'): print_keyboard_help() while True: c = getch() if c == '1': - q.put("cruise_up") + q.put(control_cmd_gen("cruise_up")) elif c == '2': - q.put("cruise_down") + q.put(control_cmd_gen("cruise_down")) elif c == '3': - q.put("cruise_cancel") + q.put(control_cmd_gen("cruise_cancel")) elif c == 'w': - q.put("throttle_%f" % 1.0) + q.put(control_cmd_gen(f"throttle_{1.0}")) elif c == 'a': - q.put("steer_%f" % -0.15) + q.put(control_cmd_gen(f"steer_{-0.15}")) elif c == 's': - q.put("brake_%f" % 1.0) + q.put(control_cmd_gen(f"brake_{1.0}")) elif c == 'd': - q.put("steer_%f" % 0.15) + q.put(control_cmd_gen(f"steer_{0.15}")) elif c == 'z': - q.put("blinker_left") + q.put(control_cmd_gen("blinker_left")) elif c == 'x': - q.put("blinker_right") + q.put(control_cmd_gen("blinker_right")) elif c == 'i': - q.put("ignition") + q.put(control_cmd_gen("ignition")) elif c == 'r': - q.put("reset") + q.put(control_cmd_gen("reset")) elif c == 'q': - q.put("quit") + q.put(control_cmd_gen("quit")) break else: print_keyboard_help() @@ -92,7 +95,7 @@ def test(q: 'Queue[str]') -> NoReturn: if __name__ == '__main__': from multiprocessing import Process, Queue - q: Queue[str] = Queue() + q: 'Queue[QueueMessage]' = Queue() p = Process(target=test, args=(q,)) p.daemon = True p.start() diff --git a/tools/sim/lib/manual_ctrl.py b/tools/sim/lib/manual_ctrl.py index 8a7229653..972f7023b 100755 --- a/tools/sim/lib/manual_ctrl.py +++ b/tools/sim/lib/manual_ctrl.py @@ -6,6 +6,8 @@ import struct from fcntl import ioctl from typing import NoReturn +from openpilot.tools.sim.bridge.common import control_cmd_gen + # Iterate over the joystick devices. print('Available devices:') for fn in os.listdir('/dev/input'): @@ -153,33 +155,33 @@ def wheel_poll_thread(q: 'Queue[str]') -> NoReturn: fvalue = value / 32767.0 axis_states[axis] = fvalue normalized = (1 - fvalue) * 50 - q.put(f"throttle_{normalized:f}") + q.put(control_cmd_gen(f"throttle_{normalized:f}")) elif axis == "rz": # brake fvalue = value / 32767.0 axis_states[axis] = fvalue normalized = (1 - fvalue) * 50 - q.put(f"brake_{normalized:f}") + q.put(control_cmd_gen(f"brake_{normalized:f}")) elif axis == "x": # steer angle fvalue = value / 32767.0 axis_states[axis] = fvalue normalized = fvalue - q.put(f"steer_{normalized:f}") + q.put(control_cmd_gen(f"steer_{normalized:f}")) elif mtype & 0x01: # buttons if value == 1: # press down if number in [0, 19]: # X - q.put("cruise_down") + q.put(control_cmd_gen("cruise_down")) elif number in [3, 18]: # triangle - q.put("cruise_up") + q.put(control_cmd_gen("cruise_up")) elif number in [1, 6]: # square - q.put("cruise_cancel") + q.put(control_cmd_gen("cruise_cancel")) elif number in [10, 21]: # R3 - q.put("reverse_switch") + q.put(control_cmd_gen("reverse_switch")) if __name__ == '__main__': from multiprocessing import Process, Queue From 52acae579763a15510b6788b31c22de975d54271 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 20:00:10 -0700 Subject: [PATCH 011/220] remove dead webcam dockerfile --- tools/webcam/Dockerfile | 41 ----------------------------------------- tools/webcam/README.md | 3 --- 2 files changed, 44 deletions(-) delete mode 100644 tools/webcam/Dockerfile diff --git a/tools/webcam/Dockerfile b/tools/webcam/Dockerfile deleted file mode 100644 index 78a25e836..000000000 --- a/tools/webcam/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -FROM ghcr.io/commaai/openpilot-base:latest - -ENV PYTHONUNBUFFERED 1 -ENV PYTHONPATH /tmp/openpilot:${PYTHONPATH} - -# Install opencv -ENV OPENCV_VERSION '4.2.0' -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends \ - libvtk6-dev \ - libdc1394-22-dev \ - libavcodec-dev \ - libavformat-dev \ - libswscale-dev \ - libtheora-dev \ - libvorbis-dev \ - libxvidcore-dev \ - libx264-dev \ - yasm \ - libopencore-amrnb-dev \ - libopencore-amrwb-dev \ - libv4l-dev \ - libxine2-dev \ - libtbb-dev \ - && rm -rf /var/lib/apt/lists/* && \ - - mkdir /tmp/opencv_build && \ - cd /tmp/opencv_build && \ - - curl -L -O https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.tar.gz && \ - tar -xvf ${OPENCV_VERSION}.tar.gz && \ - mv opencv-${OPENCV_VERSION} OpenCV && \ - cd OpenCV && mkdir build && cd build && \ - cmake -DWITH_OPENGL=ON -DFORCE_VTK=ON -DWITH_TBB=ON -DWITH_GDAL=ON \ - -DWITH_XINE=ON -DENABLE_PRECOMPILED_HEADERS=OFF -DBUILD_TESTS=OFF \ - -DBUILD_PERF_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_opencv_apps=OFF .. && \ - make -j8 && \ - make install && \ - ldconfig && \ - - cd / && rm -rf /tmp/* diff --git a/tools/webcam/README.md b/tools/webcam/README.md index 709e8514c..76733b173 100644 --- a/tools/webcam/README.md +++ b/tools/webcam/README.md @@ -14,10 +14,7 @@ cd ~ git clone https://github.com/commaai/openpilot.git ``` - Follow [this readme](https://github.com/commaai/openpilot/tree/master/tools) to install the requirements -- Add line "export PYTHONPATH=$HOME/openpilot" to your ~/.bashrc -- Install tensorflow 2.2 and nvidia drivers: nvidia-xxx/cuda10.0/cudnn7.6.5 - Install [OpenCL Driver](https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532/l_opencl_p_18.1.0.015.tgz) -- Install [OpenCV4](https://www.pyimagesearch.com/2018/08/15/how-to-install-opencv-4-on-ubuntu/) (ignore the Python part) ## Build openpilot for webcam ``` From dd6e2a400b1b9543fad0c3c4a78463abf756da6b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 May 2024 11:18:41 +0800 Subject: [PATCH 012/220] ui: single-threaded CameraView (#32291) single thread cameraview --- selfdrive/ui/qt/offroad/driverview.cc | 13 +- selfdrive/ui/qt/offroad/driverview.h | 2 +- selfdrive/ui/qt/onroad/annotated_camera.cc | 30 +-- selfdrive/ui/qt/onroad/annotated_camera.h | 1 - selfdrive/ui/qt/widgets/cameraview.cc | 213 ++++++++------------- selfdrive/ui/qt/widgets/cameraview.h | 60 +++--- selfdrive/ui/watch3.cc | 8 +- tools/cabana/videowidget.cc | 5 +- tools/cabana/videowidget.h | 4 +- 9 files changed, 138 insertions(+), 198 deletions(-) diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc index df9bb2465..f14d05933 100644 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ b/selfdrive/ui/qt/offroad/driverview.cc @@ -7,7 +7,7 @@ const int FACE_IMG_SIZE = 130; -DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraWidget("camerad", VISION_STREAM_DRIVER, true, parent) { +DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraView("camerad", VISION_STREAM_DRIVER, true, parent) { face_img = loadPixmap("../assets/img_driver_face_static.png", {FACE_IMG_SIZE, FACE_IMG_SIZE}); QObject::connect(this, &CameraWidget::clicked, this, &DriverViewWindow::done); QObject::connect(device(), &Device::interactiveTimeout, this, [this]() { @@ -20,22 +20,20 @@ DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraWidget("camerad", VI void DriverViewWindow::showEvent(QShowEvent* event) { params.putBool("IsDriverViewEnabled", true); device()->resetInteractiveTimeout(60); - CameraWidget::showEvent(event); + CameraView::showEvent(event); } void DriverViewWindow::hideEvent(QHideEvent* event) { params.putBool("IsDriverViewEnabled", false); - stopVipcThread(); - CameraWidget::hideEvent(event); + CameraView::hideEvent(event); } void DriverViewWindow::paintGL() { - CameraWidget::paintGL(); + CameraView::paintGL(); - std::lock_guard lk(frame_lock); QPainter p(this); // startup msg - if (frames.empty()) { + if (recent_frames.empty()) { p.setPen(Qt::white); p.setRenderHint(QPainter::TextAntialiasing); p.setFont(InterFont(100, QFont::Bold)); @@ -47,7 +45,6 @@ void DriverViewWindow::paintGL() { cereal::DriverStateV2::Reader driver_state = sm["driverStateV2"].getDriverStateV2(); bool is_rhd = driver_state.getWheelOnRightProb() > 0.5; auto driver_data = is_rhd ? driver_state.getRightDriverData() : driver_state.getLeftDriverData(); - bool face_detected = driver_data.getFaceProb() > 0.7; if (face_detected) { auto fxy_list = driver_data.getFacePosition(); diff --git a/selfdrive/ui/qt/offroad/driverview.h b/selfdrive/ui/qt/offroad/driverview.h index 155e4ede3..97dd2faa7 100644 --- a/selfdrive/ui/qt/offroad/driverview.h +++ b/selfdrive/ui/qt/offroad/driverview.h @@ -2,7 +2,7 @@ #include "selfdrive/ui/qt/widgets/cameraview.h" -class DriverViewWindow : public CameraWidget { +class DriverViewWindow : public CameraView { Q_OBJECT public: diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index f7fb6b480..637d72758 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -6,11 +6,11 @@ #include #include "common/swaglog.h" -#include "selfdrive/ui/qt/onroad/buttons.h" #include "selfdrive/ui/qt/util.h" // Window that shows camera view and variety of info drawn on top -AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { +AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget *parent) + : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { pm = std::make_unique>({"uiDebug"}); main_layout = new QVBoxLayout(this); @@ -76,6 +76,8 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { map_settings_btn->setVisible(!hideBottomIcons); main_layout->setAlignment(map_settings_btn, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignBottom); } + + update(); } void AnnotatedCameraWidget::drawHud(QPainter &p) { @@ -353,25 +355,8 @@ void AnnotatedCameraWidget::paintGL() { UIState *s = uiState(); SubMaster &sm = *(s->sm); const double start_draw_t = millis_since_boot(); - const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); - // draw camera frame { - std::lock_guard lk(frame_lock); - - if (frames.empty()) { - if (skip_frame_count > 0) { - skip_frame_count--; - qDebug() << "skipping frame, not ready"; - return; - } - } else { - // skip drawing up to this many frames if we're - // missing camera frames. this smooths out the - // transitions from the narrow and wide cameras - skip_frame_count = 5; - } - // Wide or narrow cam dependent on speed bool has_wide_cam = available_streams.count(VISION_STREAM_WIDE_ROAD); if (has_wide_cam) { @@ -387,14 +372,16 @@ void AnnotatedCameraWidget::paintGL() { } CameraWidget::setStreamType(wide_cam_requested ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); - s->scene.wide_cam = CameraWidget::getStreamType() == VISION_STREAM_WIDE_ROAD; + s->scene.wide_cam = CameraWidget::streamType() == VISION_STREAM_WIDE_ROAD; if (s->scene.calibration_valid) { auto calib = s->scene.wide_cam ? s->scene.view_from_wide_calib : s->scene.view_from_calib; CameraWidget::updateCalibration(calib); } else { CameraWidget::updateCalibration(DEFAULT_CALIBRATION); } - CameraWidget::setFrameId(model.getFrameId()); + + // Draw the frame based on the UI plan's frame ID + CameraWidget::setFrameId(sm["uiPlan"].getUiPlan().getFrameId()); CameraWidget::paintGL(); } @@ -403,6 +390,7 @@ void AnnotatedCameraWidget::paintGL() { painter.setPen(Qt::NoPen); if (s->scene.world_objects_visible) { + const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); update_model(s, model, sm["uiPlan"].getUiPlan()); drawLaneLines(painter, s); diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h index 0be4adfff..b25846001 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/qt/onroad/annotated_camera.h @@ -37,7 +37,6 @@ private: int status = STATUS_DISENGAGED; std::unique_ptr pm; - int skip_frame_count = 0; bool wide_cam_requested = false; protected: diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index e4f139626..a7d4432de 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -97,37 +97,22 @@ mat4 get_fit_view_transform(float widget_aspect_ratio, float frame_aspect_ratio) } // namespace -CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) : - stream_name(stream_name), active_stream_type(type), requested_stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { - setAttribute(Qt::WA_OpaquePaintEvent); - qRegisterMetaType>("availableStreams"); - QObject::connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); - QObject::connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived, Qt::QueuedConnection); - QObject::connect(this, &CameraWidget::vipcAvailableStreamsUpdated, this, &CameraWidget::availableStreamsUpdated, Qt::QueuedConnection); +CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget *parent) + : stream_name(stream_name), stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { } CameraWidget::~CameraWidget() { makeCurrent(); - stopVipcThread(); if (isValid()) { glDeleteVertexArrays(1, &frame_vao); glDeleteBuffers(1, &frame_vbo); glDeleteBuffers(1, &frame_ibo); glDeleteBuffers(2, textures); } + clearEGLImages(); doneCurrent(); } -// Qt uses device-independent pixels, depending on platform this may be -// different to what OpenGL uses -int CameraWidget::glWidth() { - return width() * devicePixelRatio(); -} - -int CameraWidget::glHeight() { - return height() * devicePixelRatio(); -} - void CameraWidget::initializeGL() { initializeOpenGLFunctions(); @@ -141,7 +126,7 @@ void CameraWidget::initializeGL() { GLint frame_pos_loc = program->attributeLocation("aPosition"); GLint frame_texcoord_loc = program->attributeLocation("aTexCoord"); - auto [x1, x2, y1, y2] = requested_stream_type == VISION_STREAM_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); + auto [x1, x2, y1, y2] = stream_type == VISION_STREAM_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; const float frame_coords[4][4] = { {-1.0, -1.0, x2, y1}, // bl @@ -178,45 +163,11 @@ void CameraWidget::initializeGL() { #endif } -void CameraWidget::showEvent(QShowEvent *event) { - if (!vipc_thread) { - clearFrames(); - vipc_thread = new QThread(); - connect(vipc_thread, &QThread::started, [=]() { vipcThread(); }); - connect(vipc_thread, &QThread::finished, vipc_thread, &QObject::deleteLater); - vipc_thread->start(); - } -} - -void CameraWidget::stopVipcThread() { - makeCurrent(); - if (vipc_thread) { - vipc_thread->requestInterruption(); - vipc_thread->quit(); - vipc_thread->wait(); - vipc_thread = nullptr; - } - -#ifdef QCOM2 - EGLDisplay egl_display = eglGetCurrentDisplay(); - assert(egl_display != EGL_NO_DISPLAY); - for (auto &pair : egl_images) { - eglDestroyImageKHR(egl_display, pair.second); - assert(eglGetError() == EGL_SUCCESS); - } - egl_images.clear(); -#endif -} - -void CameraWidget::availableStreamsUpdated(std::set streams) { - available_streams = streams; -} - void CameraWidget::updateFrameMat() { int w = glWidth(), h = glHeight(); if (zoomed_view) { - if (active_stream_type == VISION_STREAM_DRIVER) { + if (streamType() == VISION_STREAM_DRIVER) { if (stream_width > 0 && stream_height > 0) { frame_mat = get_driver_view_transform(w, h, stream_width, stream_height); } @@ -225,7 +176,7 @@ void CameraWidget::updateFrameMat() { // to ensure this ends up in the middle of the screen // for narrow come and a little lower for wide cam. // TODO: use proper perspective transform? - if (active_stream_type == VISION_STREAM_WIDE_ROAD) { + if (streamType() == VISION_STREAM_WIDE_ROAD) { intrinsic_matrix = ECAM_INTRINSIC_MATRIX; zoom = 2.0; } else { @@ -247,13 +198,12 @@ void CameraWidget::updateFrameMat() { float zx = zoom * 2 * intrinsic_matrix.v[2] / w; float zy = zoom * 2 * intrinsic_matrix.v[5] / h; - const mat4 frame_transform = {{ + frame_mat = {{ zx, 0.0, 0.0, -x_offset / w * 2, 0.0, zy, 0.0, y_offset / h * 2, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }}; - frame_mat = frame_transform; } } else if (stream_width > 0 && stream_height > 0) { // fit frame to widget size @@ -271,25 +221,15 @@ void CameraWidget::paintGL() { glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - std::lock_guard lk(frame_lock); - if (frames.empty()) return; - - int frame_idx = frames.size() - 1; - - // Always draw latest frame until sync logic is more stable - // for (frame_idx = 0; frame_idx < frames.size() - 1; frame_idx++) { - // if (frames[frame_idx].first == draw_frame_id) break; - // } + VisionBuf *frame = receiveFrame(draw_frame_id); + if (!frame) return; // Log duplicate/dropped frames - if (frames[frame_idx].first == prev_frame_id) { - qDebug() << "Drawing same frame twice" << frames[frame_idx].first; - } else if (frames[frame_idx].first != prev_frame_id + 1) { - qDebug() << "Skipped frame" << frames[frame_idx].first; + uint32_t frame_id = frame->get_frame_id(); + if (prev_frame_id != INVALID_FRAME_ID && frame_id != prev_frame_id + 1) { + qDebug() << (frame_id == prev_frame_id ? "Drawing same frame twice" : "Skip frame") << frame_id; } - prev_frame_id = frames[frame_idx].first; - VisionBuf *frame = frames[frame_idx].second; - assert(frame != nullptr); + prev_frame_id = frame_id; updateFrameMat(); @@ -329,20 +269,14 @@ void CameraWidget::paintGL() { glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } -void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { - makeCurrent(); +void CameraWidget::vipcConnected() { stream_width = vipc_client->buffers[0].width; stream_height = vipc_client->buffers[0].height; stream_stride = vipc_client->buffers[0].stride; #ifdef QCOM2 + clearEGLImages(); EGLDisplay egl_display = eglGetCurrentDisplay(); - assert(egl_display != EGL_NO_DISPLAY); - for (auto &pair : egl_images) { - eglDestroyImageKHR(egl_display, pair.second); - } - egl_images.clear(); - for (int i = 0; i < vipc_client->num_buffers; i++) { // import buffers into OpenGL int fd = dup(vipc_client->buffers[i].fd); // eglDestroyImageKHR will close, so duplicate EGLint img_attrs[] = { @@ -379,59 +313,78 @@ void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { #endif } -void CameraWidget::vipcFrameReceived() { - update(); -} +VisionBuf *CameraWidget::receiveFrame(uint64_t request_frame_id) { + if (!ensureConnection()) { + return nullptr; + } -void CameraWidget::vipcThread() { - VisionStreamType cur_stream = requested_stream_type; - std::unique_ptr vipc_client; - VisionIpcBufExtra meta_main = {0}; - - while (!QThread::currentThread()->isInterruptionRequested()) { - if (!vipc_client || cur_stream != requested_stream_type) { - clearFrames(); - qDebug().nospace() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; - cur_stream = requested_stream_type; - vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); - } - active_stream_type = cur_stream; - - if (!vipc_client->connected) { - clearFrames(); - auto streams = VisionIpcClient::getAvailableStreams(stream_name, false); - if (streams.empty()) { - QThread::msleep(100); - continue; - } - emit vipcAvailableStreamsUpdated(streams); - - if (!vipc_client->connect(false)) { - QThread::msleep(100); - continue; - } - emit vipcThreadConnected(vipc_client.get()); - } - - if (VisionBuf *buf = vipc_client->recv(&meta_main, 1000)) { - { - std::lock_guard lk(frame_lock); - frames.push_back(std::make_pair(meta_main.frame_id, buf)); - while (frames.size() > FRAME_BUFFER_SIZE) { - frames.pop_front(); - } - } - emit vipcThreadFrameReceived(); - } else { - if (!isVisible()) { - vipc_client->connected = false; - } + // Receive frames and store them in recent_frames + while (auto buf = vipc_client->recv(nullptr, 0)) { + recent_frames.emplace_back(buf); + if (recent_frames.size() > FRAME_BUFFER_SIZE) { + recent_frames.pop_front(); } } + if (!vipc_client->connected || recent_frames.empty()) { + return nullptr; + } + + // Find the requested frame + auto it = std::find_if(recent_frames.rbegin(), recent_frames.rend(), + [request_frame_id](VisionBuf *buf) { return buf->get_frame_id() == request_frame_id; }); + return it != recent_frames.rend() ? *it : recent_frames.back(); +} + +bool CameraWidget::ensureConnection() { + // Reconnect if the client is not initialized or the stream type has changed + if (!vipc_client || vipc_client->type != stream_type) { + qDebug() << "connecting to stream" << stream_type; + vipc_client.reset(new VisionIpcClient(stream_name, stream_type, false)); + } + + // Re-establish connection if not connected + if (!vipc_client->connected) { + clearFrames(); + available_streams = VisionIpcClient::getAvailableStreams(stream_name, false); + if (available_streams.empty() || !vipc_client->connect(false)) { + return false; + } + emit vipcAvailableStreamsUpdated(); + vipcConnected(); + } + return true; } void CameraWidget::clearFrames() { - std::lock_guard lk(frame_lock); - frames.clear(); - available_streams.clear(); + recent_frames.clear(); + draw_frame_id = INVALID_FRAME_ID; + prev_frame_id = INVALID_FRAME_ID; +} + +void CameraWidget::clearEGLImages() { +#ifdef QCOM2 + EGLDisplay egl_display = eglGetCurrentDisplay(); + assert(egl_display != EGL_NO_DISPLAY); + for (auto &pair : egl_images) { + eglDestroyImageKHR(egl_display, pair.second); + } + egl_images.clear(); +#endif +} + +// Cameraview + +CameraView::CameraView(const std::string &name, VisionStreamType stream_type, bool zoom, QWidget *parent) + : CameraWidget(name, stream_type, zoom, parent) { + timer = new QTimer(this); + timer->setInterval(1000.0 / UI_FREQ); + timer->callOnTimeout(this, [this]() { update(); }); +} + +void CameraView::showEvent(QShowEvent *event) { + timer->start(); +} + +void CameraView::hideEvent(QHideEvent *event) { + timer->stop(); } diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index c97038cf4..fb31d094b 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -11,7 +10,7 @@ #include #include #include -#include +#include #ifdef QCOM2 #define EGL_EGLEXT_PROTOTYPES @@ -27,40 +26,40 @@ #include "selfdrive/ui/ui.h" const int FRAME_BUFFER_SIZE = 5; +const uint32_t INVALID_FRAME_ID = -1; static_assert(FRAME_BUFFER_SIZE <= YUV_BUFFER_COUNT); class CameraWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: - using QOpenGLWidget::QOpenGLWidget; explicit CameraWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr); ~CameraWidget(); void setBackgroundColor(const QColor &color) { bg = color; } void setFrameId(int frame_id) { draw_frame_id = frame_id; } - void setStreamType(VisionStreamType type) { requested_stream_type = type; } - VisionStreamType getStreamType() { return active_stream_type; } - void stopVipcThread(); + void setStreamType(VisionStreamType type) { stream_type = type; } + inline VisionStreamType streamType() const { return stream_type; } + inline const std::set &availableStreams() const { return available_streams; } + VisionBuf *receiveFrame(uint64_t request_frame_id = INVALID_FRAME_ID); signals: + void vipcAvailableStreamsUpdated(); void clicked(); - void vipcThreadConnected(VisionIpcClient *); - void vipcThreadFrameReceived(); - void vipcAvailableStreamsUpdated(std::set); protected: + bool ensureConnection(); void paintGL() override; void initializeGL() override; + void vipcConnected(); + void clearFrames(); + void clearEGLImages(); + void resizeGL(int w, int h) override { updateFrameMat(); } - void showEvent(QShowEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override { emit clicked(); } virtual void updateFrameMat(); void updateCalibration(const mat3 &calib); - void vipcThread(); - void clearFrames(); - - int glWidth(); - int glHeight(); + int glWidth() const { return width() * devicePixelRatio(); } + int glHeight() const { return height() * devicePixelRatio(); } bool zoomed_view; GLuint frame_vao, frame_vbo, frame_ibo; @@ -77,10 +76,7 @@ protected: int stream_width = 0; int stream_height = 0; int stream_stride = 0; - std::atomic active_stream_type; - std::atomic requested_stream_type; - std::set available_streams; - QThread *vipc_thread = nullptr; + VisionStreamType stream_type; // Calibration float x_offset = 0; @@ -89,15 +85,21 @@ protected: mat3 calibration = DEFAULT_CALIBRATION; mat3 intrinsic_matrix = FCAM_INTRINSIC_MATRIX; - std::recursive_mutex frame_lock; - std::deque> frames; - uint32_t draw_frame_id = 0; - uint32_t prev_frame_id = 0; - -protected slots: - void vipcConnected(VisionIpcClient *vipc_client); - void vipcFrameReceived(); - void availableStreamsUpdated(std::set streams); + std::set available_streams; + std::unique_ptr vipc_client; + std::deque recent_frames; + uint32_t draw_frame_id = INVALID_FRAME_ID; + uint32_t prev_frame_id = INVALID_FRAME_ID; }; -Q_DECLARE_METATYPE(std::set); +// update frames based on timer +class CameraView : public CameraWidget { + Q_OBJECT +public: + CameraView(const std::string &name, VisionStreamType stream_type, bool zoom, QWidget *parent = nullptr); + void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; + +private: + QTimer *timer; +}; diff --git a/selfdrive/ui/watch3.cc b/selfdrive/ui/watch3.cc index ec35c29b6..cb12f82ea 100644 --- a/selfdrive/ui/watch3.cc +++ b/selfdrive/ui/watch3.cc @@ -19,15 +19,15 @@ int main(int argc, char *argv[]) { { QHBoxLayout *hlayout = new QHBoxLayout(); layout->addLayout(hlayout); - hlayout->addWidget(new CameraWidget("navd", VISION_STREAM_MAP, false)); - hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_ROAD, false)); + hlayout->addWidget(new CameraView("navd", VISION_STREAM_MAP, false)); + hlayout->addWidget(new CameraView("camerad", VISION_STREAM_ROAD, false)); } { QHBoxLayout *hlayout = new QHBoxLayout(); layout->addLayout(hlayout); - hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_DRIVER, false)); - hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_WIDE_ROAD, false)); + hlayout->addWidget(new CameraView("camerad", VISION_STREAM_DRIVER, false)); + hlayout->addWidget(new CameraView("camerad", VISION_STREAM_WIDE_ROAD, false)); } return a.exec(); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index cd412f727..8ce812282 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -139,7 +139,7 @@ QWidget *VideoWidget::createCameraWidget() { QStackedLayout *stacked = new QStackedLayout(); stacked->setStackingMode(QStackedLayout::StackAll); - stacked->addWidget(cam_widget = new CameraWidget("camerad", VISION_STREAM_ROAD, false)); + stacked->addWidget(cam_widget = new CameraView("camerad", VISION_STREAM_ROAD, false)); cam_widget->setMinimumHeight(MIN_VIDEO_HEIGHT); cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); stacked->addWidget(alert_label = new InfoLabel(this)); @@ -161,12 +161,13 @@ QWidget *VideoWidget::createCameraWidget() { return w; } -void VideoWidget::vipcAvailableStreamsUpdated(std::set streams) { +void VideoWidget::vipcAvailableStreamsUpdated() { static const QString stream_names[] = { [VISION_STREAM_ROAD] = "Road camera", [VISION_STREAM_WIDE_ROAD] = "Wide road camera", [VISION_STREAM_DRIVER] = "Driver camera"}; + const auto &streams = cam_widget->availableStreams(); for (int i = 0; i < streams.size(); ++i) { if (camera_tab->count() <= i) { camera_tab->addTab(QString()); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index b2039e09a..ae095fd55 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -73,9 +73,9 @@ protected: QWidget *createCameraWidget(); QHBoxLayout *createPlaybackController(); void loopPlaybackClicked(); - void vipcAvailableStreamsUpdated(std::set streams); + void vipcAvailableStreamsUpdated(); - CameraWidget *cam_widget; + CameraView *cam_widget; double maximum_time = 0; QToolButton *time_btn = nullptr; ToolButton *seek_backward_btn = nullptr; From 861c52e01579f4ce86a2f19f2014afa2af1ae501 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 20:53:52 -0700 Subject: [PATCH 013/220] bump up cars timeout for the GHA runners --- .github/workflows/selfdrive_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index e8c776642..d3c8009bc 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -249,7 +249,7 @@ jobs: - name: Build openpilot run: ${{ env.RUN }} "scons -j$(nproc)" - name: Test car models - timeout-minutes: 10 + timeout-minutes: 20 run: | ${{ env.RUN }} "$PYTEST selfdrive/car/tests/test_models.py && \ chmod -R 777 /tmp/comma_download_cache" From 173d96644436c9c4e36b3adbc38acf03811dc4a5 Mon Sep 17 00:00:00 2001 From: cl0cks4fe <108313040+cl0cks4fe@users.noreply.github.com> Date: Fri, 17 May 2024 20:54:08 -0700 Subject: [PATCH 014/220] remove unittest dependency from test_ui (#32432) --- selfdrive/ui/tests/test_ui/run.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/selfdrive/ui/tests/test_ui/run.py b/selfdrive/ui/tests/test_ui/run.py index 79f30e79b..871333563 100644 --- a/selfdrive/ui/tests/test_ui/run.py +++ b/selfdrive/ui/tests/test_ui/run.py @@ -8,9 +8,7 @@ import numpy as np import os import pywinctl import time -import unittest # noqa: TID251 -from parameterized import parameterized from cereal import messaging, car, log from cereal.visionipc import VisionIpcServer, VisionStreamType @@ -122,16 +120,11 @@ TEST_OUTPUT_DIR = TEST_DIR / "report" SCREENSHOTS_DIR = TEST_OUTPUT_DIR / "screenshots" -class TestUI(unittest.TestCase): - @classmethod - def setUpClass(cls): +class TestUI: + def __init__(self): os.environ["SCALE"] = "1" sys.modules["mouseinfo"] = False - @classmethod - def tearDownClass(cls): - del sys.modules["mouseinfo"] - def setup(self): self.sm = SubMaster(["uiDebug"]) self.pm = PubMaster(["deviceState", "pandaStates", "controlsState", 'roadCameraState', 'wideRoadCameraState', 'liveLocationKalman']) @@ -147,8 +140,8 @@ class TestUI(unittest.TestCase): def screenshot(self): import pyautogui im = pyautogui.screenshot(region=(self.ui.left, self.ui.top, self.ui.width, self.ui.height)) - self.assertEqual(im.width, 2160) - self.assertEqual(im.height, 1080) + assert im.width == 2160 + assert im.height == 1080 img = np.array(im) im.close() return img @@ -158,7 +151,6 @@ class TestUI(unittest.TestCase): pyautogui.click(self.ui.left + x, self.ui.top + y, *args, **kwargs) time.sleep(UI_DELAY) # give enough time for the UI to react - @parameterized.expand(CASES.items()) @with_processes(["ui"]) def test_ui(self, name, setup_case): self.setup() @@ -188,7 +180,10 @@ def create_screenshots(): shutil.rmtree(TEST_OUTPUT_DIR) SCREENSHOTS_DIR.mkdir(parents=True) - unittest.main(exit=False) + + t = TestUI() + for name, setup in CASES.items(): + t.test_ui(name, setup) if __name__ == "__main__": print("creating test screenshots") From 3e023146d24364daf0a40311b3fe366e7bcd36cd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 21:06:18 -0700 Subject: [PATCH 015/220] remove gcc from mac_setup.sh --- tools/mac_setup.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index 9ec2097ea..d26ec3cfe 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -63,7 +63,6 @@ brew "pyenv" brew "pyenv-virtualenv" brew "qt@5" brew "zeromq" -brew "gcc@13" cask "gcc-arm-embedded" brew "portaudio" EOS From 8e87655a128f6b2ebcc6fdcf639167d647c99fe0 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Fri, 17 May 2024 21:38:03 -0700 Subject: [PATCH 016/220] dmonitoringd: don't check for buttonEvents or vCruise change (#32454) * drop check for carState.buttonEvents * 100% people not use this * huge oof * ref comit --------- Co-authored-by: Shane Smiskol --- selfdrive/monitoring/dmonitoringd.py | 9 ++------- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/selfdrive/monitoring/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py index c18bbf29b..91a493258 100755 --- a/selfdrive/monitoring/dmonitoringd.py +++ b/selfdrive/monitoring/dmonitoringd.py @@ -19,7 +19,6 @@ def dmonitoringd_thread(): driver_status = DriverStatus(rhd_saved=params.get_bool("IsRhdDetected"), always_on=params.get_bool("AlwaysOnDM")) - v_cruise_last = 0 driver_engaged = False # 20Hz <- dmonitoringmodeld @@ -30,12 +29,8 @@ def dmonitoringd_thread(): # Get interaction if sm.updated['carState']: - v_cruise = sm['carState'].cruiseState.speed - driver_engaged = len(sm['carState'].buttonEvents) > 0 or \ - v_cruise != v_cruise_last or \ - sm['carState'].steeringPressed or \ - sm['carState'].gasPressed - v_cruise_last = v_cruise + driver_engaged = sm['carState'].steeringPressed or \ + sm['carState'].gasPressed if sm.updated['modelV2']: driver_status.set_policy(sm['modelV2'], sm['carState'].vEgo) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a61fd8e23..3fc6acc3c 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -e5a385503e4307ae77c73736a602380b08e61334 +f1ecdf9048fb12e289baf4933cb3ef12e486252c From 985b22d4b77c20a81a6329fe8cf810103f871aa6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 May 2024 21:43:57 -0700 Subject: [PATCH 017/220] add [project] section to pyproject.toml --- pyproject.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a4e31145d..eb2701760 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,12 @@ +[project] +name = "openpilot" +requires-python = ">= 3.11" +readme = "README.md" +license = {text = "MIT License"} + +[project.urls] +Homepage = "https://comma.ai" + [tool.pytest.ini_options] minversion = "6.0" addopts = "--ignore=openpilot/ --ignore=cereal/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=teleoprtc_repo/ -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" From 1a4e022d70610acbd74602f80d76876d94a4fdaa Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 18 May 2024 16:03:50 -0500 Subject: [PATCH 018/220] [bot] Fingerprints: add missing FW versions from new users (#32468) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 1 + selfdrive/car/hyundai/fingerprints.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 0dafbbaa6..95565ebf9 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -425,6 +425,7 @@ FW_VERSIONS = { b'68631938AA', b'68631939AA', b'68631940AA', + b'68631940AB', b'68631942AA', b'68631943AB', ], diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index b6318eb8f..e0680ba82 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -1002,8 +1002,8 @@ FW_VERSIONS = { }, CAR.HYUNDAI_TUCSON_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ - b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.01 99211-N9100 14A', b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N9260 14Y', + b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.01 99211-N9100 14A', b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9220 14K', b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 2.02 99211-N9000 14E', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9210 14G', From 950aeae5443123e59177444d06a7654a41504373 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Sat, 18 May 2024 17:04:22 -0400 Subject: [PATCH 019/220] CI: fix metadrive test (#32457) * fix test * this? * fix * this? * deprecation warning inside * comment --- .github/workflows/tools_tests.yaml | 2 +- tools/sim/tests/test_metadrive_bridge.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index ccd3368cb..f33f8b775 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -76,7 +76,7 @@ jobs: ${{ env.RUN }} "export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' && \ source selfdrive/test/setup_xvfb.sh && \ source selfdrive/test/setup_vsound.sh && \ - CI=1 tools/sim/tests/test_metadrive_bridge.py" + CI=1 pytest tools/sim/tests/test_metadrive_bridge.py -W ignore::pyopencl.CompilerWarning" devcontainer: name: devcontainer diff --git a/tools/sim/tests/test_metadrive_bridge.py b/tools/sim/tests/test_metadrive_bridge.py index 28fa462a1..b53f4524a 100755 --- a/tools/sim/tests/test_metadrive_bridge.py +++ b/tools/sim/tests/test_metadrive_bridge.py @@ -1,5 +1,8 @@ #!/usr/bin/env python3 import pytest +import warnings +# Since metadrive depends on pkg_resources, and pkg_resources is deprecated as an API +warnings.filterwarnings("ignore", category=DeprecationWarning) from openpilot.tools.sim.bridge.metadrive.metadrive_bridge import MetaDriveBridge from openpilot.tools.sim.tests.test_sim_bridge import TestSimBridgeBase From 48e24321e814b4b8a805276a0adb3ea2ca19d2f8 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 18 May 2024 14:29:49 -0700 Subject: [PATCH 020/220] remove libopencv-dev (#32469) --- tools/install_ubuntu_dependencies.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 70a7ff2ea..72402b3bf 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -51,7 +51,6 @@ function install_ubuntu_common_requirements() { libncurses5-dev \ libncursesw5-dev \ libomp-dev \ - libopencv-dev \ libpng16-16 \ libportaudio2 \ libssl-dev \ From 1e08132cdf0e1b6182ac935295fafcea83bfbfbd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 18 May 2024 14:51:49 -0700 Subject: [PATCH 021/220] gc unused python deps --- poetry.lock | 230 +++++++++++++++++-------------------------------- pyproject.toml | 3 - 2 files changed, 79 insertions(+), 154 deletions(-) diff --git a/poetry.lock b/poetry.lock index f1f8d9f51..6a3f66be4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "aiohttp" @@ -733,27 +733,6 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pill test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] -[[package]] -name = "control" -version = "0.10.0" -description = "Python Control Systems Library" -optional = false -python-versions = ">=3.10" -files = [ - {file = "control-0.10.0-py3-none-any.whl", hash = "sha256:ed1e0eb73f1e2945fc9af9d7b9121ef328fe980e7903b2a14b149d4f1855a808"}, - {file = "control-0.10.0.tar.gz", hash = "sha256:2c18b767537f45c7fd07b2e4afe8fbe5964019499b5f52f888edb5d8560bab53"}, -] - -[package.dependencies] -matplotlib = ">=3.6" -numpy = ">=1.23" -scipy = ">=1.8" - -[package.extras] -cvxopt = ["cvxopt (>=1.2.0)"] -slycot = ["slycot (>=0.4.0)"] -test = ["pytest", "pytest-timeout"] - [[package]] name = "coverage" version = "7.5.1" @@ -1301,50 +1280,6 @@ files = [ {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, ] -[[package]] -name = "ft4222" -version = "1.10.0" -description = "Python wrapper around libFT4222." -optional = false -python-versions = "*" -files = [ - {file = "ft4222-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dd003a91ecaf20bc4d4ce8f0aea4a5ecfbc17a3840d41b0ce27410e027530cd0"}, - {file = "ft4222-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1cedabcd6c554e78f3479350153c5a347355ccc977ceeb24726edc37d3e7edb7"}, - {file = "ft4222-1.10.0-cp310-cp310-win32.whl", hash = "sha256:a039d4230926fa9b600baa12903843c53d6b238eb93e99ae68eeeb450d6f4bdc"}, - {file = "ft4222-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:b05e499fd3f1baef225671f3afd25bf93e1f287fa17326c90c1f8db70abb3e89"}, - {file = "ft4222-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df9da4d5575d51511ba58e73ee434061dc709ce69491656ec109d995ce304167"}, - {file = "ft4222-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20f2cb89e63ea755d69a4d41c2dcba94d2f720b6e736ea51bdf681f1e809763c"}, - {file = "ft4222-1.10.0-cp311-cp311-win32.whl", hash = "sha256:806d4117d0814c390c7f280345aa99168ec989ca49b20259ce593ea79bcd246f"}, - {file = "ft4222-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:ad626507e9b1520f2f3b6f98ddca0d257c93b844824a1ab7cbb58759b0fbca84"}, - {file = "ft4222-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ecaae4e5ec3bedcdbe04a5792bf08119040669cf58c02df947395e6a96bd18c"}, - {file = "ft4222-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c8c2655fe7192eb80ef25ab750123139f591e0f079fe2a5e6f31b7cd6f015a9f"}, - {file = "ft4222-1.10.0-cp312-cp312-win32.whl", hash = "sha256:fe668caa43bcacfbf3287cff8b4b11bb586a71d4722307e574f60180bb4a351e"}, - {file = "ft4222-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:4d7a49febc2b96ebed4b843262ab1f00843d158d6f4877c8ee19219f1c41f0da"}, - {file = "ft4222-1.10.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18a6f99e31c767b6ccb7e2f0e7f6cc51d15c9b685e2b81fd12ab08cac0924289"}, - {file = "ft4222-1.10.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83efcb50649a7ab4c7e045467357029f16ef0be064d46ffe7ea1e06eb9ad85f8"}, - {file = "ft4222-1.10.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e051c89cb45f964640e355506efa74b41c424e9ea9046367534180075be0a95c"}, - {file = "ft4222-1.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9cae991a917602635238c144395bb59a516b7684b6599da251a88cfe37a5ed8f"}, - {file = "ft4222-1.10.0-cp37-cp37m-win32.whl", hash = "sha256:713ed85fbb8f11755ae7ed932302192a34d2aa8834ffa45a7c345d3a5ba8f67b"}, - {file = "ft4222-1.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:6f2458e6c62d251b6219cfa0fbcfb9ccfa22854c5d7463b862f11b268019ec66"}, - {file = "ft4222-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db4b489cd434b92748e45695c1313716db4e00bdda4f70b6bcf99cdc042a34d8"}, - {file = "ft4222-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b0bd0632063b0e4bb2852ccde3fb95252ea7f0a0bfd3e4c3ee677f4ec63c2520"}, - {file = "ft4222-1.10.0-cp38-cp38-win32.whl", hash = "sha256:057c88eaa2db14a05163b90a7ba2938c0aa6e3870fec31c70051fb791cfbbc22"}, - {file = "ft4222-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:648a739bb5c0ca53b5cb0698e0ebb54ddaea090878a02cbe9039b3d80cf818ba"}, - {file = "ft4222-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88170a0aaa321ae8c974a664b2316fab00f86dd8249ff5927ea4d58a2ed7fa23"}, - {file = "ft4222-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:69fa55d8b5bc7da5a20254d480d4764dbcaa1ca74cd2d10bbc0ce39d39891f2a"}, - {file = "ft4222-1.10.0-cp39-cp39-win32.whl", hash = "sha256:9eb40e86fd43ab8d12b33d092369419e275292a6d57f1ef7de30e63cd8dc9bd5"}, - {file = "ft4222-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:875478f2c8c0fa128037c389969375ede546dde8cf7a5ae796421832aa6dd634"}, - {file = "ft4222-1.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:834b9e549d66f3cc0bbe75983b32e756258523b70363bb67970a7be21c9e3d8f"}, - {file = "ft4222-1.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7af52e4d61e2bcaa10b802e6f1af29823da12a27f520c799823490e6fd9ebb19"}, - {file = "ft4222-1.10.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca8c5aff74e213d8b658e7cdd8df3012e55023a2d379b5074628f6bb8947359a"}, - {file = "ft4222-1.10.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:755a70ab2c5d3fd94030e51fd82c332bc2463c6c455adf093d12e2f3803ea207"}, - {file = "ft4222-1.10.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:035ea7fc9ad627b44be57c31e87bc8d445ebd7cf6ac991d750fedc999683d64e"}, - {file = "ft4222-1.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2df65d174200c1451f5646a109e683aada9d7a076bf5f7ce682145d10725445a"}, - {file = "ft4222-1.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99ef3c412017a85ef9f90d8fc884ba66dae71e85433c8890da6aec38eb0288ab"}, - {file = "ft4222-1.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d00b36bdac3960c377f3a625fc352eca20e36825ddff178feaae97c2d9a8846c"}, - {file = "ft4222-1.10.0.tar.gz", hash = "sha256:74eab32dfc5c012d11952c8645b72157f8828685972669ef3c22025491d96001"}, -] - [[package]] name = "future-fstrings" version = "1.2.0" @@ -2033,9 +1968,13 @@ files = [ {file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"}, {file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"}, {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"}, {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"}, {file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"}, {file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"}, @@ -2201,39 +2140,40 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.4" +version = "3.9.0" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014"}, - {file = "matplotlib-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106"}, - {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10"}, - {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0"}, - {file = "matplotlib-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef"}, - {file = "matplotlib-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338"}, - {file = "matplotlib-3.8.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661"}, - {file = "matplotlib-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c"}, - {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa"}, - {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71"}, - {file = "matplotlib-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b"}, - {file = "matplotlib-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae"}, - {file = "matplotlib-3.8.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616"}, - {file = "matplotlib-3.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732"}, - {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb"}, - {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30"}, - {file = "matplotlib-3.8.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25"}, - {file = "matplotlib-3.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a"}, - {file = "matplotlib-3.8.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6"}, - {file = "matplotlib-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67"}, - {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc"}, - {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9"}, - {file = "matplotlib-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54"}, - {file = "matplotlib-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"}, - {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"}, + {file = "matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56"}, + {file = "matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b"}, + {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241"}, + {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d"}, + {file = "matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4"}, + {file = "matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463"}, + {file = "matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38"}, + {file = "matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152"}, + {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85"}, + {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb"}, + {file = "matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674"}, + {file = "matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be"}, + {file = "matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382"}, + {file = "matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84"}, + {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5"}, + {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db"}, + {file = "matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7"}, + {file = "matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf"}, + {file = "matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956"}, + {file = "matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a"}, + {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321"}, + {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89"}, + {file = "matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b"}, + {file = "matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e"}, + {file = "matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a"}, ] [package.dependencies] @@ -2241,12 +2181,15 @@ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" kiwisolver = ">=1.3.1" -numpy = ">=1.21" +numpy = ">=1.23" packaging = ">=20.0" pillow = ">=8" pyparsing = ">=2.3.1" python-dateutil = ">=2.7" +[package.extras] +dev = ["meson-python (>=0.13.1)", "numpy (>=1.25)", "pybind11 (>=2.6)", "setuptools (>=64)", "setuptools_scm (>=7)"] + [[package]] name = "mdit-py-plugins" version = "0.4.1" @@ -2699,36 +2642,36 @@ reference = ["Pillow", "google-re2"] [[package]] name = "onnxruntime" -version = "1.17.3" +version = "1.18.0" description = "ONNX Runtime is a runtime accelerator for Machine Learning models" optional = false python-versions = "*" files = [ - {file = "onnxruntime-1.17.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d86dde9c0bb435d709e51bd25991c9fe5b9a5b168df45ce119769edc4d198b15"}, - {file = "onnxruntime-1.17.3-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9d87b68bf931ac527b2d3c094ead66bb4381bac4298b65f46c54fe4d1e255865"}, - {file = "onnxruntime-1.17.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26e950cf0333cf114a155f9142e71da344d2b08dfe202763a403ae81cc02ebd1"}, - {file = "onnxruntime-1.17.3-cp310-cp310-win32.whl", hash = "sha256:0962a4d0f5acebf62e1f0bf69b6e0adf16649115d8de854c1460e79972324d68"}, - {file = "onnxruntime-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:468ccb8a0faa25c681a41787b1594bf4448b0252d3efc8b62fd8b2411754340f"}, - {file = "onnxruntime-1.17.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e8cd90c1c17d13d47b89ab076471e07fb85467c01dcd87a8b8b5cdfbcb40aa51"}, - {file = "onnxruntime-1.17.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a058b39801baefe454eeb8acf3ada298c55a06a4896fafc224c02d79e9037f60"}, - {file = "onnxruntime-1.17.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f823d5eb4807007f3da7b27ca972263df6a1836e6f327384eb266274c53d05d"}, - {file = "onnxruntime-1.17.3-cp311-cp311-win32.whl", hash = "sha256:b66b23f9109e78ff2791628627a26f65cd335dcc5fbd67ff60162733a2f7aded"}, - {file = "onnxruntime-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:570760ca53a74cdd751ee49f13de70d1384dcf73d9888b8deac0917023ccda6d"}, - {file = "onnxruntime-1.17.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:77c318178d9c16e9beadd9a4070d8aaa9f57382c3f509b01709f0f010e583b99"}, - {file = "onnxruntime-1.17.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23da8469049b9759082e22c41a444f44a520a9c874b084711b6343672879f50b"}, - {file = "onnxruntime-1.17.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2949730215af3f9289008b2e31e9bbef952012a77035b911c4977edea06f3f9e"}, - {file = "onnxruntime-1.17.3-cp312-cp312-win32.whl", hash = "sha256:6c7555a49008f403fb3b19204671efb94187c5085976ae526cb625f6ede317bc"}, - {file = "onnxruntime-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:58672cf20293a1b8a277a5c6c55383359fcdf6119b2f14df6ce3b140f5001c39"}, - {file = "onnxruntime-1.17.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4395ba86e3c1e93c794a00619ef1aec597ab78f5a5039f3c6d2e9d0695c0a734"}, - {file = "onnxruntime-1.17.3-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdf354c04344ec38564fc22394e1fe08aa6d70d790df00159205a0055c4a4d3f"}, - {file = "onnxruntime-1.17.3-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a94b600b7af50e922d44b95a57981e3e35103c6e3693241a03d3ca204740bbda"}, - {file = "onnxruntime-1.17.3-cp38-cp38-win32.whl", hash = "sha256:5a335c76f9c002a8586c7f38bc20fe4b3725ced21f8ead835c3e4e507e42b2ab"}, - {file = "onnxruntime-1.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f56a86fbd0ddc8f22696ddeda0677b041381f4168a2ca06f712ef6ec6050d6d"}, - {file = "onnxruntime-1.17.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:e0ae39f5452278cd349520c296e7de3e90d62dc5b0157c6868e2748d7f28b871"}, - {file = "onnxruntime-1.17.3-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ff2dc012bd930578aff5232afd2905bf16620815f36783a941aafabf94b3702"}, - {file = "onnxruntime-1.17.3-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf6c37483782e4785019b56e26224a25e9b9a35b849d0169ce69189867a22bb1"}, - {file = "onnxruntime-1.17.3-cp39-cp39-win32.whl", hash = "sha256:351bf5a1140dcc43bfb8d3d1a230928ee61fcd54b0ea664c8e9a889a8e3aa515"}, - {file = "onnxruntime-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:57a3de15778da8d6cc43fbf6cf038e1e746146300b5f0b1fbf01f6f795dc6440"}, + {file = "onnxruntime-1.18.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:5a3b7993a5ecf4a90f35542a4757e29b2d653da3efe06cdd3164b91167bbe10d"}, + {file = "onnxruntime-1.18.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15b944623b2cdfe7f7945690bfb71c10a4531b51997c8320b84e7b0bb59af902"}, + {file = "onnxruntime-1.18.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e61ce5005118064b1a0ed73ebe936bc773a102f067db34108ea6c64dd62a179"}, + {file = "onnxruntime-1.18.0-cp310-cp310-win32.whl", hash = "sha256:a4fc8a2a526eb442317d280610936a9f73deece06c7d5a91e51570860802b93f"}, + {file = "onnxruntime-1.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:71ed219b768cab004e5cd83e702590734f968679bf93aa488c1a7ffbe6e220c3"}, + {file = "onnxruntime-1.18.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:3d24bd623872a72a7fe2f51c103e20fcca2acfa35d48f2accd6be1ec8633d960"}, + {file = "onnxruntime-1.18.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f15e41ca9b307a12550bfd2ec93f88905d9fba12bab7e578f05138ad0ae10d7b"}, + {file = "onnxruntime-1.18.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f45ca2887f62a7b847d526965686b2923efa72538c89b7703c7b3fe970afd59"}, + {file = "onnxruntime-1.18.0-cp311-cp311-win32.whl", hash = "sha256:9e24d9ecc8781323d9e2eeda019b4b24babc4d624e7d53f61b1fe1a929b0511a"}, + {file = "onnxruntime-1.18.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8608398976ed18aef450d83777ff6f77d0b64eced1ed07a985e1a7db8ea3771"}, + {file = "onnxruntime-1.18.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f1d79941f15fc40b1ee67738b2ca26b23e0181bf0070b5fb2984f0988734698f"}, + {file = "onnxruntime-1.18.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e8caf3a8565c853a22d323a3eebc2a81e3de7591981f085a4f74f7a60aab2d"}, + {file = "onnxruntime-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:498d2b8380635f5e6ebc50ec1b45f181588927280f32390fb910301d234f97b8"}, + {file = "onnxruntime-1.18.0-cp312-cp312-win32.whl", hash = "sha256:ba7cc0ce2798a386c082aaa6289ff7e9bedc3dee622eef10e74830cff200a72e"}, + {file = "onnxruntime-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:1fa175bd43f610465d5787ae06050c81f7ce09da2bf3e914eb282cb8eab363ef"}, + {file = "onnxruntime-1.18.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0284c579c20ec8b1b472dd190290a040cc68b6caec790edb960f065d15cf164a"}, + {file = "onnxruntime-1.18.0-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d47353d036d8c380558a5643ea5f7964d9d259d31c86865bad9162c3e916d1f6"}, + {file = "onnxruntime-1.18.0-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:885509d2b9ba4b01f08f7fa28d31ee54b6477953451c7ccf124a84625f07c803"}, + {file = "onnxruntime-1.18.0-cp38-cp38-win32.whl", hash = "sha256:8614733de3695656411d71fc2f39333170df5da6c7efd6072a59962c0bc7055c"}, + {file = "onnxruntime-1.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:47af3f803752fce23ea790fd8d130a47b2b940629f03193f780818622e856e7a"}, + {file = "onnxruntime-1.18.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:9153eb2b4d5bbab764d0aea17adadffcfc18d89b957ad191b1c3650b9930c59f"}, + {file = "onnxruntime-1.18.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c7fd86eca727c989bb8d9c5104f3c45f7ee45f445cc75579ebe55d6b99dfd7c"}, + {file = "onnxruntime-1.18.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac67a4de9c1326c4d87bcbfb652c923039b8a2446bb28516219236bec3b494f5"}, + {file = "onnxruntime-1.18.0-cp39-cp39-win32.whl", hash = "sha256:6ffb445816d06497df7a6dd424b20e0b2c39639e01e7fe210e247b82d15a23b9"}, + {file = "onnxruntime-1.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:46de6031cb6745f33f7eca9e51ab73e8c66037fb7a3b6b4560887c5b55ab5d5d"}, ] [package.dependencies] @@ -3104,13 +3047,13 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.2.1" +version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, - {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [package.extras] @@ -7211,13 +7154,13 @@ stats = ["scipy (>=1.7)", "statsmodels (>=0.12)"] [[package]] name = "sentry-sdk" -version = "2.1.1" +version = "2.2.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" files = [ - {file = "sentry_sdk-2.1.1-py2.py3-none-any.whl", hash = "sha256:99aeb78fb76771513bd3b2829d12613130152620768d00cd3e45ac00cb17950f"}, - {file = "sentry_sdk-2.1.1.tar.gz", hash = "sha256:95d8c0bb41c8b0bc37ab202c2c4a295bb84398ee05f4cdce55051cd75b926ec1"}, + {file = "sentry_sdk-2.2.0-py2.py3-none-any.whl", hash = "sha256:674f58da37835ea7447fe0e34c57b4a4277fad558b0a7cb4a6c83bcb263086be"}, + {file = "sentry_sdk-2.2.0.tar.gz", hash = "sha256:70eca103cf4c6302365a9d7cf522e7ed7720828910eb23d43ada8e50d1ecda9d"}, ] [package.dependencies] @@ -7718,21 +7661,6 @@ files = [ [package.extras] widechars = ["wcwidth"] -[[package]] -name = "tenacity" -version = "8.3.0" -description = "Retry code until it succeeds" -optional = false -python-versions = ">=3.8" -files = [ - {file = "tenacity-8.3.0-py3-none-any.whl", hash = "sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185"}, - {file = "tenacity-8.3.0.tar.gz", hash = "sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2"}, -] - -[package.extras] -doc = ["reno", "sphinx"] -test = ["pytest", "tornado (>=4.5)", "typeguard"] - [[package]] name = "timezonefinder" version = "6.5.0" @@ -7851,13 +7779,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.26.1" +version = "20.26.2" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.26.1-py3-none-any.whl", hash = "sha256:7aa9982a728ae5892558bff6a2839c00b9ed145523ece2274fad6f414690ae75"}, - {file = "virtualenv-20.26.1.tar.gz", hash = "sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b"}, + {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, + {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, ] [package.dependencies] @@ -8006,20 +7934,20 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.18.1" +version = "3.18.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, - {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, + {file = "zipp-3.18.2-py3-none-any.whl", hash = "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e"}, + {file = "zipp-3.18.2.tar.gz", hash = "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "9f69dc7862f33f61e94e960f0ead2cbcd306b4502163d1934381d476143344f4" +content-hash = "50879c7afcb98ba425147a816ae74d05979f443e32c2ffd4c348d29adf2cb579" diff --git a/pyproject.toml b/pyproject.toml index eb2701760..720c6a4d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -131,10 +131,8 @@ av = "*" azure-identity = "*" azure-storage-blob = "*" breathe = "*" -control = "*" coverage = "*" dictdiffer = "*" -ft4222 = "*" flaky = "*" hypothesis = "~6.47" inputs = "*" @@ -170,7 +168,6 @@ sphinx = "*" sphinx-rtd-theme = "*" sphinx-sitemap = "*" tabulate = "*" -tenacity = "*" types-requests = "*" types-tabulate = "*" tqdm = "*" From 4c558e45b99f1fc1cbafc08a58d639885552eeaf Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 18 May 2024 15:15:41 -0700 Subject: [PATCH 022/220] control is still used --- poetry.lock | 23 ++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 6a3f66be4..0e3c760c3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -733,6 +733,27 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pill test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] +[[package]] +name = "control" +version = "0.10.0" +description = "Python Control Systems Library" +optional = false +python-versions = ">=3.10" +files = [ + {file = "control-0.10.0-py3-none-any.whl", hash = "sha256:ed1e0eb73f1e2945fc9af9d7b9121ef328fe980e7903b2a14b149d4f1855a808"}, + {file = "control-0.10.0.tar.gz", hash = "sha256:2c18b767537f45c7fd07b2e4afe8fbe5964019499b5f52f888edb5d8560bab53"}, +] + +[package.dependencies] +matplotlib = ">=3.6" +numpy = ">=1.23" +scipy = ">=1.8" + +[package.extras] +cvxopt = ["cvxopt (>=1.2.0)"] +slycot = ["slycot (>=0.4.0)"] +test = ["pytest", "pytest-timeout"] + [[package]] name = "coverage" version = "7.5.1" @@ -7950,4 +7971,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "50879c7afcb98ba425147a816ae74d05979f443e32c2ffd4c348d29adf2cb579" +content-hash = "0afca2f38c4c3da806ff0b42f10f981455c29e2166b4ff2f5f8d9ef82c10358d" diff --git a/pyproject.toml b/pyproject.toml index 720c6a4d2..54f5fdf7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -131,6 +131,7 @@ av = "*" azure-identity = "*" azure-storage-blob = "*" breathe = "*" +control = "*" coverage = "*" dictdiffer = "*" flaky = "*" From 04d8a4ecad7d9554c5968535ce3760728a6ff1a7 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 18 May 2024 16:08:10 -0700 Subject: [PATCH 023/220] CI: remove redundant pj job --- .github/workflows/tools_tests.yaml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index f33f8b775..4466260af 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -20,23 +20,6 @@ env: jobs: - plotjuggler: - name: plotjuggler - runs-on: ubuntu-latest - timeout-minutes: 45 - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: Build openpilot - timeout-minutes: 5 - run: ${{ env.RUN }} "scons -j$(nproc) cereal/ common/ opendbc/ --minimal" - - name: Test PlotJuggler - timeout-minutes: 2 - run: | - ${{ env.RUN }} "pytest tools/plotjuggler/" - simulator_build: name: simulator docker build runs-on: ubuntu-latest From c9531b463a6cb4a2a56792046fd69f9041006d81 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 18 May 2024 16:34:03 -0700 Subject: [PATCH 024/220] Revert "ui: single-threaded CameraView (#32291)" This reverts commit dd6e2a400b1b9543fad0c3c4a78463abf756da6b. --- selfdrive/ui/qt/offroad/driverview.cc | 13 +- selfdrive/ui/qt/offroad/driverview.h | 2 +- selfdrive/ui/qt/onroad/annotated_camera.cc | 30 ++- selfdrive/ui/qt/onroad/annotated_camera.h | 1 + selfdrive/ui/qt/widgets/cameraview.cc | 209 +++++++++++++-------- selfdrive/ui/qt/widgets/cameraview.h | 60 +++--- selfdrive/ui/watch3.cc | 8 +- tools/cabana/videowidget.cc | 5 +- tools/cabana/videowidget.h | 4 +- 9 files changed, 196 insertions(+), 136 deletions(-) diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc index f14d05933..df9bb2465 100644 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ b/selfdrive/ui/qt/offroad/driverview.cc @@ -7,7 +7,7 @@ const int FACE_IMG_SIZE = 130; -DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraView("camerad", VISION_STREAM_DRIVER, true, parent) { +DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraWidget("camerad", VISION_STREAM_DRIVER, true, parent) { face_img = loadPixmap("../assets/img_driver_face_static.png", {FACE_IMG_SIZE, FACE_IMG_SIZE}); QObject::connect(this, &CameraWidget::clicked, this, &DriverViewWindow::done); QObject::connect(device(), &Device::interactiveTimeout, this, [this]() { @@ -20,20 +20,22 @@ DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraView("camerad", VISI void DriverViewWindow::showEvent(QShowEvent* event) { params.putBool("IsDriverViewEnabled", true); device()->resetInteractiveTimeout(60); - CameraView::showEvent(event); + CameraWidget::showEvent(event); } void DriverViewWindow::hideEvent(QHideEvent* event) { params.putBool("IsDriverViewEnabled", false); - CameraView::hideEvent(event); + stopVipcThread(); + CameraWidget::hideEvent(event); } void DriverViewWindow::paintGL() { - CameraView::paintGL(); + CameraWidget::paintGL(); + std::lock_guard lk(frame_lock); QPainter p(this); // startup msg - if (recent_frames.empty()) { + if (frames.empty()) { p.setPen(Qt::white); p.setRenderHint(QPainter::TextAntialiasing); p.setFont(InterFont(100, QFont::Bold)); @@ -45,6 +47,7 @@ void DriverViewWindow::paintGL() { cereal::DriverStateV2::Reader driver_state = sm["driverStateV2"].getDriverStateV2(); bool is_rhd = driver_state.getWheelOnRightProb() > 0.5; auto driver_data = is_rhd ? driver_state.getRightDriverData() : driver_state.getLeftDriverData(); + bool face_detected = driver_data.getFaceProb() > 0.7; if (face_detected) { auto fxy_list = driver_data.getFacePosition(); diff --git a/selfdrive/ui/qt/offroad/driverview.h b/selfdrive/ui/qt/offroad/driverview.h index 97dd2faa7..155e4ede3 100644 --- a/selfdrive/ui/qt/offroad/driverview.h +++ b/selfdrive/ui/qt/offroad/driverview.h @@ -2,7 +2,7 @@ #include "selfdrive/ui/qt/widgets/cameraview.h" -class DriverViewWindow : public CameraView { +class DriverViewWindow : public CameraWidget { Q_OBJECT public: diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 637d72758..f7fb6b480 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -6,11 +6,11 @@ #include #include "common/swaglog.h" +#include "selfdrive/ui/qt/onroad/buttons.h" #include "selfdrive/ui/qt/util.h" // Window that shows camera view and variety of info drawn on top -AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget *parent) - : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { +AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { pm = std::make_unique>({"uiDebug"}); main_layout = new QVBoxLayout(this); @@ -76,8 +76,6 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { map_settings_btn->setVisible(!hideBottomIcons); main_layout->setAlignment(map_settings_btn, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignBottom); } - - update(); } void AnnotatedCameraWidget::drawHud(QPainter &p) { @@ -355,8 +353,25 @@ void AnnotatedCameraWidget::paintGL() { UIState *s = uiState(); SubMaster &sm = *(s->sm); const double start_draw_t = millis_since_boot(); + const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); + // draw camera frame { + std::lock_guard lk(frame_lock); + + if (frames.empty()) { + if (skip_frame_count > 0) { + skip_frame_count--; + qDebug() << "skipping frame, not ready"; + return; + } + } else { + // skip drawing up to this many frames if we're + // missing camera frames. this smooths out the + // transitions from the narrow and wide cameras + skip_frame_count = 5; + } + // Wide or narrow cam dependent on speed bool has_wide_cam = available_streams.count(VISION_STREAM_WIDE_ROAD); if (has_wide_cam) { @@ -372,16 +387,14 @@ void AnnotatedCameraWidget::paintGL() { } CameraWidget::setStreamType(wide_cam_requested ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); - s->scene.wide_cam = CameraWidget::streamType() == VISION_STREAM_WIDE_ROAD; + s->scene.wide_cam = CameraWidget::getStreamType() == VISION_STREAM_WIDE_ROAD; if (s->scene.calibration_valid) { auto calib = s->scene.wide_cam ? s->scene.view_from_wide_calib : s->scene.view_from_calib; CameraWidget::updateCalibration(calib); } else { CameraWidget::updateCalibration(DEFAULT_CALIBRATION); } - - // Draw the frame based on the UI plan's frame ID - CameraWidget::setFrameId(sm["uiPlan"].getUiPlan().getFrameId()); + CameraWidget::setFrameId(model.getFrameId()); CameraWidget::paintGL(); } @@ -390,7 +403,6 @@ void AnnotatedCameraWidget::paintGL() { painter.setPen(Qt::NoPen); if (s->scene.world_objects_visible) { - const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); update_model(s, model, sm["uiPlan"].getUiPlan()); drawLaneLines(painter, s); diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h index b25846001..0be4adfff 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/qt/onroad/annotated_camera.h @@ -37,6 +37,7 @@ private: int status = STATUS_DISENGAGED; std::unique_ptr pm; + int skip_frame_count = 0; bool wide_cam_requested = false; protected: diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index a7d4432de..e4f139626 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -97,22 +97,37 @@ mat4 get_fit_view_transform(float widget_aspect_ratio, float frame_aspect_ratio) } // namespace -CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget *parent) - : stream_name(stream_name), stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { +CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) : + stream_name(stream_name), active_stream_type(type), requested_stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { + setAttribute(Qt::WA_OpaquePaintEvent); + qRegisterMetaType>("availableStreams"); + QObject::connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); + QObject::connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived, Qt::QueuedConnection); + QObject::connect(this, &CameraWidget::vipcAvailableStreamsUpdated, this, &CameraWidget::availableStreamsUpdated, Qt::QueuedConnection); } CameraWidget::~CameraWidget() { makeCurrent(); + stopVipcThread(); if (isValid()) { glDeleteVertexArrays(1, &frame_vao); glDeleteBuffers(1, &frame_vbo); glDeleteBuffers(1, &frame_ibo); glDeleteBuffers(2, textures); } - clearEGLImages(); doneCurrent(); } +// Qt uses device-independent pixels, depending on platform this may be +// different to what OpenGL uses +int CameraWidget::glWidth() { + return width() * devicePixelRatio(); +} + +int CameraWidget::glHeight() { + return height() * devicePixelRatio(); +} + void CameraWidget::initializeGL() { initializeOpenGLFunctions(); @@ -126,7 +141,7 @@ void CameraWidget::initializeGL() { GLint frame_pos_loc = program->attributeLocation("aPosition"); GLint frame_texcoord_loc = program->attributeLocation("aTexCoord"); - auto [x1, x2, y1, y2] = stream_type == VISION_STREAM_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); + auto [x1, x2, y1, y2] = requested_stream_type == VISION_STREAM_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; const float frame_coords[4][4] = { {-1.0, -1.0, x2, y1}, // bl @@ -163,11 +178,45 @@ void CameraWidget::initializeGL() { #endif } +void CameraWidget::showEvent(QShowEvent *event) { + if (!vipc_thread) { + clearFrames(); + vipc_thread = new QThread(); + connect(vipc_thread, &QThread::started, [=]() { vipcThread(); }); + connect(vipc_thread, &QThread::finished, vipc_thread, &QObject::deleteLater); + vipc_thread->start(); + } +} + +void CameraWidget::stopVipcThread() { + makeCurrent(); + if (vipc_thread) { + vipc_thread->requestInterruption(); + vipc_thread->quit(); + vipc_thread->wait(); + vipc_thread = nullptr; + } + +#ifdef QCOM2 + EGLDisplay egl_display = eglGetCurrentDisplay(); + assert(egl_display != EGL_NO_DISPLAY); + for (auto &pair : egl_images) { + eglDestroyImageKHR(egl_display, pair.second); + assert(eglGetError() == EGL_SUCCESS); + } + egl_images.clear(); +#endif +} + +void CameraWidget::availableStreamsUpdated(std::set streams) { + available_streams = streams; +} + void CameraWidget::updateFrameMat() { int w = glWidth(), h = glHeight(); if (zoomed_view) { - if (streamType() == VISION_STREAM_DRIVER) { + if (active_stream_type == VISION_STREAM_DRIVER) { if (stream_width > 0 && stream_height > 0) { frame_mat = get_driver_view_transform(w, h, stream_width, stream_height); } @@ -176,7 +225,7 @@ void CameraWidget::updateFrameMat() { // to ensure this ends up in the middle of the screen // for narrow come and a little lower for wide cam. // TODO: use proper perspective transform? - if (streamType() == VISION_STREAM_WIDE_ROAD) { + if (active_stream_type == VISION_STREAM_WIDE_ROAD) { intrinsic_matrix = ECAM_INTRINSIC_MATRIX; zoom = 2.0; } else { @@ -198,12 +247,13 @@ void CameraWidget::updateFrameMat() { float zx = zoom * 2 * intrinsic_matrix.v[2] / w; float zy = zoom * 2 * intrinsic_matrix.v[5] / h; - frame_mat = {{ + const mat4 frame_transform = {{ zx, 0.0, 0.0, -x_offset / w * 2, 0.0, zy, 0.0, y_offset / h * 2, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }}; + frame_mat = frame_transform; } } else if (stream_width > 0 && stream_height > 0) { // fit frame to widget size @@ -221,15 +271,25 @@ void CameraWidget::paintGL() { glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - VisionBuf *frame = receiveFrame(draw_frame_id); - if (!frame) return; + std::lock_guard lk(frame_lock); + if (frames.empty()) return; + + int frame_idx = frames.size() - 1; + + // Always draw latest frame until sync logic is more stable + // for (frame_idx = 0; frame_idx < frames.size() - 1; frame_idx++) { + // if (frames[frame_idx].first == draw_frame_id) break; + // } // Log duplicate/dropped frames - uint32_t frame_id = frame->get_frame_id(); - if (prev_frame_id != INVALID_FRAME_ID && frame_id != prev_frame_id + 1) { - qDebug() << (frame_id == prev_frame_id ? "Drawing same frame twice" : "Skip frame") << frame_id; + if (frames[frame_idx].first == prev_frame_id) { + qDebug() << "Drawing same frame twice" << frames[frame_idx].first; + } else if (frames[frame_idx].first != prev_frame_id + 1) { + qDebug() << "Skipped frame" << frames[frame_idx].first; } - prev_frame_id = frame_id; + prev_frame_id = frames[frame_idx].first; + VisionBuf *frame = frames[frame_idx].second; + assert(frame != nullptr); updateFrameMat(); @@ -269,14 +329,20 @@ void CameraWidget::paintGL() { glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } -void CameraWidget::vipcConnected() { +void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { + makeCurrent(); stream_width = vipc_client->buffers[0].width; stream_height = vipc_client->buffers[0].height; stream_stride = vipc_client->buffers[0].stride; #ifdef QCOM2 - clearEGLImages(); EGLDisplay egl_display = eglGetCurrentDisplay(); + assert(egl_display != EGL_NO_DISPLAY); + for (auto &pair : egl_images) { + eglDestroyImageKHR(egl_display, pair.second); + } + egl_images.clear(); + for (int i = 0; i < vipc_client->num_buffers; i++) { // import buffers into OpenGL int fd = dup(vipc_client->buffers[i].fd); // eglDestroyImageKHR will close, so duplicate EGLint img_attrs[] = { @@ -313,78 +379,59 @@ void CameraWidget::vipcConnected() { #endif } -VisionBuf *CameraWidget::receiveFrame(uint64_t request_frame_id) { - if (!ensureConnection()) { - return nullptr; - } - - // Receive frames and store them in recent_frames - while (auto buf = vipc_client->recv(nullptr, 0)) { - recent_frames.emplace_back(buf); - if (recent_frames.size() > FRAME_BUFFER_SIZE) { - recent_frames.pop_front(); - } - } - if (!vipc_client->connected || recent_frames.empty()) { - return nullptr; - } - - // Find the requested frame - auto it = std::find_if(recent_frames.rbegin(), recent_frames.rend(), - [request_frame_id](VisionBuf *buf) { return buf->get_frame_id() == request_frame_id; }); - return it != recent_frames.rend() ? *it : recent_frames.back(); +void CameraWidget::vipcFrameReceived() { + update(); } -bool CameraWidget::ensureConnection() { - // Reconnect if the client is not initialized or the stream type has changed - if (!vipc_client || vipc_client->type != stream_type) { - qDebug() << "connecting to stream" << stream_type; - vipc_client.reset(new VisionIpcClient(stream_name, stream_type, false)); - } +void CameraWidget::vipcThread() { + VisionStreamType cur_stream = requested_stream_type; + std::unique_ptr vipc_client; + VisionIpcBufExtra meta_main = {0}; - // Re-establish connection if not connected - if (!vipc_client->connected) { - clearFrames(); - available_streams = VisionIpcClient::getAvailableStreams(stream_name, false); - if (available_streams.empty() || !vipc_client->connect(false)) { - return false; + while (!QThread::currentThread()->isInterruptionRequested()) { + if (!vipc_client || cur_stream != requested_stream_type) { + clearFrames(); + qDebug().nospace() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; + cur_stream = requested_stream_type; + vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); + } + active_stream_type = cur_stream; + + if (!vipc_client->connected) { + clearFrames(); + auto streams = VisionIpcClient::getAvailableStreams(stream_name, false); + if (streams.empty()) { + QThread::msleep(100); + continue; + } + emit vipcAvailableStreamsUpdated(streams); + + if (!vipc_client->connect(false)) { + QThread::msleep(100); + continue; + } + emit vipcThreadConnected(vipc_client.get()); + } + + if (VisionBuf *buf = vipc_client->recv(&meta_main, 1000)) { + { + std::lock_guard lk(frame_lock); + frames.push_back(std::make_pair(meta_main.frame_id, buf)); + while (frames.size() > FRAME_BUFFER_SIZE) { + frames.pop_front(); + } + } + emit vipcThreadFrameReceived(); + } else { + if (!isVisible()) { + vipc_client->connected = false; + } } - emit vipcAvailableStreamsUpdated(); - vipcConnected(); } - return true; } void CameraWidget::clearFrames() { - recent_frames.clear(); - draw_frame_id = INVALID_FRAME_ID; - prev_frame_id = INVALID_FRAME_ID; -} - -void CameraWidget::clearEGLImages() { -#ifdef QCOM2 - EGLDisplay egl_display = eglGetCurrentDisplay(); - assert(egl_display != EGL_NO_DISPLAY); - for (auto &pair : egl_images) { - eglDestroyImageKHR(egl_display, pair.second); - } - egl_images.clear(); -#endif -} - -// Cameraview - -CameraView::CameraView(const std::string &name, VisionStreamType stream_type, bool zoom, QWidget *parent) - : CameraWidget(name, stream_type, zoom, parent) { - timer = new QTimer(this); - timer->setInterval(1000.0 / UI_FREQ); - timer->callOnTimeout(this, [this]() { update(); }); -} - -void CameraView::showEvent(QShowEvent *event) { - timer->start(); -} - -void CameraView::hideEvent(QHideEvent *event) { - timer->stop(); + std::lock_guard lk(frame_lock); + frames.clear(); + available_streams.clear(); } diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index fb31d094b..c97038cf4 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -10,7 +11,7 @@ #include #include #include -#include +#include #ifdef QCOM2 #define EGL_EGLEXT_PROTOTYPES @@ -26,40 +27,40 @@ #include "selfdrive/ui/ui.h" const int FRAME_BUFFER_SIZE = 5; -const uint32_t INVALID_FRAME_ID = -1; static_assert(FRAME_BUFFER_SIZE <= YUV_BUFFER_COUNT); class CameraWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: + using QOpenGLWidget::QOpenGLWidget; explicit CameraWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr); ~CameraWidget(); void setBackgroundColor(const QColor &color) { bg = color; } void setFrameId(int frame_id) { draw_frame_id = frame_id; } - void setStreamType(VisionStreamType type) { stream_type = type; } - inline VisionStreamType streamType() const { return stream_type; } - inline const std::set &availableStreams() const { return available_streams; } - VisionBuf *receiveFrame(uint64_t request_frame_id = INVALID_FRAME_ID); + void setStreamType(VisionStreamType type) { requested_stream_type = type; } + VisionStreamType getStreamType() { return active_stream_type; } + void stopVipcThread(); signals: - void vipcAvailableStreamsUpdated(); void clicked(); + void vipcThreadConnected(VisionIpcClient *); + void vipcThreadFrameReceived(); + void vipcAvailableStreamsUpdated(std::set); protected: - bool ensureConnection(); void paintGL() override; void initializeGL() override; - void vipcConnected(); - void clearFrames(); - void clearEGLImages(); - void resizeGL(int w, int h) override { updateFrameMat(); } + void showEvent(QShowEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override { emit clicked(); } virtual void updateFrameMat(); void updateCalibration(const mat3 &calib); - int glWidth() const { return width() * devicePixelRatio(); } - int glHeight() const { return height() * devicePixelRatio(); } + void vipcThread(); + void clearFrames(); + + int glWidth(); + int glHeight(); bool zoomed_view; GLuint frame_vao, frame_vbo, frame_ibo; @@ -76,7 +77,10 @@ protected: int stream_width = 0; int stream_height = 0; int stream_stride = 0; - VisionStreamType stream_type; + std::atomic active_stream_type; + std::atomic requested_stream_type; + std::set available_streams; + QThread *vipc_thread = nullptr; // Calibration float x_offset = 0; @@ -85,21 +89,15 @@ protected: mat3 calibration = DEFAULT_CALIBRATION; mat3 intrinsic_matrix = FCAM_INTRINSIC_MATRIX; - std::set available_streams; - std::unique_ptr vipc_client; - std::deque recent_frames; - uint32_t draw_frame_id = INVALID_FRAME_ID; - uint32_t prev_frame_id = INVALID_FRAME_ID; + std::recursive_mutex frame_lock; + std::deque> frames; + uint32_t draw_frame_id = 0; + uint32_t prev_frame_id = 0; + +protected slots: + void vipcConnected(VisionIpcClient *vipc_client); + void vipcFrameReceived(); + void availableStreamsUpdated(std::set streams); }; -// update frames based on timer -class CameraView : public CameraWidget { - Q_OBJECT -public: - CameraView(const std::string &name, VisionStreamType stream_type, bool zoom, QWidget *parent = nullptr); - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - -private: - QTimer *timer; -}; +Q_DECLARE_METATYPE(std::set); diff --git a/selfdrive/ui/watch3.cc b/selfdrive/ui/watch3.cc index cb12f82ea..ec35c29b6 100644 --- a/selfdrive/ui/watch3.cc +++ b/selfdrive/ui/watch3.cc @@ -19,15 +19,15 @@ int main(int argc, char *argv[]) { { QHBoxLayout *hlayout = new QHBoxLayout(); layout->addLayout(hlayout); - hlayout->addWidget(new CameraView("navd", VISION_STREAM_MAP, false)); - hlayout->addWidget(new CameraView("camerad", VISION_STREAM_ROAD, false)); + hlayout->addWidget(new CameraWidget("navd", VISION_STREAM_MAP, false)); + hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_ROAD, false)); } { QHBoxLayout *hlayout = new QHBoxLayout(); layout->addLayout(hlayout); - hlayout->addWidget(new CameraView("camerad", VISION_STREAM_DRIVER, false)); - hlayout->addWidget(new CameraView("camerad", VISION_STREAM_WIDE_ROAD, false)); + hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_DRIVER, false)); + hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_WIDE_ROAD, false)); } return a.exec(); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 8ce812282..cd412f727 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -139,7 +139,7 @@ QWidget *VideoWidget::createCameraWidget() { QStackedLayout *stacked = new QStackedLayout(); stacked->setStackingMode(QStackedLayout::StackAll); - stacked->addWidget(cam_widget = new CameraView("camerad", VISION_STREAM_ROAD, false)); + stacked->addWidget(cam_widget = new CameraWidget("camerad", VISION_STREAM_ROAD, false)); cam_widget->setMinimumHeight(MIN_VIDEO_HEIGHT); cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); stacked->addWidget(alert_label = new InfoLabel(this)); @@ -161,13 +161,12 @@ QWidget *VideoWidget::createCameraWidget() { return w; } -void VideoWidget::vipcAvailableStreamsUpdated() { +void VideoWidget::vipcAvailableStreamsUpdated(std::set streams) { static const QString stream_names[] = { [VISION_STREAM_ROAD] = "Road camera", [VISION_STREAM_WIDE_ROAD] = "Wide road camera", [VISION_STREAM_DRIVER] = "Driver camera"}; - const auto &streams = cam_widget->availableStreams(); for (int i = 0; i < streams.size(); ++i) { if (camera_tab->count() <= i) { camera_tab->addTab(QString()); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index ae095fd55..b2039e09a 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -73,9 +73,9 @@ protected: QWidget *createCameraWidget(); QHBoxLayout *createPlaybackController(); void loopPlaybackClicked(); - void vipcAvailableStreamsUpdated(); + void vipcAvailableStreamsUpdated(std::set streams); - CameraView *cam_widget; + CameraWidget *cam_widget; double maximum_time = 0; QToolButton *time_btn = nullptr; ToolButton *seek_backward_btn = nullptr; From bd6bea39bf9ff61ac0c5e942e929d12851c5c4b7 Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Sat, 18 May 2024 17:21:04 -0700 Subject: [PATCH 025/220] deps: add rerun-sdk into pyproject.toml (#32472) * add rerun-sdk into pyproject.toml * install/wheel cleanup * unpin version --- poetry.lock | 74 +++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + tools/rerun/run.py | 26 ++-------------- 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/poetry.lock b/poetry.lock index 0e3c760c3..471994a72 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3217,6 +3217,54 @@ files = [ [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +[[package]] +name = "pyarrow" +version = "16.1.0" +description = "Python library for Apache Arrow" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyarrow-16.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:17e23b9a65a70cc733d8b738baa6ad3722298fa0c81d88f63ff94bf25eaa77b9"}, + {file = "pyarrow-16.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4740cc41e2ba5d641071d0ab5e9ef9b5e6e8c7611351a5cb7c1d175eaf43674a"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98100e0268d04e0eec47b73f20b39c45b4006f3c4233719c3848aa27a03c1aef"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68f409e7b283c085f2da014f9ef81e885d90dcd733bd648cfba3ef265961848"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a8914cd176f448e09746037b0c6b3a9d7688cef451ec5735094055116857580c"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:48be160782c0556156d91adbdd5a4a7e719f8d407cb46ae3bb4eaee09b3111bd"}, + {file = "pyarrow-16.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cf389d444b0f41d9fe1444b70650fea31e9d52cfcb5f818b7888b91b586efff"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b"}, + {file = "pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7"}, + {file = "pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444"}, + {file = "pyarrow-16.1.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b5f5705ab977947a43ac83b52ade3b881eb6e95fcc02d76f501d549a210ba77f"}, + {file = "pyarrow-16.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d27bf89dfc2576f6206e9cd6cf7a107c9c06dc13d53bbc25b0bd4556f19cf5f"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d07de3ee730647a600037bc1d7b7994067ed64d0eba797ac74b2bc77384f4c2"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbef391b63f708e103df99fbaa3acf9f671d77a183a07546ba2f2c297b361e83"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19741c4dbbbc986d38856ee7ddfdd6a00fc3b0fc2d928795b95410d38bb97d15"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f2c5fb249caa17b94e2b9278b36a05ce03d3180e6da0c4c3b3ce5b2788f30eed"}, + {file = "pyarrow-16.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:e6b6d3cd35fbb93b70ade1336022cc1147b95ec6af7d36906ca7fe432eb09710"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:18da9b76a36a954665ccca8aa6bd9f46c1145f79c0bb8f4f244f5f8e799bca55"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99f7549779b6e434467d2aa43ab2b7224dd9e41bdde486020bae198978c9e05e"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f07fdffe4fd5b15f5ec15c8b64584868d063bc22b86b46c9695624ca3505b7b4"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddfe389a08ea374972bd4065d5f25d14e36b43ebc22fc75f7b951f24378bf0b5"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b20bd67c94b3a2ea0a749d2a5712fc845a69cb5d52e78e6449bbd295611f3aa"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ba8ac20693c0bb0bf4b238751d4409e62852004a8cf031c73b0e0962b03e45e3"}, + {file = "pyarrow-16.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:31a1851751433d89a986616015841977e0a188662fcffd1a5677453f1df2de0a"}, + {file = "pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315"}, +] + +[package.dependencies] +numpy = ">=1.16.6" + [[package]] name = "pyaudio" version = "0.2.14" @@ -7058,6 +7106,30 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "rerun-sdk" +version = "0.16.0" +description = "The Rerun Logging SDK" +optional = false +python-versions = "<3.13,>=3.8" +files = [ + {file = "rerun_sdk-0.16.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1cc6dc66d089e296f945dc238301889efb61dd6d338b5d00f76981cf7aed0a74"}, + {file = "rerun_sdk-0.16.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:faf231897655e46eb975695df2b0ace07db362d697e697f9a3dff52f81c0dc5d"}, + {file = "rerun_sdk-0.16.0-cp38-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:860a6394380d3e9b9e48bf34423bd56dda54d5b0158d2ae0e433698659b34198"}, + {file = "rerun_sdk-0.16.0-cp38-abi3-manylinux_2_31_x86_64.whl", hash = "sha256:5b8d1476f73a3ad1a5d3f21b61c633f3ab62aa80fa0b049f5ad10bf1227681ab"}, + {file = "rerun_sdk-0.16.0-cp38-abi3-win_amd64.whl", hash = "sha256:aff0051a263b8c3067243c0126d319845baf4fe640899f04aeef7daf151f35e4"}, +] + +[package.dependencies] +attrs = ">=23.1.0" +numpy = ">=1.23,<2" +pillow = ">=8.0.0" +pyarrow = ">=14.0.2" +typing-extensions = ">=4.5" + +[package.extras] +tests = ["pytest (==7.1.2)"] + [[package]] name = "rubicon-objc" version = "0.4.9" @@ -7971,4 +8043,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "0afca2f38c4c3da806ff0b42f10f981455c29e2166b4ff2f5f8d9ef82c10358d" +content-hash = "debffdd8b49091d256508f53c11e9d79fb4164995678d7e02d1720175cf265ec" diff --git a/pyproject.toml b/pyproject.toml index 54f5fdf7e..544f9ee18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,6 +108,7 @@ pycryptodome = "*" PyJWT = "*" pyserial = "*" pyzmq = "*" +rerun-sdk = "*" requests = "*" scons = "*" sentry-sdk = "*" diff --git a/tools/rerun/run.py b/tools/rerun/run.py index 271f127d3..8a002f68b 100755 --- a/tools/rerun/run.py +++ b/tools/rerun/run.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -import subprocess import sys import argparse import multiprocessing +import rerun as rr +import rerun.blueprint as rrb from functools import partial from openpilot.tools.lib.logreader import LogReader @@ -11,14 +12,6 @@ from cereal.services import SERVICE_LIST NUM_CPUS = multiprocessing.cpu_count() DEMO_ROUTE = "a2a0ccea32023010|2023-07-27--13-01-19" -WHEEL_URL = "https://build.rerun.io/commit/660463d/wheels" - - -def install(): - # currently requires a preview release build - subprocess.run([sys.executable, "-m", "pip", "install", "--pre", "-f", WHEEL_URL, "--upgrade", "rerun-sdk"], check=True) - print("Rerun installed") - def log_msg(msg, parent_key=''): stack = [(msg, parent_key)] @@ -45,7 +38,6 @@ def log_msg(msg, parent_key=''): else: pass # Not a plottable value - def createBlueprint(): timeSeriesViews = [] for topic in sorted(SERVICE_LIST.keys()): @@ -55,12 +47,10 @@ def createBlueprint(): rrb.Spatial2DView(name="thumbnail", origin="/thumbnail"))) return blueprint - def log_thumbnail(thumbnailMsg): bytesImgData = thumbnailMsg.get('thumbnail') rr.log("/thumbnail", rr.ImageEncoded(contents=bytesImgData)) - def process(blueprint, lr): ret = [] rr.init("rerun_test", spawn=True, default_blueprint=blueprint) @@ -73,12 +63,10 @@ def process(blueprint, lr): log_thumbnail(msg.to_dict()[msg.which()]) return ret - if __name__ == '__main__': parser = argparse.ArgumentParser(description="A helper to run rerun on openpilot routes", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--demo", action="store_true", help="Use the demo route instead of providing one") - parser.add_argument("--install", action="store_true", help="Install or update rerun") parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name to plot") if len(sys.argv) == 1: @@ -86,16 +74,6 @@ if __name__ == '__main__': sys.exit() args = parser.parse_args() - if args.install: - install() - sys.exit() - - try: - import rerun as rr - import rerun.blueprint as rrb - except ImportError: - print("Rerun is not installed, run with --install first") - sys.exit() route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip() blueprint = createBlueprint() From b742776bffb3e49649c17b54197a993e9d547403 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 19 May 2024 08:46:34 +0800 Subject: [PATCH 026/220] encoderd: publish i-frame as thumbnail (#32202) * pusblish i-frame as thumbnail * generic * disable for now * fix --------- Co-authored-by: Adeeb Shihadeh --- cereal | 2 +- system/loggerd/encoder/encoder.cc | 20 ++++++++++++++++++-- system/loggerd/encoder/encoder.h | 2 ++ system/loggerd/loggerd.h | 2 ++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index 591e389bf..0a9b426e5 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 591e389bf8e31f6f6ab921ec6598cafa53c19d36 +Subproject commit 0a9b426e55653daea6cc9d3c40c3f7600ec0db49 diff --git a/system/loggerd/encoder/encoder.cc b/system/loggerd/encoder/encoder.cc index c4bd91bcf..313a0f57a 100644 --- a/system/loggerd/encoder/encoder.cc +++ b/system/loggerd/encoder/encoder.cc @@ -6,7 +6,12 @@ VideoEncoder::VideoEncoder(const EncoderInfo &encoder_info, int in_width, int in out_width = encoder_info.frame_width > 0 ? encoder_info.frame_width : in_width; out_height = encoder_info.frame_height > 0 ? encoder_info.frame_height : in_height; - pm.reset(new PubMaster({encoder_info.publish_name})); + + std::vector pubs = {encoder_info.publish_name}; + if (encoder_info.thumbnail_name != NULL) { + pubs.push_back(encoder_info.thumbnail_name); + } + pm.reset(new PubMaster(pubs)); } void VideoEncoder::publisher_publish(VideoEncoder *e, int segment_num, uint32_t idx, VisionIpcBufExtra &extra, @@ -40,4 +45,15 @@ void VideoEncoder::publisher_publish(VideoEncoder *e, int segment_num, uint32_t kj::ArrayOutputStream output_stream(kj::ArrayPtr(e->msg_cache.data(), bytes_size)); capnp::writeMessage(output_stream, msg); e->pm->send(e->encoder_info.publish_name, e->msg_cache.data(), bytes_size); -} + + // Publish keyframe thumbnail + if ((flags & V4L2_BUF_FLAG_KEYFRAME) && e->encoder_info.thumbnail_name != NULL) { + MessageBuilder tm; + auto thumbnail = tm.initEvent().initThumbnail(); + thumbnail.setFrameId(extra.frame_id); + thumbnail.setTimestampEof(extra.timestamp_eof); + thumbnail.setThumbnail(dat); + thumbnail.setEncoding(cereal::Thumbnail::Encoding::KEYFRAME); + pm->send(e->encoder_info.thumbnail_name, tm); + } +} \ No newline at end of file diff --git a/system/loggerd/encoder/encoder.h b/system/loggerd/encoder/encoder.h index 7c203f919..75183611b 100644 --- a/system/loggerd/encoder/encoder.h +++ b/system/loggerd/encoder/encoder.h @@ -25,6 +25,8 @@ public: void publisher_publish(VideoEncoder *e, int segment_num, uint32_t idx, VisionIpcBufExtra &extra, unsigned int flags, kj::ArrayPtr header, kj::ArrayPtr dat); protected: + void publish_thumbnail(uint32_t frame_id, uint64_t timestamp_eof, kj::ArrayPtr dat); + int in_width, in_height; int out_width, out_height; const EncoderInfo encoder_info; diff --git a/system/loggerd/loggerd.h b/system/loggerd/loggerd.h index ea288f486..5eef16183 100644 --- a/system/loggerd/loggerd.h +++ b/system/loggerd/loggerd.h @@ -33,6 +33,7 @@ constexpr char PRESERVE_ATTR_VALUE = '1'; class EncoderInfo { public: const char *publish_name; + const char *thumbnail_name = NULL; const char *filename = NULL; bool record = true; int frame_width = -1; @@ -76,6 +77,7 @@ const EncoderInfo main_driver_encoder_info = { const EncoderInfo stream_road_encoder_info = { .publish_name = "livestreamRoadEncodeData", + //.thumbnail_name = "thumbnail", .encode_type = cereal::EncodeIndex::Type::QCAMERA_H264, .record = false, .bitrate = LIVESTREAM_BITRATE, From 075176f869088f9e2021aadc9e236edd8cac7d3e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 18 May 2024 17:55:52 -0700 Subject: [PATCH 027/220] define alert for actuatorsApiUnavailable --- selfdrive/controls/lib/events.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 99246a139..e697eb010 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -331,6 +331,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { # ********** events with no alerts ********** EventName.stockFcw: {}, + EventName.actuatorsApiUnavailable: {}, # ********** events only containing alerts displayed in all states ********** From 220fcc16753ce87c8997275733f62bc385342a7e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 19 May 2024 03:07:12 -0500 Subject: [PATCH 028/220] process replay: regen routes (#32464) * regen * regen * update * undo * update refs * fix * real fix * test * test2 * test3 * stash * Revert "stash" This reverts commit bf6765f526b48426f49a4b29c4042097f57fc4b0. * rk.lagging can not be trusted. BODY segment has radarFault while modelV2 is not valid, causing radarState to not be valid * order * update refs again * we never logged carOutput! * bump * add back checks --- selfdrive/controls/controlsd.py | 2 +- .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- .../test/process_replay/test_processes.py | 40 +++++++++---------- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 92c933112..e3c456766 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -296,7 +296,7 @@ class Controls: self.events.add(EventName.cameraFrameRate) if not REPLAY and self.rk.lagging: self.events.add(EventName.controlsdLagging) - if len(self.sm['radarState'].radarErrors) or (not self.rk.lagging and not self.sm.all_checks(['radarState'])): + if len(self.sm['radarState'].radarErrors) or ((not self.rk.lagging or REPLAY) and not self.sm.all_checks(['radarState'])): self.events.add(EventName.radarFault) if not self.sm.valid['pandaStates']: self.events.add(EventName.usbError) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 233f5d746..f55f2c4e2 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -466,7 +466,7 @@ CONFIGS = [ "modelV2", "driverCameraState", "roadCameraState", "wideRoadCameraState", "managerState", "testJoystick", "liveTorqueParameters", "accelerometer", "gyroscope" ], - subs=["controlsState", "carState", "carControl", "sendcan", "onroadEvents", "carParams"], + subs=["controlsState", "carState", "carControl", "carOutput", "sendcan", "onroadEvents", "carParams"], ignore=["logMonoTime", "controlsState.startMonoTime", "controlsState.cumLagMs"], config_callback=controlsd_config_callback, init_callback=controlsd_fingerprint_callback, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 3fc6acc3c..2af30b5b4 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f1ecdf9048fb12e289baf4933cb3ef12e486252c +cc4e23ca0fceb300a3048c187ae9bc793794c095 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 7a482c1bd..b3dcbb03d 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -41,23 +41,23 @@ source_segments = [ ] segments = [ - ("BODY", "regen997DF2697CB|2023-10-30--23-14-29--0"), - ("HYUNDAI", "regen2A9D2A8E0B4|2023-10-30--23-13-34--0"), - ("HYUNDAI2", "regen6CA24BC3035|2023-10-30--23-14-28--0"), - ("TOYOTA", "regen5C019D76307|2023-10-30--23-13-31--0"), - ("TOYOTA2", "regen5DCADA88A96|2023-10-30--23-14-57--0"), - ("TOYOTA3", "regen7204CA3A498|2023-10-30--23-15-55--0"), - ("HONDA", "regen048F8FA0B24|2023-10-30--23-15-53--0"), - ("HONDA2", "regen7D2D3F82D5B|2023-10-30--23-15-55--0"), - ("CHRYSLER", "regen7125C42780C|2023-10-30--23-16-21--0"), - ("RAM", "regen2731F3213D2|2023-10-30--23-18-11--0"), - ("SUBARU", "regen86E4C1B4DDD|2023-10-30--23-18-14--0"), - ("GM", "regenF6393D64745|2023-10-30--23-17-18--0"), - ("GM2", "regen220F830C05B|2023-10-30--23-18-39--0"), - ("NISSAN", "regen4F671F7C435|2023-10-30--23-18-40--0"), - ("VOLKSWAGEN", "regen8BDFE7307A0|2023-10-30--23-19-36--0"), - ("MAZDA", "regen2E9F1A15FD5|2023-10-30--23-20-36--0"), - ("FORD", "regen6D39E54606E|2023-10-30--23-20-54--0"), + ("BODY", "regen02ECB79BACC|2024-05-18--04-29-29--0"), + ("HYUNDAI", "regen845DC1916E6|2024-05-18--04-30-52--0"), + ("HYUNDAI2", "regenBAE0915FE22|2024-05-18--04-33-11--0"), + ("TOYOTA", "regen1108D19FC2E|2024-05-18--04-34-34--0"), + ("TOYOTA2", "regen846521F39C7|2024-05-18--04-35-58--0"), + ("TOYOTA3", "regen788C3623D11|2024-05-18--04-38-21--0"), + ("HONDA", "regenDE43F170E99|2024-05-18--04-39-47--0"), + ("HONDA2", "regen1EE0FA383C3|2024-05-18--04-41-12--0"), + ("CHRYSLER", "regen9C5A30F471C|2024-05-18--04-42-36--0"), + ("RAM", "regenCCA313D117D|2024-05-18--04-44-53--0"), + ("SUBARU", "regenA41511F882A|2024-05-18--04-47-14--0"), + ("GM", "regen9D7B9CE4A66|2024-05-18--04-48-36--0"), + ("GM2", "regen07CECA52D41|2024-05-18--04-50-55--0"), + ("NISSAN", "regen2D6B856D0AE|2024-05-18--04-52-17--0"), + ("VOLKSWAGEN", "regen2D3AC6A6F05|2024-05-18--04-53-41--0"), + ("MAZDA", "regen0D5A777DD16|2024-05-18--04-56-02--0"), + ("FORD", "regen235D0937965|2024-05-18--04-58-16--0"), ] # dashcamOnly makes don't need to be tested until a full port is done @@ -107,11 +107,9 @@ def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=Non # check to make sure openpilot is engaged in the route if cfg.proc_name == "controlsd": if not check_openpilot_enabled(log_msgs): - # FIXME: these segments should work, but the replay enabling logic is too brittle - if segment not in ("regen6CA24BC3035|2023-10-30--23-14-28--0", "regen7D2D3F82D5B|2023-10-30--23-15-55--0"): - return f"Route did not enable at all or for long enough: {new_log_path}", log_msgs + return f"Route did not enable at all or for long enough: {new_log_path}", log_msgs - if cfg.proc_name != 'ubloxd' or segment != 'regen6CA24BC3035|2023-10-30--23-14-28--0': + if cfg.proc_name != 'ubloxd' or segment != 'regenBAE0915FE22|2024-05-18--04-33-11--0': seen_msgs = {m.which() for m in log_msgs} expected_msgs = set(cfg.subs) if seen_msgs != expected_msgs: From 09f2077f587e9c3abfb1cc1d9420dcb6d452938e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 19 May 2024 12:39:29 -0500 Subject: [PATCH 029/220] [bot] Fingerprints: add missing FW versions from new users (#32477) Export fingerprints --- selfdrive/car/honda/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/honda/fingerprints.py b/selfdrive/car/honda/fingerprints.py index 052b4b60a..4d70c2c35 100644 --- a/selfdrive/car/honda/fingerprints.py +++ b/selfdrive/car/honda/fingerprints.py @@ -882,6 +882,7 @@ FW_VERSIONS = { b'37805-5YF-A430\x00\x00', b'37805-5YF-A750\x00\x00', b'37805-5YF-A760\x00\x00', + b'37805-5YF-A770\x00\x00', b'37805-5YF-A850\x00\x00', b'37805-5YF-A860\x00\x00', b'37805-5YF-A870\x00\x00', From 833316835aedaf259e6d6333a1be57cc31dce360 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 May 2024 11:48:51 -0500 Subject: [PATCH 030/220] [bot] Fingerprints: add missing FW versions from new users (#32486) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 95565ebf9..a5b81650e 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -68,6 +68,7 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'68267018AO ', b'68267020AJ ', + b'68303534AG ', b'68303534AJ ', b'68340762AD ', b'68340764AD ', @@ -106,6 +107,7 @@ FW_VERSIONS = { b'68405565AB', b'68405565AC', b'68444299AC', + b'68480707AC', b'68480708AC', b'68526663AB', ], @@ -147,6 +149,7 @@ FW_VERSIONS = { b'68443120AE ', b'68443123AC ', b'68443125AC ', + b'68496647AI ', b'68496647AJ ', b'68496650AH ', b'68496650AI ', From f3f22a56980d7a3fb2cd7c07fec8ac0e9e376a38 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Mon, 20 May 2024 17:41:31 -0400 Subject: [PATCH 031/220] CI/simulator: Fix metadrive test `pyopencl.CompilerWarning` (#32487) * add pytest.mark.filterwarnings * remove -W pyopencl.CompilerWarning * add comment --- .github/workflows/tools_tests.yaml | 2 +- tools/sim/tests/test_metadrive_bridge.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 4466260af..c2e900fb1 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -59,7 +59,7 @@ jobs: ${{ env.RUN }} "export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' && \ source selfdrive/test/setup_xvfb.sh && \ source selfdrive/test/setup_vsound.sh && \ - CI=1 pytest tools/sim/tests/test_metadrive_bridge.py -W ignore::pyopencl.CompilerWarning" + CI=1 pytest tools/sim/tests/test_metadrive_bridge.py" devcontainer: name: devcontainer diff --git a/tools/sim/tests/test_metadrive_bridge.py b/tools/sim/tests/test_metadrive_bridge.py index b53f4524a..37bae6378 100755 --- a/tools/sim/tests/test_metadrive_bridge.py +++ b/tools/sim/tests/test_metadrive_bridge.py @@ -8,6 +8,7 @@ from openpilot.tools.sim.bridge.metadrive.metadrive_bridge import MetaDriveBridg from openpilot.tools.sim.tests.test_sim_bridge import TestSimBridgeBase @pytest.mark.slow +@pytest.mark.filterwarnings("ignore::pyopencl.CompilerWarning") # Unimportant warning of non-empty compile log class TestMetaDriveBridge(TestSimBridgeBase): def create_bridge(self): return MetaDriveBridge(False, False) From 3279dbeff7d4f696804c94de1573be2b5f3f2f9d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 14:59:43 -0700 Subject: [PATCH 032/220] athena: move to system/ (#32488) * athena: move to system/ * slash --- pyproject.toml | 2 +- release/files_common | 8 ++++---- selfdrive/manager/manager.py | 2 +- selfdrive/manager/process_config.py | 2 +- selfdrive/sentry.py | 2 +- {selfdrive => system}/athena/__init__.py | 0 {selfdrive => system}/athena/athenad.py | 0 {selfdrive => system}/athena/manage_athenad.py | 2 +- {selfdrive => system}/athena/registration.py | 0 {selfdrive => system}/athena/tests/__init__.py | 0 {selfdrive => system}/athena/tests/helpers.py | 0 {selfdrive => system}/athena/tests/test_athenad.py | 8 ++++---- .../athena/tests/test_athenad_ping.py | 4 ++-- .../athena/tests/test_registration.py | 12 ++++++------ 14 files changed, 21 insertions(+), 21 deletions(-) rename {selfdrive => system}/athena/__init__.py (100%) rename {selfdrive => system}/athena/athenad.py (100%) rename {selfdrive => system}/athena/manage_athenad.py (92%) rename {selfdrive => system}/athena/registration.py (100%) rename {selfdrive => system}/athena/tests/__init__.py (100%) rename {selfdrive => system}/athena/tests/helpers.py (100%) rename {selfdrive => system}/athena/tests/test_athenad.py (97%) rename {selfdrive => system}/athena/tests/test_athenad_ping.py (95%) rename {selfdrive => system}/athena/tests/test_registration.py (80%) diff --git a/pyproject.toml b/pyproject.toml index 544f9ee18..2578d0a85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ markers = [ ] testpaths = [ "common", - "selfdrive/athena", "selfdrive/boardd", "selfdrive/car", "selfdrive/controls", @@ -31,6 +30,7 @@ testpaths = [ "selfdrive/test/longitudinal_maneuvers", "selfdrive/test/process_replay/test_fuzzy.py", "selfdrive/updated", + "system/athena", "system/camerad", "system/hardware/tici", "system/loggerd", diff --git a/release/files_common b/release/files_common index 34d8f0097..7dfccceb8 100644 --- a/release/files_common +++ b/release/files_common @@ -65,10 +65,10 @@ system/version.py selfdrive/SConscript -selfdrive/athena/__init__.py -selfdrive/athena/athenad.py -selfdrive/athena/manage_athenad.py -selfdrive/athena/registration.py +system/athena/__init__.py +system/athena/athenad.py +system/athena/manage_athenad.py +system/athena/registration.py selfdrive/boardd/.gitignore selfdrive/boardd/SConscript diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 512320a8d..33c9ce9f5 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -14,7 +14,7 @@ from openpilot.system.hardware import HARDWARE, PC from openpilot.selfdrive.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog from openpilot.selfdrive.manager.process import ensure_running from openpilot.selfdrive.manager.process_config import managed_processes -from openpilot.selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID +from openpilot.system.athena.registration import register, UNREGISTERED_DONGLE_ID from openpilot.common.swaglog import cloudlog, add_file_handler from openpilot.system.version import get_build_metadata, terms_version, training_version diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 4c34e7339..5a501c216 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -42,7 +42,7 @@ def only_offroad(started, params, CP: car.CarParams) -> bool: return not started procs = [ - DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"), + DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"), NativeProcess("camerad", "system/camerad", ["./camerad"], driverview), NativeProcess("logcatd", "system/logcatd", ["./logcatd"], only_onroad), diff --git a/selfdrive/sentry.py b/selfdrive/sentry.py index 204d9cab0..5f4772fa7 100644 --- a/selfdrive/sentry.py +++ b/selfdrive/sentry.py @@ -4,7 +4,7 @@ from enum import Enum from sentry_sdk.integrations.threading import ThreadingIntegration from openpilot.common.params import Params -from openpilot.selfdrive.athena.registration import is_registered_device +from openpilot.system.athena.registration import is_registered_device from openpilot.system.hardware import HARDWARE, PC from openpilot.common.swaglog import cloudlog from openpilot.system.version import get_build_metadata, get_version diff --git a/selfdrive/athena/__init__.py b/system/athena/__init__.py similarity index 100% rename from selfdrive/athena/__init__.py rename to system/athena/__init__.py diff --git a/selfdrive/athena/athenad.py b/system/athena/athenad.py similarity index 100% rename from selfdrive/athena/athenad.py rename to system/athena/athenad.py diff --git a/selfdrive/athena/manage_athenad.py b/system/athena/manage_athenad.py similarity index 92% rename from selfdrive/athena/manage_athenad.py rename to system/athena/manage_athenad.py index 2ec92cc3e..853a7cd95 100755 --- a/selfdrive/athena/manage_athenad.py +++ b/system/athena/manage_athenad.py @@ -28,7 +28,7 @@ def main(): try: while 1: cloudlog.info("starting athena daemon") - proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad', 'athenad')) + proc = Process(name='athenad', target=launcher, args=('system.athena.athenad', 'athenad')) proc.start() proc.join() cloudlog.event("athenad exited", exitcode=proc.exitcode) diff --git a/selfdrive/athena/registration.py b/system/athena/registration.py similarity index 100% rename from selfdrive/athena/registration.py rename to system/athena/registration.py diff --git a/selfdrive/athena/tests/__init__.py b/system/athena/tests/__init__.py similarity index 100% rename from selfdrive/athena/tests/__init__.py rename to system/athena/tests/__init__.py diff --git a/selfdrive/athena/tests/helpers.py b/system/athena/tests/helpers.py similarity index 100% rename from selfdrive/athena/tests/helpers.py rename to system/athena/tests/helpers.py diff --git a/selfdrive/athena/tests/test_athenad.py b/system/athena/tests/test_athenad.py similarity index 97% rename from selfdrive/athena/tests/test_athenad.py rename to system/athena/tests/test_athenad.py index bdce3dcce..895cd8eb5 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/system/athena/tests/test_athenad.py @@ -19,9 +19,9 @@ from cereal import messaging from openpilot.common.params import Params from openpilot.common.timeout import Timeout -from openpilot.selfdrive.athena import athenad -from openpilot.selfdrive.athena.athenad import MAX_RETRY_COUNT, dispatcher -from openpilot.selfdrive.athena.tests.helpers import HTTPRequestHandler, MockWebsocket, MockApi, EchoSocket +from openpilot.system.athena import athenad +from openpilot.system.athena.athenad import MAX_RETRY_COUNT, dispatcher +from openpilot.system.athena.tests.helpers import HTTPRequestHandler, MockWebsocket, MockApi, EchoSocket from openpilot.selfdrive.test.helpers import http_server_context from openpilot.system.hardware.hw import Paths @@ -50,7 +50,7 @@ def with_upload_handler(func): @pytest.fixture def mock_create_connection(mocker): - return mocker.patch('openpilot.selfdrive.athena.athenad.create_connection') + return mocker.patch('openpilot.system.athena.athenad.create_connection') @pytest.fixture def host(): diff --git a/selfdrive/athena/tests/test_athenad_ping.py b/system/athena/tests/test_athenad_ping.py similarity index 95% rename from selfdrive/athena/tests/test_athenad_ping.py rename to system/athena/tests/test_athenad_ping.py index 44fa0b848..3152ca427 100755 --- a/selfdrive/athena/tests/test_athenad_ping.py +++ b/system/athena/tests/test_athenad_ping.py @@ -7,7 +7,7 @@ from typing import cast from openpilot.common.params import Params from openpilot.common.timeout import Timeout -from openpilot.selfdrive.athena import athenad +from openpilot.system.athena import athenad from openpilot.selfdrive.manager.helpers import write_onroad_params from openpilot.system.hardware import TICI @@ -59,7 +59,7 @@ class TestAthenadPing: def assertTimeout(self, reconnect_time: float, subtests, mocker) -> None: self.athenad.start() - mock_create_connection = mocker.patch('openpilot.selfdrive.athena.athenad.create_connection', + mock_create_connection = mocker.patch('openpilot.system.athena.athenad.create_connection', new_callable=lambda: mocker.MagicMock(wraps=athenad.create_connection)) time.sleep(1) diff --git a/selfdrive/athena/tests/test_registration.py b/system/athena/tests/test_registration.py similarity index 80% rename from selfdrive/athena/tests/test_registration.py rename to system/athena/tests/test_registration.py index a808dd566..85c065c1b 100755 --- a/selfdrive/athena/tests/test_registration.py +++ b/system/athena/tests/test_registration.py @@ -4,8 +4,8 @@ from Crypto.PublicKey import RSA from pathlib import Path from openpilot.common.params import Params -from openpilot.selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID -from openpilot.selfdrive.athena.tests.helpers import MockResponse +from openpilot.system.athena.registration import register, UNREGISTERED_DONGLE_ID +from openpilot.system.athena.tests.helpers import MockResponse from openpilot.system.hardware.hw import Paths @@ -36,7 +36,7 @@ class TestRegistration: self.params.put("HardwareSerial", "serial") self._generate_keys() - m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) + m = mocker.patch("openpilot.system.athena.registration.api_get", autospec=True) dongle = "DONGLE_ID_123" self.params.put("DongleId", dongle) assert register() == dongle @@ -44,7 +44,7 @@ class TestRegistration: def test_no_keys(self, mocker): # missing pubkey - m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) + m = mocker.patch("openpilot.system.athena.registration.api_get", autospec=True) dongle = register() assert m.call_count == 0 assert dongle == UNREGISTERED_DONGLE_ID @@ -53,7 +53,7 @@ class TestRegistration: def test_missing_cache(self, mocker): # keys exist but no dongle id self._generate_keys() - m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) + m = mocker.patch("openpilot.system.athena.registration.api_get", autospec=True) dongle = "DONGLE_ID_123" m.return_value = MockResponse(json.dumps({'dongle_id': dongle}), 200) assert register() == dongle @@ -67,7 +67,7 @@ class TestRegistration: def test_unregistered(self, mocker): # keys exist, but unregistered self._generate_keys() - m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True) + m = mocker.patch("openpilot.system.athena.registration.api_get", autospec=True) m.return_value = MockResponse(None, 402) dongle = register() assert m.call_count == 1 From 19c8e72c7494307c311fd2fc0cdb229e89a7ed0e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 15:50:54 -0700 Subject: [PATCH 033/220] Update BOUNTIES.md --- docs/BOUNTIES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/BOUNTIES.md b/docs/BOUNTIES.md index 7e7ee3b8d..9d0718c57 100644 --- a/docs/BOUNTIES.md +++ b/docs/BOUNTIES.md @@ -9,6 +9,7 @@ Get paid to improve openpilot! * once you open a PR, the bounty is locked to you until you stop working on it * open a ticket at [comma.ai/support](https://comma.ai/support/shop-order) with links to your PRs to claim * get an extra 20% if you redeem your bounty in [comma shop](https://comma.ai/shop) credit (including refunds on previous orders) +* for bounties >$100, the first PR gets a lock, which times out after a week of no progress We put up each bounty with the intention that it'll get merged, but occasionally the right resolution is to close the bounty, which only becomes clear once some effort is put in. This is still valuable work, so we'll pay out $100 for getting any bounty closed with a good explanation. From 332542fad842a4d12ef289c89d5e8a8709c3c7a7 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 16:01:17 -0700 Subject: [PATCH 034/220] cleanup old ignore paths --- .gitignore | 4 ---- .pre-commit-config.yaml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 98fc70d02..693c532c5 100644 --- a/.gitignore +++ b/.gitignore @@ -55,12 +55,8 @@ selfdrive/modeld/_modeld selfdrive/modeld/_dmonitoringmodeld /src/ -one notebooks -xx -yy hyperthneed -panda_jungle provisioning .coverage* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 692c69456..c08ab1d5d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -47,7 +47,7 @@ repos: args: - --local-partial-types - --explicit-package-bases - exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(xx/)' + exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' - repo: local hooks: - id: cppcheck From af991b143ae4b89a15217cee77fcf8e93ec2508f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 16:46:34 -0700 Subject: [PATCH 035/220] fix pre-commit warning --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c08ab1d5d..190425285 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -89,7 +89,7 @@ repos: entry: selfdrive/ui/tests/test_translations.py language: script pass_filenames: false - files: 'selfdrive/ui/translations/*' + files: '^selfdrive/ui/translations/' - repo: https://github.com/python-poetry/poetry rev: '1.8.0' hooks: From e0fa26b1a44bf54388392d54c8437459d870d78c Mon Sep 17 00:00:00 2001 From: macdoos <127897805+macdoos@users.noreply.github.com> Date: Tue, 21 May 2024 02:35:33 +0200 Subject: [PATCH 036/220] split out dev apt dependencies (#32476) * init * add more extra packages * update Dockerfile * cleanup * Update Dockerfile.openpilot_base * needed to build --------- Co-authored-by: Adeeb Shihadeh --- Dockerfile.openpilot_base | 12 ++++------ tools/install_ubuntu_dependencies.sh | 35 +++++++++++++++++++++------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index a6c4c7179..0789a39c3 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -13,14 +13,10 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 COPY tools/install_ubuntu_dependencies.sh /tmp/tools/ -RUN cd /tmp && \ - tools/install_ubuntu_dependencies.sh && \ - rm -rf /var/lib/apt/lists/* && \ - rm -rf /tmp/* && \ - # remove unused architectures from gcc for panda +RUN INSTALL_EXTRA_PACKAGES=no /tmp/tools/install_ubuntu_dependencies.sh && \ + rm -rf /var/lib/apt/lists/* /tmp/* && \ cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \ - rm -rf arm/ && \ - rm -rf thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp + rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp # Add OpenCL RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -83,4 +79,4 @@ RUN cd /tmp && \ rm -rf /home/$USER/pyenv/versions/3.11.4/lib/python3.11/test USER root -RUN sudo git config --global --add safe.directory /tmp/openpilot \ No newline at end of file +RUN sudo git config --global --add safe.directory /tmp/openpilot diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 72402b3bf..7abfbf51c 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -12,21 +12,17 @@ if [[ ! $(id -u) -eq 0 ]]; then SUDO="sudo" fi -# Install packages present in all supported versions of Ubuntu +# Install common packages function install_ubuntu_common_requirements() { $SUDO apt-get update $SUDO apt-get install -y --no-install-recommends \ autoconf \ build-essential \ ca-certificates \ - casync \ clang \ - cmake \ - make \ cppcheck \ libtool \ gcc-arm-none-eabi \ - bzip2 \ liblzma-dev \ libarchive-dev \ libbz2-dev \ @@ -62,9 +58,7 @@ function install_ubuntu_common_requirements() { opencl-headers \ ocl-icd-libopencl1 \ ocl-icd-opencl-dev \ - clinfo \ portaudio19-dev \ - qml-module-qtquick2 \ qtmultimedia5-dev \ qtlocation5-dev \ qtpositioning5-dev \ @@ -75,7 +69,18 @@ function install_ubuntu_common_requirements() { libqt5serialbus5-dev \ libqt5x11extras5-dev \ libqt5opengl5-dev \ - libreadline-dev \ + libreadline-dev +} + +# Install extra packages +function install_extra_packages() { + echo "Installing extra packages..." + $SUDO apt-get install -y --no-install-recommends \ + bzip2 \ + clinfo \ + casync \ + cmake \ + make \ libdw1 } @@ -125,7 +130,19 @@ if [ -f "/etc/os-release" ]; then install_ubuntu_lts_latest_requirements fi esac + + # Install extra packages + if [[ -z "$INSTALL_EXTRA_PACKAGES" ]]; then + read -p "Base setup done. Do you want to install extra development packages? [Y/n]: " -n 1 -r + echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + INSTALL_EXTRA_PACKAGES="yes" + fi + fi + if [[ "$INSTALL_EXTRA_PACKAGES" == "yes" ]]; then + install_extra_packages + fi else - echo "No /etc/os-release in the system" + echo "No /etc/os-release in the system. Make sure you're running on Ubuntu, or similar." exit 1 fi From 1ea2411575a04176637856af5ce54aae01b1cd8e Mon Sep 17 00:00:00 2001 From: LostEon <86137295+LostEon@users.noreply.github.com> Date: Mon, 20 May 2024 18:38:47 -0600 Subject: [PATCH 037/220] Fingerprint 2016 Jeep Grand Cherokee (#32491) * Fingerprint 2016 Grand Cherokee * sort --------- Co-authored-by: Shane Smiskol --- selfdrive/car/chrysler/fingerprints.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index a5b81650e..b974d3dd4 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -267,6 +267,7 @@ FW_VERSIONS = { }, CAR.JEEP_GRAND_CHEROKEE: { (Ecu.combinationMeter, 0x742, None): [ + b'68243549AG', b'68302211AC', b'68302212AD', b'68302223AC', @@ -278,18 +279,22 @@ FW_VERSIONS = { b'68340272AD', ], (Ecu.srs, 0x744, None): [ + b'68309533AA', b'68316742AB', b'68355363AB', ], (Ecu.abs, 0x747, None): [ + b'68252642AG', b'68306178AD', b'68336276AB', ], (Ecu.fwdRadar, 0x753, None): [ b'04672627AB', + b'68251506AF', b'68332015AB', ], (Ecu.eps, 0x75a, None): [ + b'68276201AG', b'68321644AB', b'68321644AC', b'68321646AC', @@ -297,6 +302,7 @@ FW_VERSIONS = { ], (Ecu.engine, 0x7e0, None): [ b'05035920AE ', + b'68252272AG ', b'68284455AI ', b'68284456AI ', b'68284477AF ', @@ -307,6 +313,7 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x7e1, None): [ b'05035517AH', + b'68253222AF', b'68311218AC', b'68311223AF', b'68311223AG', From 788c4edeecc0f35d8c74f486f664c1835098cdf4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 17:40:46 -0700 Subject: [PATCH 038/220] ruff: enable NPY --- pyproject.toml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2578d0a85..e445df047 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -184,8 +184,16 @@ build-backend = "poetry.core.masonry.api" # https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml [tool.ruff] indent-width = 2 -lint.select = ["E", "F", "W", "PIE", "C4", "ISC", "RUF008", "RUF100", "A", "B", "TID251"] -lint.ignore = ["E741", "E402", "C408", "ISC003", "B027", "B024"] +lint.select = ["E", "F", "W", "PIE", "C4", "ISC", "NPY", "RUF008", "RUF100", "A", "B", "TID251"] +lint.ignore = [ + "E741", + "E402", + "C408", + "ISC003", + "B027", + "B024", + "NPY002", # new numpy random syntax is worse +] line-length = 160 target-version="py311" exclude = [ From b2e4c64cf8fe3256d1e411e8715c29e2eb6f4f00 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 17:43:54 -0700 Subject: [PATCH 039/220] ruff: enable UP --- common/api/__init__.py | 2 +- common/gpio.py | 4 ++-- common/spinner.py | 2 +- common/stat_live.py | 4 ++-- pyproject.toml | 3 ++- selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py | 2 +- selfdrive/controls/lib/pid.py | 2 +- selfdrive/controls/radard.py | 4 ++-- selfdrive/controls/tests/test_following_distance.py | 2 +- selfdrive/debug/vw_mqb_config.py | 2 +- selfdrive/locationd/models/car_kf.py | 2 +- selfdrive/locationd/models/live_kf.py | 4 ++-- selfdrive/modeld/modeld.py | 5 ++--- selfdrive/monitoring/driver_monitor.py | 8 ++++---- selfdrive/statsd.py | 4 ++-- selfdrive/test/longitudinal_maneuvers/plant.py | 2 +- selfdrive/test/process_replay/test_imgproc.py | 4 ++-- selfdrive/test/profiling/lib.py | 4 ++-- system/athena/tests/helpers.py | 6 +++--- system/loggerd/tests/loggerd_tests_common.py | 6 +++--- system/ubloxd/pigeond.py | 2 +- system/updated/casync/tar.py | 3 ++- system/version.py | 2 +- system/webrtc/tests/test_webrtcd.py | 2 +- tools/lib/api.py | 2 +- 25 files changed, 42 insertions(+), 41 deletions(-) diff --git a/common/api/__init__.py b/common/api/__init__.py index 79875023a..f3a7d8384 100644 --- a/common/api/__init__.py +++ b/common/api/__init__.py @@ -7,7 +7,7 @@ from openpilot.system.version import get_version API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com') -class Api(): +class Api: def __init__(self, dongle_id): self.dongle_id = dongle_id with open(Paths.persist_root()+'/comma/id_rsa') as f: diff --git a/common/gpio.py b/common/gpio.py index 68932cb87..66b2adf43 100644 --- a/common/gpio.py +++ b/common/gpio.py @@ -1,5 +1,5 @@ import os -from functools import lru_cache +from functools import cache def gpio_init(pin: int, output: bool) -> None: try: @@ -35,7 +35,7 @@ def gpio_export(pin: int) -> None: except Exception: print(f"Failed to export gpio {pin}") -@lru_cache(maxsize=None) +@cache def get_irq_action(irq: int) -> list[str]: try: with open(f"/sys/kernel/irq/{irq}/actions") as f: diff --git a/common/spinner.py b/common/spinner.py index 43d4bb2cc..dcf22641c 100644 --- a/common/spinner.py +++ b/common/spinner.py @@ -3,7 +3,7 @@ import subprocess from openpilot.common.basedir import BASEDIR -class Spinner(): +class Spinner: def __init__(self): try: self.spinner_proc = subprocess.Popen(["./spinner"], diff --git a/common/stat_live.py b/common/stat_live.py index a91c1819b..3901c448d 100644 --- a/common/stat_live.py +++ b/common/stat_live.py @@ -1,6 +1,6 @@ import numpy as np -class RunningStat(): +class RunningStat: # tracks realtime mean and standard deviation without storing any data def __init__(self, priors=None, max_trackable=-1): self.max_trackable = max_trackable @@ -51,7 +51,7 @@ class RunningStat(): def params_to_save(self): return [self.M, self.S, self.n] -class RunningStatFilter(): +class RunningStatFilter: def __init__(self, raw_priors=None, filtered_priors=None, max_trackable=-1): self.raw_stat = RunningStat(raw_priors, -1) self.filtered_stat = RunningStat(filtered_priors, max_trackable) diff --git a/pyproject.toml b/pyproject.toml index e445df047..ce3cf4b6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -184,7 +184,7 @@ build-backend = "poetry.core.masonry.api" # https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml [tool.ruff] indent-width = 2 -lint.select = ["E", "F", "W", "PIE", "C4", "ISC", "NPY", "RUF008", "RUF100", "A", "B", "TID251"] +lint.select = ["E", "F", "W", "PIE", "C4", "ISC", "NPY", "UP", "RUF008", "RUF100", "A", "B", "TID251"] lint.ignore = [ "E741", "E402", @@ -193,6 +193,7 @@ lint.ignore = [ "B027", "B024", "NPY002", # new numpy random syntax is worse + "UP038", # (x, y) -> x|y for isinstance ] line-length = 160 target-version="py311" diff --git a/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py b/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py index 83ec3b3a1..ad6086108 100755 --- a/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py +++ b/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py @@ -128,7 +128,7 @@ def gen_lat_ocp(): return ocp -class LateralMpc(): +class LateralMpc: def __init__(self, x0=None): if x0 is None: x0 = np.zeros(X_DIM) diff --git a/selfdrive/controls/lib/pid.py b/selfdrive/controls/lib/pid.py index f4ec7e599..29c4d8bd4 100644 --- a/selfdrive/controls/lib/pid.py +++ b/selfdrive/controls/lib/pid.py @@ -4,7 +4,7 @@ from numbers import Number from openpilot.common.numpy_fast import clip, interp -class PIDController(): +class PIDController: def __init__(self, k_p, k_i, k_f=0., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100): self._k_p = k_p self._k_i = k_i diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 16c9e0635..7420f666f 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -2,7 +2,7 @@ import importlib import math from collections import deque -from typing import Any, Optional +from typing import Any import capnp from cereal import messaging, log, car @@ -208,7 +208,7 @@ class RadarD: self.ready = False - def update(self, sm: messaging.SubMaster, rr: Optional[car.RadarData]): + def update(self, sm: messaging.SubMaster, rr): self.ready = sm.seen['modelV2'] self.current_time = 1e-9*max(sm.logMonoTime.values()) diff --git a/selfdrive/controls/tests/test_following_distance.py b/selfdrive/controls/tests/test_following_distance.py index 5d6091180..89a575a9a 100755 --- a/selfdrive/controls/tests/test_following_distance.py +++ b/selfdrive/controls/tests/test_following_distance.py @@ -32,7 +32,7 @@ def run_following_distance_simulation(v_lead, t_end=100.0, e2e=False, personalit log.LongitudinalPersonality.standard, log.LongitudinalPersonality.aggressive], [0,10,35])) # speed -class TestFollowingDistance(): +class TestFollowingDistance: def test_following_distance(self): v_lead = float(self.speed) simulation_steady_state = run_following_distance_simulation(v_lead, e2e=self.e2e, personality=self.personality) diff --git a/selfdrive/debug/vw_mqb_config.py b/selfdrive/debug/vw_mqb_config.py index 64bc2bc63..6df1e57ce 100755 --- a/selfdrive/debug/vw_mqb_config.py +++ b/selfdrive/debug/vw_mqb_config.py @@ -139,7 +139,7 @@ if __name__ == "__main__": # so fib a little and say that same tester did the programming current_date = date.today() formatted_date = current_date.strftime('%y-%m-%d') - year, month, day = [int(part) for part in formatted_date.split('-')] + year, month, day = (int(part) for part in formatted_date.split('-')) prog_date = bytes([year, month, day]) uds_client.write_data_by_identifier(DATA_IDENTIFIER_TYPE.PROGRAMMING_DATE, prog_date) tester_num = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.CALIBRATION_REPAIR_SHOP_CODE_OR_CALIBRATION_EQUIPMENT_SERIAL_NUMBER) diff --git a/selfdrive/locationd/models/car_kf.py b/selfdrive/locationd/models/car_kf.py index 1f3e447a1..87a93cdd0 100755 --- a/selfdrive/locationd/models/car_kf.py +++ b/selfdrive/locationd/models/car_kf.py @@ -28,7 +28,7 @@ def _slice(n): return s -class States(): +class States: # Vehicle model params STIFFNESS = _slice(1) # [-] STEER_RATIO = _slice(1) # [-] diff --git a/selfdrive/locationd/models/live_kf.py b/selfdrive/locationd/models/live_kf.py index c4933a612..0cc3eca61 100755 --- a/selfdrive/locationd/models/live_kf.py +++ b/selfdrive/locationd/models/live_kf.py @@ -20,7 +20,7 @@ def numpy2eigenstring(arr): return f"(Eigen::VectorXd({len(arr)}) << {arr_str}).finished()" -class States(): +class States: ECEF_POS = slice(0, 3) # x, y and z in ECEF in meters ECEF_ORIENTATION = slice(3, 7) # quat for pose of phone in ecef ECEF_VELOCITY = slice(7, 10) # ecef velocity in m/s @@ -39,7 +39,7 @@ class States(): ACC_BIAS_ERR = slice(18, 21) -class LiveKalman(): +class LiveKalman: name = 'live' initial_x = np.array([3.88e6, -3.37e6, 3.76e6, diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 35e2a29aa..66563a3c1 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -206,9 +206,8 @@ def main(demo=False): continue if abs(meta_main.timestamp_sof - meta_extra.timestamp_sof) > 10000000: - cloudlog.error("frames out of sync! main: {} ({:.5f}), extra: {} ({:.5f})".format( - meta_main.frame_id, meta_main.timestamp_sof / 1e9, - meta_extra.frame_id, meta_extra.timestamp_sof / 1e9)) + cloudlog.error(f"frames out of sync! main: {meta_main.frame_id} ({meta_main.timestamp_sof / 1e9:.5f}),\ + extra: {meta_extra.frame_id} ({meta_extra.timestamp_sof / 1e9:.5f})") else: # Use single camera diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py index 9faa5f4d0..85cc19eb8 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -15,7 +15,7 @@ EventName = car.CarEvent.EventName # We recommend that you do not change these numbers from the defaults. # ****************************************************************************************** -class DRIVER_MONITOR_SETTINGS(): +class DRIVER_MONITOR_SETTINGS: def __init__(self): self._DT_DMON = DT_DMON # ref (page15-16): https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:42018X1947&rid=2 @@ -102,7 +102,7 @@ def face_orientation_from_net(angles_desc, pos_desc, rpy_calib): yaw -= rpy_calib[2] return roll_net, pitch, yaw -class DriverPose(): +class DriverPose: def __init__(self, max_trackable): self.yaw = 0. self.pitch = 0. @@ -116,12 +116,12 @@ class DriverPose(): self.cfactor_pitch = 1. self.cfactor_yaw = 1. -class DriverBlink(): +class DriverBlink: def __init__(self): self.left_blink = 0. self.right_blink = 0. -class DriverStatus(): +class DriverStatus: def __init__(self, rhd_saved=False, settings=None, always_on=False): if settings is None: settings = DRIVER_MONITOR_SETTINGS() diff --git a/selfdrive/statsd.py b/selfdrive/statsd.py index 2f9149b09..2b5a7bb3a 100755 --- a/selfdrive/statsd.py +++ b/selfdrive/statsd.py @@ -4,7 +4,7 @@ import zmq import time from pathlib import Path from collections import defaultdict -from datetime import datetime, timezone +from datetime import datetime, UTC from typing import NoReturn from openpilot.common.params import Params @@ -133,7 +133,7 @@ def main() -> NoReturn: # flush when started state changes or after FLUSH_TIME_S if (time.monotonic() > last_flush_time + STATS_FLUSH_TIME_S) or (sm['deviceState'].started != started_prev): result = "" - current_time = datetime.utcnow().replace(tzinfo=timezone.utc) + current_time = datetime.utcnow().replace(tzinfo=UTC) tags['started'] = sm['deviceState'].started for key, value in gauges.items(): diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index ac54967f8..daf7cec32 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -83,7 +83,7 @@ class Plant: lead = log.RadarState.LeadData.new_message() lead.dRel = float(d_rel) - lead.yRel = float(0.0) + lead.yRel = 0.0 lead.vRel = float(v_rel) lead.aRel = float(a_lead - self.acceleration) lead.vLead = float(v_lead) diff --git a/selfdrive/test/process_replay/test_imgproc.py b/selfdrive/test/process_replay/test_imgproc.py index a980548ba..036f21b9e 100755 --- a/selfdrive/test/process_replay/test_imgproc.py +++ b/selfdrive/test/process_replay/test_imgproc.py @@ -93,7 +93,7 @@ if __name__ == "__main__": if pix_hash != ref_hash: print("result changed! please check kernel") - print("ref: %s" % ref_hash) - print("new: %s" % pix_hash) + print(f"ref: {ref_hash}") + print(f"new: {pix_hash}") else: print("test passed") diff --git a/selfdrive/test/profiling/lib.py b/selfdrive/test/profiling/lib.py index 7f3b0126f..93ba21538 100644 --- a/selfdrive/test/profiling/lib.py +++ b/selfdrive/test/profiling/lib.py @@ -8,7 +8,7 @@ class ReplayDone(Exception): pass -class SubSocket(): +class SubSocket: def __init__(self, msgs, trigger): self.i = 0 self.trigger = trigger @@ -28,7 +28,7 @@ class SubSocket(): return msg -class PubSocket(): +class PubSocket: def send(self, data): pass diff --git a/system/athena/tests/helpers.py b/system/athena/tests/helpers.py index 322e9d81d..a0a9cccdc 100644 --- a/system/athena/tests/helpers.py +++ b/system/athena/tests/helpers.py @@ -9,7 +9,7 @@ class MockResponse: self.status_code = status_code -class EchoSocket(): +class EchoSocket: def __init__(self, port): self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.bind(('127.0.0.1', port)) @@ -34,7 +34,7 @@ class EchoSocket(): self.socket.close() -class MockApi(): +class MockApi: def __init__(self, dongle_id): pass @@ -42,7 +42,7 @@ class MockApi(): return "fake-token" -class MockWebsocket(): +class MockWebsocket: sock = socket.socket() def __init__(self, recv_queue, send_queue): diff --git a/system/loggerd/tests/loggerd_tests_common.py b/system/loggerd/tests/loggerd_tests_common.py index e8a6d031c..15fd997eb 100644 --- a/system/loggerd/tests/loggerd_tests_common.py +++ b/system/loggerd/tests/loggerd_tests_common.py @@ -28,12 +28,12 @@ def create_random_file(file_path: Path, size_mb: float, lock: bool = False, uplo if upload_xattr is not None: setxattr(str(file_path), uploader.UPLOAD_ATTR_NAME, upload_xattr) -class MockResponse(): +class MockResponse: def __init__(self, text, status_code): self.text = text self.status_code = status_code -class MockApi(): +class MockApi: def __init__(self, dongle_id): pass @@ -43,7 +43,7 @@ class MockApi(): def get_token(self): return "fake-token" -class MockApiIgnore(): +class MockApiIgnore: def __init__(self, dongle_id): pass diff --git a/system/ubloxd/pigeond.py b/system/ubloxd/pigeond.py index 21b3a86f9..5711992cf 100755 --- a/system/ubloxd/pigeond.py +++ b/system/ubloxd/pigeond.py @@ -61,7 +61,7 @@ def get_assistnow_messages(token: bytes) -> list[bytes]: return msgs -class TTYPigeon(): +class TTYPigeon: def __init__(self): self.tty = serial.VTIMESerial(UBLOX_TTY, baudrate=9600, timeout=0) diff --git a/system/updated/casync/tar.py b/system/updated/casync/tar.py index 5c547e73a..a5a8238bb 100644 --- a/system/updated/casync/tar.py +++ b/system/updated/casync/tar.py @@ -1,6 +1,7 @@ import pathlib import tarfile -from typing import IO, Callable +from typing import IO +from collections.abc import Callable def include_default(_) -> bool: diff --git a/system/version.py b/system/version.py index f5b8cd49e..d258fe049 100755 --- a/system/version.py +++ b/system/version.py @@ -27,7 +27,7 @@ def get_version(path: str = BASEDIR) -> str: def get_release_notes(path: str = BASEDIR) -> str: - with open(os.path.join(path, "RELEASES.md"), "r") as f: + with open(os.path.join(path, "RELEASES.md")) as f: return f.read().split('\n\n', 1)[0] diff --git a/system/webrtc/tests/test_webrtcd.py b/system/webrtc/tests/test_webrtcd.py index 684c7cf35..b0bc7b196 100755 --- a/system/webrtc/tests/test_webrtcd.py +++ b/system/webrtc/tests/test_webrtcd.py @@ -20,7 +20,7 @@ from parameterized import parameterized_class ([], []), ]) @pytest.mark.asyncio -class TestWebrtcdProc(): +class TestWebrtcdProc: async def assertCompletesWithTimeout(self, awaitable, timeout=1): try: async with asyncio.timeout(timeout): diff --git a/tools/lib/api.py b/tools/lib/api.py index 6ff9242f2..92a75d2a3 100644 --- a/tools/lib/api.py +++ b/tools/lib/api.py @@ -2,7 +2,7 @@ import os import requests API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com') -class CommaApi(): +class CommaApi: def __init__(self, token=None): self.session = requests.Session() self.session.headers['User-agent'] = 'OpenpilotTools' From 0e3df5ae4d673c3644f04861a73e3aa599dd03ae Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 17:47:48 -0700 Subject: [PATCH 040/220] ruff: enable TRY --- pyproject.toml | 9 ++++++++- system/webrtc/webrtcd.py | 12 ++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ce3cf4b6c..2b183c983 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -184,7 +184,14 @@ build-backend = "poetry.core.masonry.api" # https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml [tool.ruff] indent-width = 2 -lint.select = ["E", "F", "W", "PIE", "C4", "ISC", "NPY", "UP", "RUF008", "RUF100", "A", "B", "TID251"] +lint.select = [ + "E", "F", "W", "PIE", "C4", "ISC", "A", "B", + "NPY", # numpy + "UP", # pyupgrade + "TRY302", "TRY400", "TRY401", # try/excepts + "RUF008", "RUF100", + "TID251" +] lint.ignore = [ "E741", "E402", diff --git a/system/webrtc/webrtcd.py b/system/webrtc/webrtcd.py index 51c86aacc..76c3cd847 100755 --- a/system/webrtc/webrtcd.py +++ b/system/webrtc/webrtcd.py @@ -97,8 +97,8 @@ class CerealProxyRunner: except InvalidStateError: self.logger.warning("Cereal outgoing proxy invalid state (connection closed)") break - except Exception as ex: - self.logger.error("Cereal outgoing proxy failure: %s", ex) + except Exception: + self.logger.exception("Cereal outgoing proxy failure") await asyncio.sleep(0.01) @@ -175,8 +175,8 @@ class StreamSession: assert self.incoming_bridge is not None try: self.incoming_bridge.send(message) - except Exception as ex: - self.logger.error("Cereal incoming proxy failure: %s", ex) + except Exception: + self.logger.exception("Cereal incoming proxy failure") async def run(self): try: @@ -200,8 +200,8 @@ class StreamSession: await self.post_run_cleanup() self.logger.info("Stream session (%s) ended", self.identifier) - except Exception as ex: - self.logger.error("Stream session failure: %s", ex) + except Exception: + self.logger.exception("Stream session failure") async def post_run_cleanup(self): await self.stream.stop() From 0678644a8f1c5292d7904ecde6e55aeb90550b52 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 21 May 2024 10:38:24 +0800 Subject: [PATCH 041/220] ui: improve `update_line_data()` (#32354) improve update_line_data --- selfdrive/ui/ui.cc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index e5309c969..c4ddd17e2 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -57,26 +57,23 @@ void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, con void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert=true) { const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ(); - QPolygonF left_points, right_points; - left_points.reserve(max_idx + 1); - right_points.reserve(max_idx + 1); - + QPointF left, right; + pvd->clear(); for (int i = 0; i <= max_idx; i++) { // highly negative x positions are drawn above the frame and cause flickering, clip to zy plane of camera if (line_x[i] < 0) continue; - QPointF left, right; + bool l = calib_frame_to_full_frame(s, line_x[i], line_y[i] - y_off, line_z[i] + z_off, &left); bool r = calib_frame_to_full_frame(s, line_x[i], line_y[i] + y_off, line_z[i] + z_off, &right); if (l && r) { // For wider lines the drawn polygon will "invert" when going over a hill and cause artifacts - if (!allow_invert && left_points.size() && left.y() > left_points.back().y()) { + if (!allow_invert && pvd->size() && left.y() > pvd->back().y()) { continue; } - left_points.push_back(left); - right_points.push_front(right); + pvd->push_back(left); + pvd->push_front(right); } } - *pvd = left_points + right_points; } void update_model(UIState *s, From 1203f5eeb363f4ccdf149d6fa1c32380c0c90027 Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Mon, 20 May 2024 20:47:53 -0700 Subject: [PATCH 042/220] minimize ubuntu deps. needed to run build openpilot (#32492) * minimize common deps list * fix * fix endline error * add portaudio3 * add build-essential * upload old loggerd deps * libqt5charts5-dev * libncurses5-dev * libbz2-dev * libsqlite3-dev --- tools/install_ubuntu_dependencies.sh | 33 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 7abfbf51c..0e3d453ce 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -16,16 +16,12 @@ fi function install_ubuntu_common_requirements() { $SUDO apt-get update $SUDO apt-get install -y --no-install-recommends \ - autoconf \ - build-essential \ ca-certificates \ clang \ cppcheck \ - libtool \ + build-essential \ gcc-arm-none-eabi \ liblzma-dev \ - libarchive-dev \ - libbz2-dev \ capnproto \ libcapnp-dev \ curl \ @@ -38,21 +34,21 @@ function install_ubuntu_common_requirements() { libavdevice-dev \ libavutil-dev \ libavfilter-dev \ + libbz2-dev \ libeigen3-dev \ libffi-dev \ libglew-dev \ libgles2-mesa-dev \ libglfw3-dev \ libglib2.0-0 \ - libncurses5-dev \ - libncursesw5-dev \ libomp-dev \ libpng16-16 \ - libportaudio2 \ + libqt5charts5-dev \ + libncurses5-dev \ libssl-dev \ - libsqlite3-dev \ libusb-1.0-0-dev \ libzmq3-dev \ + libsqlite3-dev \ libsystemd-dev \ locales \ opencl-headers \ @@ -63,25 +59,30 @@ function install_ubuntu_common_requirements() { qtlocation5-dev \ qtpositioning5-dev \ qttools5-dev-tools \ - libqt5sql5-sqlite \ libqt5svg5-dev \ - libqt5charts5-dev \ libqt5serialbus5-dev \ libqt5x11extras5-dev \ - libqt5opengl5-dev \ - libreadline-dev + libqt5opengl5-dev } # Install extra packages function install_extra_packages() { echo "Installing extra packages..." $SUDO apt-get install -y --no-install-recommends \ - bzip2 \ - clinfo \ casync \ cmake \ make \ - libdw1 + clinfo \ + libqt5sql5-sqlite \ + libreadline-dev \ + libdw1 \ + autoconf \ + libtool \ + bzip2 \ + libarchive-dev \ + libncursesw5-dev \ + libportaudio2 \ + locales } # Install Ubuntu 24.04 LTS packages From da6fd751257bcd3aa087ac4114e9f1529f7d3d12 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 22:39:25 -0700 Subject: [PATCH 043/220] move sentry/stats to system/ (#32490) * move sentry/stats to system/ * fix --- release/files_common | 7 ++++--- selfdrive/manager/manager.py | 2 +- selfdrive/manager/process.py | 2 +- selfdrive/manager/process_config.py | 4 ++-- selfdrive/modeld/modeld.py | 2 +- selfdrive/test/test_onroad.py | 4 ++-- selfdrive/thermald/power_monitoring.py | 2 +- selfdrive/thermald/thermald.py | 2 +- {selfdrive => system}/sentry.py | 0 {selfdrive => system}/statsd.py | 0 {selfdrive => system}/tombstoned.py | 2 +- 11 files changed, 14 insertions(+), 13 deletions(-) rename {selfdrive => system}/sentry.py (100%) rename {selfdrive => system}/statsd.py (100%) rename {selfdrive => system}/tombstoned.py (99%) diff --git a/release/files_common b/release/files_common index 7dfccceb8..19a93bc7d 100644 --- a/release/files_common +++ b/release/files_common @@ -53,9 +53,6 @@ tools/replay/*.cc tools/replay/*.h selfdrive/__init__.py -selfdrive/sentry.py -selfdrive/tombstoned.py -selfdrive/statsd.py selfdrive/updated/** @@ -162,6 +159,10 @@ selfdrive/controls/lib/longitudinal_mpc_lib/* system/__init__.py system/*.py +system/sentry.py +system/tombstoned.py +system/statsd.py + system/hardware/__init__.py system/hardware/base.h system/hardware/base.py diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 33c9ce9f5..408314d62 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -7,7 +7,7 @@ import traceback from cereal import log import cereal.messaging as messaging -import openpilot.selfdrive.sentry as sentry +import openpilot.system.sentry as sentry from openpilot.common.params import Params, ParamKeyType from openpilot.common.text_window import TextWindow from openpilot.system.hardware import HARDWARE, PC diff --git a/selfdrive/manager/process.py b/selfdrive/manager/process.py index 7964f5229..36f299ae6 100644 --- a/selfdrive/manager/process.py +++ b/selfdrive/manager/process.py @@ -12,7 +12,7 @@ from setproctitle import setproctitle from cereal import car, log import cereal.messaging as messaging -import openpilot.selfdrive.sentry as sentry +import openpilot.system.sentry as sentry from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params from openpilot.common.swaglog import cloudlog diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 5a501c216..5ea4b81b8 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -76,10 +76,10 @@ procs = [ PythonProcess("plannerd", "selfdrive.controls.plannerd", only_onroad), PythonProcess("radard", "selfdrive.controls.radard", only_onroad), PythonProcess("thermald", "selfdrive.thermald.thermald", always_run), - PythonProcess("tombstoned", "selfdrive.tombstoned", always_run, enabled=not PC), + PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC), PythonProcess("updated", "selfdrive.updated.updated", only_offroad, enabled=not PC), PythonProcess("uploader", "system.loggerd.uploader", always_run), - PythonProcess("statsd", "selfdrive.statsd", always_run), + PythonProcess("statsd", "system.statsd", always_run), # debug procs NativeProcess("bridge", "cereal/messaging", ["./bridge"], notcar), diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 66563a3c1..526fd4d21 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -15,7 +15,7 @@ from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.realtime import config_realtime_process from openpilot.common.transformations.camera import DEVICE_CAMERAS from openpilot.common.transformations.model import get_warp_matrix -from openpilot.selfdrive import sentry +from openpilot.system import sentry from openpilot.selfdrive.car.car_helpers import get_demo_car_params from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper from openpilot.selfdrive.modeld.runners import ModelRunner, Runtime diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 9aca9afcd..53db737fc 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -54,12 +54,12 @@ PROCS = { "selfdrive.monitoring.dmonitoringd": 4.0, "./proclogd": 1.54, "system.logmessaged": 0.2, - "selfdrive.tombstoned": 0, + "system.tombstoned": 0, "./logcatd": 0, "system.micd": 6.0, "system.timed": 0, "selfdrive.boardd.pandad": 0, - "selfdrive.statsd": 0.4, + "system.statsd": 0.4, "selfdrive.navd.navd": 0.4, "system.loggerd.uploader": (0.5, 15.0), "system.loggerd.deleter": 0.1, diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index 073589edb..5a94625b4 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -4,7 +4,7 @@ import threading from openpilot.common.params import Params from openpilot.system.hardware import HARDWARE from openpilot.common.swaglog import cloudlog -from openpilot.selfdrive.statsd import statlog +from openpilot.system.statsd import statlog CAR_VOLTAGE_LOW_PASS_K = 0.011 # LPF gain for 45s tau (dt/tau / (dt/tau + 1)) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index f5fc94963..d44ce6c18 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -19,7 +19,7 @@ from openpilot.common.realtime import DT_TRML from openpilot.selfdrive.controls.lib.alertmanager import set_offroad_alert from openpilot.system.hardware import HARDWARE, TICI, AGNOS from openpilot.system.loggerd.config import get_available_percent -from openpilot.selfdrive.statsd import statlog +from openpilot.system.statsd import statlog from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.thermald.power_monitoring import PowerMonitoring from openpilot.selfdrive.thermald.fan_controller import TiciFanController diff --git a/selfdrive/sentry.py b/system/sentry.py similarity index 100% rename from selfdrive/sentry.py rename to system/sentry.py diff --git a/selfdrive/statsd.py b/system/statsd.py similarity index 100% rename from selfdrive/statsd.py rename to system/statsd.py diff --git a/selfdrive/tombstoned.py b/system/tombstoned.py similarity index 99% rename from selfdrive/tombstoned.py rename to system/tombstoned.py index 2c99c7eaf..5bcced266 100755 --- a/selfdrive/tombstoned.py +++ b/system/tombstoned.py @@ -9,7 +9,7 @@ import time import glob from typing import NoReturn -import openpilot.selfdrive.sentry as sentry +import openpilot.system.sentry as sentry from openpilot.system.hardware.hw import Paths from openpilot.common.swaglog import cloudlog from openpilot.system.version import get_build_metadata From b2cf9b35f68061587fd6ab7a94a58f7b433b2da2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 22:51:29 -0700 Subject: [PATCH 044/220] thermald: move to system/ (#32494) * thermald: move to system/ * fix path * revert --- pyproject.toml | 2 +- release/files_common | 6 +++--- selfdrive/manager/process_config.py | 2 +- selfdrive/test/test_onroad.py | 2 +- {selfdrive => system}/thermald/__init__.py | 0 {selfdrive => system}/thermald/fan_controller.py | 0 {selfdrive => system}/thermald/power_monitoring.py | 0 {selfdrive => system}/thermald/tests/__init__.py | 0 {selfdrive => system}/thermald/tests/test_fan_controller.py | 2 +- .../thermald/tests/test_power_monitoring.py | 6 +++--- {selfdrive => system}/thermald/thermald.py | 4 ++-- 11 files changed, 12 insertions(+), 12 deletions(-) rename {selfdrive => system}/thermald/__init__.py (100%) rename {selfdrive => system}/thermald/fan_controller.py (100%) rename {selfdrive => system}/thermald/power_monitoring.py (100%) rename {selfdrive => system}/thermald/tests/__init__.py (100%) rename {selfdrive => system}/thermald/tests/test_fan_controller.py (96%) rename {selfdrive => system}/thermald/tests/test_power_monitoring.py (96%) rename {selfdrive => system}/thermald/thermald.py (99%) diff --git a/pyproject.toml b/pyproject.toml index 2b183c983..db1b4195a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,10 +26,10 @@ testpaths = [ "selfdrive/locationd", "selfdrive/monitoring", "selfdrive/navd/tests", - "selfdrive/thermald", "selfdrive/test/longitudinal_maneuvers", "selfdrive/test/process_replay/test_fuzzy.py", "selfdrive/updated", + "system/thermald", "system/athena", "system/camerad", "system/hardware/tici", diff --git a/release/files_common b/release/files_common index 19a93bc7d..8636959da 100644 --- a/release/files_common +++ b/release/files_common @@ -253,9 +253,9 @@ system/webrtc/schema.py system/webrtc/device/audio.py system/webrtc/device/video.py -selfdrive/thermald/thermald.py -selfdrive/thermald/power_monitoring.py -selfdrive/thermald/fan_controller.py +system/thermald/thermald.py +system/thermald/power_monitoring.py +system/thermald/fan_controller.py selfdrive/test/__init__.py selfdrive/test/fuzzy_generation.py diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 5ea4b81b8..c2aa3b44e 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -75,7 +75,7 @@ procs = [ PythonProcess("pigeond", "system.ubloxd.pigeond", ublox, enabled=TICI), PythonProcess("plannerd", "selfdrive.controls.plannerd", only_onroad), PythonProcess("radard", "selfdrive.controls.radard", only_onroad), - PythonProcess("thermald", "selfdrive.thermald.thermald", always_run), + PythonProcess("thermald", "system.thermald.thermald", always_run), PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC), PythonProcess("updated", "selfdrive.updated.updated", only_offroad, enabled=not PC), PythonProcess("uploader", "system.loggerd.uploader", always_run), diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 53db737fc..14f777330 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -47,7 +47,7 @@ PROCS = { "selfdrive.controls.radard": 7.0, "selfdrive.modeld.modeld": 13.0, "selfdrive.modeld.dmonitoringmodeld": 8.0, - "selfdrive.thermald.thermald": 3.87, + "system.thermald.thermald": 3.87, "selfdrive.locationd.calibrationd": 2.0, "selfdrive.locationd.torqued": 5.0, "selfdrive.ui.soundd": 3.5, diff --git a/selfdrive/thermald/__init__.py b/system/thermald/__init__.py similarity index 100% rename from selfdrive/thermald/__init__.py rename to system/thermald/__init__.py diff --git a/selfdrive/thermald/fan_controller.py b/system/thermald/fan_controller.py similarity index 100% rename from selfdrive/thermald/fan_controller.py rename to system/thermald/fan_controller.py diff --git a/selfdrive/thermald/power_monitoring.py b/system/thermald/power_monitoring.py similarity index 100% rename from selfdrive/thermald/power_monitoring.py rename to system/thermald/power_monitoring.py diff --git a/selfdrive/thermald/tests/__init__.py b/system/thermald/tests/__init__.py similarity index 100% rename from selfdrive/thermald/tests/__init__.py rename to system/thermald/tests/__init__.py diff --git a/selfdrive/thermald/tests/test_fan_controller.py b/system/thermald/tests/test_fan_controller.py similarity index 96% rename from selfdrive/thermald/tests/test_fan_controller.py rename to system/thermald/tests/test_fan_controller.py index c2b1a6450..5c858132a 100755 --- a/selfdrive/thermald/tests/test_fan_controller.py +++ b/system/thermald/tests/test_fan_controller.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import pytest -from openpilot.selfdrive.thermald.fan_controller import TiciFanController +from openpilot.system.thermald.fan_controller import TiciFanController ALL_CONTROLLERS = [TiciFanController] diff --git a/selfdrive/thermald/tests/test_power_monitoring.py b/system/thermald/tests/test_power_monitoring.py similarity index 96% rename from selfdrive/thermald/tests/test_power_monitoring.py rename to system/thermald/tests/test_power_monitoring.py index f68191475..0795a29c8 100755 --- a/selfdrive/thermald/tests/test_power_monitoring.py +++ b/system/thermald/tests/test_power_monitoring.py @@ -2,7 +2,7 @@ import pytest from openpilot.common.params import Params -from openpilot.selfdrive.thermald.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \ +from openpilot.system.thermald.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \ CAR_CHARGING_RATE_W, VBATT_PAUSE_CHARGING, DELAY_SHUTDOWN_TIME_S # Create fake time @@ -18,9 +18,9 @@ VOLTAGE_BELOW_PAUSE_CHARGING = (VBATT_PAUSE_CHARGING - 1) * 1e3 def pm_patch(mocker, name, value, constant=False): if constant: - mocker.patch(f"openpilot.selfdrive.thermald.power_monitoring.{name}", value) + mocker.patch(f"openpilot.system.thermald.power_monitoring.{name}", value) else: - mocker.patch(f"openpilot.selfdrive.thermald.power_monitoring.{name}", return_value=value) + mocker.patch(f"openpilot.system.thermald.power_monitoring.{name}", return_value=value) @pytest.fixture(autouse=True) diff --git a/selfdrive/thermald/thermald.py b/system/thermald/thermald.py similarity index 99% rename from selfdrive/thermald/thermald.py rename to system/thermald/thermald.py index d44ce6c18..90f6494a2 100755 --- a/selfdrive/thermald/thermald.py +++ b/system/thermald/thermald.py @@ -21,8 +21,8 @@ from openpilot.system.hardware import HARDWARE, TICI, AGNOS from openpilot.system.loggerd.config import get_available_percent from openpilot.system.statsd import statlog from openpilot.common.swaglog import cloudlog -from openpilot.selfdrive.thermald.power_monitoring import PowerMonitoring -from openpilot.selfdrive.thermald.fan_controller import TiciFanController +from openpilot.system.thermald.power_monitoring import PowerMonitoring +from openpilot.system.thermald.fan_controller import TiciFanController from openpilot.system.version import terms_version, training_version ThermalStatus = log.DeviceState.ThermalStatus From 936e8d3d801e3ef52660eb0940293197598514bf Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 23:01:42 -0700 Subject: [PATCH 045/220] CI: merge build jobs (#32495) --- .github/workflows/selfdrive_tests.yaml | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index d3c8009bc..1c83c39bb 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -76,24 +76,8 @@ jobs: - uses: actions/checkout@v4 with: submodules: true - - uses: ./.github/workflows/setup-with-retry - with: - docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }} - - uses: ./.github/workflows/compile-openpilot - timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache - - docker_push: - name: docker push - strategy: - matrix: - arch: ${{ fromJson( (github.repository == 'commaai/openpilot') && '["x86_64", "aarch64"]' || '["x86_64"]' ) }} - runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-latest' }} - if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Setup to push to repo + - name: Setup docker push + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' run: | echo "PUSH_IMAGE=true" >> "$GITHUB_ENV" echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV" @@ -101,12 +85,14 @@ jobs: - uses: ./.github/workflows/setup-with-retry with: docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }} + - uses: ./.github/workflows/compile-openpilot + timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache docker_push_multiarch: name: docker push multiarch tag runs-on: ubuntu-latest if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' - needs: [docker_push] + needs: [build] steps: - uses: actions/checkout@v4 with: From da42c4a561343749a4970d7908ed7a3b2ed0402e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 23:11:19 -0700 Subject: [PATCH 046/220] CI: move car docs diff job (#32496) * CI: move car docs diff job * no if --- .github/workflows/auto_pr_review.yaml | 54 +++++++++++++++++++++++++- .github/workflows/selfdrive_tests.yaml | 54 -------------------------- 2 files changed, 53 insertions(+), 55 deletions(-) diff --git a/.github/workflows/auto_pr_review.yaml b/.github/workflows/auto_pr_review.yaml index 8316fedda..2c41dc8bd 100644 --- a/.github/workflows/auto_pr_review.yaml +++ b/.github/workflows/auto_pr_review.yaml @@ -54,6 +54,59 @@ jobs: comment_tag: run_id GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + car_docs_diff: + name: PR comments + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + ref: ${{ github.event.pull_request.base.ref }} + - run: git lfs pull + - uses: ./.github/workflows/setup-with-retry + - name: Get base car info + run: | + ${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_docs.py --path /tmp/openpilot_cache/base_car_docs" + sudo chown -R $USER:$USER ${{ github.workspace }} + - uses: actions/checkout@v4 + with: + submodules: true + path: current + - run: cd current && git lfs pull + - name: Save car docs diff + id: save_diff + run: | + cd current + ${{ env.RUN }} "scons -j$(nproc)" + output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_docs") + output="${output//$'\n'/'%0A'}" + echo "::set-output name=diff::$output" + - name: Find comment + if: ${{ env.AZURE_TOKEN != '' }} + uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + body-includes: This PR makes changes to + - name: Update comment + if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }} + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: "${{ steps.save_diff.outputs.diff }}" + edit-mode: replace + - name: Delete comment + if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }} + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ steps.fc.outputs.comment-id }} + }) + check-pr-template: runs-on: ubuntu-latest permissions: @@ -224,4 +277,3 @@ jobs: console.log("Label 'in-bot-review' not found, ignoring"); }); } - diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 1c83c39bb..2068eeb01 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -249,60 +249,6 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - car_docs_diff: - name: PR comments - runs-on: ubuntu-latest - if: github.event_name == 'pull_request' - steps: - - uses: actions/checkout@v4 - with: - submodules: true - ref: ${{ github.event.pull_request.base.ref }} - - run: git lfs pull - - uses: ./.github/workflows/setup-with-retry - - name: Get base car info - run: | - ${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_docs.py --path /tmp/openpilot_cache/base_car_docs" - sudo chown -R $USER:$USER ${{ github.workspace }} - - uses: actions/checkout@v4 - with: - submodules: true - path: current - - run: cd current && git lfs pull - - name: Save car docs diff - id: save_diff - run: | - cd current - ${{ env.RUN }} "scons -j$(nproc)" - output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_docs") - output="${output//$'\n'/'%0A'}" - echo "::set-output name=diff::$output" - - name: Find comment - if: ${{ env.AZURE_TOKEN != '' }} - uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e - id: fc - with: - issue-number: ${{ github.event.pull_request.number }} - body-includes: This PR makes changes to - - name: Update comment - if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }} - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: "${{ steps.save_diff.outputs.diff }}" - edit-mode: replace - - name: Delete comment - if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }} - uses: actions/github-script@v7 - with: - script: | - github.rest.issues.deleteComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: ${{ steps.fc.outputs.comment-id }} - }) - create_ui_report: name: Create UI Report runs-on: ubuntu-latest From ce136317d8e7c9d1c2981dacc77df414859c0e21 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 May 2024 01:26:47 -0500 Subject: [PATCH 047/220] regen: use existing carParams msg (#32493) use existing msg --- selfdrive/test/process_replay/migration.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/selfdrive/test/process_replay/migration.py b/selfdrive/test/process_replay/migration.py index 152f28194..be78c92d7 100644 --- a/selfdrive/test/process_replay/migration.py +++ b/selfdrive/test/process_replay/migration.py @@ -183,9 +183,7 @@ def migrate_carParams(lr, old_logtime=False): all_msgs = [] for msg in lr: if msg.which() == 'carParams': - CP = messaging.new_message('carParams') - CP.valid = True - CP.carParams = msg.carParams.as_builder() + CP = msg.as_builder() CP.carParams.carFingerprint = MIGRATION.get(CP.carParams.carFingerprint, CP.carParams.carFingerprint) for car_fw in CP.carParams.carFw: car_fw.brand = CP.carParams.carName From 5e98d9e2895330264a42c90c81c347b7d5bd1f5c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 23:19:09 -0700 Subject: [PATCH 048/220] also tag as latest --- selfdrive/test/docker_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/docker_build.sh b/selfdrive/test/docker_build.sh index 5f77ceb10..4d58a1507 100755 --- a/selfdrive/test/docker_build.sh +++ b/selfdrive/test/docker_build.sh @@ -17,7 +17,7 @@ fi source $SCRIPT_DIR/docker_common.sh $1 "$TAG_SUFFIX" -DOCKER_BUILDKIT=1 docker buildx build --provenance false --pull --platform $PLATFORM --load --cache-to type=inline --cache-from type=registry,ref=$REMOTE_TAG -t $REMOTE_TAG -t $LOCAL_TAG -f $OPENPILOT_DIR/$DOCKER_FILE $OPENPILOT_DIR +DOCKER_BUILDKIT=1 docker buildx build --provenance false --pull --platform $PLATFORM --load --cache-to type=inline --cache-from type=registry,ref=$REMOTE_TAG -t $DOCKER_IMAGE:latest -t $REMOTE_TAG -t $LOCAL_TAG -f $OPENPILOT_DIR/$DOCKER_FILE $OPENPILOT_DIR if [ -n "$PUSH_IMAGE" ]; then docker push $REMOTE_TAG From 49d7edfe11add9abc09b46b271ea8b646797c080 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 May 2024 23:33:16 -0700 Subject: [PATCH 049/220] Revert "CI: move car docs diff job (#32496)" This reverts commit da42c4a561343749a4970d7908ed7a3b2ed0402e. --- .github/workflows/auto_pr_review.yaml | 54 +------------------------- .github/workflows/selfdrive_tests.yaml | 54 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/.github/workflows/auto_pr_review.yaml b/.github/workflows/auto_pr_review.yaml index 2c41dc8bd..8316fedda 100644 --- a/.github/workflows/auto_pr_review.yaml +++ b/.github/workflows/auto_pr_review.yaml @@ -54,59 +54,6 @@ jobs: comment_tag: run_id GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - car_docs_diff: - name: PR comments - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - ref: ${{ github.event.pull_request.base.ref }} - - run: git lfs pull - - uses: ./.github/workflows/setup-with-retry - - name: Get base car info - run: | - ${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_docs.py --path /tmp/openpilot_cache/base_car_docs" - sudo chown -R $USER:$USER ${{ github.workspace }} - - uses: actions/checkout@v4 - with: - submodules: true - path: current - - run: cd current && git lfs pull - - name: Save car docs diff - id: save_diff - run: | - cd current - ${{ env.RUN }} "scons -j$(nproc)" - output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_docs") - output="${output//$'\n'/'%0A'}" - echo "::set-output name=diff::$output" - - name: Find comment - if: ${{ env.AZURE_TOKEN != '' }} - uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e - id: fc - with: - issue-number: ${{ github.event.pull_request.number }} - body-includes: This PR makes changes to - - name: Update comment - if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }} - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: "${{ steps.save_diff.outputs.diff }}" - edit-mode: replace - - name: Delete comment - if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }} - uses: actions/github-script@v7 - with: - script: | - github.rest.issues.deleteComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: ${{ steps.fc.outputs.comment-id }} - }) - check-pr-template: runs-on: ubuntu-latest permissions: @@ -277,3 +224,4 @@ jobs: console.log("Label 'in-bot-review' not found, ignoring"); }); } + diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 2068eeb01..1c83c39bb 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -249,6 +249,60 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + car_docs_diff: + name: PR comments + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + with: + submodules: true + ref: ${{ github.event.pull_request.base.ref }} + - run: git lfs pull + - uses: ./.github/workflows/setup-with-retry + - name: Get base car info + run: | + ${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_docs.py --path /tmp/openpilot_cache/base_car_docs" + sudo chown -R $USER:$USER ${{ github.workspace }} + - uses: actions/checkout@v4 + with: + submodules: true + path: current + - run: cd current && git lfs pull + - name: Save car docs diff + id: save_diff + run: | + cd current + ${{ env.RUN }} "scons -j$(nproc)" + output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_docs") + output="${output//$'\n'/'%0A'}" + echo "::set-output name=diff::$output" + - name: Find comment + if: ${{ env.AZURE_TOKEN != '' }} + uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + body-includes: This PR makes changes to + - name: Update comment + if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }} + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: "${{ steps.save_diff.outputs.diff }}" + edit-mode: replace + - name: Delete comment + if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }} + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ steps.fc.outputs.comment-id }} + }) + create_ui_report: name: Create UI Report runs-on: ubuntu-latest From 71f5c441fe32184d94a9f26565a36c661e2ccf28 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 May 2024 03:18:10 -0500 Subject: [PATCH 050/220] card: process that abstracts car interface and CAN (#32380) * format card * standalone process * no class member CS, there's no point also can be confusing; what else could be using this? * rename CoS * Update selfdrive/controls/controlsd.py * never works first time :D * canRcvTimeout is bool * hack * add cpu * see what testing closet comes up with * first * some clean up * support passable CI, fix test models * fix startup alert * process replay changes * test_fuzzy * gate carOutput valid on carControl valid * we should publish after we update carOutput * controlsd was using actuatorsOutput from 2 frames ago for torque, not the most up to date * check all checks for carControl in case controlsd dies * log more timestamps * more generic latency logger; needs some clean up latency_logger.py was difficult to understand and modify * card polls on can and carControl to get latest carControl possible * temp try to send earlier * add log * remove latencylogger * no mpld3! * old loop * detect first event * normal send * revert "card polls on can and carControl to get latest carControl possible" how it was is best * sheesh! update should be first * first timestamp * temp comment ( timestamp is slow :( ) * more final ordering, and make polling on/off test repeatable * Received can * new plot timestamps * clean up * no poll * add controllers (draft) * Revert "add controllers (draft)" This reverts commit e2c3f01b2fadcff74347bac90c8a5cc1ef4e27b3. * fix that * conventions * just use CS * consider controlsd state machine in card: not fully done * hmm it's just becoming controlsd * rm debugging * Revert "hmm it's just becoming controlsd" This reverts commit 534a357ee95bec4ed070667186af55d59421bbc7. * Revert "just use CS" This reverts commit 9fa7406f30c86200f20457f7b9ff95e731201bf9. * add vCruise * migrate car state * Revert "migrate car state" This reverts commit 4ae86ca163c6920070f410f608f7644ab632850b. * Revert "add vCruise" This reverts commit af247a8da41c3626ada4231b98042da1a1ae4633. * simple state machine in card (doesn't work as is) * Revert "simple state machine in card (doesn't work as is)" This reverts commit b4af8a9b0a2e17fdfc89d344c64678ef51305c24. * poll carState without conflate * bump * remove state transition * fix * update refs * ignore cumLagMs and don't ignore valid * fix controls mismatch; controlsd used to set alt exp * controlsd_config_callback not needed for card * revert ref temp * update refs * no poll * not builder! * test fix * need to migrate initialized * CC will be a reader * more as_reader! * fix None * init after publish like before - no real difference * controlsd clean up * remove redundant check and check passive for init * stash * flip * migrate missing carOutput for controlsd * Update ref_commit * bump cereal * comment * no class params * no class * Revert "no class" This reverts commit 5499b83c2dcb5462070626f8523e3aec6f4c209d. * add todo * regen and update refs * fix * update refs * and fix that * should be controlsstate * remove controlsState migration CoS.initialized isn't needed yet * fix * flip! * bump * fix that * update refs * fix * if canValid goes false, controlsd would still send * bump * rm diff * need to be very careful with initializing * update refs --- cereal | 2 +- selfdrive/car/body/carcontroller.py | 2 +- selfdrive/car/card.py | 104 ++++++++++++------ selfdrive/car/chrysler/carcontroller.py | 2 +- selfdrive/car/ford/carcontroller.py | 2 +- selfdrive/car/gm/carcontroller.py | 2 +- selfdrive/car/honda/carcontroller.py | 2 +- selfdrive/car/hyundai/carcontroller.py | 2 +- selfdrive/car/mazda/carcontroller.py | 2 +- selfdrive/car/mock/carcontroller.py | 2 +- selfdrive/car/nissan/carcontroller.py | 2 +- selfdrive/car/subaru/carcontroller.py | 2 +- selfdrive/car/tesla/carcontroller.py | 2 +- selfdrive/car/tests/test_car_interfaces.py | 4 +- selfdrive/car/tests/test_models.py | 12 +- selfdrive/car/toyota/carcontroller.py | 2 +- selfdrive/car/volkswagen/carcontroller.py | 2 +- selfdrive/controls/controlsd.py | 42 +++---- selfdrive/controls/tests/test_startup.py | 3 +- selfdrive/manager/process_config.py | 1 + selfdrive/test/process_replay/migration.py | 18 +++ .../test/process_replay/process_replay.py | 32 ++++-- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/process_replay/test_fuzzy.py | 2 +- .../test/process_replay/test_processes.py | 36 +++--- selfdrive/test/test_onroad.py | 3 +- 26 files changed, 181 insertions(+), 106 deletions(-) diff --git a/cereal b/cereal index 0a9b426e5..5812f2c07 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 0a9b426e55653daea6cc9d3c40c3f7600ec0db49 +Subproject commit 5812f2c075a5364cecafe4e8ed68a12b12a5631f diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index db34320ca..259126c41 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -75,7 +75,7 @@ class CarController(CarControllerBase): can_sends = [] can_sends.append(bodycan.create_control(self.packer, torque_l, torque_r)) - new_actuators = CC.actuators.copy() + new_actuators = CC.actuators.as_builder() new_actuators.accel = torque_l new_actuators.steer = torque_r new_actuators.steerOutputCan = torque_r diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index ed916a6fe..2705a3c01 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -9,7 +9,7 @@ from cereal import car from panda import ALTERNATIVE_EXPERIENCE from openpilot.common.params import Params -from openpilot.common.realtime import DT_CTRL +from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp from openpilot.selfdrive.car.car_helpers import get_car, get_one_can @@ -21,22 +21,24 @@ REPLAY = "REPLAY" in os.environ EventName = car.CarEvent.EventName -class CarD: +class Car: CI: CarInterfaceBase def __init__(self, CI=None): self.can_sock = messaging.sub_sock('can', timeout=20) - self.sm = messaging.SubMaster(['pandaStates']) + self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents']) self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput']) self.can_rcv_timeout_counter = 0 # consecutive timeout count self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count self.CC_prev = car.CarControl.new_message() + self.CS_prev = car.CarState.new_message() + self.initialized_prev = False - self.last_actuators = None + self.last_actuators_output = car.CarControl.Actuators.new_message() - self.params = Params() + params = Params() if CI is None: # wait for one pandaState and one CAN packet @@ -44,18 +46,18 @@ class CarD: get_one_can(self.can_sock) num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates) - experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled") + experimental_long_allowed = params.get_bool("ExperimentalLongitudinalEnabled") self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas) else: self.CI, self.CP = CI, CI.CP # set alternative experiences from parameters - self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator") + self.disengage_on_accelerator = params.get_bool("DisengageOnAccelerator") self.CP.alternativeExperience = 0 if not self.disengage_on_accelerator: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS - openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle") + openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle") controller_available = self.CI.CC is not None and openpilot_enabled_toggle and not self.CP.dashcamOnly @@ -66,22 +68,20 @@ class CarD: self.CP.safetyConfigs = [safety_config] # Write previous route's CarParams - prev_cp = self.params.get("CarParamsPersistent") + prev_cp = params.get("CarParamsPersistent") if prev_cp is not None: - self.params.put("CarParamsPrevRoute", prev_cp) + params.put("CarParamsPrevRoute", prev_cp) # Write CarParams for controls and radard cp_bytes = self.CP.to_bytes() - self.params.put("CarParams", cp_bytes) - self.params.put_nonblocking("CarParamsCache", cp_bytes) - self.params.put_nonblocking("CarParamsPersistent", cp_bytes) + params.put("CarParams", cp_bytes) + params.put_nonblocking("CarParamsCache", cp_bytes) + params.put_nonblocking("CarParamsPersistent", cp_bytes) - self.CS_prev = car.CarState.new_message() self.events = Events() - def initialize(self): - """Initialize CarInterface, once controls are ready""" - self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan']) + # card is driven by can recv, expected at 100Hz + self.rk = Ratekeeper(100, print_delay_threshold=None) def state_update(self) -> car.CarState: """carState update loop, driven by can""" @@ -106,11 +106,6 @@ class CarD: if can_rcv_valid and REPLAY: self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime - self.update_events(CS) - self.state_publish(CS) - - CS = CS.as_reader() - self.CS_prev = CS return CS def update_events(self, CS: car.CarState) -> car.CarState: @@ -129,12 +124,6 @@ class CarD: def state_publish(self, CS: car.CarState): """carState and carParams publish loop""" - # carState - cs_send = messaging.new_message('carState') - cs_send.valid = CS.canValid - cs_send.carState = CS - self.pm.send('carState', cs_send) - # carParams - logged every 50 seconds (> 1 per segment) if self.sm.frame % int(50. / DT_CTRL) == 0: cp_send = messaging.new_message('carParams') @@ -144,17 +133,60 @@ class CarD: # publish new carOutput co_send = messaging.new_message('carOutput') - co_send.valid = True - if self.last_actuators is not None: - co_send.carOutput.actuatorsOutput = self.last_actuators + co_send.valid = self.sm.all_checks(['carControl']) + co_send.carOutput.actuatorsOutput = self.last_actuators_output self.pm.send('carOutput', co_send) + # kick off controlsd step while we actuate the latest carControl packet + cs_send = messaging.new_message('carState') + cs_send.valid = CS.canValid + cs_send.carState = CS + cs_send.carState.canRcvTimeout = self.can_rcv_timeout + cs_send.carState.canErrorCounter = self.can_rcv_cum_timeout_counter + cs_send.carState.cumLagMs = -self.rk.remaining * 1000. + self.pm.send('carState', cs_send) + def controls_update(self, CS: car.CarState, CC: car.CarControl): """control update loop, driven by carControl""" - # send car controls over can - now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9) - self.last_actuators, can_sends = self.CI.apply(CC, now_nanos) - self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid)) + if not self.initialized_prev: + # Initialize CarInterface, once controls are ready + self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan']) - self.CC_prev = CC + if self.sm.all_alive(['carControl']): + # send car controls over can + now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9) + self.last_actuators_output, can_sends = self.CI.apply(CC, now_nanos) + self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid)) + + self.CC_prev = CC + + def step(self): + CS = self.state_update() + + self.update_events(CS) + + self.state_publish(CS) + + initialized = (not any(e.name == EventName.controlsInitializing for e in self.sm['onroadEvents']) and + self.sm.seen['onroadEvents']) + if not self.CP.passive and initialized: + self.controls_update(CS, self.sm['carControl']) + + self.initialized_prev = initialized + self.CS_prev = CS.as_reader() + + def card_thread(self): + while True: + self.step() + self.rk.monitor_time() + + +def main(): + config_realtime_process(4, Priority.CTRL_HIGH) + car = Car() + car.card_thread() + + +if __name__ == "__main__": + main() diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 39248f3f7..85f53f68e 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -78,7 +78,7 @@ class CarController(CarControllerBase): self.frame += 1 - new_actuators = CC.actuators.copy() + new_actuators = CC.actuators.as_builder() new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 47082fb56..7be3b2ebe 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -113,7 +113,7 @@ class CarController(CarControllerBase): self.steer_alert_last = steer_alert self.lead_distance_bars_last = hud_control.leadDistanceBars - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.curvature = self.apply_curvature_last self.frame += 1 diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index f8d747029..b204d3b80 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -155,7 +155,7 @@ class CarController(CarControllerBase): if self.frame % 10 == 0: can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status)) - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last new_actuators.gas = self.apply_gas diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 6fe8c2758..fe023ea17 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -244,7 +244,7 @@ class CarController(CarControllerBase): self.speed = pcm_speed self.gas = pcm_accel / self.params.NIDEC_GAS_MAX - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.speed = self.speed new_actuators.accel = self.accel new_actuators.gas = self.gas diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 7829d764b..4038ddcca 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -163,7 +163,7 @@ class CarController(CarControllerBase): if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl: can_sends.append(hyundaican.create_frt_radar_opt(self.packer)) - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.steer = apply_steer / self.params.STEER_MAX new_actuators.steerOutputCan = apply_steer new_actuators.accel = accel diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 8d3a59b4e..3d4163487 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -58,7 +58,7 @@ class CarController(CarControllerBase): can_sends.append(mazdacan.create_steering_control(self.packer, self.CP, self.frame, apply_steer, CS.cam_lkas)) - new_actuators = CC.actuators.copy() + new_actuators = CC.actuators.as_builder() new_actuators.steer = apply_steer / CarControllerParams.STEER_MAX new_actuators.steerOutputCan = apply_steer diff --git a/selfdrive/car/mock/carcontroller.py b/selfdrive/car/mock/carcontroller.py index 2b2da954f..0cd37c036 100644 --- a/selfdrive/car/mock/carcontroller.py +++ b/selfdrive/car/mock/carcontroller.py @@ -2,4 +2,4 @@ from openpilot.selfdrive.car.interfaces import CarControllerBase class CarController(CarControllerBase): def update(self, CC, CS, now_nanos): - return CC.actuators.copy(), [] + return CC.actuators.as_builder(), [] diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index 83775462b..c7bd23139 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -75,7 +75,7 @@ class CarController(CarControllerBase): self.packer, CS.lkas_hud_info_msg, steer_hud_alert )) - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.steeringAngleDeg = apply_angle self.frame += 1 diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 22a1475b5..d89ae8c63 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -136,7 +136,7 @@ class CarController(CarControllerBase): if self.frame % 2 == 0: can_sends.append(subarucan.create_es_static_2(self.packer)) - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.steer = self.apply_steer_last / self.p.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last diff --git a/selfdrive/car/tesla/carcontroller.py b/selfdrive/car/tesla/carcontroller.py index f217c4692..e460111e3 100644 --- a/selfdrive/car/tesla/carcontroller.py +++ b/selfdrive/car/tesla/carcontroller.py @@ -60,7 +60,7 @@ class CarController(CarControllerBase): # TODO: HUD control - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.steeringAngleDeg = self.apply_angle_last self.frame += 1 diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 4bbecd99f..dfdf44215 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -91,14 +91,14 @@ class TestCarInterfaces: CC = car.CarControl.new_message(**cc_msg) for _ in range(10): car_interface.update(CC, []) - car_interface.apply(CC, now_nanos) + car_interface.apply(CC.as_reader(), now_nanos) now_nanos += DT_CTRL * 1e9 # 10 ms CC = car.CarControl.new_message(**cc_msg) CC.enabled = True for _ in range(10): car_interface.update(CC, []) - car_interface.apply(CC, now_nanos) + car_interface.apply(CC.as_reader(), now_nanos) now_nanos += DT_CTRL * 1e9 # 10ms # Test controller initialization diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 026693bdc..8807db69d 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -15,7 +15,7 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car import gen_empty_fingerprint -from openpilot.selfdrive.car.card import CarD +from openpilot.selfdrive.car.card import Car from openpilot.selfdrive.car.fingerprints import all_known_cars, MIGRATION from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, interfaces from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags @@ -215,7 +215,7 @@ class TestCarModelBase(unittest.TestCase): # TODO: also check for checksum violations from can parser can_invalid_cnt = 0 can_valid = False - CC = car.CarControl.new_message() + CC = car.CarControl.new_message().as_reader() for i, msg in enumerate(self.can_msgs): CS = self.CI.update(CC, (msg.as_builder().to_bytes(),)) @@ -308,17 +308,17 @@ class TestCarModelBase(unittest.TestCase): # Make sure we can send all messages while inactive CC = car.CarControl.new_message() - test_car_controller(CC) + test_car_controller(CC.as_reader()) # Test cancel + general messages (controls_allowed=False & cruise_engaged=True) self.safety.set_cruise_engaged_prev(True) CC = car.CarControl.new_message(cruiseControl={'cancel': True}) - test_car_controller(CC) + test_car_controller(CC.as_reader()) # Test resume + general messages (controls_allowed=True & cruise_engaged=True) self.safety.set_controls_allowed(True) CC = car.CarControl.new_message(cruiseControl={'resume': True}) - test_car_controller(CC) + test_car_controller(CC.as_reader()) # Skip stdout/stderr capture with pytest, causes elevated memory usage @pytest.mark.nocapture @@ -406,7 +406,7 @@ class TestCarModelBase(unittest.TestCase): controls_allowed_prev = False CS_prev = car.CarState.new_message() checks = defaultdict(int) - card = CarD(CI=self.CI) + card = Car(CI=self.CI) for idx, can in enumerate(self.can_msgs): CS = self.CI.update(CC, (can.as_builder().to_bytes(), )) for msg in filter(lambda m: m.src in range(64), can.can): diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 354d10a90..f9b7a478e 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -168,7 +168,7 @@ class CarController(CarControllerBase): if self.frame % 20 == 0 and self.CP.flags & ToyotaFlags.DISABLE_RADAR.value: can_sends.append([0x750, 0, b"\x0F\x02\x3E\x00\x00\x00\x00\x00", 0]) - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.steer = apply_steer / self.params.STEER_MAX new_actuators.steerOutputCan = apply_steer new_actuators.steeringAngleDeg = self.last_angle diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 5fc47c51c..a4e0c8946 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -112,7 +112,7 @@ class CarController(CarControllerBase): can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, self.ext_bus, CS.gra_stock_values, cancel=CC.cruiseControl.cancel, resume=CC.cruiseControl.resume)) - new_actuators = actuators.copy() + new_actuators = actuators.as_builder() new_actuators.steer = self.apply_steer_last / self.CCP.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index e3c456766..d007cd947 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -18,8 +18,7 @@ from openpilot.common.params import Params from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL from openpilot.common.swaglog import cloudlog -from openpilot.selfdrive.car.car_helpers import get_startup_event -from openpilot.selfdrive.car.card import CarD +from openpilot.selfdrive.car.car_helpers import get_car_interface, get_startup_event from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert from openpilot.selfdrive.controls.lib.drive_helpers import VCruiseHelper, clip_curvature from openpilot.selfdrive.controls.lib.events import Events, ET @@ -61,16 +60,19 @@ ENABLED_STATES = (State.preEnabled, *ACTIVE_STATES) class Controls: def __init__(self, CI=None): - self.card = CarD(CI) - self.params = Params() - with car.CarParams.from_bytes(self.params.get("CarParams", block=True)) as msg: - # TODO: this shouldn't need to be a builder - self.CP = msg.as_builder() - - self.CI = self.card.CI + if CI is None: + cloudlog.info("controlsd is waiting for CarParams") + with car.CarParams.from_bytes(self.params.get("CarParams", block=True)) as msg: + # TODO: this shouldn't need to be a builder + self.CP = msg.as_builder() + cloudlog.info("controlsd got CarParams") + # Uses car interface helper functions, altering state won't be considered by card for actuation + self.CI = get_car_interface(self.CP) + else: + self.CI, self.CP = CI, CI.CP # Ensure the current branch is cached, otherwise the first iteration of controlsd lags self.branch = get_short_branch() @@ -83,6 +85,9 @@ class Controls: self.log_sock = messaging.sub_sock('androidLog') + # TODO: de-couple controlsd with card/conflate on carState without introducing controls mismatches + self.car_state_sock = messaging.sub_sock('carState', timeout=20) + ignore = self.sensor_packets + ['testJoystick'] if SIMULATION: ignore += ['driverCameraState', 'managerState'] @@ -110,6 +115,7 @@ class Controls: if not self.CP.openpilotLongitudinalControl: self.params.remove("ExperimentalMode") + self.CS_prev = car.CarState.new_message() self.AM = AlertManager() self.events = Events() @@ -161,7 +167,7 @@ class Controls: elif self.CP.passive: self.events.add(EventName.dashcamMode, static=True) - # controlsd is driven by can recv, expected at 100Hz + # controlsd is driven by carState, expected at 100Hz self.rk = Ratekeeper(100, print_delay_threshold=None) def set_initial_state(self): @@ -308,7 +314,7 @@ class Controls: # generic catch-all. ideally, a more specific event should be added above instead has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE)) no_system_errors = (not has_disable_events) or (len(self.events) == num_events) - if (not self.sm.all_checks() or self.card.can_rcv_timeout) and no_system_errors: + if (not self.sm.all_checks() or CS.canRcvTimeout) and no_system_errors: if not self.sm.all_alive(): self.events.add(EventName.commIssue) elif not self.sm.all_freq_ok(): @@ -320,7 +326,7 @@ class Controls: 'invalid': [s for s, valid in self.sm.valid.items() if not valid], 'not_alive': [s for s, alive in self.sm.alive.items() if not alive], 'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok], - 'can_rcv_timeout': self.card.can_rcv_timeout, + 'can_rcv_timeout': CS.canRcvTimeout, } if logs != self.logged_comm_issue: cloudlog.event("commIssue", error=True, **logs) @@ -380,9 +386,10 @@ class Controls: self.events.add(EventName.modeldLagging) def data_sample(self): - """Receive data from sockets and update carState""" + """Receive data from sockets""" - CS = self.card.state_update() + car_state = messaging.recv_one(self.car_state_sock) + CS = car_state.carState if car_state else self.CS_prev self.sm.update(0) @@ -396,9 +403,6 @@ class Controls: if VisionStreamType.VISION_STREAM_WIDE_ROAD not in available_streams: self.sm.ignore_alive.append('wideRoadCameraState') - if not self.CP.passive: - self.card.initialize() - self.initialized = True self.set_initial_state() self.params.put_bool_nonblocking("ControlsReady", True) @@ -709,7 +713,6 @@ class Controls: hudControl.visualAlert = current_alert.visual_alert if not self.CP.passive and self.initialized: - self.card.controls_update(CS, CC) CO = self.sm['carOutput'] if self.CP.steerControlType == car.CarParams.SteerControlType.angle: self.steer_limited = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \ @@ -757,7 +760,6 @@ class Controls: controlsState.cumLagMs = -self.rk.remaining * 1000. controlsState.startMonoTime = int(start_time * 1e9) controlsState.forceDecel = bool(force_decel) - controlsState.canErrorCounter = self.card.can_rcv_cum_timeout_counter controlsState.experimentalMode = self.experimental_mode controlsState.personality = self.personality @@ -807,6 +809,8 @@ class Controls: # Publish data self.publish_logs(CS, start_time, CC, lac_log) + self.CS_prev = CS + def read_personality_param(self): try: return int(self.params.get('LongitudinalPersonality')) diff --git a/selfdrive/controls/tests/test_startup.py b/selfdrive/controls/tests/test_startup.py index 23cc96a2e..5b69a7cd8 100644 --- a/selfdrive/controls/tests/test_startup.py +++ b/selfdrive/controls/tests/test_startup.py @@ -87,6 +87,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand): os.environ['SKIP_FW_QUERY'] = '1' managed_processes['controlsd'].start() + managed_processes['card'].start() assert pm.wait_for_readers_to_update('can', 5) pm.send('can', can_list_to_can_capnp([[0, 0, b"", 0]])) @@ -104,7 +105,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand): msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()] for _ in range(1000): - # controlsd waits for boardd to echo back that it has changed the multiplexing mode + # card waits for boardd to echo back that it has changed the multiplexing mode if not params.get_bool("ObdMultiplexingChanged"): params.put_bool("ObdMultiplexingChanged", True) diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index c2aa3b44e..a8ab204da 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -64,6 +64,7 @@ procs = [ PythonProcess("calibrationd", "selfdrive.locationd.calibrationd", only_onroad), PythonProcess("torqued", "selfdrive.locationd.torqued", only_onroad), PythonProcess("controlsd", "selfdrive.controls.controlsd", only_onroad), + PythonProcess("card", "selfdrive.car.card", only_onroad), PythonProcess("deleter", "system.loggerd.deleter", always_run), PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", driverview, enabled=(not PC or WEBCAM)), PythonProcess("qcomgpsd", "system.qcomgpsd.qcomgpsd", qcomgps, enabled=TICI), diff --git a/selfdrive/test/process_replay/migration.py b/selfdrive/test/process_replay/migration.py index be78c92d7..c8d0504de 100644 --- a/selfdrive/test/process_replay/migration.py +++ b/selfdrive/test/process_replay/migration.py @@ -14,6 +14,7 @@ def migrate_all(lr, old_logtime=False, manager_states=False, panda_states=False, msgs = migrate_carParams(msgs, old_logtime) msgs = migrate_gpsLocation(msgs) msgs = migrate_deviceState(msgs) + msgs = migrate_carOutput(msgs) if manager_states: msgs = migrate_managerState(msgs) if panda_states: @@ -69,6 +70,23 @@ def migrate_deviceState(lr): return all_msgs +def migrate_carOutput(lr): + # migration needed only for routes before carOutput + if any(msg.which() == 'carOutput' for msg in lr): + return lr + + all_msgs = [] + for msg in lr: + if msg.which() == 'carControl': + co = messaging.new_message('carOutput') + co.valid = msg.valid + co.logMonoTime = msg.logMonoTime + co.carOutput.actuatorsOutput = msg.carControl.actuatorsOutputDEPRECATED + all_msgs.append(co.as_reader()) + all_msgs.append(msg) + return all_msgs + + def migrate_pandaStates(lr): all_msgs = [] # TODO: safety param migration should be handled automatically diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index f55f2c4e2..fd1d75346 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -317,12 +317,12 @@ class ProcessContainer: return output_msgs -def controlsd_fingerprint_callback(rc, pm, msgs, fingerprint): +def card_fingerprint_callback(rc, pm, msgs, fingerprint): print("start fingerprinting") params = Params() canmsgs = [msg for msg in msgs if msg.which() == "can"][:300] - # controlsd expects one arbitrary can and pandaState + # card expects one arbitrary can and pandaState rc.send_sync(pm, "can", messaging.new_message("can", 1)) pm.send("pandaStates", messaging.new_message("pandaStates", 1)) rc.send_sync(pm, "can", messaging.new_message("can", 1)) @@ -356,12 +356,20 @@ def get_car_params_callback(rc, pm, msgs, fingerprint): for m in canmsgs[:300]: can.send(m.as_builder().to_bytes()) _, CP = get_car(can, sendcan, Params().get_bool("ExperimentalLongitudinalEnabled")) + + if not params.get_bool("DisengageOnAccelerator"): + CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS + params.put("CarParams", CP.to_bytes()) return CP def controlsd_rcv_callback(msg, cfg, frame): - # no sendcan until controlsd is initialized + return (frame - 1) == 0 or msg.which() == 'carState' + + +def card_rcv_callback(msg, cfg, frame): + # no sendcan until card is initialized if msg.which() != "can": return False @@ -461,18 +469,28 @@ CONFIGS = [ ProcessConfig( proc_name="controlsd", pubs=[ - "can", "deviceState", "pandaStates", "peripheralState", "liveCalibration", "driverMonitoringState", + "carState", "deviceState", "pandaStates", "peripheralState", "liveCalibration", "driverMonitoringState", "longitudinalPlan", "liveLocationKalman", "liveParameters", "radarState", "modelV2", "driverCameraState", "roadCameraState", "wideRoadCameraState", "managerState", - "testJoystick", "liveTorqueParameters", "accelerometer", "gyroscope" + "testJoystick", "liveTorqueParameters", "accelerometer", "gyroscope", "carOutput" ], - subs=["controlsState", "carState", "carControl", "carOutput", "sendcan", "onroadEvents", "carParams"], + subs=["controlsState", "carControl", "onroadEvents"], ignore=["logMonoTime", "controlsState.startMonoTime", "controlsState.cumLagMs"], config_callback=controlsd_config_callback, - init_callback=controlsd_fingerprint_callback, + init_callback=get_car_params_callback, should_recv_callback=controlsd_rcv_callback, tolerance=NUMPY_TOLERANCE, processing_time=0.004, + ), + ProcessConfig( + proc_name="card", + pubs=["pandaStates", "carControl", "onroadEvents", "can"], + subs=["sendcan", "carState", "carParams", "carOutput"], + ignore=["logMonoTime", "carState.cumLagMs"], + init_callback=card_fingerprint_callback, + should_recv_callback=card_rcv_callback, + tolerance=NUMPY_TOLERANCE, + processing_time=0.004, main_pub="can", ), ProcessConfig( diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 2af30b5b4..dc7e59b54 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -cc4e23ca0fceb300a3048c187ae9bc793794c095 \ No newline at end of file +c84b55c256ccb0ee042643a8a7f7f4dc429ff157 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_fuzzy.py b/selfdrive/test/process_replay/test_fuzzy.py index d295092b2..6bcc94911 100755 --- a/selfdrive/test/process_replay/test_fuzzy.py +++ b/selfdrive/test/process_replay/test_fuzzy.py @@ -12,7 +12,7 @@ import openpilot.selfdrive.test.process_replay.process_replay as pr # These processes currently fail because of unrealistic data breaking assumptions # that openpilot makes causing error with NaN, inf, int size, array indexing ... # TODO: Make each one testable -NOT_TESTED = ['controlsd', 'plannerd', 'calibrationd', 'dmonitoringd', 'paramsd', 'dmonitoringmodeld', 'modeld'] +NOT_TESTED = ['controlsd', 'card', 'plannerd', 'calibrationd', 'dmonitoringd', 'paramsd', 'dmonitoringmodeld', 'modeld'] TEST_CASES = [(cfg.proc_name, copy.deepcopy(cfg)) for cfg in pr.CONFIGS if cfg.proc_name not in NOT_TESTED] diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index b3dcbb03d..c0a425b59 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -41,23 +41,23 @@ source_segments = [ ] segments = [ - ("BODY", "regen02ECB79BACC|2024-05-18--04-29-29--0"), - ("HYUNDAI", "regen845DC1916E6|2024-05-18--04-30-52--0"), - ("HYUNDAI2", "regenBAE0915FE22|2024-05-18--04-33-11--0"), - ("TOYOTA", "regen1108D19FC2E|2024-05-18--04-34-34--0"), - ("TOYOTA2", "regen846521F39C7|2024-05-18--04-35-58--0"), - ("TOYOTA3", "regen788C3623D11|2024-05-18--04-38-21--0"), - ("HONDA", "regenDE43F170E99|2024-05-18--04-39-47--0"), - ("HONDA2", "regen1EE0FA383C3|2024-05-18--04-41-12--0"), - ("CHRYSLER", "regen9C5A30F471C|2024-05-18--04-42-36--0"), - ("RAM", "regenCCA313D117D|2024-05-18--04-44-53--0"), - ("SUBARU", "regenA41511F882A|2024-05-18--04-47-14--0"), - ("GM", "regen9D7B9CE4A66|2024-05-18--04-48-36--0"), - ("GM2", "regen07CECA52D41|2024-05-18--04-50-55--0"), - ("NISSAN", "regen2D6B856D0AE|2024-05-18--04-52-17--0"), - ("VOLKSWAGEN", "regen2D3AC6A6F05|2024-05-18--04-53-41--0"), - ("MAZDA", "regen0D5A777DD16|2024-05-18--04-56-02--0"), - ("FORD", "regen235D0937965|2024-05-18--04-58-16--0"), + ("BODY", "regen29FD9FF7760|2024-05-21--06-58-51--0"), + ("HYUNDAI", "regen0B1B76A1C27|2024-05-21--06-57-53--0"), + ("HYUNDAI2", "regen3BB55FA5E20|2024-05-21--06-59-03--0"), + ("TOYOTA", "regenF6FB954C1E2|2024-05-21--06-57-53--0"), + ("TOYOTA2", "regen0AC637CE7BA|2024-05-21--06-57-54--0"), + ("TOYOTA3", "regenC7BE3FAE496|2024-05-21--06-59-01--0"), + ("HONDA", "regen58E9F8B695A|2024-05-21--06-57-55--0"), + ("HONDA2", "regen8695608EB15|2024-05-21--06-57-55--0"), + ("CHRYSLER", "regenB0F8C25C902|2024-05-21--06-59-47--0"), + ("RAM", "regenB3B2C7A105B|2024-05-21--07-00-47--0"), + ("SUBARU", "regen860FD736DCC|2024-05-21--07-00-50--0"), + ("GM", "regen8CB3048DEB9|2024-05-21--06-59-49--0"), + ("GM2", "regen379D446541D|2024-05-21--07-00-51--0"), + ("NISSAN", "regen24871108F80|2024-05-21--07-00-38--0"), + ("VOLKSWAGEN", "regenF390392F275|2024-05-21--07-00-52--0"), + ("MAZDA", "regenE5A36020581|2024-05-21--07-01-51--0"), + ("FORD", "regenDC288ED0D78|2024-05-21--07-02-18--0"), ] # dashcamOnly makes don't need to be tested until a full port is done @@ -109,7 +109,7 @@ def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=Non if not check_openpilot_enabled(log_msgs): return f"Route did not enable at all or for long enough: {new_log_path}", log_msgs - if cfg.proc_name != 'ubloxd' or segment != 'regenBAE0915FE22|2024-05-18--04-33-11--0': + if cfg.proc_name != 'ubloxd' or segment != 'regen3BB55FA5E20|2024-05-21--06-59-03--0': seen_msgs = {m.which() for m in log_msgs} expected_msgs = set(cfg.subs) if seen_msgs != expected_msgs: diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 14f777330..038bba7b2 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -35,7 +35,8 @@ CPU usage budget MAX_TOTAL_CPU = 250. # total for all 8 cores PROCS = { # Baseline CPU usage by process - "selfdrive.controls.controlsd": 46.0, + "selfdrive.controls.controlsd": 32.0, + "selfdrive.car.card": 22.0, "./loggerd": 14.0, "./encoderd": 17.0, "./camerad": 14.5, From e836845f02adc7abab05de8852859c315780c9d3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 May 2024 01:19:55 -0700 Subject: [PATCH 051/220] update TOTAL_SCONS_NODES --- selfdrive/manager/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/manager/build.py b/selfdrive/manager/build.py index 859d0920c..ac7822d51 100755 --- a/selfdrive/manager/build.py +++ b/selfdrive/manager/build.py @@ -14,7 +14,7 @@ from openpilot.system.version import get_build_metadata MAX_CACHE_SIZE = 4e9 if "CI" in os.environ else 2e9 CACHE_DIR = Path("/data/scons_cache" if AGNOS else "/tmp/scons_cache") -TOTAL_SCONS_NODES = 2560 +TOTAL_SCONS_NODES = 2410 MAX_BUILD_PROGRESS = 100 def build(spinner: Spinner, dirty: bool = False, minimal: bool = False) -> None: From b9c1c1dd37a195660ce44fbb24aaf5057155a6bf Mon Sep 17 00:00:00 2001 From: Shotaro Watanabe Date: Wed, 22 May 2024 02:59:15 +0900 Subject: [PATCH 052/220] devcontainer: mount /dev (#32500) --- .devcontainer/devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7174ee280..3f5b38d12 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -14,6 +14,7 @@ "force_color_prompt": "1" }, "runArgs": [ + "--volume=/dev:/dev", "--volume=/tmp/.X11-unix:/tmp/.X11-unix", "--volume=${localWorkspaceFolder}/.devcontainer/.host/.Xauthority:/home/batman/.Xauthority", "--volume=${localEnv:HOME}/.comma:/home/batman/.comma", @@ -49,4 +50,4 @@ "mounts": [ "type=volume,source=scons_cache,target=/tmp/scons_cache" ] -} \ No newline at end of file +} From e29ed6849e4bd8e53b6ce03cfb860af071d75b16 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 May 2024 16:37:24 -0500 Subject: [PATCH 053/220] [bot] Fingerprints: add missing FW versions from new users (#32501) Export fingerprints --- selfdrive/car/hyundai/fingerprints.py | 1 + selfdrive/car/toyota/fingerprints.py | 1 + 2 files changed, 2 insertions(+) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index e0680ba82..8e574f7a2 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -864,6 +864,7 @@ FW_VERSIONS = { b'\xf1\x00CN7_ SCC FNCUP 1.00 1.01 99110-AA000 ', ], (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA050 4CNDC106', b'\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106', b'\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106', b'\xf1\x00CN7 MDPS C 1.00 1.07 56310AA050\x00 4CNDC107', diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index d23929439..38105e0d9 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -1476,6 +1476,7 @@ FW_VERSIONS = { b'\x01896630E41200\x00\x00\x00\x00', b'\x01896630E41500\x00\x00\x00\x00', b'\x01896630EA3100\x00\x00\x00\x00', + b'\x01896630EA3300\x00\x00\x00\x00', b'\x01896630EA3400\x00\x00\x00\x00', b'\x01896630EA4100\x00\x00\x00\x00', b'\x01896630EA4300\x00\x00\x00\x00', From 527cd74b21a182d423f41db2a04e5f4af3632d16 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 May 2024 15:25:50 -0700 Subject: [PATCH 054/220] CI: cleanup PR review jobs (#32503) --- .github/workflows/auto_pr_review.yaml | 222 +++----------------------- 1 file changed, 24 insertions(+), 198 deletions(-) diff --git a/.github/workflows/auto_pr_review.yaml b/.github/workflows/auto_pr_review.yaml index 8316fedda..447e559c9 100644 --- a/.github/workflows/auto_pr_review.yaml +++ b/.github/workflows/auto_pr_review.yaml @@ -5,7 +5,7 @@ on: jobs: labeler: - name: apply labels + name: review permissions: contents: read pull-requests: write @@ -14,17 +14,17 @@ jobs: - uses: actions/checkout@v4 with: submodules: false + + # Label PRs - uses: actions/labeler@v5.0.0 with: dot: true configuration-path: .github/labeler.yaml - pr_branch_check: - name: check branch - runs-on: ubuntu-latest - if: github.repository == 'commaai/openpilot' - steps: - - uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5 + # Check PR target branch + - name: check branch + uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5 + if: github.repository == 'commaai/openpilot' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -34,194 +34,20 @@ jobs: already-exists-action: close_this already-exists-comment: "Your PR should be made against the `master` branch" - comment: - runs-on: ubuntu-latest - steps: - - name: comment - uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 - if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot' - with: - message: | - - Thanks for contributing to openpilot! In order for us to review your PR as quickly as possible, check the following: - * Convert your PR to a draft unless it's ready to review - * Read the [contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md) - * Before marking as "ready for review", ensure: - * the goal is clearly stated in the description - * all the tests are passing - * the change is [something we merge](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged) - * include a route or your device' dongle ID if relevant - comment_tag: run_id - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - check-pr-template: - runs-on: ubuntu-latest - permissions: - contents: read - issues: write - pull-requests: write - actions: read - if: false && github.event.pull_request.head.repo.full_name != 'commaai/openpilot' - steps: - - uses: actions/github-script@v7 - with: - script: | - // Comment to add to the PR if no template has been used - const NO_TEMPLATE_MESSAGE = - "It looks like you didn't use one of the Pull Request templates. Please check [the contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md). \ - Also make sure that you didn't modify any of the checkboxes or headings within the template."; - // body data for future requests - const body_data = { - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - }; - - // Utility function to extract all headings - const extractHeadings = (markdown) => { - const headingRegex = /^(#{1,6})\s+(.+)$/gm; - const boldTextRegex = /^(?:\*\*|__)(.+?)(?:\*\*|__)\s*$/gm; - const headings = []; - let headingMatch; - while ((headingMatch = headingRegex.exec(markdown))) { - headings.push(headingMatch[2].trim()); - } - let boldMatch; - while ((boldMatch = boldTextRegex.exec(markdown))) { - headings.push(boldMatch[1].trim()); - } - return headings; - }; - - // Utility function to extract all check box descriptions - const extractCheckBoxTexts = (markdown) => { - const checkboxRegex = /^\s*-\s*\[( |x)\]\s+(.+)$/gm; - const checkboxes = []; - let match; - while ((match = checkboxRegex.exec(markdown))) { - checkboxes.push(match[2].trim()); - } - return checkboxes; - }; - - // Utility function to check if a list is a subset of another list - isSubset = (subset, superset) => { - return subset.every((item) => superset.includes(item)); - }; - - // Utility function to check if a list of checkboxes is a subset of another list of checkboxes - isCheckboxSubset = (templateCheckBoxTexts, prTextCheckBoxTexts) => { - // Check if each template checkbox text is a substring of at least one PR checkbox text - // (user should be allowed to add additional text) - return templateCheckBoxTexts.every((item) => prTextCheckBoxTexts.some((element) => element.includes(item))) - } - - // Get filenames of all currently checked-in PR templates - const template_contents = await github.rest.repos.getContent({ - owner: context.repo.owner, - repo: context.repo.repo, - path: ".github/PULL_REQUEST_TEMPLATE", - }); - var template_filenames = []; - for (const content of template_contents.data) { - template_filenames.push(content.path); - } - console.debug("Received template filenames: " + template_filenames); - // Retrieve templates - var templates = []; - for (const template_filename of template_filenames) { - const template_response = await github.rest.repos.getContent({ - owner: context.repo.owner, - repo: context.repo.repo, - path: template_filename, - }); - // Convert Base64 content back - const decoded_template = atob(template_response.data.content); - const headings = extractHeadings(decoded_template); - const checkboxes = extractCheckBoxTexts(decoded_template); - if (!headings.length && !checkboxes.length) { - console.warn( - "Invalid template! Contains neither headings nor checkboxes, ignoring it: \n" + - decoded_template - ); - } else { - templates.push({ headings: headings, checkboxes: checkboxes }); - } - } - // Retrieve the PR Body - const pull_request = await github.rest.issues.get({ - ...body_data, - }); - const pull_request_text = pull_request.data.body; - console.debug("Received Pull Request body: \n" + pull_request_text); - - /* Check if the PR Body matches one of the templates - A template is defined by all headings and checkboxes it contains - We extract all Headings and Checkboxes from the PR text and check if any of the templates is a subset of that - */ - const pr_headings = extractHeadings(pull_request_text); - const pr_checkboxes = extractCheckBoxTexts(pull_request_text); - console.debug("Found Headings in PR body:\n" + pr_headings); - console.debug("Found Checkboxes in PR body:\n" + pr_checkboxes); - var template_found = false; - // Iterate over each template to check if it applies - for (const template of templates) { - console.log( - "Checking for headings: [" + - template.headings + - "] and checkboxes: [" + - template.checkboxes + "]" - ); - if ( - isCheckboxSubset(template.checkboxes, pr_checkboxes) && - isSubset(template.headings, pr_headings) - ) { - console.debug("Found matching template!"); - template_found = true; - } - } - - // List comments from previous runs - var existing_comments = []; - const comments = await github.rest.issues.listComments({ - ...body_data, - }); - for (const comment of comments.data) { - if (comment.body === NO_TEMPLATE_MESSAGE) { - existing_comments.push(comment); - } - } - - // Add a comment to the PR that it is not using a the template (but only if this comment does not exist already) - if (!template_found) { - var comment_already_sent = false; - - // Add an 'in-bot-review' label since this PR doesn't have the template - github.rest.issues.addLabels({ - ...body_data, - labels: ["in-bot-review"], - }); - - if (existing_comments.length < 1) { - github.rest.issues.createComment({ - ...body_data, - body: NO_TEMPLATE_MESSAGE, - }); - } - } else { - // If template has been found, delete any old comment about missing template - for (const existing_comment of existing_comments) { - github.rest.issues.deleteComment({ - ...body_data, - comment_id: existing_comment.id, - }); - } - // Remove the 'in-bot-review' label after the review is done and the PR has passed - github.rest.issues.removeLabel({ - ...body_data, - name: "in-bot-review", - }).catch((error) => { - console.log("Label 'in-bot-review' not found, ignoring"); - }); - } - + # Welcome comment + - name: comment + uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 + if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot' + with: + message: | + + Thanks for contributing to openpilot! In order for us to review your PR as quickly as possible, check the following: + * Convert your PR to a draft unless it's ready to review + * Read the [contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md) + * Before marking as "ready for review", ensure: + * the goal is clearly stated in the description + * all the tests are passing + * the change is [something we merge](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged) + * include a route or your device' dongle ID if relevant + comment_tag: run_id + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 406f30add493006b99569bfbf49562e3192038cc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 May 2024 15:40:00 -0700 Subject: [PATCH 055/220] more apt dependency cleanup (#32502) rm --- tools/install_ubuntu_dependencies.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 0e3d453ce..1f8ef24ea 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -41,8 +41,6 @@ function install_ubuntu_common_requirements() { libgles2-mesa-dev \ libglfw3-dev \ libglib2.0-0 \ - libomp-dev \ - libpng16-16 \ libqt5charts5-dev \ libncurses5-dev \ libssl-dev \ From 9f327aeb4824576497a57f077fe9b8243b95e8c0 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 22 May 2024 01:01:04 +0100 Subject: [PATCH 056/220] Ford: detect missing LKAS from EPS configuration (#31821) * debug: disable FW cache * Ford: detect missing TJA/LCA config and disable LKAS * set dashcamOnly * revert * clean up * clean up * some CAN FD do not have 0x01 block for PSCM * bump cereal (fork) * remove confusing comment * add flags/event * remove duplicate from events * copy can be next pr * dashcamOnly if no config comes back either (this shouldn't happen) * flipped * can do this * Revert "can do this" This reverts commit c3d311b2ffb7bbc346c7f702ac5c1934bc495c65. * Revert "flipped" This reverts commit 75c01fb4c5f7fdc9222ea13b8901f76b5b419c99. * Revert "dashcamOnly if no config comes back either (this shouldn't happen)" This reverts commit f82624a0eb28bf683660f86b3ddfd44717a6915f. --------- Co-authored-by: Shane Smiskol --- selfdrive/car/ford/interface.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 7dca45808..1ae57965e 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -39,6 +39,18 @@ class CarInterface(CarInterfaceBase): if ret.flags & FordFlags.CANFD: ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_FORD_CANFD + else: + # Lock out if the car does not have needed lateral and longitudinal control APIs. + # Note that we also check CAN for adaptive cruise, but no known signal for LCA exists + pscm_config = next((fw for fw in car_fw if fw.ecu == Ecu.eps and b'\x22\xDE\x01' in fw.request), None) + if pscm_config: + if len(pscm_config.response) != 24: + ret.dashcamOnly = True + else: + config_tja = pscm_config.response[7] # Traffic Jam Assist + config_lca = pscm_config.response[8] # Lane Centering Assist + if config_tja != 0xFF or config_lca != 0xFF: + ret.dashcamOnly = True # Auto Transmission: 0x732 ECU or Gear_Shift_by_Wire_FD1 found_ecus = [fw.ecu for fw in car_fw] From d2340854967197836d6cc8f27d55039c1f205243 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 22 May 2024 08:27:25 +0800 Subject: [PATCH 057/220] ui/update_dmonitoring: Improve readability of r_xyz matrix initialization (#32359) --- selfdrive/ui/ui.cc | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index c4ddd17e2..0ff4f3111 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -125,25 +125,27 @@ void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &drivers scene.driver_pose_coss[i] = cosf(scene.driver_pose_vals[i]*(1.0-dm_fade_state)); } + auto [sin_y, sin_x, sin_z] = scene.driver_pose_sins; + auto [cos_y, cos_x, cos_z] = scene.driver_pose_coss; + const mat3 r_xyz = (mat3){{ - scene.driver_pose_coss[1]*scene.driver_pose_coss[2], - scene.driver_pose_coss[1]*scene.driver_pose_sins[2], - -scene.driver_pose_sins[1], + cos_x * cos_z, + cos_x * sin_z, + -sin_x, - -scene.driver_pose_sins[0]*scene.driver_pose_sins[1]*scene.driver_pose_coss[2] - scene.driver_pose_coss[0]*scene.driver_pose_sins[2], - -scene.driver_pose_sins[0]*scene.driver_pose_sins[1]*scene.driver_pose_sins[2] + scene.driver_pose_coss[0]*scene.driver_pose_coss[2], - -scene.driver_pose_sins[0]*scene.driver_pose_coss[1], + -sin_y * sin_x * cos_z - cos_y * sin_z, + -sin_y * sin_x * sin_z + cos_y * cos_z, + -sin_y * cos_x, - scene.driver_pose_coss[0]*scene.driver_pose_sins[1]*scene.driver_pose_coss[2] - scene.driver_pose_sins[0]*scene.driver_pose_sins[2], - scene.driver_pose_coss[0]*scene.driver_pose_sins[1]*scene.driver_pose_sins[2] + scene.driver_pose_sins[0]*scene.driver_pose_coss[2], - scene.driver_pose_coss[0]*scene.driver_pose_coss[1], + cos_y * sin_x * cos_z - sin_y * sin_z, + cos_y * sin_x * sin_z + sin_y * cos_z, + cos_y * cos_x, }}; // transform vertices for (int kpi = 0; kpi < std::size(default_face_kpts_3d); kpi++) { - vec3 kpt_this = default_face_kpts_3d[kpi]; - kpt_this = matvecmul3(r_xyz, kpt_this); - scene.face_kpts_draw[kpi] = (vec3){{(float)kpt_this.v[0], (float)kpt_this.v[1], (float)(kpt_this.v[2] * (1.0-dm_fade_state) + 8 * dm_fade_state)}}; + vec3 kpt_this = matvecmul3(r_xyz, default_face_kpts_3d[kpi]); + scene.face_kpts_draw[kpi] = (vec3){{kpt_this.v[0], kpt_this.v[1], (float)(kpt_this.v[2] * (1.0-dm_fade_state) + 8 * dm_fade_state)}}; } } From 25cc8a96ef22df5c8d6951c159045ae4e6d94807 Mon Sep 17 00:00:00 2001 From: 19igari <71631129+19igari@users.noreply.github.com> Date: Wed, 22 May 2024 10:41:04 +0900 Subject: [PATCH 058/220] fix(modeld): Fix for unpredictable behavior in commonmodel_pyx.pyx (#32482) Avoid undefined behavior Co-authored-by: 19igari --- selfdrive/modeld/models/commonmodel_pyx.pyx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/selfdrive/modeld/models/commonmodel_pyx.pyx b/selfdrive/modeld/models/commonmodel_pyx.pyx index e33d301af..bc59b7a23 100644 --- a/selfdrive/modeld/models/commonmodel_pyx.pyx +++ b/selfdrive/modeld/models/commonmodel_pyx.pyx @@ -37,7 +37,11 @@ cdef class ModelFrame: def prepare(self, VisionBuf buf, float[:] projection, CLMem output): cdef mat3 cprojection memcpy(cprojection.v, &projection[0], 9*sizeof(float)) - cdef float * data = self.frame.prepare(buf.buf.buf_cl, buf.width, buf.height, buf.stride, buf.uv_offset, cprojection, output.mem) + cdef float * data + if output is None: + data = self.frame.prepare(buf.buf.buf_cl, buf.width, buf.height, buf.stride, buf.uv_offset, cprojection, NULL) + else: + data = self.frame.prepare(buf.buf.buf_cl, buf.width, buf.height, buf.stride, buf.uv_offset, cprojection, output.mem) if not data: return None return np.asarray( data) From 5e63906a3f4ef4eb01c99f23592aa87f2cc419a9 Mon Sep 17 00:00:00 2001 From: Marcin Perlikowski Date: Wed, 22 May 2024 05:24:45 +0200 Subject: [PATCH 059/220] Hyundai: add fingerprint for 2020 IONIQ PHEV (#31301) add fingerprint for 2020 Hyundai IONIQ PHEV Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 8e574f7a2..a4b84361a 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -117,6 +117,7 @@ FW_VERSIONS = { b'\xf1\x00AEhe SCC FHCUP 1.00 1.02 99110-G2100 ', ], (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2210 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2310 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2510 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2560 4APHC101', From b059f2eda807aca543b7e33031d52fc5a45be31f Mon Sep 17 00:00:00 2001 From: roberttruong Date: Wed, 22 May 2024 13:31:47 +1000 Subject: [PATCH 060/220] Additional Subaru Impreza 2022 Fingerprint (#31916) * Update fingerprints.py Add fingerprint for Subaru Impreza 2022 Australia * auto_fingerprint --------- Co-authored-by: Shane Smiskol --- selfdrive/car/subaru/fingerprints.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/car/subaru/fingerprints.py b/selfdrive/car/subaru/fingerprints.py index 41727d762..e3bd9d909 100644 --- a/selfdrive/car/subaru/fingerprints.py +++ b/selfdrive/car/subaru/fingerprints.py @@ -164,6 +164,7 @@ FW_VERSIONS = { b'\xa2 \x194\x00', b'\xa2 `\x00', b'\xa2 !3\x00', + b'\xa2 !6\x00', b'\xa2 !`\x00', b'\xa2 !i\x00', ], @@ -172,6 +173,7 @@ FW_VERSIONS = { b'\n\xc0\x04\x01', b'\x9a\xc0\x00\x00', b'\x9a\xc0\x04\x00', + b'\x9a\xc0\n\x01', ], (Ecu.fwdCamera, 0x787, None): [ b'\x00\x00eb\x1f@ "', @@ -181,6 +183,7 @@ FW_VERSIONS = { b'\x00\x00e\x8f\x1f@ )', b'\x00\x00e\x92\x00\x00\x00\x00', b'\x00\x00e\xa4\x00\x00\x00\x00', + b'\x00\x00e\xa4\x1f@ (', ], (Ecu.engine, 0x7e0, None): [ b'\xca!`0\x07', @@ -188,6 +191,7 @@ FW_VERSIONS = { b'\xca!ap\x07', b'\xca!f@\x07', b'\xca!fp\x07', + b'\xcaacp\x07', b'\xcc!`p\x07', b'\xcc!fp\x07', b'\xcc"f0\x07', @@ -200,6 +204,7 @@ FW_VERSIONS = { b'\xf3"fr\x07', ], (Ecu.transmission, 0x7e1, None): [ + b'\xe6\x15\x042\x00', b'\xe6\xf5\x04\x00\x00', b'\xe6\xf5$\x00\x00', b'\xe6\xf5D0\x00', From 9fa92c222513731a19009781ce463bb9e69158db Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 May 2024 23:23:14 -0500 Subject: [PATCH 061/220] card: only exit ELM once done with ECU knock outs (#32505) * only exit elm once done with knock outs * comments! --- selfdrive/car/card.py | 21 ++++++++++++--------- selfdrive/controls/controlsd.py | 1 - 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 2705a3c01..199c42578 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -38,7 +38,7 @@ class Car: self.last_actuators_output = car.CarControl.Actuators.new_message() - params = Params() + self.params = Params() if CI is None: # wait for one pandaState and one CAN packet @@ -46,18 +46,18 @@ class Car: get_one_can(self.can_sock) num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates) - experimental_long_allowed = params.get_bool("ExperimentalLongitudinalEnabled") + experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled") self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas) else: self.CI, self.CP = CI, CI.CP # set alternative experiences from parameters - self.disengage_on_accelerator = params.get_bool("DisengageOnAccelerator") + self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator") self.CP.alternativeExperience = 0 if not self.disengage_on_accelerator: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS - openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle") + openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle") controller_available = self.CI.CC is not None and openpilot_enabled_toggle and not self.CP.dashcamOnly @@ -68,15 +68,15 @@ class Car: self.CP.safetyConfigs = [safety_config] # Write previous route's CarParams - prev_cp = params.get("CarParamsPersistent") + prev_cp = self.params.get("CarParamsPersistent") if prev_cp is not None: - params.put("CarParamsPrevRoute", prev_cp) + self.params.put("CarParamsPrevRoute", prev_cp) # Write CarParams for controls and radard cp_bytes = self.CP.to_bytes() - params.put("CarParams", cp_bytes) - params.put_nonblocking("CarParamsCache", cp_bytes) - params.put_nonblocking("CarParamsPersistent", cp_bytes) + self.params.put("CarParams", cp_bytes) + self.params.put_nonblocking("CarParamsCache", cp_bytes) + self.params.put_nonblocking("CarParamsPersistent", cp_bytes) self.events = Events() @@ -151,7 +151,10 @@ class Car: if not self.initialized_prev: # Initialize CarInterface, once controls are ready + # TODO: this can make us miss at least a few cycles when doing an ECU knockout self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan']) + # signal boardd to switch to car safety mode + self.params.put_bool_nonblocking("ControlsReady", True) if self.sm.all_alive(['carControl']): # send car controls over can diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index d007cd947..110826d94 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -405,7 +405,6 @@ class Controls: self.initialized = True self.set_initial_state() - self.params.put_bool_nonblocking("ControlsReady", True) cloudlog.event( "controlsd.initialized", From ffb34e558fe369bb5a5d6d7ff476c3b8e601f6db Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 May 2024 23:21:31 -0700 Subject: [PATCH 062/220] Revert "Ford: detect missing LKAS from EPS configuration (#31821)" This reverts commit 9f327aeb4824576497a57f077fe9b8243b95e8c0. --- selfdrive/car/ford/interface.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 1ae57965e..7dca45808 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -39,18 +39,6 @@ class CarInterface(CarInterfaceBase): if ret.flags & FordFlags.CANFD: ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_FORD_CANFD - else: - # Lock out if the car does not have needed lateral and longitudinal control APIs. - # Note that we also check CAN for adaptive cruise, but no known signal for LCA exists - pscm_config = next((fw for fw in car_fw if fw.ecu == Ecu.eps and b'\x22\xDE\x01' in fw.request), None) - if pscm_config: - if len(pscm_config.response) != 24: - ret.dashcamOnly = True - else: - config_tja = pscm_config.response[7] # Traffic Jam Assist - config_lca = pscm_config.response[8] # Lane Centering Assist - if config_tja != 0xFF or config_lca != 0xFF: - ret.dashcamOnly = True # Auto Transmission: 0x732 ECU or Gear_Shift_by_Wire_FD1 found_ecus = [fw.ecu for fw in car_fw] From a5ff4a94a6686dacfe0edc3c91951c2b56d2952e Mon Sep 17 00:00:00 2001 From: Shotaro Watanabe Date: Wed, 22 May 2024 23:40:10 +0900 Subject: [PATCH 063/220] devcontainer: add bash-completion (#32510) --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 2bd1ccfd6..af67bdbe5 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,6 @@ FROM ghcr.io/commaai/openpilot-base:latest -RUN apt update && apt install -y vim net-tools usbutils htop ripgrep tmux wget mesa-utils xvfb libxtst6 libxv1 libglu1-mesa libegl1-mesa gdb +RUN apt update && apt install -y vim net-tools usbutils htop ripgrep tmux wget mesa-utils xvfb libxtst6 libxv1 libglu1-mesa libegl1-mesa gdb bash-completion RUN pip install ipython jupyter jupyterlab RUN cd /tmp && \ From d96b8bbc01f8c18c38b52cb440f8d72f1d211398 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 May 2024 12:02:26 -0500 Subject: [PATCH 064/220] [bot] Fingerprints: add missing FW versions from new users (#32511) Export fingerprints --- selfdrive/car/hyundai/fingerprints.py | 1 + selfdrive/car/toyota/fingerprints.py | 1 + 2 files changed, 2 insertions(+) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index a4b84361a..c1880567b 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -976,6 +976,7 @@ FW_VERSIONS = { b'\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ', ], (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00NE1 MFC AT CAN LHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT CAN LHD 1.00 1.05 99211-GI010 220614', b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813', diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index 38105e0d9..631953571 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -521,6 +521,7 @@ FW_VERSIONS = { ], (Ecu.abs, 0x7b0, None): [ b'\x01F152602280\x00\x00\x00\x00\x00\x00', + b'\x01F152602281\x00\x00\x00\x00\x00\x00', b'\x01F152602470\x00\x00\x00\x00\x00\x00', b'\x01F152602560\x00\x00\x00\x00\x00\x00', b'\x01F152602590\x00\x00\x00\x00\x00\x00', From fe9a091f116dc0c3bb55d35b31512866663af6af Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Wed, 22 May 2024 13:04:43 -0400 Subject: [PATCH 065/220] CI: Drive a loop in MetaDrive (#32308) * finish failure on crossing any line * update * standardize queue messages * update control_command_gen * fix * fix logic * update closing type * update test * update logic * update test * add out of lane to local * ci arrive_dest * pytest integration * update ci_config * fix ruff * move test termination to time * better * better order * curve_len * add buffer * cleanup * cleanup * cleanup * cleanup * out_of_lane * cleanup * merge tests * run 90s * change test name * local out of lane detect * out_of_lane * static anal * cleanup * test_duration * change setup_class -> setup_create_bridge * no print state during test * new out_of_lane detect * cleanup print in common.py * fix * fix * check distance vs time * cleanup * cleanup increase check time * minimum bridge test time * wording * cleanup --- tools/sim/bridge/common.py | 5 +- .../sim/bridge/metadrive/metadrive_bridge.py | 22 +++-- .../sim/bridge/metadrive/metadrive_process.py | 31 +++++-- tools/sim/bridge/metadrive/metadrive_world.py | 41 ++++++++- tools/sim/scenarios/metadrive/stay_in_lane.py | 92 ------------------- tools/sim/tests/conftest.py | 8 ++ tools/sim/tests/test_metadrive_bridge.py | 10 +- tools/sim/tests/test_sim_bridge.py | 15 ++- 8 files changed, 110 insertions(+), 114 deletions(-) delete mode 100755 tools/sim/scenarios/metadrive/stay_in_lane.py create mode 100644 tools/sim/tests/conftest.py diff --git a/tools/sim/bridge/common.py b/tools/sim/bridge/common.py index 275a9a764..64407143f 100644 --- a/tools/sim/bridge/common.py +++ b/tools/sim/bridge/common.py @@ -60,6 +60,8 @@ class SimulatorBridge(ABC): self.past_startup_engaged = False self.startup_button_prev = True + self.test_run = False + def _on_shutdown(self, signal, frame): self.shutdown() @@ -193,7 +195,8 @@ Ignition: {self.simulator_state.ignition} Engaged: {self.simulator_state.is_enga self.world.tick() self.world.read_cameras() - if self.rk.frame % 25 == 0: + # don't print during test, so no print/IO Block between OP and metadrive processes + if not self.test_run and self.rk.frame % 25 == 0: self.print_status() self.started.value = True diff --git a/tools/sim/bridge/metadrive/metadrive_bridge.py b/tools/sim/bridge/metadrive/metadrive_bridge.py index cbac21509..74dc1210b 100644 --- a/tools/sim/bridge/metadrive/metadrive_bridge.py +++ b/tools/sim/bridge/metadrive/metadrive_bridge.py @@ -1,3 +1,4 @@ +import math from multiprocessing import Queue from metadrive.component.sensors.base_camera import _cuda_enable @@ -27,20 +28,21 @@ def curve_block(length, angle=45, direction=0): } def create_map(track_size=60): + curve_len = track_size * 2 return dict( type=MapGenerateMethod.PG_MAP_FILE, lane_num=2, - lane_width=3.5, + lane_width=4.5, config=[ None, straight_block(track_size), - curve_block(track_size*2, 90), + curve_block(curve_len, 90), straight_block(track_size), - curve_block(track_size*2, 90), + curve_block(curve_len, 90), straight_block(track_size), - curve_block(track_size*2, 90), + curve_block(curve_len, 90), straight_block(track_size), - curve_block(track_size*2, 90), + curve_block(curve_len, 90), ] ) @@ -48,11 +50,13 @@ def create_map(track_size=60): class MetaDriveBridge(SimulatorBridge): TICKS_PER_FRAME = 5 - def __init__(self, dual_camera, high_quality): - self.should_render = False - + def __init__(self, dual_camera, high_quality, test_duration=math.inf, test_run=False): super().__init__(dual_camera, high_quality) + self.should_render = False + self.test_run = test_run + self.test_duration = test_duration if self.test_run else math.inf + def spawn_world(self, queue: Queue): sensors = { "rgb_road": (RGBCameraRoad, W, H, ) @@ -83,4 +87,4 @@ class MetaDriveBridge(SimulatorBridge): preload_models=False ) - return MetaDriveWorld(queue, config, self.dual_camera) + return MetaDriveWorld(queue, config, self.test_duration, self.test_run, self.dual_camera) diff --git a/tools/sim/bridge/metadrive/metadrive_process.py b/tools/sim/bridge/metadrive/metadrive_process.py index 79eefcd54..ec10b96b3 100644 --- a/tools/sim/bridge/metadrive/metadrive_process.py +++ b/tools/sim/bridge/metadrive/metadrive_process.py @@ -1,4 +1,5 @@ import math +import time import numpy as np from collections import namedtuple @@ -49,7 +50,7 @@ def apply_metadrive_patches(arrive_dest_done=True): def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera_array, image_lock, controls_recv: Connection, simulation_state_send: Connection, vehicle_state_send: Connection, - exit_event): + exit_event, start_time, test_duration, test_run): arrive_dest_done = config.pop("arrive_dest_done", True) apply_metadrive_patches(arrive_dest_done) @@ -60,9 +61,15 @@ def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera env = MetaDriveEnv(config) + def get_current_lane_info(vehicle): + _, lane_info, on_lane = vehicle.navigation._get_current_lane(vehicle) + lane_idx = lane_info[2] if lane_info is not None else None + return lane_idx, on_lane + def reset(): env.reset() env.vehicle.config["max_speed_km_h"] = 1000 + lane_idx_prev, _ = get_current_lane_info(env.vehicle) simulation_state = metadrive_simulation_state( running=True, @@ -71,7 +78,9 @@ def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera ) simulation_state_send.send(simulation_state) - reset() + return lane_idx_prev + + lane_idx_prev = reset() def get_cam_as_rgb(cam): cam = env.engine.sensors[cam] @@ -108,13 +117,23 @@ def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera vc = [steer_metadrive, gas] if should_reset: - reset() + lane_idx_prev = reset() if rk.frame % 5 == 0: - obs, _, terminated, _, info = env.step(vc) + _, _, terminated, _, _ = env.step(vc) + timeout = True if time.monotonic() - start_time >= test_duration else False + lane_idx_curr, on_lane = get_current_lane_info(env.vehicle) + out_of_lane = lane_idx_curr != lane_idx_prev or not on_lane + lane_idx_prev = lane_idx_curr + + if terminated or ((out_of_lane or timeout) and test_run): + if terminated: + done_result = env.done_function("default_agent") + elif out_of_lane: + done_result = (True, {"out_of_lane" : True}) + elif timeout: + done_result = (True, {"timeout" : True}) - if terminated: - done_result = env.done_function("default_agent") simulation_state = metadrive_simulation_state( running=False, done=done_result[0], diff --git a/tools/sim/bridge/metadrive/metadrive_world.py b/tools/sim/bridge/metadrive/metadrive_world.py index 35a828868..5d1a2f307 100644 --- a/tools/sim/bridge/metadrive/metadrive_world.py +++ b/tools/sim/bridge/metadrive/metadrive_world.py @@ -14,7 +14,7 @@ from openpilot.tools.sim.lib.camerad import W, H class MetaDriveWorld(World): - def __init__(self, status_q, config, dual_camera = False): + def __init__(self, status_q, config, test_duration, test_run, dual_camera=False): super().__init__(dual_camera) self.status_q = status_q self.camera_array = Array(ctypes.c_uint8, W*H*3) @@ -30,11 +30,18 @@ class MetaDriveWorld(World): self.exit_event = multiprocessing.Event() + self.test_run = test_run + + self.start_time = time.monotonic() + self.first_engage = None + self.last_check_timestamp = 0 + self.distance_moved = 0 + self.metadrive_process = multiprocessing.Process(name="metadrive process", target= functools.partial(metadrive_process, dual_camera, config, self.camera_array, self.wide_camera_array, self.image_lock, self.controls_recv, self.simulation_state_send, - self.vehicle_state_send, self.exit_event)) + self.vehicle_state_send, self.exit_event, self.start_time, test_duration, self.test_run)) self.metadrive_process.start() self.status_q.put(QueueMessage(QueueMessageType.START_STATUS, "starting")) @@ -43,7 +50,7 @@ class MetaDriveWorld(World): print("---- Spawning Metadrive world, this might take awhile ----") print("----------------------------------------------------------") - self.vehicle_state_recv.recv() # wait for a state message to ensure metadrive is launched + self.vehicle_last_pos = self.vehicle_state_recv.recv().position # wait for a state message to ensure metadrive is launched self.status_q.put(QueueMessage(QueueMessageType.START_STATUS, "started")) self.steer_ratio = 15 @@ -76,12 +83,38 @@ class MetaDriveWorld(World): def read_sensors(self, state: SimulatorState): while self.vehicle_state_recv.poll(0): md_vehicle: metadrive_vehicle_state = self.vehicle_state_recv.recv() + curr_pos = md_vehicle.position + state.velocity = md_vehicle.velocity state.bearing = md_vehicle.bearing state.steering_angle = md_vehicle.steering_angle - state.gps.from_xy(md_vehicle.position) + state.gps.from_xy(curr_pos) state.valid = True + is_engaged = state.is_engaged + if is_engaged and self.first_engage is None: + self.first_engage = time.monotonic() + # check moving 5 seconds after engaged, doesn't move right away + after_engaged_check = is_engaged and time.monotonic() - self.first_engage >= 5 and self.test_run + + x_dist = abs(curr_pos[0] - self.vehicle_last_pos[0]) + y_dist = abs(curr_pos[1] - self.vehicle_last_pos[1]) + dist_threshold = 1 + if x_dist >= dist_threshold or y_dist >= dist_threshold: # position not the same during staying still, > threshold is considered moving + self.distance_moved += x_dist + y_dist + + time_check_threshold = 30 + current_time = time.monotonic() + since_last_check = current_time - self.last_check_timestamp + if since_last_check >= time_check_threshold: + if after_engaged_check and self.distance_moved == 0: + self.status_q.put(QueueMessage(QueueMessageType.TERMINATION_INFO, {"vehicle_not_moving" : True})) + self.exit_event.set() + + self.last_check_timestamp = current_time + self.distance_moved = 0 + self.vehicle_last_pos = curr_pos + def read_cameras(self): pass diff --git a/tools/sim/scenarios/metadrive/stay_in_lane.py b/tools/sim/scenarios/metadrive/stay_in_lane.py deleted file mode 100755 index 683ce5516..000000000 --- a/tools/sim/scenarios/metadrive/stay_in_lane.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python - -from multiprocessing import Queue - -from metadrive.component.sensors.base_camera import _cuda_enable -from metadrive.component.map.pg_map import MapGenerateMethod - -from openpilot.tools.sim.bridge.common import SimulatorBridge -from openpilot.tools.sim.bridge.metadrive.metadrive_common import RGBCameraRoad, RGBCameraWide -from openpilot.tools.sim.bridge.metadrive.metadrive_world import MetaDriveWorld -from openpilot.tools.sim.lib.camerad import W, H - - -def create_map(): - return dict( - type=MapGenerateMethod.PG_MAP_FILE, - lane_num=2, - lane_width=3.5, - config=[ - { - "id": "S", - "pre_block_socket_index": 0, - "length": 60, - }, - { - "id": "C", - "pre_block_socket_index": 0, - "length": 60, - "radius": 600, - "angle": 45, - "dir": 0, - }, - ] - ) - - -class MetaDriveBridge(SimulatorBridge): - TICKS_PER_FRAME = 5 - - def __init__(self, world_status_q, dual_camera, high_quality): - self.world_status_q = world_status_q - self.should_render = False - - super().__init__(dual_camera, high_quality) - - def spawn_world(self): - sensors = { - "rgb_road": (RGBCameraRoad, W, H, ) - } - - if self.dual_camera: - sensors["rgb_wide"] = (RGBCameraWide, W, H) - - config = dict( - use_render=self.should_render, - vehicle_config=dict( - enable_reverse=False, - image_source="rgb_road", - ), - sensors=sensors, - image_on_cuda=_cuda_enable, - image_observation=True, - interface_panel=[], - out_of_route_done=True, - on_continuous_line_done=True, - crash_vehicle_done=True, - crash_object_done=True, - arrive_dest_done=True, - traffic_density=0.0, - map_config=create_map(), - map_region_size=2048, - decision_repeat=1, - physics_world_step_size=self.TICKS_PER_FRAME/100, - preload_models=False - ) - - return MetaDriveWorld(world_status_q, config, self.dual_camera) - - -if __name__ == "__main__": - command_queue: Queue = Queue() - world_status_q: Queue = Queue() - simulator_bridge = MetaDriveBridge(world_status_q, True, False) - simulator_process = simulator_bridge.run(command_queue) - - while True: - world_status = world_status_q.get() - print(f"World Status: {str(world_status)}") - if world_status["status"] == "terminating": - break - - simulator_process.join() diff --git a/tools/sim/tests/conftest.py b/tools/sim/tests/conftest.py new file mode 100644 index 000000000..ddf663527 --- /dev/null +++ b/tools/sim/tests/conftest.py @@ -0,0 +1,8 @@ +import pytest + +def pytest_addoption(parser): + parser.addoption("--test_duration", action="store", default=60, type=int, help="Seconds to run metadrive drive") + +@pytest.fixture +def test_duration(request): + return request.config.getoption("--test_duration") diff --git a/tools/sim/tests/test_metadrive_bridge.py b/tools/sim/tests/test_metadrive_bridge.py index 37bae6378..f06110184 100755 --- a/tools/sim/tests/test_metadrive_bridge.py +++ b/tools/sim/tests/test_metadrive_bridge.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import pytest import warnings + # Since metadrive depends on pkg_resources, and pkg_resources is deprecated as an API warnings.filterwarnings("ignore", category=DeprecationWarning) @@ -10,5 +11,12 @@ from openpilot.tools.sim.tests.test_sim_bridge import TestSimBridgeBase @pytest.mark.slow @pytest.mark.filterwarnings("ignore::pyopencl.CompilerWarning") # Unimportant warning of non-empty compile log class TestMetaDriveBridge(TestSimBridgeBase): + @pytest.fixture(autouse=True) + def setup_create_bridge(self, test_duration): + # run bridge test for at least 60s, since not-moving check runs every 30s + if test_duration < 60: + test_duration = 60 + self.test_duration = test_duration + def create_bridge(self): - return MetaDriveBridge(False, False) + return MetaDriveBridge(False, False, self.test_duration, True) diff --git a/tools/sim/tests/test_sim_bridge.py b/tools/sim/tests/test_sim_bridge.py index 6b8b811fb..aaa90f153 100644 --- a/tools/sim/tests/test_sim_bridge.py +++ b/tools/sim/tests/test_sim_bridge.py @@ -7,6 +7,7 @@ from multiprocessing import Queue from cereal import messaging from openpilot.common.basedir import BASEDIR +from openpilot.tools.sim.bridge.common import QueueMessageType SIM_DIR = os.path.join(BASEDIR, "tools/sim") @@ -19,7 +20,7 @@ class TestSimBridgeBase: def setup_method(self): self.processes = [] - def test_engage(self): + def test_driving(self): # Startup manager and bridge.py. Check processes are running, then engage and verify. p_manager = subprocess.Popen("./launch_openpilot.sh", cwd=SIM_DIR) self.processes.append(p_manager) @@ -70,6 +71,18 @@ class TestSimBridgeBase: assert min_counts_control_active == control_active, f"Simulator did not engage a minimal of {min_counts_control_active} steps was {control_active}" + failure_states = [] + while bridge.started.value: + continue + + while not q.empty(): + state = q.get() + if state.type == QueueMessageType.TERMINATION_INFO: + done_info = state.info + failure_states = [done_state for done_state in done_info if done_state != "timeout" and done_info[done_state]] + break + assert len(failure_states) == 0, f"Simulator fails to finish a loop. Failure states: {failure_states}" + def teardown_method(self): print("Test shutting down. CommIssues are acceptable") for p in reversed(self.processes): From fa2d5bca57a10bc54667d7e5e3e2ef5fbe80992f Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 22 May 2024 15:18:06 -0700 Subject: [PATCH 066/220] controlsd: explicitly ignore camera states in process replay (#32515) * explicitly ignore * Update selfdrive/controls/controlsd.py Co-authored-by: Shane Smiskol --------- Co-authored-by: Shane Smiskol --- selfdrive/controls/controlsd.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 110826d94..1fb7f5949 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -91,6 +91,9 @@ class Controls: ignore = self.sensor_packets + ['testJoystick'] if SIMULATION: ignore += ['driverCameraState', 'managerState'] + if REPLAY: + # no vipc in replay will make them ignored anyways + ignore += ['roadCameraState', 'wideRoadCameraState'] self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration', 'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman', 'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters', From 749455c91dc27ed876d1b194c1d84bd481eefb00 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 22 May 2024 15:47:11 -0700 Subject: [PATCH 067/220] Update process replay refs with updated submaster alive behavior (#32508) * add cereal * update cereal * cereal master * lol really * ref com * ref --- cereal | 2 +- selfdrive/test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index 5812f2c07..51cbf6294 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 5812f2c075a5364cecafe4e8ed68a12b12a5631f +Subproject commit 51cbf6294efb356347b2c18b3df9904d11a7ff43 diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index fd1d75346..4b754b989 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -555,7 +555,7 @@ CONFIGS = [ ), ProcessConfig( proc_name="torqued", - pubs=["liveLocationKalman", "carState", "carControl"], + pubs=["liveLocationKalman", "carState", "carControl", "carOutput"], subs=["liveTorqueParameters"], ignore=["logMonoTime"], init_callback=get_car_params_callback, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index dc7e59b54..c3ab38396 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c84b55c256ccb0ee042643a8a7f7f4dc429ff157 \ No newline at end of file +da1b19b2d1d54412ac72f2e9645046d262f9c7ab \ No newline at end of file From ef1b6b47032b862ca220e7c2ca6d9ccfd41d6957 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 May 2024 19:12:54 -0500 Subject: [PATCH 068/220] test car interfaces: catch more FW-related failures (#32514) * only pick ecus from brand * use superset of all requests * much better * clean up * clean up * try 150 * ? * ??? * faster debug * wtf * no clue * run push! * this shouldn't catch it * clean up * rm --- selfdrive/car/tests/test_car_interfaces.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index dfdf44215..618bcd962 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -11,7 +11,7 @@ from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car import gen_empty_fingerprint from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.fingerprints import all_known_cars -from openpilot.selfdrive.car.fw_versions import FW_VERSIONS +from openpilot.selfdrive.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS from openpilot.selfdrive.car.interfaces import get_interface_attr from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID @@ -19,7 +19,10 @@ from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque from openpilot.selfdrive.controls.lib.longcontrol import LongControl from openpilot.selfdrive.test.fuzzy_generation import DrawType, FuzzyGenerator -ALL_ECUS = list({ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()}) +ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()} +ALL_ECUS |= {ecu for config in FW_QUERY_CONFIGS.values() for ecu in config.extra_ecus} + +ALL_REQUESTS = {tuple(r.request) for config in FW_QUERY_CONFIGS.values() for r in config.requests} MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '40')) @@ -31,7 +34,7 @@ def get_fuzzy_car_interface_args(draw: DrawType) -> dict: gen_empty_fingerprint()}) # only pick from possible ecus to reduce search space - car_fw_strategy = st.lists(st.sampled_from(ALL_ECUS)) + car_fw_strategy = st.lists(st.sampled_from(sorted(ALL_ECUS))) params_strategy = st.fixed_dictionaries({ 'fingerprints': fingerprint_strategy, @@ -40,7 +43,9 @@ def get_fuzzy_car_interface_args(draw: DrawType) -> dict: }) params: dict = draw(params_strategy) - params['car_fw'] = [car.CarParams.CarFw(ecu=fw[0], address=fw[1], subAddress=fw[2] or 0) for fw in params['car_fw']] + params['car_fw'] = [car.CarParams.CarFw(ecu=fw[0], address=fw[1], subAddress=fw[2] or 0, + request=draw(st.sampled_from(sorted(ALL_REQUESTS)))) + for fw in params['car_fw']] return params From 423016d6e9213e10fe7ababa128ee8a99b168540 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 22 May 2024 17:16:05 -0700 Subject: [PATCH 069/220] rm disabled notebooks test --- .github/workflows/tools_tests.yaml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index c2e900fb1..fd05300f0 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -87,21 +87,3 @@ jobs: devcontainer exec --workspace-folder . pip install pip-install-test devcontainer exec --workspace-folder . touch /home/batman/.comma/auth.json devcontainer exec --workspace-folder . sudo touch /root/test.txt - - notebooks: - name: notebooks - runs-on: ubuntu-latest - if: false && github.repository == 'commaai/openpilot' - timeout-minutes: 45 - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: Build openpilot - timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache - run: ${{ env.RUN }} "scons -j$(nproc)" - - name: Test notebooks - timeout-minutes: 3 - run: | - ${{ env.RUN }} "pip install nbmake && pytest --nbmake tools/car_porting/examples/" From 7a6818da7edc888ab51f5631775af1eb452375c7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 May 2024 19:27:22 -0500 Subject: [PATCH 070/220] Reapply "Ford: detect missing LKAS from EPS configuration (#31821)" (#32518) * Reapply "Ford: detect missing LKAS from EPS configuration (#31821)" This reverts commit ffb34e558fe369bb5a5d6d7ff476c3b8e601f6db. * catch * now fix * clean up --- selfdrive/car/ford/interface.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 7dca45808..2ef5d427e 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -39,6 +39,18 @@ class CarInterface(CarInterfaceBase): if ret.flags & FordFlags.CANFD: ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_FORD_CANFD + else: + # Lock out if the car does not have needed lateral and longitudinal control APIs. + # Note that we also check CAN for adaptive cruise, but no known signal for LCA exists + pscm_config = next((fw for fw in car_fw if fw.ecu == Ecu.eps and b'\x22\xDE\x01' in fw.request), None) + if pscm_config: + if len(pscm_config.fwVersion) != 24: + ret.dashcamOnly = True + else: + config_tja = pscm_config.fwVersion[7] # Traffic Jam Assist + config_lca = pscm_config.fwVersion[8] # Lane Centering Assist + if config_tja != 0xFF or config_lca != 0xFF: + ret.dashcamOnly = True # Auto Transmission: 0x732 ECU or Gear_Shift_by_Wire_FD1 found_ecus = [fw.ecu for fw in car_fw] From f5752121f8a2029050c63cfa04f2533901ae4f3a Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Thu, 23 May 2024 07:56:18 -0700 Subject: [PATCH 071/220] Removal of pyenv (#32512) * initial removal of pyenv * remove .python-version copy in dockerfile * successful image build with ppa * update prompt * pip install scons * apt install scons * finally fix dockerfile to work with venv * cleanup userflow * increase memory to 100m * typos * wrong variable * lmao --- .python-version | 1 - Dockerfile.openpilot_base | 13 +++----- selfdrive/test/ci_shell.sh | 1 + tools/install_python_dependencies.sh | 46 +++------------------------- tools/install_ubuntu_dependencies.sh | 26 +++++++++++++++- tools/mac_setup.sh | 5 ++- 6 files changed, 38 insertions(+), 54 deletions(-) delete mode 100644 .python-version diff --git a/.python-version b/.python-version deleted file mode 100644 index 0c7d5f5f5..000000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.11.4 diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index 0789a39c3..857f796fd 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -13,7 +13,7 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 COPY tools/install_ubuntu_dependencies.sh /tmp/tools/ -RUN INSTALL_EXTRA_PACKAGES=no /tmp/tools/install_ubuntu_dependencies.sh && \ +RUN INSTALL_EXTRA_PACKAGES=no INSTALL_DEADSNAKES_PPA=yes /tmp/tools/install_ubuntu_dependencies.sh && \ rm -rf /var/lib/apt/lists/* /tmp/* && \ cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \ rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp @@ -64,19 +64,16 @@ RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER $USER ENV POETRY_VIRTUALENVS_CREATE=false -ENV PYENV_VERSION=3.11.4 -ENV PYENV_ROOT="/home/$USER/pyenv" -ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" +ENV VIRTUAL_ENV_ROOT="/home/$USER/venv" +ENV PATH="$VIRTUAL_ENV_ROOT/bin:$PYENV_ROOT/lib:$PATH" -COPY --chown=$USER pyproject.toml poetry.lock .python-version /tmp/ +COPY --chown=$USER pyproject.toml poetry.lock /tmp/ COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/ RUN cd /tmp && \ tools/install_python_dependencies.sh && \ rm -rf /tmp/* && \ - rm -rf /home/$USER/.cache && \ - find /home/$USER/pyenv -type d -name ".git" | xargs rm -rf && \ - rm -rf /home/$USER/pyenv/versions/3.11.4/lib/python3.11/test + rm -rf /home/$USER/.cache USER root RUN sudo git config --global --add safe.directory /tmp/openpilot diff --git a/selfdrive/test/ci_shell.sh b/selfdrive/test/ci_shell.sh index a5ff714b2..1f3fa1f65 100755 --- a/selfdrive/test/ci_shell.sh +++ b/selfdrive/test/ci_shell.sh @@ -11,6 +11,7 @@ fi docker run \ -it \ + --shm-size=100m \ --rm \ --volume $OP_ROOT:$OP_ROOT \ --workdir $PWD \ diff --git a/tools/install_python_dependencies.sh b/tools/install_python_dependencies.sh index df815b582..0a2ae0d58 100755 --- a/tools/install_python_dependencies.sh +++ b/tools/install_python_dependencies.sh @@ -10,50 +10,15 @@ if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then RC_FILE="$HOME/.bash_profile" fi -if ! command -v "pyenv" > /dev/null 2>&1; then - echo "pyenv install ..." - curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - PYENV_PATH_SETUP="export PATH=\$HOME/.pyenv/bin:\$HOME/.pyenv/shims:\$PATH" -fi - -if [ -z "$PYENV_SHELL" ] || [ -n "$PYENV_PATH_SETUP" ]; then - echo "pyenvrc setup ..." - cat < "${HOME}/.pyenvrc" -if [ -z "\$PYENV_ROOT" ]; then - $PYENV_PATH_SETUP - export PYENV_ROOT="\$HOME/.pyenv" - eval "\$(pyenv init -)" - eval "\$(pyenv virtualenv-init -)" -fi -EOF - - SOURCE_PYENVRC="source ~/.pyenvrc" - if ! grep "^$SOURCE_PYENVRC$" $RC_FILE > /dev/null; then - printf "\n$SOURCE_PYENVRC\n" >> $RC_FILE - fi - - eval "$SOURCE_PYENVRC" - # $(pyenv init -) produces a function which is broken on bash 3.2 which ships on macOS - if [ $(uname) == "Darwin" ]; then - unset -f pyenv - fi -fi - export MAKEFLAGS="-j$(nproc)" -PYENV_PYTHON_VERSION=$(cat $ROOT/.python-version) -if ! pyenv prefix ${PYENV_PYTHON_VERSION} &> /dev/null; then - # no pyenv update on mac - if [ "$(uname)" == "Linux" ]; then - echo "pyenv update ..." - pyenv update - fi - echo "python ${PYENV_PYTHON_VERSION} install ..." - CONFIGURE_OPTS="--enable-shared" pyenv install -f ${PYENV_PYTHON_VERSION} -fi -eval "$(pyenv init --path)" + echo "update pip" +if [ ! -z "\$VIRTUAL_ENV_ROOT" ] || [ ! -z "$INSTALL_DEADSNAKES_PPA" ] ; then + python3 -m venv --system-site-packages $VIRTUAL_ENV_ROOT + source $VIRTUAL_ENV_ROOT/bin/activate +fi pip install pip==24.0 pip install poetry==1.7.0 @@ -71,7 +36,6 @@ poetry self add poetry-dotenv-plugin@^0.1.0 echo "pip packages install..." poetry install --no-cache --no-root -pyenv rehash [ -n "$POETRY_VIRTUALENVS_CREATE" ] && RUN="" || RUN="poetry run" diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 1f8ef24ea..cd3ba2934 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -99,13 +99,37 @@ function install_ubuntu_lts_latest_requirements() { # Install Ubuntu 20.04 packages function install_ubuntu_focal_requirements() { install_ubuntu_common_requirements - + install_deadsnakes_ppa $SUDO apt-get install -y --no-install-recommends \ libavresample-dev \ qt5-default \ python-dev } +# Remove once on Ubuntu 24.04 +function install_deadsnakes_ppa(){ + if [[ -z "$INSTALL_DEADSNAKES_PPA" ]]; then + read -p "Do you want to use deadsnakes python@3.11? [Y/n]: " -n 1 -r + echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + INSTALL_DEADSNAKES_PPA="yes" + export VIRTUAL_ENV_ROOT=".venv" + fi + fi + if [[ "$INSTALL_DEADSNAKES_PPA" == "yes" ]]; then + $SUDO apt-get install software-properties-common -y --no-install-recommends + $SUDO add-apt-repository ppa:deadsnakes/ppa + $SUDO apt-get install -y --no-install-recommends \ + python3.11-dev \ + python3.11 \ + python3.11-venv \ + python3.11-distutils \ + python3-pip + $SUDO update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 20 + curl -sS https://bootstrap.pypa.io/get-pip.py | python3.11 + fi +} + # Detect OS using /etc/os-release file if [ -f "/etc/os-release" ]; then source /etc/os-release diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index d26ec3cfe..b02186685 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -6,7 +6,7 @@ if [ -z "$SKIP_PROMPT" ]; then echo "--------------- macOS support ---------------" echo "Running openpilot natively on macOS is not officially supported." echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues." - echo + echo echo "Check out devcontainers for a seamless experience (see tools/README.md)." echo "-------------------------------------------------" echo -n "Are you sure you want to continue? [y/N] " @@ -59,8 +59,7 @@ brew "libusb" brew "libtool" brew "llvm" brew "openssl@3.0" -brew "pyenv" -brew "pyenv-virtualenv" +brew "python@3.11" brew "qt@5" brew "zeromq" cask "gcc-arm-embedded" From 278c31287618d79a8908cac475f57905f8538ab5 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 23 May 2024 11:24:10 -0700 Subject: [PATCH 072/220] remove a pyenv reference --- Dockerfile.openpilot_base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index 857f796fd..2e839e758 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -65,7 +65,7 @@ USER $USER ENV POETRY_VIRTUALENVS_CREATE=false ENV VIRTUAL_ENV_ROOT="/home/$USER/venv" -ENV PATH="$VIRTUAL_ENV_ROOT/bin:$PYENV_ROOT/lib:$PATH" +ENV PATH="$VIRTUAL_ENV_ROOT/bin" COPY --chown=$USER pyproject.toml poetry.lock /tmp/ COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/ From 38c0fdac473797d81277a7a8d448f2b663277289 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 23 May 2024 11:30:56 -0700 Subject: [PATCH 073/220] fix PATH --- Dockerfile.openpilot_base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index 2e839e758..2c5f9a035 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -65,7 +65,7 @@ USER $USER ENV POETRY_VIRTUALENVS_CREATE=false ENV VIRTUAL_ENV_ROOT="/home/$USER/venv" -ENV PATH="$VIRTUAL_ENV_ROOT/bin" +ENV PATH="$VIRTUAL_ENV_ROOT/bin:$PATH" COPY --chown=$USER pyproject.toml poetry.lock /tmp/ COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/ From e0d20d2cf33a4398426e7ca4886bf6231d1220ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Thu, 23 May 2024 15:30:21 -0700 Subject: [PATCH 074/220] process_replay: most messages valid check (#32521) * check_most_messages_valid impl * Add to both regen and test_processes * Refactor * Bring back carOutput * Use Counter * Use get(k, 0) --- selfdrive/test/process_replay/process_replay.py | 17 ++++++++++++++++- selfdrive/test/process_replay/regen.py | 4 +++- selfdrive/test/process_replay/test_processes.py | 5 ++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 4b754b989..529ed91f7 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -6,7 +6,7 @@ import json import heapq import signal import platform -from collections import OrderedDict +from collections import Counter, OrderedDict from dataclasses import dataclass, field from typing import Any from collections.abc import Callable, Iterable @@ -816,3 +816,18 @@ def check_openpilot_enabled(msgs: LogIterable) -> bool: max_enabled_count = max(max_enabled_count, cur_enabled_count) return max_enabled_count > int(10. / DT_CTRL) + + +def check_most_messages_valid(msgs: LogIterable, threshold: float = 0.9) -> bool: + msgs_counts = Counter(msg.which() for msg in msgs) + msgs_valid_counts = Counter(msg.which() for msg in msgs if msg.valid) + + most_valid_for_service = {} + for msg_type in msgs_counts.keys(): + valid_share = msgs_valid_counts.get(msg_type, 0) / msgs_counts[msg_type] + ok = valid_share >= threshold + if not ok: + print(f"WARNING: Service {msg_type} has {valid_share * 100:.2f}% valid messages, which is below threshold of {threshold * 100:.2f}%") + most_valid_for_service[msg_type] = ok + + return all(most_valid_for_service.values()) diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index ec3023c5d..bf7a4bfd9 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -9,7 +9,7 @@ from typing import Any from collections.abc import Iterable from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, ProcessConfig, replay_process, get_process_config, \ - check_openpilot_enabled, get_custom_params_from_lr + check_openpilot_enabled, check_most_messages_valid, get_custom_params_from_lr from openpilot.selfdrive.test.process_replay.vision_meta import DRIVER_CAMERA_FRAME_SIZES from openpilot.selfdrive.test.update_ci_routes import upload_route from openpilot.tools.lib.route import Route @@ -129,6 +129,8 @@ def regen_and_save( if not check_openpilot_enabled(output_logs): raise Exception("Route did not engage for long enough") + if not check_most_messages_valid(output_logs): + raise Exception("Route has too many invalid messages") if upload: upload_route(rel_log_dir) diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index c0a425b59..533ab125f 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -11,7 +11,8 @@ from openpilot.common.git import get_commit from openpilot.selfdrive.car.car_helpers import interface_names from openpilot.tools.lib.openpilotci import get_url, upload_file from openpilot.selfdrive.test.process_replay.compare_logs import compare_logs, format_diff -from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, PROC_REPLAY_DIR, FAKEDATA, check_openpilot_enabled, replay_process +from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, PROC_REPLAY_DIR, FAKEDATA, replay_process, \ + check_openpilot_enabled, check_most_messages_valid from openpilot.tools.lib.filereader import FileReader from openpilot.tools.lib.logreader import LogReader from openpilot.tools.lib.helpers import save_log @@ -108,6 +109,8 @@ def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=Non if cfg.proc_name == "controlsd": if not check_openpilot_enabled(log_msgs): return f"Route did not enable at all or for long enough: {new_log_path}", log_msgs + if not check_most_messages_valid(log_msgs): + return f"Route did not have enough valid messages: {new_log_path}", log_msgs if cfg.proc_name != 'ubloxd' or segment != 'regen3BB55FA5E20|2024-05-21--06-59-03--0': seen_msgs = {m.which() for m in log_msgs} From 204219695f57f6ba76347df4df99e00a28b51e9f Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Thu, 23 May 2024 20:14:28 -0700 Subject: [PATCH 075/220] dmonitoringd: simplify main loop (#32517) * one call does all * no need * update etst * filename * dbf5b05ff480145a79b5941e360d0698b70979cd --- release/files_common | 2 +- selfdrive/monitoring/dmonitoringd.py | 66 +----- .../{driver_monitor.py => helpers.py} | 205 +++++++++++------- selfdrive/monitoring/test_monitoring.py | 15 +- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 150 insertions(+), 140 deletions(-) rename selfdrive/monitoring/{driver_monitor.py => helpers.py} (82%) diff --git a/release/files_common b/release/files_common index 8636959da..f6afd9390 100644 --- a/release/files_common +++ b/release/files_common @@ -357,7 +357,7 @@ selfdrive/modeld/runners/*.h selfdrive/modeld/runners/*.py selfdrive/monitoring/dmonitoringd.py -selfdrive/monitoring/driver_monitor.py +selfdrive/monitoring/helpers.py selfdrive/navd/.gitignore selfdrive/navd/__init__.py diff --git a/selfdrive/monitoring/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py index 91a493258..e572bf5bd 100755 --- a/selfdrive/monitoring/dmonitoringd.py +++ b/selfdrive/monitoring/dmonitoringd.py @@ -2,11 +2,9 @@ import gc import cereal.messaging as messaging -from cereal import car from openpilot.common.params import Params from openpilot.common.realtime import set_realtime_priority -from openpilot.selfdrive.controls.lib.events import Events -from openpilot.selfdrive.monitoring.driver_monitor import DriverStatus +from openpilot.selfdrive.monitoring.helpers import DriverMonitoring def dmonitoringd_thread(): @@ -17,70 +15,30 @@ def dmonitoringd_thread(): pm = messaging.PubMaster(['driverMonitoringState']) sm = messaging.SubMaster(['driverStateV2', 'liveCalibration', 'carState', 'controlsState', 'modelV2'], poll='driverStateV2') - driver_status = DriverStatus(rhd_saved=params.get_bool("IsRhdDetected"), always_on=params.get_bool("AlwaysOnDM")) - - driver_engaged = False + DM = DriverMonitoring(rhd_saved=params.get_bool("IsRhdDetected"), always_on=params.get_bool("AlwaysOnDM")) # 20Hz <- dmonitoringmodeld while True: sm.update() - if not sm.updated['driverStateV2']: + if (not sm.updated['driverStateV2']) or (not sm.all_checks()): + # iterate when model has new output continue - # Get interaction - if sm.updated['carState']: - driver_engaged = sm['carState'].steeringPressed or \ - sm['carState'].gasPressed + DM.run_step(sm) - if sm.updated['modelV2']: - driver_status.set_policy(sm['modelV2'], sm['carState'].vEgo) - - # Get data from dmonitoringmodeld - events = Events() - - if sm.all_checks() and len(sm['liveCalibration'].rpyCalib): - driver_status.update_states(sm['driverStateV2'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['controlsState'].enabled) - - # Block engaging after max number of distrations or when alert active - if driver_status.terminal_alert_cnt >= driver_status.settings._MAX_TERMINAL_ALERTS or \ - driver_status.terminal_time >= driver_status.settings._MAX_TERMINAL_DURATION or \ - driver_status.always_on and driver_status.awareness <= driver_status.threshold_prompt: - events.add(car.CarEvent.EventName.tooDistracted) - - # Update events from driver state - driver_status.update_events(events, driver_engaged, sm['controlsState'].enabled, - sm['carState'].standstill, sm['carState'].gearShifter in [car.CarState.GearShifter.reverse, car.CarState.GearShifter.park], sm['carState'].vEgo) - - # build driverMonitoringState packet - dat = messaging.new_message('driverMonitoringState', valid=sm.all_checks()) - dat.driverMonitoringState = { - "events": events.to_msg(), - "faceDetected": driver_status.face_detected, - "isDistracted": driver_status.driver_distracted, - "distractedType": sum(driver_status.distracted_types), - "awarenessStatus": driver_status.awareness, - "posePitchOffset": driver_status.pose.pitch_offseter.filtered_stat.mean(), - "posePitchValidCount": driver_status.pose.pitch_offseter.filtered_stat.n, - "poseYawOffset": driver_status.pose.yaw_offseter.filtered_stat.mean(), - "poseYawValidCount": driver_status.pose.yaw_offseter.filtered_stat.n, - "stepChange": driver_status.step_change, - "awarenessActive": driver_status.awareness_active, - "awarenessPassive": driver_status.awareness_passive, - "isLowStd": driver_status.pose.low_std, - "hiStdCount": driver_status.hi_stds, - "isActiveMode": driver_status.active_monitoring_mode, - "isRHD": driver_status.wheel_on_right, - } + # publish + dat = DM.get_state_packet() pm.send('driverMonitoringState', dat) + # load live always-on toggle if sm['driverStateV2'].frameId % 40 == 1: - driver_status.always_on = params.get_bool("AlwaysOnDM") + DM.always_on = params.get_bool("AlwaysOnDM") # save rhd virtual toggle every 5 mins if (sm['driverStateV2'].frameId % 6000 == 0 and - driver_status.wheelpos_learner.filtered_stat.n > driver_status.settings._WHEELPOS_FILTER_MIN_COUNT and - driver_status.wheel_on_right == (driver_status.wheelpos_learner.filtered_stat.M > driver_status.settings._WHEELPOS_THRESHOLD)): - params.put_bool_nonblocking("IsRhdDetected", driver_status.wheel_on_right) + DM.wheelpos_learner.filtered_stat.n > DM.settings._WHEELPOS_FILTER_MIN_COUNT and + DM.wheel_on_right == (DM.wheelpos_learner.filtered_stat.M > DM.settings._WHEELPOS_THRESHOLD)): + params.put_bool_nonblocking("IsRhdDetected", DM.wheel_on_right) def main(): dmonitoringd_thread() diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/helpers.py similarity index 82% rename from selfdrive/monitoring/driver_monitor.py rename to selfdrive/monitoring/helpers.py index 85cc19eb8..347cb245d 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/helpers.py @@ -1,6 +1,8 @@ from math import atan2 from cereal import car +import cereal.messaging as messaging +from openpilot.selfdrive.controls.lib.events import Events from openpilot.common.numpy_fast import interp from openpilot.common.realtime import DT_DMON from openpilot.common.filter_simple import FirstOrderFilter @@ -71,19 +73,38 @@ class DRIVER_MONITOR_SETTINGS: self._MAX_TERMINAL_ALERTS = 3 # not allowed to engage after 3 terminal alerts self._MAX_TERMINAL_DURATION = int(30 / self._DT_DMON) # not allowed to engage after 30s of terminal alerts +class DistractedType: + NOT_DISTRACTED = 0 + DISTRACTED_POSE = 1 << 0 + DISTRACTED_BLINK = 1 << 1 + DISTRACTED_E2E = 1 << 2 + +class DriverPose: + def __init__(self, max_trackable): + self.yaw = 0. + self.pitch = 0. + self.roll = 0. + self.yaw_std = 0. + self.pitch_std = 0. + self.roll_std = 0. + self.pitch_offseter = RunningStatFilter(max_trackable=max_trackable) + self.yaw_offseter = RunningStatFilter(max_trackable=max_trackable) + self.calibrated = False + self.low_std = True + self.cfactor_pitch = 1. + self.cfactor_yaw = 1. + +class DriverBlink: + def __init__(self): + self.left = 0. + self.right = 0. + -# TODO: get these live # model output refers to center of undistorted+leveled image EFL = 598.0 # focal length in K cam = DEVICE_CAMERAS[("tici", "ar0231")] # corrected image has same size as raw W, H = (cam.dcam.width, cam.dcam.height) # corrected image has same size as raw -class DistractedType: - NOT_DISTRACTED = 0 - DISTRACTED_POSE = 1 - DISTRACTED_BLINK = 2 - DISTRACTED_E2E = 4 - def face_orientation_from_net(angles_desc, pos_desc, rpy_calib): # the output of these angles are in device frame # so from driver's perspective, pitch is up and yaw is right @@ -102,26 +123,8 @@ def face_orientation_from_net(angles_desc, pos_desc, rpy_calib): yaw -= rpy_calib[2] return roll_net, pitch, yaw -class DriverPose: - def __init__(self, max_trackable): - self.yaw = 0. - self.pitch = 0. - self.roll = 0. - self.yaw_std = 0. - self.pitch_std = 0. - self.roll_std = 0. - self.pitch_offseter = RunningStatFilter(max_trackable=max_trackable) - self.yaw_offseter = RunningStatFilter(max_trackable=max_trackable) - self.low_std = True - self.cfactor_pitch = 1. - self.cfactor_yaw = 1. -class DriverBlink: - def __init__(self): - self.left_blink = 0. - self.right_blink = 0. - -class DriverStatus: +class DriverMonitoring: def __init__(self, rhd_saved=False, settings=None, always_on=False): if settings is None: settings = DRIVER_MONITOR_SETTINGS() @@ -131,7 +134,6 @@ class DriverStatus: # init driver status self.wheelpos_learner = RunningStatFilter() self.pose = DriverPose(self.settings._POSE_OFFSET_MAX_COUNT) - self.pose_calibrated = False self.blink = DriverBlink() self.eev1 = 0. self.eev2 = 1. @@ -141,9 +143,6 @@ class DriverStatus: self.ee2_calibrated = False self.always_on = always_on - self.awareness = 1. - self.awareness_active = 1. - self.awareness_passive = 1. self.distracted_types = [] self.driver_distracted = False self.driver_distraction_filter = FirstOrderFilter(0., self.settings._DISTRACTED_FILTER_TS, self.settings._DT_DMON) @@ -160,13 +159,18 @@ class DriverStatus: self.threshold_pre = self.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME self.threshold_prompt = self.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME + self._reset_awareness() self._set_timers(active_monitoring=True) + self._reset_events() def _reset_awareness(self): self.awareness = 1. self.awareness_active = 1. self.awareness_passive = 1. + def _reset_events(self): + self.current_events = Events() + def _set_timers(self, active_monitoring): if self.active_monitoring_mode and self.awareness <= self.threshold_prompt: if active_monitoring: @@ -197,41 +201,7 @@ class DriverStatus: self.step_change = self.settings._DT_DMON / self.settings._AWARENESS_TIME self.active_monitoring_mode = False - def _get_distracted_types(self): - distracted_types = [] - - if not self.pose_calibrated: - pitch_error = self.pose.pitch - self.settings._PITCH_NATURAL_OFFSET - yaw_error = self.pose.yaw - self.settings._YAW_NATURAL_OFFSET - else: - pitch_error = self.pose.pitch - min(max(self.pose.pitch_offseter.filtered_stat.mean(), - self.settings._PITCH_MIN_OFFSET), self.settings._PITCH_MAX_OFFSET) - yaw_error = self.pose.yaw - min(max(self.pose.yaw_offseter.filtered_stat.mean(), - self.settings._YAW_MIN_OFFSET), self.settings._YAW_MAX_OFFSET) - pitch_error = 0 if pitch_error > 0 else abs(pitch_error) # no positive pitch limit - yaw_error = abs(yaw_error) - if pitch_error > (self.settings._POSE_PITCH_THRESHOLD*self.pose.cfactor_pitch if self.pose_calibrated else self.settings._PITCH_NATURAL_THRESHOLD) or \ - yaw_error > self.settings._POSE_YAW_THRESHOLD*self.pose.cfactor_yaw: - distracted_types.append(DistractedType.DISTRACTED_POSE) - - if (self.blink.left_blink + self.blink.right_blink)*0.5 > self.settings._BLINK_THRESHOLD: - distracted_types.append(DistractedType.DISTRACTED_BLINK) - - if self.ee1_calibrated: - ee1_dist = self.eev1 > max(min(self.ee1_offseter.filtered_stat.M, self.settings._EE_MAX_OFFSET1), self.settings._EE_MIN_OFFSET1) \ - * self.settings._EE_THRESH12 - else: - ee1_dist = self.eev1 > self.settings._EE_THRESH11 - # if self.ee2_calibrated: - # ee2_dist = self.eev2 < self.ee2_offseter.filtered_stat.M * self.settings._EE_THRESH22 - # else: - # ee2_dist = self.eev2 < self.settings._EE_THRESH21 - if ee1_dist: - distracted_types.append(DistractedType.DISTRACTED_E2E) - - return distracted_types - - def set_policy(self, model_data, car_speed): + def _set_policy(self, model_data, car_speed): bp = model_data.meta.disengagePredictions.brakeDisengageProbs[0] # brake disengage prob in next 2s k1 = max(-0.00156*((car_speed-16)**2)+0.6, 0.2) bp_normal = max(min(bp / k1, 0.5),0) @@ -242,7 +212,37 @@ class DriverStatus: [self.settings._POSE_YAW_THRESHOLD_SLACK, self.settings._POSE_YAW_THRESHOLD_STRICT]) / self.settings._POSE_YAW_THRESHOLD - def update_states(self, driver_state, cal_rpy, car_speed, op_engaged): + def _get_distracted_types(self): + distracted_types = [] + + if not self.pose.calibrated: + pitch_error = self.pose.pitch - self.settings._PITCH_NATURAL_OFFSET + yaw_error = self.pose.yaw - self.settings._YAW_NATURAL_OFFSET + else: + pitch_error = self.pose.pitch - min(max(self.pose.pitch_offseter.filtered_stat.mean(), + self.settings._PITCH_MIN_OFFSET), self.settings._PITCH_MAX_OFFSET) + yaw_error = self.pose.yaw - min(max(self.pose.yaw_offseter.filtered_stat.mean(), + self.settings._YAW_MIN_OFFSET), self.settings._YAW_MAX_OFFSET) + pitch_error = 0 if pitch_error > 0 else abs(pitch_error) # no positive pitch limit + yaw_error = abs(yaw_error) + if pitch_error > (self.settings._POSE_PITCH_THRESHOLD*self.pose.cfactor_pitch if self.pose.calibrated else self.settings._PITCH_NATURAL_THRESHOLD) or \ + yaw_error > self.settings._POSE_YAW_THRESHOLD*self.pose.cfactor_yaw: + distracted_types.append(DistractedType.DISTRACTED_POSE) + + if (self.blink.left + self.blink.right)*0.5 > self.settings._BLINK_THRESHOLD: + distracted_types.append(DistractedType.DISTRACTED_BLINK) + + if self.ee1_calibrated: + ee1_dist = self.eev1 > max(min(self.ee1_offseter.filtered_stat.M, self.settings._EE_MAX_OFFSET1), self.settings._EE_MIN_OFFSET1) \ + * self.settings._EE_THRESH12 + else: + ee1_dist = self.eev1 > self.settings._EE_THRESH11 + if ee1_dist: + distracted_types.append(DistractedType.DISTRACTED_E2E) + + return distracted_types + + def _update_states(self, driver_state, cal_rpy, car_speed, op_engaged): rhd_pred = driver_state.wheelOnRightProb # calibrates only when there's movement and either face detected if car_speed > self.settings._WHEELPOS_CALIB_MIN_SPEED and (driver_state.leftDriverData.faceProb > self.settings._FACE_THRESHOLD or @@ -270,9 +270,9 @@ class DriverStatus: self.pose.yaw_std = driver_data.faceOrientationStd[1] model_std_max = max(self.pose.pitch_std, self.pose.yaw_std) self.pose.low_std = model_std_max < self.settings._POSESTD_THRESHOLD - self.blink.left_blink = driver_data.leftBlinkProb * (driver_data.leftEyeProb > self.settings._EYE_THRESHOLD) \ + self.blink.left = driver_data.leftBlinkProb * (driver_data.leftEyeProb > self.settings._EYE_THRESHOLD) \ * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD) - self.blink.right_blink = driver_data.rightBlinkProb * (driver_data.rightEyeProb > self.settings._EYE_THRESHOLD) \ + self.blink.right = driver_data.rightBlinkProb * (driver_data.rightEyeProb > self.settings._EYE_THRESHOLD) \ * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD) self.eev1 = driver_data.notReadyProb[0] self.eev2 = driver_data.readyProb[0] @@ -291,7 +291,7 @@ class DriverStatus: self.ee1_offseter.push_and_update(self.eev1) self.ee2_offseter.push_and_update(self.eev2) - self.pose_calibrated = self.pose.pitch_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT and \ + self.pose.calibrated = self.pose.pitch_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT and \ self.pose.yaw_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT self.ee1_calibrated = self.ee1_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT self.ee2_calibrated = self.ee2_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT @@ -303,11 +303,18 @@ class DriverStatus: elif self.face_detected and self.pose.low_std: self.hi_stds = 0 - def update_events(self, events, driver_engaged, ctrl_active, standstill, wrong_gear, car_speed): + def _update_events(self, driver_engaged, op_engaged, standstill, wrong_gear, car_speed): + self._reset_events() + # Block engaging after max number of distrations or when alert active + if self.terminal_alert_cnt >= self.settings._MAX_TERMINAL_ALERTS or \ + self.terminal_time >= self.settings._MAX_TERMINAL_DURATION or \ + self.always_on and self.awareness <= self.threshold_prompt: + self.current_events.add(EventName.tooDistracted) + always_on_valid = self.always_on and not wrong_gear if (driver_engaged and self.awareness > 0 and not self.active_monitoring_mode) or \ - (not always_on_valid and not ctrl_active) or \ - (always_on_valid and not ctrl_active and self.awareness <= 0): + (not always_on_valid and not op_engaged) or \ + (always_on_valid and not op_engaged and self.awareness <= 0): # always reset on disengage with normal mode; disengage resets only on red if always on self._reset_awareness() return @@ -331,8 +338,8 @@ class DriverStatus: _reaching_audible = self.awareness - self.step_change <= self.threshold_prompt _reaching_terminal = self.awareness - self.step_change <= 0 standstill_exemption = standstill and _reaching_audible - always_on_red_exemption = always_on_valid and not ctrl_active and _reaching_terminal - always_on_lowspeed_exemption = always_on_valid and not ctrl_active and car_speed < self.settings._ALWAYS_ON_ALERT_MIN_SPEED and _reaching_audible + always_on_red_exemption = always_on_valid and not op_engaged and _reaching_terminal + always_on_lowspeed_exemption = always_on_valid and not op_engaged and car_speed < self.settings._ALWAYS_ON_ALERT_MIN_SPEED and _reaching_audible certainly_distracted = self.driver_distraction_filter.x > 0.63 and self.driver_distracted and self.face_detected maybe_distracted = self.hi_stds > self.settings._HI_STD_FALLBACK_TIME or not self.face_detected @@ -358,4 +365,52 @@ class DriverStatus: alert = EventName.preDriverDistracted if self.active_monitoring_mode else EventName.preDriverUnresponsive if alert is not None: - events.add(alert) + self.current_events.add(alert) + + + def get_state_packet(self): + # build driverMonitoringState packet + dat = messaging.new_message('driverMonitoringState', valid=True) + dat.driverMonitoringState = { + "events": self.current_events.to_msg(), + "faceDetected": self.face_detected, + "isDistracted": self.driver_distracted, + "distractedType": sum(self.distracted_types), + "awarenessStatus": self.awareness, + "posePitchOffset": self.pose.pitch_offseter.filtered_stat.mean(), + "posePitchValidCount": self.pose.pitch_offseter.filtered_stat.n, + "poseYawOffset": self.pose.yaw_offseter.filtered_stat.mean(), + "poseYawValidCount": self.pose.yaw_offseter.filtered_stat.n, + "stepChange": self.step_change, + "awarenessActive": self.awareness_active, + "awarenessPassive": self.awareness_passive, + "isLowStd": self.pose.low_std, + "hiStdCount": self.hi_stds, + "isActiveMode": self.active_monitoring_mode, + "isRHD": self.wheel_on_right, + } + return dat + + def run_step(self, sm): + # Set strictness + self._set_policy( + model_data=sm['modelV2'], + car_speed=sm['carState'].vEgo + ) + + # Parse data from dmonitoringmodeld + self._update_states( + driver_state=sm['driverStateV2'], + cal_rpy=sm['liveCalibration'].rpyCalib, + car_speed=sm['carState'].vEgo, + op_engaged=sm['controlsState'].enabled + ) + + # Update distraction events + self._update_events( + driver_engaged=sm['carState'].steeringPressed or sm['carState'].gasPressed, + op_engaged=sm['controlsState'].enabled, + standstill=sm['carState'].standstill, + wrong_gear=sm['carState'].gearShifter in [car.CarState.GearShifter.reverse, car.CarState.GearShifter.park], + car_speed=sm['carState'].vEgo + ) diff --git a/selfdrive/monitoring/test_monitoring.py b/selfdrive/monitoring/test_monitoring.py index 9395960b6..a960a379e 100755 --- a/selfdrive/monitoring/test_monitoring.py +++ b/selfdrive/monitoring/test_monitoring.py @@ -3,8 +3,7 @@ import numpy as np from cereal import car, log from openpilot.common.realtime import DT_DMON -from openpilot.selfdrive.controls.lib.events import Events -from openpilot.selfdrive.monitoring.driver_monitor import DriverStatus, DRIVER_MONITOR_SETTINGS +from openpilot.selfdrive.monitoring.helpers import DriverMonitoring, DRIVER_MONITOR_SETTINGS EventName = car.CarEvent.EventName dm_settings = DRIVER_MONITOR_SETTINGS() @@ -51,21 +50,19 @@ always_distracted = [msg_DISTRACTED] * int(TEST_TIMESPAN / DT_DMON) always_true = [True] * int(TEST_TIMESPAN / DT_DMON) always_false = [False] * int(TEST_TIMESPAN / DT_DMON) -# TODO: this only tests DriverStatus class TestMonitoring: def _run_seq(self, msgs, interaction, engaged, standstill): - DS = DriverStatus() + DM = DriverMonitoring() events = [] for idx in range(len(msgs)): - e = Events() - DS.update_states(msgs[idx], [0, 0, 0], 0, engaged[idx]) + DM._update_states(msgs[idx], [0, 0, 0], 0, engaged[idx]) # cal_rpy and car_speed don't matter here # evaluate events at 10Hz for tests - DS.update_events(e, interaction[idx], engaged[idx], standstill[idx], 0, 0) - events.append(e) + DM._update_events(interaction[idx], engaged[idx], standstill[idx], 0, 0) + events.append(DM.current_events) assert len(events) == len(msgs), f"got {len(events)} for {len(msgs)} driverState input msgs" - return events, DS + return events, DM def _assert_no_events(self, events): assert all(not len(e) for e in events) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index c3ab38396..4fec7453f 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -da1b19b2d1d54412ac72f2e9645046d262f9c7ab \ No newline at end of file +dbf5b05ff480145a79b5941e360d0698b70979cd \ No newline at end of file From 652f15d54ee92c83e98b7bce2f0f82e241b14cd2 Mon Sep 17 00:00:00 2001 From: cipioh <30559882+cipioh@users.noreply.github.com> Date: Fri, 24 May 2024 16:39:42 -0400 Subject: [PATCH 076/220] Added ecu firmware data for 2024 Kia EV6 GT (#32524) * Update fingerprints.py added KIA EV6 GT 2024 * Update fingerprints.py added firmware from 2024 Kia EV6 GT * format * update my --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 6 +++--- selfdrive/car/hyundai/fingerprints.py | 1 + selfdrive/car/hyundai/values.py | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 4364f10b0..2fe3497f0 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -127,9 +127,9 @@ A supported vehicle is one that just works when you install a comma device. All |Kia|Carnival 2022-24[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|Carnival (China only) 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|EV6 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|EV6 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (Southeast Asia only) 2022-24[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (with HDA II) 2022-24[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|EV6 (without HDA II) 2022-24[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index c1880567b..4518f8b04 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -967,6 +967,7 @@ FW_VERSIONS = { b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.05 99210-CV000 211027', b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV100 220630', + b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV200 230510', b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.05 99210-CV000 211027', b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.06 99210-CV000 220328', ], diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1e752185e..9f281f772 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -478,9 +478,9 @@ class CAR(Platforms): ) KIA_EV6 = HyundaiCanFDPlatformConfig( [ - HyundaiCarDocs("Kia EV6 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_p])), - HyundaiCarDocs("Kia EV6 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_l])), - HyundaiCarDocs("Kia EV6 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p])) + HyundaiCarDocs("Kia EV6 (Southeast Asia only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_p])), + HyundaiCarDocs("Kia EV6 (without HDA II) 2022-24", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_l])), + HyundaiCarDocs("Kia EV6 (with HDA II) 2022-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p])) ], CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65), flags=HyundaiFlags.EV, From 937ff7f4187aff657d6e447c2f87b28c3d08bc3a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 May 2024 17:48:26 -0500 Subject: [PATCH 077/220] Kia: update Forte 2019-21 min enable speed (#32528) * forte enable speed fix * update docs --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 2fe3497f0..c32bd5c41 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -130,7 +130,7 @@ A supported vehicle is one that just works when you install a comma device. All |Kia|EV6 (Southeast Asia only) 2022-24[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|EV6 (with HDA II) 2022-24[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|EV6 (without HDA II) 2022-24[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 9f281f772..3157aa6ac 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -341,7 +341,7 @@ class CAR(Platforms): # Kia KIA_FORTE = HyundaiPlatformConfig( [ - HyundaiCarDocs("Kia Forte 2019-21", car_parts=CarParts.common([CarHarness.hyundai_g])), + HyundaiCarDocs("Kia Forte 2019-21", min_enable_speed=6 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_g])), HyundaiCarDocs("Kia Forte 2023", car_parts=CarParts.common([CarHarness.hyundai_e])), ], CarSpecs(mass=2878 * CV.LB_TO_KG, wheelbase=2.8, steerRatio=13.75, tireStiffnessFactor=0.5) From a7065d158b22a6a64ec914bad16546349c952206 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 May 2024 15:49:45 -0700 Subject: [PATCH 078/220] Kia: add 2022 Forte model year The minimum enable speed is also 0 mph with a lead like the 2023, so it's likely supported with this harness --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c32bd5c41..899c6f821 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -131,7 +131,7 @@ A supported vehicle is one that just works when you install a comma device. All |Kia|EV6 (with HDA II) 2022-24[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|EV6 (without HDA II) 2022-24[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Kia|K8 Hybrid (with HDA II) 2023[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 3157aa6ac..72513c849 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -342,7 +342,7 @@ class CAR(Platforms): KIA_FORTE = HyundaiPlatformConfig( [ HyundaiCarDocs("Kia Forte 2019-21", min_enable_speed=6 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_g])), - HyundaiCarDocs("Kia Forte 2023", car_parts=CarParts.common([CarHarness.hyundai_e])), + HyundaiCarDocs("Kia Forte 2022-23", car_parts=CarParts.common([CarHarness.hyundai_e])), ], CarSpecs(mass=2878 * CV.LB_TO_KG, wheelbase=2.8, steerRatio=13.75, tireStiffnessFactor=0.5) ) From 8183715beb961658755b2f19dbba6b07582830cd Mon Sep 17 00:00:00 2001 From: Yassine Date: Fri, 24 May 2024 19:44:14 -0700 Subject: [PATCH 079/220] wip /500 --- selfdrive/modeld/models/supercombo.onnx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index c0f8b16fb..46bc5d1ab 100644 --- a/selfdrive/modeld/models/supercombo.onnx +++ b/selfdrive/modeld/models/supercombo.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b31b504bc0b440d3bc72967507a00eb4f112285626fbfb3135011500325ee6d6 -size 51452435 +oid sha256:fb503a5698dc76fa992da2b4d5d3f163b2371756dc6e8bc5522eacf76f5cbe4f +size 50229837 From 8bd4540636cf36eb59efcc0ee3a0f0ad81fbb680 Mon Sep 17 00:00:00 2001 From: Yassine Date: Fri, 24 May 2024 19:45:00 -0700 Subject: [PATCH 080/220] Revert "wip /500" This reverts commit 8183715beb961658755b2f19dbba6b07582830cd. --- selfdrive/modeld/models/supercombo.onnx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index 46bc5d1ab..c0f8b16fb 100644 --- a/selfdrive/modeld/models/supercombo.onnx +++ b/selfdrive/modeld/models/supercombo.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb503a5698dc76fa992da2b4d5d3f163b2371756dc6e8bc5522eacf76f5cbe4f -size 50229837 +oid sha256:b31b504bc0b440d3bc72967507a00eb4f112285626fbfb3135011500325ee6d6 +size 51452435 From f4322666c6adc4dd2da569f483f6e108f18fe32a Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Fri, 24 May 2024 21:38:23 -0700 Subject: [PATCH 081/220] `ubuntu_setup`: fix `No module apt_pkg` error when setting up (#32526) * no apt_pkg fix * check arch * fix if * cleanup * reorder * increase shm size for selfdrive tests * add comment explaining reinstall * refine --- .github/workflows/selfdrive_tests.yaml | 2 +- tools/install_python_dependencies.sh | 5 ++++- tools/install_ubuntu_dependencies.sh | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 1c83c39bb..1aa08f205 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -19,7 +19,7 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: selfdrive/test/docker_build.sh base - RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c + RUN: docker run --shm-size 1.5G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical diff --git a/tools/install_python_dependencies.sh b/tools/install_python_dependencies.sh index 0a2ae0d58..eaa32a0a4 100755 --- a/tools/install_python_dependencies.sh +++ b/tools/install_python_dependencies.sh @@ -15,7 +15,10 @@ export MAKEFLAGS="-j$(nproc)" echo "update pip" -if [ ! -z "\$VIRTUAL_ENV_ROOT" ] || [ ! -z "$INSTALL_DEADSNAKES_PPA" ] ; then +if [ ! -z "$VIRTUAL_ENV_ROOT" ] || [ ! -z "$INSTALL_DEADSNAKES_PPA" ] ; then + if [ -z "$VIRTUAL_ENV_ROOT" ]; then + export VIRTUAL_ENV_ROOT="venv" + fi python3 -m venv --system-site-packages $VIRTUAL_ENV_ROOT source $VIRTUAL_ENV_ROOT/bin/activate fi diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index cd3ba2934..2469168c7 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -113,11 +113,13 @@ function install_deadsnakes_ppa(){ echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then INSTALL_DEADSNAKES_PPA="yes" - export VIRTUAL_ENV_ROOT=".venv" fi fi if [[ "$INSTALL_DEADSNAKES_PPA" == "yes" ]]; then - $SUDO apt-get install software-properties-common -y --no-install-recommends + # The reinstall ensures that apt_pkg.cpython-35m-x86_64-linux-gnu.so exists + # by reinstalling python3-minimal since it's not present in /usr/lib/python3/dist-packages. + $SUDO apt install -y --no-install-recommends --reinstall python3-minimal + $SUDO apt-get install -y --no-install-recommends python3-apt software-properties-common $SUDO add-apt-repository ppa:deadsnakes/ppa $SUDO apt-get install -y --no-install-recommends \ python3.11-dev \ From 6ecb7103057073a11dfa0e93262d22f8d41228e5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 25 May 2024 05:29:54 -0500 Subject: [PATCH 082/220] LongitudinalMpc: use DT_MDL (#32532) bad magic number --- selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py | 6 ++++-- selfdrive/controls/lib/longitudinal_planner.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index 39cfda4e8..bad37add6 100755 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -4,6 +4,7 @@ import time import numpy as np from cereal import log from openpilot.common.numpy_fast import clip +from openpilot.common.realtime import DT_MDL from openpilot.common.swaglog import cloudlog # WARNING: imports outside of constants will not trigger a rebuild from openpilot.selfdrive.modeld.constants import index_function @@ -220,8 +221,9 @@ def gen_long_ocp(): class LongitudinalMpc: - def __init__(self, mode='acc'): + def __init__(self, mode='acc', dt=DT_MDL): self.mode = mode + self.dt = dt self.solver = AcadosOcpSolverCython(MODEL_NAME, ACADOS_SOLVER_TYPE, N) self.reset() self.source = SOURCES[2] @@ -440,7 +442,7 @@ class LongitudinalMpc: self.a_solution = self.x_sol[:,2] self.j_solution = self.u_sol[:,0] - self.prev_a = np.interp(T_IDXS + 0.05, T_IDXS, self.a_solution) + self.prev_a = np.interp(T_IDXS + self.dt, T_IDXS, self.a_solution) t = time.monotonic() if self.solution_status != 0: diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 6cc6e80d3..9113bb5a9 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -47,7 +47,7 @@ def limit_accel_in_turns(v_ego, angle_steers, a_target, CP): class LongitudinalPlanner: def __init__(self, CP, init_v=0.0, init_a=0.0, dt=DT_MDL): self.CP = CP - self.mpc = LongitudinalMpc() + self.mpc = LongitudinalMpc(dt=dt) self.fcw = False self.dt = dt From 95aa7c4b681c8ca0f23c7396e4d7a5840383c929 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 25 May 2024 11:42:23 -0500 Subject: [PATCH 083/220] [bot] Fingerprints: add missing FW versions from new users (#32533) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 2 ++ selfdrive/car/honda/fingerprints.py | 1 + 2 files changed, 3 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index b974d3dd4..d71ec5d30 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -153,6 +153,7 @@ FW_VERSIONS = { b'68496647AJ ', b'68496650AH ', b'68496650AI ', + b'68496652AH ', b'68526752AD ', b'68526752AE ', b'68526754AE ', @@ -168,6 +169,7 @@ FW_VERSIONS = { b'68443155AC', b'68443158AB', b'68501050AD', + b'68501051AD', b'68501055AD', b'68527221AB', b'68527223AB', diff --git a/selfdrive/car/honda/fingerprints.py b/selfdrive/car/honda/fingerprints.py index 4d70c2c35..26433a8b9 100644 --- a/selfdrive/car/honda/fingerprints.py +++ b/selfdrive/car/honda/fingerprints.py @@ -794,6 +794,7 @@ FW_VERSIONS = { b'37805-RLV-L350\x00\x00', b'37805-RLV-L410\x00\x00', b'37805-RLV-L430\x00\x00', + b'37805-RLV-L830\x00\x00', b'37805-RLV-L850\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ From 613f73c53fa1cd3525a0cb3af0615783bd213fd0 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Sat, 25 May 2024 13:37:07 -0400 Subject: [PATCH 084/220] CI/simulator: metadrive test starts when OP engaged and world is initialized (#32523) * fix metadrive start time * fix --- tools/sim/bridge/metadrive/metadrive_process.py | 11 ++++++++--- tools/sim/bridge/metadrive/metadrive_world.py | 6 ++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/sim/bridge/metadrive/metadrive_process.py b/tools/sim/bridge/metadrive/metadrive_process.py index ec10b96b3..2b9203c30 100644 --- a/tools/sim/bridge/metadrive/metadrive_process.py +++ b/tools/sim/bridge/metadrive/metadrive_process.py @@ -50,7 +50,7 @@ def apply_metadrive_patches(arrive_dest_done=True): def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera_array, image_lock, controls_recv: Connection, simulation_state_send: Connection, vehicle_state_send: Connection, - exit_event, start_time, test_duration, test_run): + exit_event, op_engaged, test_duration, test_run): arrive_dest_done = config.pop("arrive_dest_done", True) apply_metadrive_patches(arrive_dest_done) @@ -81,6 +81,7 @@ def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera return lane_idx_prev lane_idx_prev = reset() + start_time = None def get_cam_as_rgb(cam): cam = env.engine.sensors[cam] @@ -104,7 +105,6 @@ def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera bearing=float(math.degrees(env.vehicle.heading_theta)), steering_angle=env.vehicle.steering * env.vehicle.MAX_STEERING ) - vehicle_state_send.send(vehicle_state) if controls_recv.poll(0): @@ -118,10 +118,15 @@ def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera if should_reset: lane_idx_prev = reset() + start_time = None + + is_engaged = op_engaged.is_set() + if is_engaged and start_time is None: + start_time = time.monotonic() if rk.frame % 5 == 0: _, _, terminated, _, _ = env.step(vc) - timeout = True if time.monotonic() - start_time >= test_duration else False + timeout = True if start_time is not None and time.monotonic() - start_time >= test_duration else False lane_idx_curr, on_lane = get_current_lane_info(env.vehicle) out_of_lane = lane_idx_curr != lane_idx_prev or not on_lane lane_idx_prev = lane_idx_curr diff --git a/tools/sim/bridge/metadrive/metadrive_world.py b/tools/sim/bridge/metadrive/metadrive_world.py index 5d1a2f307..5bb4555dc 100644 --- a/tools/sim/bridge/metadrive/metadrive_world.py +++ b/tools/sim/bridge/metadrive/metadrive_world.py @@ -29,10 +29,10 @@ class MetaDriveWorld(World): self.vehicle_state_send, self.vehicle_state_recv = Pipe() self.exit_event = multiprocessing.Event() + self.op_engaged = multiprocessing.Event() self.test_run = test_run - self.start_time = time.monotonic() self.first_engage = None self.last_check_timestamp = 0 self.distance_moved = 0 @@ -41,7 +41,7 @@ class MetaDriveWorld(World): functools.partial(metadrive_process, dual_camera, config, self.camera_array, self.wide_camera_array, self.image_lock, self.controls_recv, self.simulation_state_send, - self.vehicle_state_send, self.exit_event, self.start_time, test_duration, self.test_run)) + self.vehicle_state_send, self.exit_event, self.op_engaged, test_duration, self.test_run)) self.metadrive_process.start() self.status_q.put(QueueMessage(QueueMessageType.START_STATUS, "starting")) @@ -94,6 +94,8 @@ class MetaDriveWorld(World): is_engaged = state.is_engaged if is_engaged and self.first_engage is None: self.first_engage = time.monotonic() + self.op_engaged.set() + # check moving 5 seconds after engaged, doesn't move right away after_engaged_check = is_engaged and time.monotonic() - self.first_engage >= 5 and self.test_run From b9244f103114607c0ca8e543660a284339c045f1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 25 May 2024 11:09:08 -0700 Subject: [PATCH 085/220] move rerun to dev dependencies (#32534) --- poetry.lock | 340 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 168 insertions(+), 174 deletions(-) diff --git a/poetry.lock b/poetry.lock index 471994a72..01ec394f2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohttp" @@ -1152,53 +1152,53 @@ files = [ [[package]] name = "fonttools" -version = "4.51.0" +version = "4.52.1" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74"}, - {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308"}, - {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037"}, - {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716"}, - {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438"}, - {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039"}, - {file = "fonttools-4.51.0-cp310-cp310-win32.whl", hash = "sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77"}, - {file = "fonttools-4.51.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b"}, - {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74"}, - {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2"}, - {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f"}, - {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097"}, - {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0"}, - {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1"}, - {file = "fonttools-4.51.0-cp311-cp311-win32.whl", hash = "sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034"}, - {file = "fonttools-4.51.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1"}, - {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba"}, - {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc"}, - {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a"}, - {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2"}, - {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671"}, - {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5"}, - {file = "fonttools-4.51.0-cp312-cp312-win32.whl", hash = "sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15"}, - {file = "fonttools-4.51.0-cp312-cp312-win_amd64.whl", hash = "sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e"}, - {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e"}, - {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5"}, - {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e"}, - {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1"}, - {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14"}, - {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed"}, - {file = "fonttools-4.51.0-cp38-cp38-win32.whl", hash = "sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f"}, - {file = "fonttools-4.51.0-cp38-cp38-win_amd64.whl", hash = "sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836"}, - {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b"}, - {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936"}, - {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55"}, - {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce"}, - {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051"}, - {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7"}, - {file = "fonttools-4.51.0-cp39-cp39-win32.whl", hash = "sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636"}, - {file = "fonttools-4.51.0-cp39-cp39-win_amd64.whl", hash = "sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a"}, - {file = "fonttools-4.51.0-py3-none-any.whl", hash = "sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f"}, - {file = "fonttools-4.51.0.tar.gz", hash = "sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68"}, + {file = "fonttools-4.52.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:67a30b872e79577e5319ce660ede4a5131fa8a45de76e696746545e17db4437f"}, + {file = "fonttools-4.52.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a5bff35738f8f6607c4303561ee1d1e5f64d5b14cf3c472d3030566c82e763"}, + {file = "fonttools-4.52.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c9622593dfff042480a1b7e5b72c4d7dc00b96d2b4f98b0bf8acf071087e0db"}, + {file = "fonttools-4.52.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33cfc9fe27af5e113d157d5147e24fc8e5bda3c5aadb55bea9847ec55341ce30"}, + {file = "fonttools-4.52.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa5bec5027d947ee4b2242caecf7dc6e4ea03833e92e9b5211ebb6ab4eede8b2"}, + {file = "fonttools-4.52.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:10e44bf8e5654050a332a79285bacd6bd3069084540aec46c0862391147a1daa"}, + {file = "fonttools-4.52.1-cp310-cp310-win32.whl", hash = "sha256:7fba390ac2ca18ebdd456f3a9acfb4557d6dcb2eaba5cc3eadce01003892a770"}, + {file = "fonttools-4.52.1-cp310-cp310-win_amd64.whl", hash = "sha256:15df3517eb95035422a5c953ca19aac99913c16aa0e4ef061aeaef5f3bcaf369"}, + {file = "fonttools-4.52.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40730aab9cf42286f314b985b483eea574f1bcf3a23e28223084cbb9e256457c"}, + {file = "fonttools-4.52.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a19bc2be3af5b22ff5c7fe858c380862e31052c74f62e2c6d565ed0855bed7a6"}, + {file = "fonttools-4.52.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f859066d8afde53f2ddabcd0705061e6d9d9868757c6ae28abe49bc885292df4"}, + {file = "fonttools-4.52.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74cd3e3e9ba501e87a391b62e91f7b1610e8b3f3d706a368e5aee51614c1674e"}, + {file = "fonttools-4.52.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:958957b81418647f66820480363cb617ba6b5bcf189ec6c4cea307d051048545"}, + {file = "fonttools-4.52.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56addf1f995d94dad13aaaf56eb6def3d9ca97c2fada5e27af8190b3141e8633"}, + {file = "fonttools-4.52.1-cp311-cp311-win32.whl", hash = "sha256:fea5456b2af42db8ecb1a6c2f144655ca6dcdcebd970f3145c56e668084ded7e"}, + {file = "fonttools-4.52.1-cp311-cp311-win_amd64.whl", hash = "sha256:228faab7638cd726cdde5e2ec9ee10f780fbf9de9aa38d7f1e56a270437dff36"}, + {file = "fonttools-4.52.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7c6aeb0d53e2ea92009b11c3d4ad9c03d0ecdfe602d547bed8537836e464f51e"}, + {file = "fonttools-4.52.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e871123d12c92e2c9bda6369b69ce2da9cef40b119cc340451e413e90355fa38"}, + {file = "fonttools-4.52.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ff8857dc9bb3e407c25aef3e025409cfbb23adb646a835636bebb1bdfc27a41"}, + {file = "fonttools-4.52.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7685fdc6e23267844eef2b9af585d7f171cca695e4eb369d7682544c3e2e1123"}, + {file = "fonttools-4.52.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1e1b2774485fbbb41a1beccc913b9c6f7971f78da61dd34207b9acc3cc2963e"}, + {file = "fonttools-4.52.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1e2c415160397fd6ed3964155aeec4bfefceeee365ab17161a5b3fe3f8dab077"}, + {file = "fonttools-4.52.1-cp312-cp312-win32.whl", hash = "sha256:3ba2c4647e7decfb8e9cd346661c7d151dae1fba23d37b48bcf5fa8351f7b8c8"}, + {file = "fonttools-4.52.1-cp312-cp312-win_amd64.whl", hash = "sha256:d39b926f14a2f7a7f92ded7d266b18f0108d867364769ab59da88ac2fa90d288"}, + {file = "fonttools-4.52.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6e58d8097a269b6c43ec0abb3fa8d6c350ff0c7dfd23fc14d004610df88a4bb3"}, + {file = "fonttools-4.52.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:20f0fc969817c50539dc919ed8c4aef4de28c2d6e0111a064112301f157aede4"}, + {file = "fonttools-4.52.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d62e84d38969491c6c1f6fe3dd63108e99d02de01bb3d98c160a5d4d24120910"}, + {file = "fonttools-4.52.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8eb5a389bbdee6f4c422881de422ee0e7efdfcd9310b13d540b12aa8ae2c9e7b"}, + {file = "fonttools-4.52.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0caf05c969cbde6729dd97b64bea445ee152bb19215d5886f7b93bd0fb455468"}, + {file = "fonttools-4.52.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:df08bee1dd29a767311b50c62c0cfe4d72ae8c793e567d4c60b8c16c7c63a4f0"}, + {file = "fonttools-4.52.1-cp38-cp38-win32.whl", hash = "sha256:82ffcf4782ceda09842b5b7875b36834c15d7cc0d5dd3d23a658ee9cf8819cd6"}, + {file = "fonttools-4.52.1-cp38-cp38-win_amd64.whl", hash = "sha256:26b43bab5a3bce55ed4d9699b16568795eef5597d154f52dcabef5b4804c4b21"}, + {file = "fonttools-4.52.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e8dbc13c4bc12e60df1b1f5e484112a5e96a6e8bba995e2965988ad73c5ea1b"}, + {file = "fonttools-4.52.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7352ba2226e45e8fba11c3fb416363faf1b06f3f2e80d07d2930401265f3bf9c"}, + {file = "fonttools-4.52.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8834d43763e9e92349ce8bb25dfb612aef6691eefefad885212d5e8f36a94a4"}, + {file = "fonttools-4.52.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee2a8c1101d06cc8fca7851dceb67afd53dd6fc0288bacaa632e647bc5afff58"}, + {file = "fonttools-4.52.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a99b738227c0f6f2bbe381b45804a7c46653c95b9d7bf13f6f02884bc87e4930"}, + {file = "fonttools-4.52.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:75aa00a16b9a64d1550e2e70d3582c7fe1ef18560e0cf066a4087fe6d11908a2"}, + {file = "fonttools-4.52.1-cp39-cp39-win32.whl", hash = "sha256:c2f09b4aa699cfed4bbebc1829c5f044b41976707dac9230ed00d5a9fc6452c1"}, + {file = "fonttools-4.52.1-cp39-cp39-win_amd64.whl", hash = "sha256:78ea6e0d4c89f8e216995923b854dd10bd09e48d3a5a3ccb48bb68f436a409ad"}, + {file = "fonttools-4.52.1-py3-none-any.whl", hash = "sha256:faf5c83f83f7ddebdafdb453d02efdbea7fb494080d7a8d45a8a20db06ea8da5"}, + {file = "fonttools-4.52.1.tar.gz", hash = "sha256:8c9204435aa6e5e9479a5ba4e669f05dea28b0c61958e0c0923cb164296d9329"}, ] [package.extras] @@ -2616,42 +2616,37 @@ files = [ [[package]] name = "onnx" -version = "1.16.0" +version = "1.16.1" description = "Open Neural Network Exchange" optional = false python-versions = ">=3.8" files = [ - {file = "onnx-1.16.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:9eadbdce25b19d6216f426d6d99b8bc877a65ed92cbef9707751c6669190ba4f"}, - {file = "onnx-1.16.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:034ae21a2aaa2e9c14119a840d2926d213c27aad29e5e3edaa30145a745048e1"}, - {file = "onnx-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec22a43d74eb1f2303373e2fbe7fbcaa45fb225f4eb146edfed1356ada7a9aea"}, - {file = "onnx-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:298f28a2b5ac09145fa958513d3d1e6b349ccf86a877dbdcccad57713fe360b3"}, - {file = "onnx-1.16.0-cp310-cp310-win32.whl", hash = "sha256:66300197b52beca08bc6262d43c103289c5d45fde43fb51922ed1eb83658cf0c"}, - {file = "onnx-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae0029f5e47bf70a1a62e7f88c80bca4ef39b844a89910039184221775df5e43"}, - {file = "onnx-1.16.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:f51179d4af3372b4f3800c558d204b592c61e4b4a18b8f61e0eea7f46211221a"}, - {file = "onnx-1.16.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:5202559070afec5144332db216c20f2fff8323cf7f6512b0ca11b215eacc5bf3"}, - {file = "onnx-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77579e7c15b4df39d29465b216639a5f9b74026bdd9e4b6306cd19a32dcfe67c"}, - {file = "onnx-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e60ca76ac24b65c25860d0f2d2cdd96d6320d062a01dd8ce87c5743603789b8"}, - {file = "onnx-1.16.0-cp311-cp311-win32.whl", hash = "sha256:81b4ee01bc554e8a2b11ac6439882508a5377a1c6b452acd69a1eebb83571117"}, - {file = "onnx-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:7449241e70b847b9c3eb8dae622df8c1b456d11032a9d7e26e0ee8a698d5bf86"}, - {file = "onnx-1.16.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:03a627488b1a9975d95d6a55582af3e14c7f3bb87444725b999935ddd271d352"}, - {file = "onnx-1.16.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:c392faeabd9283ee344ccb4b067d1fea9dfc614fa1f0de7c47589efd79e15e78"}, - {file = "onnx-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0efeb46985de08f0efe758cb54ad3457e821a05c2eaf5ba2ccb8cd1602c08084"}, - {file = "onnx-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf14a3d32234f23e44abb73a755cb96a423fac7f004e8f046f36b10214151ee"}, - {file = "onnx-1.16.0-cp312-cp312-win32.whl", hash = "sha256:62a2e27ae8ba5fc9b4a2620301446a517b5ffaaf8566611de7a7c2160f5bcf4c"}, - {file = "onnx-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:3e0860fea94efde777e81a6f68f65761ed5e5f3adea2e050d7fbe373a9ae05b3"}, - {file = "onnx-1.16.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:70a90649318f3470985439ea078277c9fb2a2e6e2fd7c8f3f2b279402ad6c7e6"}, - {file = "onnx-1.16.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:71839546b7f93be4fa807995b182ab4b4414c9dbf049fee11eaaced16fcf8df2"}, - {file = "onnx-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7665217c45a61eb44718c8e9349d2ad004efa0cb9fbc4be5c6d5e18b9fe12b52"}, - {file = "onnx-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5752bbbd5717304a7643643dba383a2fb31e8eb0682f4e7b7d141206328a73b"}, - {file = "onnx-1.16.0-cp38-cp38-win32.whl", hash = "sha256:257858cbcb2055284f09fa2ae2b1cfd64f5850367da388d6e7e7b05920a40c90"}, - {file = "onnx-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:209fe84995a28038e29ae8369edd35f33e0ef1ebc3bddbf6584629823469deb1"}, - {file = "onnx-1.16.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:8cf3e518b1b1b960be542e7c62bed4e5219e04c85d540817b7027029537dec92"}, - {file = "onnx-1.16.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:30f02beaf081c7d9fa3a8c566a912fc4408e28fc33b1452d58f890851691d364"}, - {file = "onnx-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fb29a9a692b522deef1f6b8f2145da62c0c43ea1ed5b4c0f66f827fdc28847d"}, - {file = "onnx-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7755cbd5f4e47952e37276ea5978a46fc8346684392315902b5ed4a719d87d06"}, - {file = "onnx-1.16.0-cp39-cp39-win32.whl", hash = "sha256:7532343dc5b8b5e7c3e3efa441a3100552f7600155c4db9120acd7574f64ffbf"}, - {file = "onnx-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:d7886c05aa6d583ec42f6287678923c1e343afc4350e49d5b36a0023772ffa22"}, - {file = "onnx-1.16.0.tar.gz", hash = "sha256:237c6987c6c59d9f44b6136f5819af79574f8d96a760a1fa843bede11f3822f7"}, + {file = "onnx-1.16.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:bb2d392e5b7060082c2fb38eb5c44f67eb34ff5f0681bd6f45beff9abc6f7094"}, + {file = "onnx-1.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15abf94a7868eed6db15a8b5024ba570c891cae77ca4d0e7258dabdad76980df"}, + {file = "onnx-1.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6251910e554f811fdd070164b0bc76d76b067b95576cb9dad4d52ae64fe014b5"}, + {file = "onnx-1.16.1-cp310-cp310-win32.whl", hash = "sha256:c11e3b15eee46cd20767e505cc3ba97457ef5ac93c3e459cdfb77943ff8fe9a7"}, + {file = "onnx-1.16.1-cp310-cp310-win_amd64.whl", hash = "sha256:b3d10405706807ec2ef493b2a78519fa0264cf190363e89478585aac1179b596"}, + {file = "onnx-1.16.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:006ba5059c85ce43e89a1486cc0276d0f1a8ec9c6efd1a9334fd3fa0f6e33b64"}, + {file = "onnx-1.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1521ea7cd3497ecaf57d3b5e72d637ca5ebca632122a0806a9df99bedbeecdf8"}, + {file = "onnx-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45cf20421aeac03872bea5fd6ebf92abe15c4d1461a2572eb839add5059e2a09"}, + {file = "onnx-1.16.1-cp311-cp311-win32.whl", hash = "sha256:f98e275b4f46a617a9c527e60c02531eae03cf67a04c26db8a1c20acee539533"}, + {file = "onnx-1.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:95aa20aa65a9035d7543e81713e8b0f611e213fc02171959ef4ee09311d1bf28"}, + {file = "onnx-1.16.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:32e11d39bee04f927fab09f74c46cf76584094462311bab1aca9ccdae6ed3366"}, + {file = "onnx-1.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8884bf53b552873c0c9b072cb8625e7d4e8f3cc0529191632d24e3de58a3b93a"}, + {file = "onnx-1.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595b2830093f81361961295f7b0ebb6000423bcd04123d516d081c306002e387"}, + {file = "onnx-1.16.1-cp312-cp312-win32.whl", hash = "sha256:2fde4dd5bc278b3fc8148f460bce8807b2874c66f48529df9444cdbc9ecf456b"}, + {file = "onnx-1.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:e69ad8c110d8c37d759cad019d498fdf3fd24e0bfaeb960e52fed0469a5d2974"}, + {file = "onnx-1.16.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0fc189195a40b5862fb77d97410c89823197fe19c1088ce150444eec72f200c1"}, + {file = "onnx-1.16.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:496ba17b16a74711081772e1b03f3207959972e351298e51abdc600051027a22"}, + {file = "onnx-1.16.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3faf239b48418b3ea6fe73bd4d86807b903d0b2ebd20b8b8c84f83741b0f18"}, + {file = "onnx-1.16.1-cp38-cp38-win32.whl", hash = "sha256:18b22143836838591f6551b089196e69f60c47fabce52b4b72b4cb37522645aa"}, + {file = "onnx-1.16.1-cp38-cp38-win_amd64.whl", hash = "sha256:8c2b70d602acfb90056fbdc60ef26f4658f964591212a4e9dbbda922ff43061b"}, + {file = "onnx-1.16.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:2bed6fe05905b073206cabbb4463c58050cf8d544192303c09927b229f93ac14"}, + {file = "onnx-1.16.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5798414332534a41404a7ff83677d49ced01d70160e1541484cce647f2295051"}, + {file = "onnx-1.16.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa7518d6d27f357261a4014079dec364cad6fef827d0b3fe1d3ff59939a68394"}, + {file = "onnx-1.16.1-cp39-cp39-win32.whl", hash = "sha256:67f372db4fe8fe61e00b762af5b0833aa72b5baa37e7e2f47d8668964ebff411"}, + {file = "onnx-1.16.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c059fea6229c44d2d39c8f6e2f2f0d676d587c97f4c854c86f3e7bc97e0b31c"}, + {file = "onnx-1.16.1.tar.gz", hash = "sha256:8299193f0f2a3849bfc069641aa8e4f93696602da8d165632af8ee48ec7556b6"}, ] [package.dependencies] @@ -2705,21 +2700,21 @@ sympy = "*" [[package]] name = "onnxruntime-gpu" -version = "1.17.1" +version = "1.18.0" description = "ONNX Runtime is a runtime accelerator for Machine Learning models" optional = false python-versions = "*" files = [ - {file = "onnxruntime_gpu-1.17.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a55fe84ee11a59ea069c6a790ee960f1c7da0d7d6c74822b2a8b357027c93646"}, - {file = "onnxruntime_gpu-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:a9abefceb32879cbee9f57977d6bb8d58cbac501f8a64bf96bca2f4fdff157fe"}, - {file = "onnxruntime_gpu-1.17.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:b2cd54f2b0a05e6bc9ab30182b859364d30115a19c31be24aa2edef40be00277"}, - {file = "onnxruntime_gpu-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdffcced8a5f6275c0df202220e9232138b336f868cd671c9d2c571e834d2a80"}, - {file = "onnxruntime_gpu-1.17.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a1c871e8d0ae4121ea6528fc9410a5a7cbc5e43714b30521d5514fd10b987c83"}, - {file = "onnxruntime_gpu-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:9a0a94eda080e9f4a8e5035fdf0b3c24f5533e7861d88833a94493e63fca0812"}, - {file = "onnxruntime_gpu-1.17.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:624fdb65a632833f13de36854855818680be4f77942d8114524491d58f60d3ab"}, - {file = "onnxruntime_gpu-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:29fa78d232bbb5a5be3a3e0a022148a7b3df2ca66b4c21a11eef56e6f22859e9"}, - {file = "onnxruntime_gpu-1.17.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b0f8c70f2f9aeae825f3a397cc0c5f45124f9ae7c173263cf13c495982b0b99a"}, - {file = "onnxruntime_gpu-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:b1a27a104334461b690e4fc62775e1e71c68936399874932225d7fea21a0c261"}, + {file = "onnxruntime_gpu-1.18.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ebee59886d4a63d54cec673c73bdcc58b5496f9946e3c539af51550c6f222e88"}, + {file = "onnxruntime_gpu-1.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:c33a2bfd100bd2b82542c72deaaed40d3de858ac9624dc5730e548869dac2f2f"}, + {file = "onnxruntime_gpu-1.18.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:aa673c044f450b21163265cca2e35eb1ded03d48fb01dec6be1c412811e9b2b0"}, + {file = "onnxruntime_gpu-1.18.0-cp311-cp311-win_amd64.whl", hash = "sha256:1dfb1172de0043f7bdc32724619f5bc151dbdc5bb8e50e806271d2efa8d72715"}, + {file = "onnxruntime_gpu-1.18.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:40ce4aec8499352b96f8c67d1f2fe4ac170dbc9281dd8ebe36339d9e1c0bcdb7"}, + {file = "onnxruntime_gpu-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:97df451777322a534dbedff49d43a4f6f74bd5258ccf31b2161e1af606bc724d"}, + {file = "onnxruntime_gpu-1.18.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:05b5f17bc78586741715903b5ec7fcef4c64d136aee94d6583dd17035190d550"}, + {file = "onnxruntime_gpu-1.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:40fab33312d02fdaa93b8cc14ffb1fc3aceaef5db50383a579fd8b7ad5a03b17"}, + {file = "onnxruntime_gpu-1.18.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e0d9e200afe57c69c6407c90189c7f16a55ce326d1ac45864353e13bfe574b3c"}, + {file = "onnxruntime_gpu-1.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:a7d13f0983eec46857acab8bdace7e3178428d17ad3c6d5b84b5b211c98e5acd"}, ] [package.dependencies] @@ -3171,22 +3166,22 @@ files = [ [[package]] name = "protobuf" -version = "5.26.1" +version = "5.27.0" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-5.26.1-cp310-abi3-win32.whl", hash = "sha256:3c388ea6ddfe735f8cf69e3f7dc7611e73107b60bdfcf5d0f024c3ccd3794e23"}, - {file = "protobuf-5.26.1-cp310-abi3-win_amd64.whl", hash = "sha256:e6039957449cb918f331d32ffafa8eb9255769c96aa0560d9a5bf0b4e00a2a33"}, - {file = "protobuf-5.26.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:38aa5f535721d5bb99861166c445c4105c4e285c765fbb2ac10f116e32dcd46d"}, - {file = "protobuf-5.26.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fbfe61e7ee8c1860855696e3ac6cfd1b01af5498facc6834fcc345c9684fb2ca"}, - {file = "protobuf-5.26.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:f7417703f841167e5a27d48be13389d52ad705ec09eade63dfc3180a959215d7"}, - {file = "protobuf-5.26.1-cp38-cp38-win32.whl", hash = "sha256:d693d2504ca96750d92d9de8a103102dd648fda04540495535f0fec7577ed8fc"}, - {file = "protobuf-5.26.1-cp38-cp38-win_amd64.whl", hash = "sha256:9b557c317ebe6836835ec4ef74ec3e994ad0894ea424314ad3552bc6e8835b4e"}, - {file = "protobuf-5.26.1-cp39-cp39-win32.whl", hash = "sha256:b9ba3ca83c2e31219ffbeb9d76b63aad35a3eb1544170c55336993d7a18ae72c"}, - {file = "protobuf-5.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ee014c2c87582e101d6b54260af03b6596728505c79f17c8586e7523aaa8f8c"}, - {file = "protobuf-5.26.1-py3-none-any.whl", hash = "sha256:da612f2720c0183417194eeaa2523215c4fcc1a1949772dc65f05047e08d5932"}, - {file = "protobuf-5.26.1.tar.gz", hash = "sha256:8ca2a1d97c290ec7b16e4e5dff2e5ae150cc1582f55b5ab300d45cb0dfa90e51"}, + {file = "protobuf-5.27.0-cp310-abi3-win32.whl", hash = "sha256:2f83bf341d925650d550b8932b71763321d782529ac0eaf278f5242f513cc04e"}, + {file = "protobuf-5.27.0-cp310-abi3-win_amd64.whl", hash = "sha256:b276e3f477ea1eebff3c2e1515136cfcff5ac14519c45f9b4aa2f6a87ea627c4"}, + {file = "protobuf-5.27.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:744489f77c29174328d32f8921566fb0f7080a2f064c5137b9d6f4b790f9e0c1"}, + {file = "protobuf-5.27.0-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:f51f33d305e18646f03acfdb343aac15b8115235af98bc9f844bf9446573827b"}, + {file = "protobuf-5.27.0-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:56937f97ae0dcf4e220ff2abb1456c51a334144c9960b23597f044ce99c29c89"}, + {file = "protobuf-5.27.0-cp38-cp38-win32.whl", hash = "sha256:a17f4d664ea868102feaa30a674542255f9f4bf835d943d588440d1f49a3ed15"}, + {file = "protobuf-5.27.0-cp38-cp38-win_amd64.whl", hash = "sha256:aabbbcf794fbb4c692ff14ce06780a66d04758435717107c387f12fb477bf0d8"}, + {file = "protobuf-5.27.0-cp39-cp39-win32.whl", hash = "sha256:587be23f1212da7a14a6c65fd61995f8ef35779d4aea9e36aad81f5f3b80aec5"}, + {file = "protobuf-5.27.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cb65fc8fba680b27cf7a07678084c6e68ee13cab7cace734954c25a43da6d0f"}, + {file = "protobuf-5.27.0-py3-none-any.whl", hash = "sha256:673ad60f1536b394b4fa0bcd3146a4130fcad85bfe3b60eaa86d6a0ace0fa374"}, + {file = "protobuf-5.27.0.tar.gz", hash = "sha256:07f2b9a15255e3cf3f137d884af7972407b556a7a220912b252f26dc3121e6bf"}, ] [[package]] @@ -6635,13 +6630,13 @@ cp2110 = ["hidapi"] [[package]] name = "pytest" -version = "8.2.0" +version = "8.2.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.2.0-py3-none-any.whl", hash = "sha256:1733f0620f6cda4095bbf0d9ff8022486e91892245bb9e7d5542c018f612f233"}, - {file = "pytest-8.2.0.tar.gz", hash = "sha256:d507d4482197eac0ba2bae2e9babf0672eb333017bcedaa5fb1a3d42c1174b3f"}, + {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, + {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, ] [package.dependencies] @@ -6655,13 +6650,13 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "pytest-asyncio" -version = "0.23.6" +version = "0.23.7" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, - {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, + {file = "pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b"}, + {file = "pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268"}, ] [package.dependencies] @@ -6824,13 +6819,13 @@ files = [ [[package]] name = "pytools" -version = "2024.1.2" +version = "2024.1.3" description = "A collection of tools for Python" optional = false python-versions = "~=3.8" files = [ - {file = "pytools-2024.1.2-py2.py3-none-any.whl", hash = "sha256:f61287b5341e53e3fe96c82385469b57a8983ff3db815a2bf3f533c38e8d516b"}, - {file = "pytools-2024.1.2.tar.gz", hash = "sha256:081871e451505c4b986ebafa68aeeabfdc7beb3faa1baa50f726aebe21e1d057"}, + {file = "pytools-2024.1.3-py2.py3-none-any.whl", hash = "sha256:2977a7e9580fac6260d1352ed7a69a12a0c59687f834e0ebaecaf1148eceb7f3"}, + {file = "pytools-2024.1.3.tar.gz", hash = "sha256:cc2db25666aa64094d3fb4532aa8a7deaa2da8edd7340fb270ed1807dcc75202"}, ] [package.dependencies] @@ -7087,13 +7082,13 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "requests" -version = "2.31.0" +version = "2.32.2" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, + {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, ] [package.dependencies] @@ -7147,62 +7142,62 @@ docs = ["furo (==2024.4.27)", "pyenchant (==3.2.2)", "sphinx (==7.1.2)", "sphinx [[package]] name = "ruff" -version = "0.4.4" +version = "0.4.5" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.4.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:29d44ef5bb6a08e235c8249294fa8d431adc1426bfda99ed493119e6f9ea1bf6"}, - {file = "ruff-0.4.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c4efe62b5bbb24178c950732ddd40712b878a9b96b1d02b0ff0b08a090cbd891"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c8e2f1e8fc12d07ab521a9005d68a969e167b589cbcaee354cb61e9d9de9c15"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60ed88b636a463214905c002fa3eaab19795679ed55529f91e488db3fe8976ab"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b90fc5e170fc71c712cc4d9ab0e24ea505c6a9e4ebf346787a67e691dfb72e85"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8e7e6ebc10ef16dcdc77fd5557ee60647512b400e4a60bdc4849468f076f6eef"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9ddb2c494fb79fc208cd15ffe08f32b7682519e067413dbaf5f4b01a6087bcd"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c51c928a14f9f0a871082603e25a1588059b7e08a920f2f9fa7157b5bf08cfe9"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5eb0a4bfd6400b7d07c09a7725e1a98c3b838be557fee229ac0f84d9aa49c36"}, - {file = "ruff-0.4.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b1867ee9bf3acc21778dcb293db504692eda5f7a11a6e6cc40890182a9f9e595"}, - {file = "ruff-0.4.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1aecced1269481ef2894cc495647392a34b0bf3e28ff53ed95a385b13aa45768"}, - {file = "ruff-0.4.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9da73eb616b3241a307b837f32756dc20a0b07e2bcb694fec73699c93d04a69e"}, - {file = "ruff-0.4.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:958b4ea5589706a81065e2a776237de2ecc3e763342e5cc8e02a4a4d8a5e6f95"}, - {file = "ruff-0.4.4-py3-none-win32.whl", hash = "sha256:cb53473849f011bca6e754f2cdf47cafc9c4f4ff4570003a0dad0b9b6890e876"}, - {file = "ruff-0.4.4-py3-none-win_amd64.whl", hash = "sha256:424e5b72597482543b684c11def82669cc6b395aa8cc69acc1858b5ef3e5daae"}, - {file = "ruff-0.4.4-py3-none-win_arm64.whl", hash = "sha256:39df0537b47d3b597293edbb95baf54ff5b49589eb7ff41926d8243caa995ea6"}, - {file = "ruff-0.4.4.tar.gz", hash = "sha256:f87ea42d5cdebdc6a69761a9d0bc83ae9b3b30d0ad78952005ba6568d6c022af"}, + {file = "ruff-0.4.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8f58e615dec58b1a6b291769b559e12fdffb53cc4187160a2fc83250eaf54e96"}, + {file = "ruff-0.4.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:84dd157474e16e3a82745d2afa1016c17d27cb5d52b12e3d45d418bcc6d49264"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f483ad9d50b00e7fd577f6d0305aa18494c6af139bce7319c68a17180087f4"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63fde3bf6f3ad4e990357af1d30e8ba2730860a954ea9282c95fc0846f5f64af"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e3ba4620dee27f76bbcad97067766026c918ba0f2d035c2fc25cbdd04d9c97"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:441dab55c568e38d02bbda68a926a3d0b54f5510095c9de7f95e47a39e0168aa"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1169e47e9c4136c997f08f9857ae889d614c5035d87d38fda9b44b4338909cdf"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:755ac9ac2598a941512fc36a9070a13c88d72ff874a9781493eb237ab02d75df"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4b02a65985be2b34b170025a8b92449088ce61e33e69956ce4d316c0fe7cce0"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:75a426506a183d9201e7e5664de3f6b414ad3850d7625764106f7b6d0486f0a1"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6e1b139b45e2911419044237d90b60e472f57285950e1492c757dfc88259bb06"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6f29a8221d2e3d85ff0c7b4371c0e37b39c87732c969b4d90f3dad2e721c5b1"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d6ef817124d72b54cc923f3444828ba24fa45c3164bc9e8f1813db2f3d3a8a11"}, + {file = "ruff-0.4.5-py3-none-win32.whl", hash = "sha256:aed8166c18b1a169a5d3ec28a49b43340949e400665555b51ee06f22813ef062"}, + {file = "ruff-0.4.5-py3-none-win_amd64.whl", hash = "sha256:b0b03c619d2b4350b4a27e34fd2ac64d0dabe1afbf43de57d0f9d8a05ecffa45"}, + {file = "ruff-0.4.5-py3-none-win_arm64.whl", hash = "sha256:9d15de3425f53161b3f5a5658d4522e4eee5ea002bf2ac7aa380743dd9ad5fba"}, + {file = "ruff-0.4.5.tar.gz", hash = "sha256:286eabd47e7d4d521d199cab84deca135557e6d1e0f0d01c29e757c3cb151b54"}, ] [[package]] name = "scipy" -version = "1.13.0" +version = "1.13.1" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "scipy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba419578ab343a4e0a77c0ef82f088238a93eef141b2b8017e46149776dfad4d"}, - {file = "scipy-1.13.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:22789b56a999265431c417d462e5b7f2b487e831ca7bef5edeb56efe4c93f86e"}, - {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f1432ba070e90d42d7fd836462c50bf98bd08bed0aa616c359eed8a04e3922"}, - {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8434f6f3fa49f631fae84afee424e2483289dfc30a47755b4b4e6b07b2633a4"}, - {file = "scipy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dcbb9ea49b0167de4167c40eeee6e167caeef11effb0670b554d10b1e693a8b9"}, - {file = "scipy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1d2f7bb14c178f8b13ebae93f67e42b0a6b0fc50eba1cd8021c9b6e08e8fb1cd"}, - {file = "scipy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fbcf8abaf5aa2dc8d6400566c1a727aed338b5fe880cde64907596a89d576fa"}, - {file = "scipy-1.13.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5e4a756355522eb60fcd61f8372ac2549073c8788f6114449b37e9e8104f15a5"}, - {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5acd8e1dbd8dbe38d0004b1497019b2dbbc3d70691e65d69615f8a7292865d7"}, - {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ff7dad5d24a8045d836671e082a490848e8639cabb3dbdacb29f943a678683d"}, - {file = "scipy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4dca18c3ffee287ddd3bc8f1dabaf45f5305c5afc9f8ab9cbfab855e70b2df5c"}, - {file = "scipy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:a2f471de4d01200718b2b8927f7d76b5d9bde18047ea0fa8bd15c5ba3f26a1d6"}, - {file = "scipy-1.13.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d0de696f589681c2802f9090fff730c218f7c51ff49bf252b6a97ec4a5d19e8b"}, - {file = "scipy-1.13.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:b2a3ff461ec4756b7e8e42e1c681077349a038f0686132d623fa404c0bee2551"}, - {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf9fe63e7a4bf01d3645b13ff2aa6dea023d38993f42aaac81a18b1bda7a82a"}, - {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e7626dfd91cdea5714f343ce1176b6c4745155d234f1033584154f60ef1ff42"}, - {file = "scipy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:109d391d720fcebf2fbe008621952b08e52907cf4c8c7efc7376822151820820"}, - {file = "scipy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8930ae3ea371d6b91c203b1032b9600d69c568e537b7988a3073dfe4d4774f21"}, - {file = "scipy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5407708195cb38d70fd2d6bb04b1b9dd5c92297d86e9f9daae1576bd9e06f602"}, - {file = "scipy-1.13.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ac38c4c92951ac0f729c4c48c9e13eb3675d9986cc0c83943784d7390d540c78"}, - {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c74543c4fbeb67af6ce457f6a6a28e5d3739a87f62412e4a16e46f164f0ae5"}, - {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28e286bf9ac422d6beb559bc61312c348ca9b0f0dae0d7c5afde7f722d6ea13d"}, - {file = "scipy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33fde20efc380bd23a78a4d26d59fc8704e9b5fd9b08841693eb46716ba13d86"}, - {file = "scipy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:45c08bec71d3546d606989ba6e7daa6f0992918171e2a6f7fbedfa7361c2de1e"}, - {file = "scipy-1.13.0.tar.gz", hash = "sha256:58569af537ea29d3f78e5abd18398459f195546bb3be23d16677fb26616cc11e"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, + {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, + {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, + {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, + {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, + {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, + {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, + {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, + {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, + {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, ] [package.dependencies] @@ -7247,13 +7242,13 @@ stats = ["scipy (>=1.7)", "statsmodels (>=0.12)"] [[package]] name = "sentry-sdk" -version = "2.2.0" +version = "2.3.1" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" files = [ - {file = "sentry_sdk-2.2.0-py2.py3-none-any.whl", hash = "sha256:674f58da37835ea7447fe0e34c57b4a4277fad558b0a7cb4a6c83bcb263086be"}, - {file = "sentry_sdk-2.2.0.tar.gz", hash = "sha256:70eca103cf4c6302365a9d7cf522e7ed7720828910eb23d43ada8e50d1ecda9d"}, + {file = "sentry_sdk-2.3.1-py2.py3-none-any.whl", hash = "sha256:c5aeb095ba226391d337dd42a6f9470d86c9fc236ecc71cfc7cd1942b45010c6"}, + {file = "sentry_sdk-2.3.1.tar.gz", hash = "sha256:139a71a19f5e9eb5d3623942491ce03cf8ebc14ea2e39ba3e6fe79560d8a5b1f"}, ] [package.dependencies] @@ -7275,7 +7270,7 @@ django = ["django (>=1.8)"] falcon = ["falcon (>=1.4)"] fastapi = ["fastapi (>=0.79.0)"] flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] -grpcio = ["grpcio (>=1.21.1)"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] httpx = ["httpx (>=0.16.0)"] huey = ["huey (>=2)"] huggingface-hub = ["huggingface-hub (>=0.22)"] @@ -7397,19 +7392,18 @@ test = ["pytest"] [[package]] name = "setuptools" -version = "69.5.1" +version = "70.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, - {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, + {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, + {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shapely" @@ -7808,13 +7802,13 @@ telegram = ["requests"] [[package]] name = "types-requests" -version = "2.31.0.20240406" +version = "2.32.0.20240523" description = "Typing stubs for requests" optional = false python-versions = ">=3.8" files = [ - {file = "types-requests-2.31.0.20240406.tar.gz", hash = "sha256:4428df33c5503945c74b3f42e82b181e86ec7b724620419a2966e2de604ce1a1"}, - {file = "types_requests-2.31.0.20240406-py3-none-any.whl", hash = "sha256:6216cdac377c6b9a040ac1c0404f7284bd13199c0e1bb235f4324627e8898cf5"}, + {file = "types-requests-2.32.0.20240523.tar.gz", hash = "sha256:26b8a6de32d9f561192b9942b41c0ab2d8010df5677ca8aa146289d11d505f57"}, + {file = "types_requests-2.32.0.20240523-py3-none-any.whl", hash = "sha256:f19ed0e2daa74302069bbbbf9e82902854ffa780bc790742a810a9aaa52f65ec"}, ] [package.dependencies] @@ -7833,13 +7827,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, + {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, ] [[package]] @@ -8043,4 +8037,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "debffdd8b49091d256508f53c11e9d79fb4164995678d7e02d1720175cf265ec" +content-hash = "1b15d2bb9465282294cd503c019a7d023f16dbb3e44ddde7b9899c45195c6cb8" diff --git a/pyproject.toml b/pyproject.toml index db1b4195a..16908b11d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,7 +108,6 @@ pycryptodome = "*" PyJWT = "*" pyserial = "*" pyzmq = "*" -rerun-sdk = "*" requests = "*" scons = "*" sentry-sdk = "*" @@ -165,6 +164,7 @@ pytest-timeout = "*" pytest-randomly = "*" pytest-asyncio = "*" pytest-mock = "*" +rerun-sdk = "*" ruff = "*" sphinx = "*" sphinx-rtd-theme = "*" From cd21d64058d161614b7504f344e8a26df28240c2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 25 May 2024 11:40:10 -0700 Subject: [PATCH 086/220] speedup pj demo test --- tools/plotjuggler/test_plotjuggler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/plotjuggler/test_plotjuggler.py b/tools/plotjuggler/test_plotjuggler.py index 8b811f484..b9a55297e 100755 --- a/tools/plotjuggler/test_plotjuggler.py +++ b/tools/plotjuggler/test_plotjuggler.py @@ -26,7 +26,7 @@ class TestPlotJuggler: output += p.stderr.readline().decode("utf-8") # ensure plotjuggler didn't crash after exiting the plugin - time.sleep(15) + time.sleep(2) assert p.poll() is None os.killpg(os.getpgid(p.pid), signal.SIGTERM) From 73b02f2cda858d4ad08bc7fa4116d0d11ff79a02 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 25 May 2024 12:22:02 -0700 Subject: [PATCH 087/220] updated: finish system/ move (#32535) * updated: finish system/ move * add those back * skip that * skip whole file * one more time --- pyproject.toml | 2 +- release/files_common | 4 +--- scripts/stop_updater.sh | 2 +- scripts/update_now.sh | 2 +- selfdrive/manager/process_config.py | 2 +- selfdrive/test/test_updated.py | 2 +- selfdrive/ui/qt/offroad/software_settings.cc | 4 ++-- system/updated/casync/tests/test_casync.py | 2 ++ {selfdrive => system}/updated/tests/test_base.py | 0 {selfdrive => system}/updated/tests/test_git.py | 2 +- {selfdrive => system}/updated/updated.py | 0 11 files changed, 11 insertions(+), 11 deletions(-) rename {selfdrive => system}/updated/tests/test_base.py (100%) rename {selfdrive => system}/updated/tests/test_git.py (88%) rename {selfdrive => system}/updated/updated.py (100%) diff --git a/pyproject.toml b/pyproject.toml index 16908b11d..da7f1021e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ testpaths = [ "selfdrive/navd/tests", "selfdrive/test/longitudinal_maneuvers", "selfdrive/test/process_replay/test_fuzzy.py", - "selfdrive/updated", + "system/updated", "system/thermald", "system/athena", "system/camerad", diff --git a/release/files_common b/release/files_common index f6afd9390..ff3e62aa1 100644 --- a/release/files_common +++ b/release/files_common @@ -54,8 +54,6 @@ tools/replay/*.h selfdrive/__init__.py -selfdrive/updated/** - system/logmessaged.py system/micd.py system/version.py @@ -189,7 +187,7 @@ system/ubloxd/generated/* system/ubloxd/*.h system/ubloxd/*.cc -system/updated/* +system/updated/** selfdrive/locationd/__init__.py selfdrive/locationd/SConscript diff --git a/scripts/stop_updater.sh b/scripts/stop_updater.sh index 7f8219182..703b36392 100755 --- a/scripts/stop_updater.sh +++ b/scripts/stop_updater.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh # Stop updater -pkill -2 -f selfdrive.updated.updated +pkill -2 -f system.updated.updated # Remove pending update rm -f /data/safe_staging/finalized/.overlay_consistent diff --git a/scripts/update_now.sh b/scripts/update_now.sh index 3f0193f08..c34228976 100755 --- a/scripts/update_now.sh +++ b/scripts/update_now.sh @@ -1,4 +1,4 @@ #!/usr/bin/env sh # Send SIGHUP to updater -pkill -1 -f selfdrive.updated +pkill -1 -f system.updated diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index a8ab204da..b6567c2f7 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -78,7 +78,7 @@ procs = [ PythonProcess("radard", "selfdrive.controls.radard", only_onroad), PythonProcess("thermald", "system.thermald.thermald", always_run), PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC), - PythonProcess("updated", "selfdrive.updated.updated", only_offroad, enabled=not PC), + PythonProcess("updated", "system.updated.updated", only_offroad, enabled=not PC), PythonProcess("uploader", "system.loggerd.uploader", always_run), PythonProcess("statsd", "system.statsd", always_run), diff --git a/selfdrive/test/test_updated.py b/selfdrive/test/test_updated.py index 5220cfb28..12619d424 100755 --- a/selfdrive/test/test_updated.py +++ b/selfdrive/test/test_updated.py @@ -89,7 +89,7 @@ class TestUpdated: os.environ["UPDATER_STAGING_ROOT"] = self.staging_dir os.environ["UPDATER_NEOS_VERSION"] = self.neos_version os.environ["UPDATER_NEOSUPDATE_DIR"] = self.neosupdate_dir - updated_path = os.path.join(self.basedir, "selfdrive/updated.py") + updated_path = os.path.join(self.basedir, "system/updated.py") return subprocess.Popen(updated_path, env=os.environ) def _start_updater(self, offroad=True, nosleep=False): diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index d12db3f87..c8245205c 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -17,7 +17,7 @@ void SoftwarePanel::checkForUpdates() { - std::system("pkill -SIGUSR1 -f selfdrive.updated.updated"); + std::system("pkill -SIGUSR1 -f system.updated.updated"); } SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { @@ -36,7 +36,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { if (downloadBtn->text() == tr("CHECK")) { checkForUpdates(); } else { - std::system("pkill -SIGHUP -f selfdrive.updated.updated"); + std::system("pkill -SIGHUP -f system.updated.updated"); } }); addItem(downloadBtn); diff --git a/system/updated/casync/tests/test_casync.py b/system/updated/casync/tests/test_casync.py index 80c5d2705..29cf78f0f 100755 --- a/system/updated/casync/tests/test_casync.py +++ b/system/updated/casync/tests/test_casync.py @@ -14,6 +14,7 @@ from openpilot.system.updated.casync import tar LOOPBACK = os.environ.get('LOOPBACK', None) +@pytest.mark.skip("not used yet") class TestCasync: @classmethod def setup_class(cls): @@ -151,6 +152,7 @@ class TestCasync: assert stats['remote'] < len(self.contents) +@pytest.mark.skip("not used yet") class TestCasyncDirectory: """Tests extracting a directory stored as a casync tar archive""" diff --git a/selfdrive/updated/tests/test_base.py b/system/updated/tests/test_base.py similarity index 100% rename from selfdrive/updated/tests/test_base.py rename to system/updated/tests/test_base.py diff --git a/selfdrive/updated/tests/test_git.py b/system/updated/tests/test_git.py similarity index 88% rename from selfdrive/updated/tests/test_git.py rename to system/updated/tests/test_git.py index 51ea77fb8..5a5a27000 100644 --- a/selfdrive/updated/tests/test_git.py +++ b/system/updated/tests/test_git.py @@ -1,5 +1,5 @@ import contextlib -from openpilot.selfdrive.updated.tests.test_base import ParamsBaseUpdateTest, run, update_release +from openpilot.system.updated.tests.test_base import ParamsBaseUpdateTest, run, update_release class TestUpdateDGitStrategy(ParamsBaseUpdateTest): diff --git a/selfdrive/updated/updated.py b/system/updated/updated.py similarity index 100% rename from selfdrive/updated/updated.py rename to system/updated/updated.py From accdade4cfe73cdca41f5afa73cf4ad085802930 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 25 May 2024 12:41:17 -0700 Subject: [PATCH 088/220] manager: move to system/ (#32538) * manager: move to system/ * one more --- .github/workflows/selfdrive_tests.yaml | 2 +- Jenkinsfile | 20 +++++++++---------- conftest.py | 2 +- launch_chffrplus.sh | 2 +- release/build_release.sh | 2 +- release/files_common | 10 ++-------- selfdrive/boardd/tests/test_pandad.py | 2 +- selfdrive/controls/tests/test_startup.py | 2 +- selfdrive/debug/cpu_usage_stat.py | 2 +- selfdrive/debug/cycle_alerts.py | 2 +- selfdrive/debug/uiview.py | 2 +- selfdrive/locationd/test/test_locationd.py | 2 +- selfdrive/modeld/tests/test_modeld.py | 2 +- selfdrive/modeld/tests/timing/benchmark.py | 2 +- selfdrive/navd/tests/test_navd.py | 2 +- selfdrive/test/helpers.py | 2 +- selfdrive/test/process_replay/migration.py | 2 +- .../test/process_replay/process_replay.py | 2 +- selfdrive/test/test_onroad.py | 2 +- selfdrive/test/test_time_to_onroad.py | 2 +- system/athena/manage_athenad.py | 2 +- system/athena/tests/test_athenad_ping.py | 2 +- system/camerad/snapshot/snapshot.py | 2 +- system/camerad/test/test_camerad.py | 2 +- system/hardware/tici/tests/test_power_draw.py | 4 ++-- system/loggerd/tests/test_encoder.py | 2 +- system/loggerd/tests/test_loggerd.py | 2 +- {selfdrive => system}/manager/__init__.py | 0 {selfdrive => system}/manager/build.py | 0 {selfdrive => system}/manager/helpers.py | 0 {selfdrive => system}/manager/manager.py | 6 +++--- {selfdrive => system}/manager/process.py | 0 .../manager/process_config.py | 2 +- .../manager/test/__init__.py | 0 .../manager/test/test_manager.py | 6 +++--- system/qcomgpsd/tests/test_qcomgpsd.py | 2 +- system/sensord/tests/test_sensord.py | 2 +- system/sensord/tests/ttff_test.py | 2 +- system/tests/test_logmessaged.py | 2 +- system/ubloxd/tests/test_pigeond.py | 2 +- system/updated/tests/test_base.py | 2 +- tools/sim/launch_openpilot.sh | 2 +- tools/webcam/README.md | 2 +- 43 files changed, 53 insertions(+), 59 deletions(-) rename {selfdrive => system}/manager/__init__.py (100%) rename {selfdrive => system}/manager/build.py (100%) rename {selfdrive => system}/manager/helpers.py (100%) rename {selfdrive => system}/manager/manager.py (96%) rename {selfdrive => system}/manager/process.py (100%) rename {selfdrive => system}/manager/process_config.py (97%) rename {selfdrive => system}/manager/test/__init__.py (100%) rename {selfdrive => system}/manager/test/test_manager.py (91%) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 1aa08f205..4f7e57b5f 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -47,7 +47,7 @@ jobs: timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache run: | cd $STRIPPED_DIR - ${{ env.RUN }} "python selfdrive/manager/build.py" + ${{ env.RUN }} "python system/manager/build.py" - name: Run tests timeout-minutes: 3 run: | diff --git a/Jenkinsfile b/Jenkinsfile index 2e672e1a2..0a044ff03 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -183,7 +183,7 @@ node { deviceStage("onroad", "tici-needs-can", [], [ // TODO: ideally, this test runs in master-ci, but it takes 5+m to build it //["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR $SOURCE_DIR/scripts/retry.sh ./build_devel.sh"], - ["build openpilot", "cd selfdrive/manager && ./build.py"], + ["build openpilot", "cd system/manager && ./build.py"], ["check dirty", "release/check-dirty.sh"], ["onroad tests", "pytest selfdrive/test/test_onroad.py -s"], ["time to onroad", "pytest selfdrive/test/test_time_to_onroad.py"], @@ -191,51 +191,51 @@ node { }, 'HW + Unit Tests': { deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [ - ["build", "cd selfdrive/manager && ./build.py"], + ["build", "cd system/manager && ./build.py"], ["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"], ["test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"], ["test pigeond", "pytest system/ubloxd/tests/test_pigeond.py"], - ["test manager", "pytest selfdrive/manager/test/test_manager.py"], + ["test manager", "pytest system/manager/test/test_manager.py"], ]) }, 'loopback': { deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [ - ["build openpilot", "cd selfdrive/manager && ./build.py"], + ["build openpilot", "cd system/manager && ./build.py"], ["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"], ]) }, 'camerad': { deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [ - ["build", "cd selfdrive/manager && ./build.py"], + ["build", "cd system/manager && ./build.py"], ["test camerad", "pytest system/camerad/test/test_camerad.py"], ["test exposure", "pytest system/camerad/test/test_exposure.py"], ]) deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [ - ["build", "cd selfdrive/manager && ./build.py"], + ["build", "cd system/manager && ./build.py"], ["test camerad", "pytest system/camerad/test/test_camerad.py"], ["test exposure", "pytest system/camerad/test/test_exposure.py"], ]) }, 'sensord': { deviceStage("LSM + MMC", "tici-lsmc", ["UNSAFE=1"], [ - ["build", "cd selfdrive/manager && ./build.py"], + ["build", "cd system/manager && ./build.py"], ["test sensord", "pytest system/sensord/tests/test_sensord.py"], ]) deviceStage("BMX + LSM", "tici-bmx-lsm", ["UNSAFE=1"], [ - ["build", "cd selfdrive/manager && ./build.py"], + ["build", "cd system/manager && ./build.py"], ["test sensord", "pytest system/sensord/tests/test_sensord.py"], ]) }, 'replay': { deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [ - ["build", "cd selfdrive/manager && ./build.py"], + ["build", "cd system/manager && ./build.py"], ["model replay", "selfdrive/test/process_replay/model_replay.py"], ]) }, 'tizi': { deviceStage("tizi", "tizi", ["UNSAFE=1"], [ - ["build openpilot", "cd selfdrive/manager && ./build.py"], + ["build openpilot", "cd system/manager && ./build.py"], ["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"], ["test boardd spi", "pytest selfdrive/boardd/tests/test_boardd_spi.py"], ["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"], diff --git a/conftest.py b/conftest.py index 0d2a4a8fc..fc4931fb5 100644 --- a/conftest.py +++ b/conftest.py @@ -5,7 +5,7 @@ import pytest import random from openpilot.common.prefix import OpenpilotPrefix -from openpilot.selfdrive.manager import manager +from openpilot.system.manager import manager from openpilot.system.hardware import TICI, HARDWARE diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index a7f61411c..9256f463a 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -82,7 +82,7 @@ function launch { tmux capture-pane -pq -S-1000 > /tmp/launch_log # start manager - cd selfdrive/manager + cd system/manager if [ ! -f $DIR/prebuilt ]; then ./build.py fi diff --git a/release/build_release.sh b/release/build_release.sh index fc15cf6cd..b381ff732 100755 --- a/release/build_release.sh +++ b/release/build_release.sh @@ -93,7 +93,7 @@ cd $SOURCE_DIR cp -pR -n --parents $TEST_FILES $BUILD_DIR/ cd $BUILD_DIR RELEASE=1 selfdrive/test/test_onroad.py -#selfdrive/manager/test/test_manager.py +#system/manager/test/test_manager.py selfdrive/car/tests/test_car_interfaces.py rm -rf $TEST_FILES diff --git a/release/files_common b/release/files_common index ff3e62aa1..cc797fb20 100644 --- a/release/files_common +++ b/release/files_common @@ -303,14 +303,8 @@ system/camerad/cameras/camera_common.cc system/camerad/sensors/*.h system/camerad/sensors/*.cc -selfdrive/manager/__init__.py -selfdrive/manager/build.py -selfdrive/manager/helpers.py -selfdrive/manager/manager.py -selfdrive/manager/process_config.py -selfdrive/manager/process.py -selfdrive/manager/test/__init__.py -selfdrive/manager/test/test_manager.py +system/manager/__init__.py +system/manager/** selfdrive/modeld/.gitignore selfdrive/modeld/__init__.py diff --git a/selfdrive/boardd/tests/test_pandad.py b/selfdrive/boardd/tests/test_pandad.py index 65f3ad657..581b9813a 100755 --- a/selfdrive/boardd/tests/test_pandad.py +++ b/selfdrive/boardd/tests/test_pandad.py @@ -7,7 +7,7 @@ import cereal.messaging as messaging from cereal import log from openpilot.common.gpio import gpio_set, gpio_init from panda import Panda, PandaDFU, PandaProtocolMismatch -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.system.hardware import HARDWARE from openpilot.system.hardware.tici.pins import GPIO diff --git a/selfdrive/controls/tests/test_startup.py b/selfdrive/controls/tests/test_startup.py index 5b69a7cd8..fc9f8ab12 100644 --- a/selfdrive/controls/tests/test_startup.py +++ b/selfdrive/controls/tests/test_startup.py @@ -9,7 +9,7 @@ from openpilot.selfdrive.car.fingerprints import _FINGERPRINTS from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA from openpilot.selfdrive.car.mazda.values import CAR as MAZDA from openpilot.selfdrive.controls.lib.events import EVENT_NAME -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes EventName = car.CarEvent.EventName Ecu = car.CarParams.Ecu diff --git a/selfdrive/debug/cpu_usage_stat.py b/selfdrive/debug/cpu_usage_stat.py index ec9d02e8f..baf44b908 100755 --- a/selfdrive/debug/cpu_usage_stat.py +++ b/selfdrive/debug/cpu_usage_stat.py @@ -24,7 +24,7 @@ import argparse import re from collections import defaultdict -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes # Do statistics every 5 seconds PRINT_INTERVAL = 5 diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py index d66f83ad5..93b0430c1 100755 --- a/selfdrive/debug/cycle_alerts.py +++ b/selfdrive/debug/cycle_alerts.py @@ -8,7 +8,7 @@ from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car.honda.interface import CarInterface from openpilot.selfdrive.controls.lib.events import ET, Events from openpilot.selfdrive.controls.lib.alertmanager import AlertManager -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes EventName = car.CarEvent.EventName diff --git a/selfdrive/debug/uiview.py b/selfdrive/debug/uiview.py index 958ee72e0..8e75769a8 100755 --- a/selfdrive/debug/uiview.py +++ b/selfdrive/debug/uiview.py @@ -3,7 +3,7 @@ import time from cereal import car, log, messaging from openpilot.common.params import Params -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.system.hardware import HARDWARE if __name__ == "__main__": diff --git a/selfdrive/locationd/test/test_locationd.py b/selfdrive/locationd/test/test_locationd.py index bac824bad..f88f423cf 100755 --- a/selfdrive/locationd/test/test_locationd.py +++ b/selfdrive/locationd/test/test_locationd.py @@ -10,7 +10,7 @@ from cereal.services import SERVICE_LIST from openpilot.common.params import Params from openpilot.common.transformations.coordinates import ecef2geodetic -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes class TestLocationdProc: diff --git a/selfdrive/modeld/tests/test_modeld.py b/selfdrive/modeld/tests/test_modeld.py index a18ce8fa4..5cbdbc2bb 100755 --- a/selfdrive/modeld/tests/test_modeld.py +++ b/selfdrive/modeld/tests/test_modeld.py @@ -7,7 +7,7 @@ from cereal.visionipc import VisionIpcServer, VisionStreamType from openpilot.common.transformations.camera import DEVICE_CAMERAS from openpilot.common.realtime import DT_MDL from openpilot.selfdrive.car.car_helpers import write_car_param -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state CAM = DEVICE_CAMERAS[("tici", "ar0231")].fcam diff --git a/selfdrive/modeld/tests/timing/benchmark.py b/selfdrive/modeld/tests/timing/benchmark.py index 4ab0afacb..c629ec2ff 100755 --- a/selfdrive/modeld/tests/timing/benchmark.py +++ b/selfdrive/modeld/tests/timing/benchmark.py @@ -6,7 +6,7 @@ import time import numpy as np import cereal.messaging as messaging -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes N = int(os.getenv("N", "5")) diff --git a/selfdrive/navd/tests/test_navd.py b/selfdrive/navd/tests/test_navd.py index 07f930365..3d899ba28 100755 --- a/selfdrive/navd/tests/test_navd.py +++ b/selfdrive/navd/tests/test_navd.py @@ -7,7 +7,7 @@ from parameterized import parameterized import cereal.messaging as messaging from openpilot.common.params import Params -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes class TestNavd: diff --git a/selfdrive/test/helpers.py b/selfdrive/test/helpers.py index 148d142bb..b7f5bb183 100644 --- a/selfdrive/test/helpers.py +++ b/selfdrive/test/helpers.py @@ -9,7 +9,7 @@ from functools import wraps import cereal.messaging as messaging from openpilot.common.params import Params -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.system.hardware import PC from openpilot.system.version import training_version, terms_version diff --git a/selfdrive/test/process_replay/migration.py b/selfdrive/test/process_replay/migration.py index c8d0504de..0715fcf7b 100644 --- a/selfdrive/test/process_replay/migration.py +++ b/selfdrive/test/process_replay/migration.py @@ -4,7 +4,7 @@ from cereal import messaging from openpilot.selfdrive.car.fingerprints import MIGRATION from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_encode_index from openpilot.selfdrive.car.toyota.values import EPS_SCALE -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from panda import Panda diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 529ed91f7..b325e6e69 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -23,7 +23,7 @@ from openpilot.common.timeout import Timeout from openpilot.common.realtime import DT_CTRL from panda.python import ALTERNATIVE_EXPERIENCE from openpilot.selfdrive.car.car_helpers import get_car, interfaces -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams from openpilot.selfdrive.test.process_replay.migration import migrate_all from openpilot.selfdrive.test.process_replay.capture import ProcessOutputCapture diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 038bba7b2..8b60b9650 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -125,7 +125,7 @@ class TestOnroad: # start manager and run openpilot for a minute proc = None try: - manager_path = os.path.join(BASEDIR, "selfdrive/manager/manager.py") + manager_path = os.path.join(BASEDIR, "system/manager/manager.py") proc = subprocess.Popen(["python", manager_path]) sm = messaging.SubMaster(['carState']) diff --git a/selfdrive/test/test_time_to_onroad.py b/selfdrive/test/test_time_to_onroad.py index b85d40dbc..11de5283b 100755 --- a/selfdrive/test/test_time_to_onroad.py +++ b/selfdrive/test/test_time_to_onroad.py @@ -17,7 +17,7 @@ EventName = car.CarEvent.EventName def test_time_to_onroad(): # launch set_params_enabled() - manager_path = os.path.join(BASEDIR, "selfdrive/manager/manager.py") + manager_path = os.path.join(BASEDIR, "system/manager/manager.py") proc = subprocess.Popen(["python", manager_path]) start_time = time.monotonic() diff --git a/system/athena/manage_athenad.py b/system/athena/manage_athenad.py index 853a7cd95..f5ab81720 100755 --- a/system/athena/manage_athenad.py +++ b/system/athena/manage_athenad.py @@ -4,7 +4,7 @@ import time from multiprocessing import Process from openpilot.common.params import Params -from openpilot.selfdrive.manager.process import launcher +from openpilot.system.manager.process import launcher from openpilot.common.swaglog import cloudlog from openpilot.system.hardware import HARDWARE from openpilot.system.version import get_build_metadata diff --git a/system/athena/tests/test_athenad_ping.py b/system/athena/tests/test_athenad_ping.py index 3152ca427..4fda13dfe 100755 --- a/system/athena/tests/test_athenad_ping.py +++ b/system/athena/tests/test_athenad_ping.py @@ -8,7 +8,7 @@ from typing import cast from openpilot.common.params import Params from openpilot.common.timeout import Timeout from openpilot.system.athena import athenad -from openpilot.selfdrive.manager.helpers import write_onroad_params +from openpilot.system.manager.helpers import write_onroad_params from openpilot.system.hardware import TICI TIMEOUT_TOLERANCE = 20 # seconds diff --git a/system/camerad/snapshot/snapshot.py b/system/camerad/snapshot/snapshot.py index 8c1b6084c..d9377eebe 100755 --- a/system/camerad/snapshot/snapshot.py +++ b/system/camerad/snapshot/snapshot.py @@ -11,7 +11,7 @@ from openpilot.common.params import Params from openpilot.common.realtime import DT_MDL from openpilot.system.hardware import PC from openpilot.selfdrive.controls.lib.alertmanager import set_offroad_alert -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes VISION_STREAMS = { diff --git a/system/camerad/test/test_camerad.py b/system/camerad/test/test_camerad.py index 408115607..dcc982563 100755 --- a/system/camerad/test/test_camerad.py +++ b/system/camerad/test/test_camerad.py @@ -8,7 +8,7 @@ from collections import defaultdict import cereal.messaging as messaging from cereal import log from cereal.services import SERVICE_LIST -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes TEST_TIMESPAN = 30 LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 0.5, # ARs use synced pulses for frame starts diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index 104329da4..1fe063c8e 100755 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -11,8 +11,8 @@ from cereal.services import SERVICE_LIST from openpilot.common.mock import mock_messages from openpilot.selfdrive.car.car_helpers import write_car_param from openpilot.system.hardware.tici.power_monitor import get_power -from openpilot.selfdrive.manager.process_config import managed_processes -from openpilot.selfdrive.manager.manager import manager_cleanup +from openpilot.system.manager.process_config import managed_processes +from openpilot.system.manager.manager import manager_cleanup SAMPLE_TIME = 8 # seconds to sample power MAX_WARMUP_TIME = 30 # seconds to wait for SAMPLE_TIME consecutive valid samples diff --git a/system/loggerd/tests/test_encoder.py b/system/loggerd/tests/test_encoder.py index f6eb9b901..ddf074d3b 100755 --- a/system/loggerd/tests/test_encoder.py +++ b/system/loggerd/tests/test_encoder.py @@ -14,7 +14,7 @@ from tqdm import trange from openpilot.common.params import Params from openpilot.common.timeout import Timeout from openpilot.system.hardware import TICI -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.tools.lib.logreader import LogReader from openpilot.system.hardware.hw import Paths diff --git a/system/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py index fdea60a28..d3789badb 100755 --- a/system/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -19,7 +19,7 @@ from openpilot.common.timeout import Timeout from openpilot.system.hardware.hw import Paths from openpilot.system.loggerd.xattr_cache import getxattr from openpilot.system.loggerd.deleter import PRESERVE_ATTR_NAME, PRESERVE_ATTR_VALUE -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.system.version import get_version from openpilot.tools.lib.helpers import RE from openpilot.tools.lib.logreader import LogReader diff --git a/selfdrive/manager/__init__.py b/system/manager/__init__.py similarity index 100% rename from selfdrive/manager/__init__.py rename to system/manager/__init__.py diff --git a/selfdrive/manager/build.py b/system/manager/build.py similarity index 100% rename from selfdrive/manager/build.py rename to system/manager/build.py diff --git a/selfdrive/manager/helpers.py b/system/manager/helpers.py similarity index 100% rename from selfdrive/manager/helpers.py rename to system/manager/helpers.py diff --git a/selfdrive/manager/manager.py b/system/manager/manager.py similarity index 96% rename from selfdrive/manager/manager.py rename to system/manager/manager.py index 408314d62..93fab3ad1 100755 --- a/selfdrive/manager/manager.py +++ b/system/manager/manager.py @@ -11,9 +11,9 @@ import openpilot.system.sentry as sentry from openpilot.common.params import Params, ParamKeyType from openpilot.common.text_window import TextWindow from openpilot.system.hardware import HARDWARE, PC -from openpilot.selfdrive.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog -from openpilot.selfdrive.manager.process import ensure_running -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog +from openpilot.system.manager.process import ensure_running +from openpilot.system.manager.process_config import managed_processes from openpilot.system.athena.registration import register, UNREGISTERED_DONGLE_ID from openpilot.common.swaglog import cloudlog, add_file_handler from openpilot.system.version import get_build_metadata, terms_version, training_version diff --git a/selfdrive/manager/process.py b/system/manager/process.py similarity index 100% rename from selfdrive/manager/process.py rename to system/manager/process.py diff --git a/selfdrive/manager/process_config.py b/system/manager/process_config.py similarity index 97% rename from selfdrive/manager/process_config.py rename to system/manager/process_config.py index b6567c2f7..5e153ffb9 100644 --- a/selfdrive/manager/process_config.py +++ b/system/manager/process_config.py @@ -3,7 +3,7 @@ import os from cereal import car from openpilot.common.params import Params from openpilot.system.hardware import PC, TICI -from openpilot.selfdrive.manager.process import PythonProcess, NativeProcess, DaemonProcess +from openpilot.system.manager.process import PythonProcess, NativeProcess, DaemonProcess WEBCAM = os.getenv("USE_WEBCAM") is not None diff --git a/selfdrive/manager/test/__init__.py b/system/manager/test/__init__.py similarity index 100% rename from selfdrive/manager/test/__init__.py rename to system/manager/test/__init__.py diff --git a/selfdrive/manager/test/test_manager.py b/system/manager/test/test_manager.py similarity index 91% rename from selfdrive/manager/test/test_manager.py rename to system/manager/test/test_manager.py index 4cdc99c24..af8397b24 100755 --- a/selfdrive/manager/test/test_manager.py +++ b/system/manager/test/test_manager.py @@ -8,9 +8,9 @@ from parameterized import parameterized from cereal import car from openpilot.common.params import Params -import openpilot.selfdrive.manager.manager as manager -from openpilot.selfdrive.manager.process import ensure_running -from openpilot.selfdrive.manager.process_config import managed_processes +import openpilot.system.manager.manager as manager +from openpilot.system.manager.process import ensure_running +from openpilot.system.manager.process_config import managed_processes from openpilot.system.hardware import HARDWARE os.environ['FAKEUPLOAD'] = "1" diff --git a/system/qcomgpsd/tests/test_qcomgpsd.py b/system/qcomgpsd/tests/test_qcomgpsd.py index d47ea5d63..33d6e5b78 100755 --- a/system/qcomgpsd/tests/test_qcomgpsd.py +++ b/system/qcomgpsd/tests/test_qcomgpsd.py @@ -8,7 +8,7 @@ import subprocess import cereal.messaging as messaging from openpilot.system.qcomgpsd.qcomgpsd import at_cmd, wait_for_modem -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes GOOD_SIGNAL = bool(int(os.getenv("GOOD_SIGNAL", '0'))) diff --git a/system/sensord/tests/test_sensord.py b/system/sensord/tests/test_sensord.py index 1b3b78da8..aed3b07b3 100755 --- a/system/sensord/tests/test_sensord.py +++ b/system/sensord/tests/test_sensord.py @@ -10,7 +10,7 @@ from cereal import log from cereal.services import SERVICE_LIST from openpilot.common.gpio import get_irqs_for_action from openpilot.common.timeout import Timeout -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes BMX = { ('bmx055', 'acceleration'), diff --git a/system/sensord/tests/ttff_test.py b/system/sensord/tests/ttff_test.py index e023489ed..a9cc16d70 100755 --- a/system/sensord/tests/ttff_test.py +++ b/system/sensord/tests/ttff_test.py @@ -4,7 +4,7 @@ import time import atexit from cereal import messaging -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes TIMEOUT = 10*60 diff --git a/system/tests/test_logmessaged.py b/system/tests/test_logmessaged.py index 6d59bdcb0..f8c5be09b 100755 --- a/system/tests/test_logmessaged.py +++ b/system/tests/test_logmessaged.py @@ -4,7 +4,7 @@ import os import time import cereal.messaging as messaging -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.system.hardware.hw import Paths from openpilot.common.swaglog import cloudlog, ipchandler diff --git a/system/ubloxd/tests/test_pigeond.py b/system/ubloxd/tests/test_pigeond.py index a24414466..cd3ad9305 100755 --- a/system/ubloxd/tests/test_pigeond.py +++ b/system/ubloxd/tests/test_pigeond.py @@ -6,7 +6,7 @@ import cereal.messaging as messaging from cereal.services import SERVICE_LIST from openpilot.common.gpio import gpio_read from openpilot.selfdrive.test.helpers import with_processes -from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.manager.process_config import managed_processes from openpilot.system.hardware.tici.pins import GPIO diff --git a/system/updated/tests/test_base.py b/system/updated/tests/test_base.py index 615d0de99..928d07cbe 100644 --- a/system/updated/tests/test_base.py +++ b/system/updated/tests/test_base.py @@ -9,7 +9,7 @@ import time import pytest from openpilot.common.params import Params -from openpilot.selfdrive.manager.process import ManagerProcess +from openpilot.system.manager.process import ManagerProcess from openpilot.selfdrive.test.helpers import processes_context diff --git a/tools/sim/launch_openpilot.sh b/tools/sim/launch_openpilot.sh index 86d9607bb..1b4ac4ef8 100755 --- a/tools/sim/launch_openpilot.sh +++ b/tools/sim/launch_openpilot.sh @@ -18,4 +18,4 @@ SCRIPT_DIR=$(dirname "$0") OPENPILOT_DIR=$SCRIPT_DIR/../../ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -cd $OPENPILOT_DIR/selfdrive/manager && exec ./manager.py +cd $OPENPILOT_DIR/system/manager && exec ./manager.py diff --git a/tools/webcam/README.md b/tools/webcam/README.md index 76733b173..7334d87b3 100644 --- a/tools/webcam/README.md +++ b/tools/webcam/README.md @@ -29,7 +29,7 @@ USE_WEBCAM=1 scons -j$(nproc) ## GO ``` -cd ~/openpilot/selfdrive/manager +cd ~/openpilot/system/manager NOSENSOR=1 USE_WEBCAM=1 ./manager.py ``` - Start the car, then the UI should show the road webcam's view From 2ff94ec374514fb5054099288cb3a070e7286e56 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Sat, 25 May 2024 18:50:10 -0400 Subject: [PATCH 089/220] CI/tools: Remove redundant build step (#32539) --- .github/workflows/tools_tests.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index fd05300f0..224b0c9d5 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -49,8 +49,6 @@ jobs: submodules: true - run: git lfs pull - uses: ./.github/workflows/setup-with-retry - - name: Build base docker image - run: eval "$BUILD" - name: Build openpilot run: | ${{ env.RUN }} "scons -j$(nproc)" From fe7d3429abd85c120f0205093149eb9eabc81cb1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 25 May 2024 18:47:16 -0700 Subject: [PATCH 090/220] Make release files a blacklist (#32540) * blacklist * little nicer * whitelist * cleanup * igore body * more skip --- .github/workflows/selfdrive_tests.yaml | 4 +- .pre-commit-config.yaml | 2 +- release/build_devel.sh | 4 +- release/build_release.sh | 14 +- release/files_common | 560 ------------------------- release/files_pc | 4 - release/files_tici | 15 - release/release_files.py | 67 +++ selfdrive/modeld/SConscript | 8 +- 9 files changed, 82 insertions(+), 596 deletions(-) delete mode 100644 release/files_common delete mode 100644 release/files_pc delete mode 100644 release/files_tici create mode 100755 release/release_files.py diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 4f7e57b5f..e73e0df2a 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -53,7 +53,7 @@ jobs: run: | cd $STRIPPED_DIR ${{ env.RUN }} "release/check-dirty.sh && \ - MAX_EXAMPLES=5 $PYTEST selfdrive/car" + MAX_EXAMPLES=5 $PYTEST -m 'not slow' selfdrive/car" - name: pre-commit timeout-minutes: 3 run: | @@ -62,7 +62,7 @@ jobs: cp pyproject.toml $STRIPPED_DIR cp poetry.lock $STRIPPED_DIR cd $STRIPPED_DIR - ${{ env.RUN }} "unset PYTHONWARNINGS && SKIP=check-added-large-files pre-commit run --all && chmod -R 777 /tmp/pre-commit" + ${{ env.RUN }} "unset PYTHONWARNINGS && SKIP=check-added-large-files,check-hooks-apply,check-useless-excludes pre-commit run --all && chmod -R 777 /tmp/pre-commit" build: strategy: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 190425285..28f8acd6e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -47,7 +47,7 @@ repos: args: - --local-partial-types - --explicit-package-bases - exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' + exclude: '^(third_party/)|(body/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' - repo: local hooks: - id: cppcheck diff --git a/release/build_devel.sh b/release/build_devel.sh index 8b6816e42..18d99bb1c 100755 --- a/release/build_devel.sh +++ b/release/build_devel.sh @@ -1,5 +1,4 @@ #!/usr/bin/bash - set -ex DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" @@ -44,11 +43,12 @@ git clean -xdff # do the files copy echo "[-] copying files T=$SECONDS" cd $SOURCE_DIR -cp -pR --parents $(cat release/files_*) $TARGET_DIR/ +cp -pR --parents $(./release/release_files.py) $TARGET_DIR/ # in the directory cd $TARGET_DIR rm -f panda/board/obj/panda.bin.signed +git submodule status # include source commit hash and build date in commit GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD) diff --git a/release/build_release.sh b/release/build_release.sh index b381ff732..c2745ea28 100755 --- a/release/build_release.sh +++ b/release/build_release.sh @@ -9,13 +9,6 @@ cd $DIR BUILD_DIR=/data/openpilot SOURCE_DIR="$(git rev-parse --show-toplevel)" -if [ -f /TICI ]; then - FILES_SRC="release/files_tici" -else - echo "no release files set" - exit 1 -fi - if [ -z "$RELEASE_BRANCH" ]; then echo "RELEASE_BRANCH is not set" exit 1 @@ -36,8 +29,7 @@ git checkout --orphan $RELEASE_BRANCH # do the files copy echo "[-] copying files T=$SECONDS" cd $SOURCE_DIR -cp -pR --parents $(cat release/files_common) $BUILD_DIR/ -cp -pR --parents $(cat $FILES_SRC) $BUILD_DIR/ +cp -pR --parents $(./release/release_files.py) $TARGET_DIR/ # in the directory cd $BUILD_DIR @@ -77,6 +69,10 @@ find . -name '__pycache__' -delete rm -rf .sconsign.dblite Jenkinsfile release/ rm selfdrive/modeld/models/supercombo.onnx +find third_party/ -name '*x86*' -exec rm -r {} + +find third_party/ -name '*Darwin*' -exec rm -r {} + + + # Restore third_party git checkout third_party/ diff --git a/release/files_common b/release/files_common deleted file mode 100644 index cc797fb20..000000000 --- a/release/files_common +++ /dev/null @@ -1,560 +0,0 @@ -.gitignore -LICENSE -launch_env.sh -launch_chffrplus.sh -launch_openpilot.sh - -Jenkinsfile -SConstruct -pyproject.toml - -README.md -RELEASES.md -docs/CARS.md -docs/CONTRIBUTING.md -docs/INTEGRATION.md -docs/LIMITATIONS.md -site_scons/site_tools/cython.py - -openpilot/__init__.py -openpilot/** - -common/.gitignore -common/__init__.py -common/*.py -common/*.pyx -common/mock/* - -common/transformations/__init__.py -common/transformations/camera.py -common/transformations/model.py - -common/transformations/SConscript -common/transformations/coordinates.py -common/transformations/coordinates.cc -common/transformations/coordinates.hpp -common/transformations/orientation.py -common/transformations/orientation.cc -common/transformations/orientation.hpp -common/transformations/transformations.pxd -common/transformations/transformations.pyx - -common/api/__init__.py - -release/* - -tools/__init__.py -tools/lib/* -tools/bodyteleop/.gitignore -tools/bodyteleop/web.py -tools/bodyteleop/static/* -tools/joystick/* -tools/replay/*.cc -tools/replay/*.h - -selfdrive/__init__.py - -system/logmessaged.py -system/micd.py -system/version.py - -selfdrive/SConscript - -system/athena/__init__.py -system/athena/athenad.py -system/athena/manage_athenad.py -system/athena/registration.py - -selfdrive/boardd/.gitignore -selfdrive/boardd/SConscript -selfdrive/boardd/__init__.py -selfdrive/boardd/boardd.cc -selfdrive/boardd/boardd.h -selfdrive/boardd/main.cc -selfdrive/boardd/boardd.py -selfdrive/boardd/boardd_api_impl.pyx -selfdrive/boardd/can_list_to_can_capnp.cc -selfdrive/boardd/panda.cc -selfdrive/boardd/panda.h -selfdrive/boardd/spi.cc -selfdrive/boardd/panda_comms.h -selfdrive/boardd/panda_comms.cc -selfdrive/boardd/pandad.py -selfdrive/boardd/tests/test_boardd_loopback.py - -selfdrive/car/__init__.py -selfdrive/car/card.py -selfdrive/car/docs_definitions.py -selfdrive/car/car_helpers.py -selfdrive/car/fingerprints.py -selfdrive/car/interfaces.py -selfdrive/car/values.py -selfdrive/car/vin.py -selfdrive/car/disable_ecu.py -selfdrive/car/fw_versions.py -selfdrive/car/fw_query_definitions.py -selfdrive/car/ecu_addrs.py -selfdrive/car/isotp_parallel_query.py -selfdrive/car/tests/__init__.py -selfdrive/car/tests/test_car_interfaces.py -selfdrive/car/torque_data/* - -selfdrive/car/body/*.py -selfdrive/car/chrysler/*.py -selfdrive/car/ford/*.py -selfdrive/car/gm/*.py -selfdrive/car/honda/*.py -selfdrive/car/hyundai/*.py -selfdrive/car/mazda/*.py -selfdrive/car/mock/*.py -selfdrive/car/nissan/*.py -selfdrive/car/subaru/*.py -selfdrive/car/tesla/*.py -selfdrive/car/toyota/*.py -selfdrive/car/volkswagen/*.py - -selfdrive/debug/can_printer.py -selfdrive/debug/check_freq.py -selfdrive/debug/dump.py -selfdrive/debug/filter_log_message.py -selfdrive/debug/format_fingerprints.py -selfdrive/debug/get_fingerprint.py -selfdrive/debug/uiview.py - -selfdrive/debug/hyundai_enable_radar_points.py -selfdrive/debug/vw_mqb_config.py - -common/SConscript -common/version.h - -common/*.h -common/*.cc - -selfdrive/controls/__init__.py -selfdrive/controls/controlsd.py -selfdrive/controls/plannerd.py -selfdrive/controls/radard.py -selfdrive/controls/lib/__init__.py -selfdrive/controls/lib/alertmanager.py -selfdrive/controls/lib/alerts_offroad.json -selfdrive/controls/lib/desire_helper.py -selfdrive/controls/lib/drive_helpers.py -selfdrive/controls/lib/events.py -selfdrive/controls/lib/latcontrol_angle.py -selfdrive/controls/lib/latcontrol_torque.py -selfdrive/controls/lib/latcontrol_pid.py -selfdrive/controls/lib/latcontrol.py -selfdrive/controls/lib/longcontrol.py -selfdrive/controls/lib/longitudinal_planner.py -selfdrive/controls/lib/pid.py -selfdrive/controls/lib/vehicle_model.py - -selfdrive/controls/lib/lateral_mpc_lib/.gitignore -selfdrive/controls/lib/longitudinal_mpc_lib/.gitignore -selfdrive/controls/lib/lateral_mpc_lib/* -selfdrive/controls/lib/longitudinal_mpc_lib/* - -system/__init__.py -system/*.py - -system/sentry.py -system/tombstoned.py -system/statsd.py - -system/hardware/__init__.py -system/hardware/base.h -system/hardware/base.py -system/hardware/hw.h -system/hardware/hw.py -system/hardware/tici/__init__.py -system/hardware/tici/hardware.h -system/hardware/tici/hardware.py -system/hardware/tici/pins.py -system/hardware/tici/agnos.py -system/hardware/tici/agnos.json -system/hardware/tici/amplifier.py -system/hardware/tici/updater -system/hardware/tici/iwlist.py -system/hardware/tici/esim.nmconnection -system/hardware/pc/__init__.py -system/hardware/pc/hardware.h -system/hardware/pc/hardware.py - -system/ubloxd/.gitignore -system/ubloxd/SConscript -system/ubloxd/pigeond.py -system/ubloxd/generated/* -system/ubloxd/*.h -system/ubloxd/*.cc - -system/updated/** - -selfdrive/locationd/__init__.py -selfdrive/locationd/SConscript -selfdrive/locationd/.gitignore -selfdrive/locationd/locationd.h -selfdrive/locationd/locationd.cc -selfdrive/locationd/paramsd.py -selfdrive/locationd/models/__init__.py -selfdrive/locationd/models/.gitignore -selfdrive/locationd/models/car_kf.py -selfdrive/locationd/models/live_kf.py -selfdrive/locationd/models/live_kf.h -selfdrive/locationd/models/live_kf.cc -selfdrive/locationd/models/constants.py - -selfdrive/locationd/torqued.py -selfdrive/locationd/calibrationd.py -selfdrive/locationd/helpers.py - -system/logcatd/.gitignore -system/logcatd/SConscript -system/logcatd/logcatd_systemd.cc - -system/proclogd/SConscript -system/proclogd/main.cc -system/proclogd/proclog.cc -system/proclogd/proclog.h - -system/loggerd/.gitignore -system/loggerd/SConscript -system/loggerd/encoder/encoder.cc -system/loggerd/encoder/encoder.h -system/loggerd/encoder/v4l_encoder.cc -system/loggerd/encoder/v4l_encoder.h -system/loggerd/video_writer.cc -system/loggerd/video_writer.h -system/loggerd/logger.cc -system/loggerd/logger.h -system/loggerd/loggerd.cc -system/loggerd/loggerd.h -system/loggerd/encoderd.cc -system/loggerd/bootlog.cc -system/loggerd/encoder/ffmpeg_encoder.cc -system/loggerd/encoder/ffmpeg_encoder.h - -system/loggerd/__init__.py -system/loggerd/config.py -system/loggerd/uploader.py -system/loggerd/deleter.py -system/loggerd/xattr_cache.py - -system/sensord/.gitignore -system/sensord/SConscript -system/sensord/sensors_qcom2.cc -system/sensord/sensors/*.cc -system/sensord/sensors/*.h - -system/webrtc/__init__.py -system/webrtc/webrtcd.py -system/webrtc/schema.py -system/webrtc/device/audio.py -system/webrtc/device/video.py - -system/thermald/thermald.py -system/thermald/power_monitoring.py -system/thermald/fan_controller.py - -selfdrive/test/__init__.py -selfdrive/test/fuzzy_generation.py -selfdrive/test/helpers.py -selfdrive/test/setup_device_ci.sh -selfdrive/test/test_onroad.py -selfdrive/test/test_time_to_onroad.py - -selfdrive/ui/.gitignore -selfdrive/ui/SConscript -selfdrive/ui/*.cc -selfdrive/ui/*.h -selfdrive/ui/text -selfdrive/ui/spinner -selfdrive/ui/soundd.py -selfdrive/ui/translations/*.ts -selfdrive/ui/translations/languages.json -selfdrive/ui/update_translations.py -selfdrive/ui/tests/test_translations.py - -selfdrive/ui/qt/*.cc -selfdrive/ui/qt/*.h -selfdrive/ui/qt/network/*.cc -selfdrive/ui/qt/network/*.h -selfdrive/ui/qt/offroad/*.cc -selfdrive/ui/qt/offroad/*.h -selfdrive/ui/qt/offroad/*.qml -selfdrive/ui/qt/onroad/*.cc -selfdrive/ui/qt/onroad/*.h -selfdrive/ui/qt/widgets/*.cc -selfdrive/ui/qt/widgets/*.h -selfdrive/ui/qt/maps/*.cc -selfdrive/ui/qt/maps/*.h -selfdrive/ui/qt/setup/*.cc -selfdrive/ui/qt/setup/*.h - -selfdrive/ui/installer/*.cc -selfdrive/ui/installer/*.h -selfdrive/ui/installer/*.cc - -system/camerad/SConscript -system/camerad/main.cc - -system/camerad/snapshot/* -system/camerad/cameras/camera_common.h -system/camerad/cameras/camera_common.cc -system/camerad/sensors/*.h -system/camerad/sensors/*.cc - -system/manager/__init__.py -system/manager/** - -selfdrive/modeld/.gitignore -selfdrive/modeld/__init__.py -selfdrive/modeld/SConscript -selfdrive/modeld/modeld.py -selfdrive/modeld/parse_model_outputs.py -selfdrive/modeld/fill_model_msg.py -selfdrive/modeld/get_model_metadata.py -selfdrive/modeld/dmonitoringmodeld.py -selfdrive/modeld/constants.py -selfdrive/modeld/modeld - -selfdrive/modeld/models/__init__.py -selfdrive/modeld/models/*.pxd -selfdrive/modeld/models/*.pyx - -selfdrive/modeld/models/commonmodel.cc -selfdrive/modeld/models/commonmodel.h - -selfdrive/modeld/models/supercombo.onnx - -selfdrive/modeld/models/dmonitoring_model_q.dlc - -selfdrive/modeld/transforms/loadyuv.cc -selfdrive/modeld/transforms/loadyuv.h -selfdrive/modeld/transforms/loadyuv.cl -selfdrive/modeld/transforms/transform.cc -selfdrive/modeld/transforms/transform.h -selfdrive/modeld/transforms/transform.cl - -selfdrive/modeld/thneed/*.py -selfdrive/modeld/thneed/thneed.h -selfdrive/modeld/thneed/thneed_common.cc -selfdrive/modeld/thneed/thneed_qcom2.cc -selfdrive/modeld/thneed/serialize.cc - -selfdrive/modeld/runners/__init__.py -selfdrive/modeld/runners/*.pxd -selfdrive/modeld/runners/*.pyx -selfdrive/modeld/runners/*.cc -selfdrive/modeld/runners/*.h -selfdrive/modeld/runners/*.py - -selfdrive/monitoring/dmonitoringd.py -selfdrive/monitoring/helpers.py - -selfdrive/navd/.gitignore -selfdrive/navd/__init__.py -selfdrive/navd/** - -selfdrive/assets/.gitignore -selfdrive/assets/assets.qrc -selfdrive/assets/*.png -selfdrive/assets/*.svg -selfdrive/assets/body/* -selfdrive/assets/fonts/*.ttf -selfdrive/assets/icons/* -selfdrive/assets/images/* -selfdrive/assets/offroad/* -selfdrive/assets/sounds/* -selfdrive/assets/training/* -selfdrive/assets/navigation/* - -third_party/.gitignore -third_party/SConscript - -third_party/linux/** -third_party/opencl/** - -third_party/json11/json11.cpp -third_party/json11/json11.hpp - -third_party/qrcode/*.cc -third_party/qrcode/*.hpp - -third_party/kaitai/*.h -third_party/kaitai/*.cpp - -third_party/libyuv/include/** - -third_party/snpe/include/** -third_party/snpe/dsp** - -third_party/acados/.gitignore -third_party/acados/include/** -third_party/acados/acados_template/** - -third_party/bootstrap/** -third_party/qt5/larch64/bin/** -third_party/maplibre-native-qt/** - -scripts/update_now.sh -scripts/stop_updater.sh - -teleoprtc/** - -rednose_repo/site_scons/site_tools/rednose_filter.py -rednose/.gitignore -rednose/** - -body/.gitignore -body/board/SConscript -body/board/*.h -body/board/*.c -body/board/*.s -body/board/*.ld -body/board/inc/** -body/board/obj/ -body/board/bldc/** -body/board/drivers/** -body/certs/** -body/crypto/** - -cereal/.gitignore -cereal/__init__.py -cereal/car.capnp -cereal/custom.capnp -cereal/legacy.capnp -cereal/log.capnp -cereal/services.py -cereal/SConscript -cereal/include/** -cereal/logger/logger.h -cereal/messaging/.gitignore -cereal/messaging/__init__.py -cereal/messaging/bridge.cc -cereal/messaging/event.cc -cereal/messaging/event.h -cereal/messaging/impl_fake.cc -cereal/messaging/impl_fake.h -cereal/messaging/impl_msgq.cc -cereal/messaging/impl_msgq.h -cereal/messaging/impl_zmq.cc -cereal/messaging/impl_zmq.h -cereal/messaging/messaging.cc -cereal/messaging/messaging.h -cereal/messaging/messaging.pxd -cereal/messaging/messaging_pyx.pyx -cereal/messaging/msgq.cc -cereal/messaging/msgq.h -cereal/messaging/socketmaster.cc -cereal/visionipc/.gitignore -cereal/visionipc/__init__.py -cereal/visionipc/*.cc -cereal/visionipc/*.h -cereal/visionipc/*.pyx -cereal/visionipc/*.pxd - -panda/.gitignore -panda/__init__.py -panda/SConscript -panda/board/** -panda/certs/** -panda/crypto/** -panda/examples/query_fw_versions.py -panda/python/** - -opendbc/.gitignore -opendbc/__init__.py -opendbc/can/__init__.py -opendbc/can/SConscript -opendbc/can/can_define.py -opendbc/can/common.cc -opendbc/can/common.h -opendbc/can/common.pxd -opendbc/can/common_dbc.h -opendbc/can/dbc.cc -opendbc/can/packer.cc -opendbc/can/packer.py -opendbc/can/packer_pyx.pyx -opendbc/can/parser.cc -opendbc/can/parser.py -opendbc/can/parser_pyx.pyx - -opendbc/comma_body.dbc - -opendbc/chrysler_ram_hd_generated.dbc -opendbc/chrysler_ram_dt_generated.dbc -opendbc/chrysler_pacifica_2017_hybrid_generated.dbc -opendbc/chrysler_pacifica_2017_hybrid_private_fusion.dbc - -opendbc/gm_global_a_powertrain_generated.dbc -opendbc/gm_global_a_object.dbc -opendbc/gm_global_a_chassis.dbc - -opendbc/FORD_CADS.dbc -opendbc/ford_fusion_2018_adas.dbc -opendbc/ford_lincoln_base_pt.dbc - -opendbc/honda_accord_2018_can_generated.dbc -opendbc/acura_ilx_2016_can_generated.dbc -opendbc/acura_rdx_2018_can_generated.dbc -opendbc/acura_rdx_2020_can_generated.dbc -opendbc/honda_civic_touring_2016_can_generated.dbc -opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc -opendbc/honda_crv_touring_2016_can_generated.dbc -opendbc/honda_crv_ex_2017_can_generated.dbc -opendbc/honda_crv_ex_2017_body_generated.dbc -opendbc/honda_crv_executive_2016_can_generated.dbc -opendbc/honda_fit_ex_2018_can_generated.dbc -opendbc/honda_odyssey_exl_2018_generated.dbc -opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc -opendbc/honda_insight_ex_2019_can_generated.dbc -opendbc/acura_ilx_2016_nidec.dbc -opendbc/honda_civic_ex_2022_can_generated.dbc - -opendbc/hyundai_canfd.dbc -opendbc/hyundai_kia_generic.dbc -opendbc/hyundai_kia_mando_front_radar_generated.dbc - -opendbc/mazda_2017.dbc - -opendbc/nissan_x_trail_2017_generated.dbc -opendbc/nissan_leaf_2018_generated.dbc - -opendbc/subaru_global_2017_generated.dbc -opendbc/subaru_global_2020_hybrid_generated.dbc -opendbc/subaru_outback_2015_generated.dbc -opendbc/subaru_outback_2019_generated.dbc -opendbc/subaru_forester_2017_generated.dbc - -opendbc/toyota_tnga_k_pt_generated.dbc -opendbc/toyota_new_mc_pt_generated.dbc -opendbc/toyota_nodsu_pt_generated.dbc -opendbc/toyota_adas.dbc -opendbc/toyota_tss2_adas.dbc - -opendbc/vw_golf_mk4.dbc -opendbc/vw_mqb_2010.dbc - -opendbc/tesla_can.dbc -opendbc/tesla_radar_bosch_generated.dbc -opendbc/tesla_radar_continental_generated.dbc -opendbc/tesla_powertrain.dbc - -tinygrad_repo/openpilot/compile2.py -tinygrad_repo/extra/onnx.py -tinygrad_repo/extra/onnx_ops.py -tinygrad_repo/extra/thneed.py -tinygrad_repo/extra/utils.py -tinygrad_repo/tinygrad/codegen/kernel.py -tinygrad_repo/tinygrad/codegen/linearizer.py -tinygrad_repo/tinygrad/features/image.py -tinygrad_repo/tinygrad/features/search.py -tinygrad_repo/tinygrad/nn/* -tinygrad_repo/tinygrad/renderer/cstyle.py -tinygrad_repo/tinygrad/renderer/opencl.py -tinygrad_repo/tinygrad/runtime/lib.py -tinygrad_repo/tinygrad/runtime/ops_cpu.py -tinygrad_repo/tinygrad/runtime/ops_disk.py -tinygrad_repo/tinygrad/runtime/ops_gpu.py -tinygrad_repo/tinygrad/shape/* -tinygrad_repo/tinygrad/*.py diff --git a/release/files_pc b/release/files_pc deleted file mode 100644 index f2bf090f2..000000000 --- a/release/files_pc +++ /dev/null @@ -1,4 +0,0 @@ -third_party/libyuv/x86_64/** -third_party/snpe/x86_64/** -third_party/snpe/x86_64-linux-clang/** -third_party/acados/x86_64/** diff --git a/release/files_tici b/release/files_tici deleted file mode 100644 index 18860e20a..000000000 --- a/release/files_tici +++ /dev/null @@ -1,15 +0,0 @@ -third_party/libyuv/larch64/** -third_party/snpe/larch64** -third_party/snpe/aarch64-ubuntu-gcc7.5/* -third_party/acados/larch64/** - -system/camerad/cameras/camera_qcom2.cc -system/camerad/cameras/camera_qcom2.h -system/camerad/cameras/camera_util.cc -system/camerad/cameras/camera_util.h -system/camerad/cameras/process_raw.cl - -system/qcomgpsd/* - -selfdrive/ui/qt/spinner_larch64 -selfdrive/ui/qt/text_larch64 diff --git a/release/release_files.py b/release/release_files.py new file mode 100755 index 000000000..bf6cd56a9 --- /dev/null +++ b/release/release_files.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +import os +import re +from pathlib import Path + +HERE = os.path.abspath(os.path.dirname(__file__)) +ROOT = HERE + "/.." + +# blacklisting is for two purposes: +# - minimizing release download size +# - keeping the diff readable +blacklist = [ + "^scripts/", + "body/STL/", + "tools/cabana/", + "panda/examples/", + "opendbc/generator/", + + "^tools/", + "^tinygrad_repo/", + + "matlab.*.md", + + ".git$", # for submodules + ".git/", + ".github/", + ".devcontainer/", + "Darwin/", + ".vscode", +] + +# gets you through the blacklist +whitelist = [ + "tools/lib/", + + "tinygrad_repo/openpilot/compile2.py", + "tinygrad_repo/extra/onnx.py", + "tinygrad_repo/extra/onnx_ops.py", + "tinygrad_repo/extra/thneed.py", + "tinygrad_repo/extra/utils.py", + "tinygrad_repo/tinygrad/codegen/kernel.py", + "tinygrad_repo/tinygrad/codegen/linearizer.py", + "tinygrad_repo/tinygrad/features/image.py", + "tinygrad_repo/tinygrad/features/search.py", + "tinygrad_repo/tinygrad/nn/*", + "tinygrad_repo/tinygrad/renderer/cstyle.py", + "tinygrad_repo/tinygrad/renderer/opencl.py", + "tinygrad_repo/tinygrad/runtime/lib.py", + "tinygrad_repo/tinygrad/runtime/ops_cpu.py", + "tinygrad_repo/tinygrad/runtime/ops_disk.py", + "tinygrad_repo/tinygrad/runtime/ops_gpu.py", + "tinygrad_repo/tinygrad/shape/*", + "tinygrad_repo/tinygrad/*.py", +] + +if __name__ == "__main__": + for f in Path(ROOT).rglob("**/*"): + if not (f.is_file() or f.is_symlink()): + continue + + rf = str(f.relative_to(ROOT)) + blacklisted = any(re.search(p, rf) for p in blacklist) + whitelisted = any(re.search(p, rf) for p in whitelist) + if blacklisted and not whitelisted: + continue + + print(rf) diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 2d15223d1..deb84d595 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -1,3 +1,5 @@ +import glob + Import('env', 'envCython', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc', 'transformations') lenv = env.Clone() lenvCython = envCython.Clone() @@ -50,11 +52,12 @@ lenvCython.Program('runners/runmodel_pyx.so', 'runners/runmodel_pyx.pyx', LIBS=c lenvCython.Program('runners/snpemodel_pyx.so', 'runners/snpemodel_pyx.pyx', LIBS=[snpemodel_lib, snpe_lib, *cython_libs], FRAMEWORKS=frameworks, RPATH=snpe_rpath) lenvCython.Program('models/commonmodel_pyx.so', 'models/commonmodel_pyx.pyx', LIBS=[commonmodel_lib, *cython_libs], FRAMEWORKS=frameworks) +tinygrad_files = ["#"+x for x in glob.glob(env.Dir("#tinygrad_repo").relpath + "/**", recursive=True, root_dir=env.Dir("#").abspath)] + # Get model metadata fn = File("models/supercombo").abspath cmd = f'python3 {Dir("#selfdrive/modeld").abspath}/get_model_metadata.py {fn}.onnx' -files = sum([lenv.Glob("#"+x) for x in open(File("#release/files_common").abspath).read().split("\n") if x.endswith("get_model_metadata.py")], []) -lenv.Command(fn + "_metadata.pkl", [fn + ".onnx"]+files, cmd) +lenv.Command(fn + "_metadata.pkl", [fn + ".onnx"] + tinygrad_files, cmd) # Build thneed model if arch == "larch64" or GetOption('pc_thneed'): @@ -64,7 +67,6 @@ if arch == "larch64" or GetOption('pc_thneed'): tinygrad_opts += ["FLOAT16=1", "PYOPENCL_NO_CACHE=1"] cmd = f"cd {Dir('#').abspath}/tinygrad_repo && " + ' '.join(tinygrad_opts) + f" python3 openpilot/compile2.py {fn}.onnx {fn}.thneed" - tinygrad_files = sum([lenv.Glob("#"+x) for x in open(File("#release/files_common").abspath).read().split("\n") if x.startswith("tinygrad_repo/")], []) lenv.Command(fn + ".thneed", [fn + ".onnx"] + tinygrad_files, cmd) thneed_lib = env.SharedLibrary('thneed', thneed_src, LIBS=[gpucommon, common, 'zmq', 'OpenCL', 'dl']) From 390caeb01169c4213d097ec9ddda724a58a93634 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 25 May 2024 21:00:29 -0700 Subject: [PATCH 091/220] pyproject: support >= 3.11 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index da7f1021e..5ebd2d89e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,7 @@ documentation = "https://docs.comma.ai" [tool.poetry.dependencies] -python = "~3.11" +python = ">=3.11" aiohttp = "*" aiortc = "*" cffi = "*" From ccbca2ac95027afefd5a5c7ab190bbb1c332ac61 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 25 May 2024 21:20:15 -0700 Subject: [PATCH 092/220] Revert "pyproject: support >= 3.11" This reverts commit 390caeb01169c4213d097ec9ddda724a58a93634. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5ebd2d89e..da7f1021e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,7 @@ documentation = "https://docs.comma.ai" [tool.poetry.dependencies] -python = ">=3.11" +python = "~3.11" aiohttp = "*" aiortc = "*" cffi = "*" From 93963207f22e5724fb334ca495591ecc51529a82 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 26 May 2024 10:41:19 -0500 Subject: [PATCH 093/220] [bot] Fingerprints: add missing FW versions from new users (#32542) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 2 ++ selfdrive/car/honda/fingerprints.py | 1 + 2 files changed, 3 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index d71ec5d30..eb9602bcc 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -493,6 +493,7 @@ FW_VERSIONS = { b'68440789AC', b'68466110AA', b'68466110AB', + b'68466113AA', b'68469901AA', b'68469907AA', b'68522583AA', @@ -605,6 +606,7 @@ FW_VERSIONS = { b'68520870AC', b'68540431AB', b'68540433AB', + b'68551676AA', b'68629935AB', b'68629936AC', ], diff --git a/selfdrive/car/honda/fingerprints.py b/selfdrive/car/honda/fingerprints.py index 26433a8b9..439568888 100644 --- a/selfdrive/car/honda/fingerprints.py +++ b/selfdrive/car/honda/fingerprints.py @@ -770,6 +770,7 @@ FW_VERSIONS = { b'37805-RLV-4070\x00\x00', b'37805-RLV-5140\x00\x00', b'37805-RLV-5230\x00\x00', + b'37805-RLV-5250\x00\x00', b'37805-RLV-A630\x00\x00', b'37805-RLV-A830\x00\x00', b'37805-RLV-A840\x00\x00', From 1eb938b8e81a3321adf1064e8ef348b8c7073d4c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 26 May 2024 21:21:50 -0700 Subject: [PATCH 094/220] Revert no pyenv (#32547) * Revert "`ubuntu_setup`: fix `No module apt_pkg` error when setting up (#32526)" This reverts commit f4322666c6adc4dd2da569f483f6e108f18fe32a. * Revert "Removal of pyenv (#32512)" This reverts commit f5752121f8a2029050c63cfa04f2533901ae4f3a. --- .github/workflows/selfdrive_tests.yaml | 2 +- .python-version | 1 + Dockerfile.openpilot_base | 13 ++++--- selfdrive/test/ci_shell.sh | 1 - tools/install_python_dependencies.sh | 49 +++++++++++++++++++++----- tools/install_ubuntu_dependencies.sh | 28 +-------------- tools/mac_setup.sh | 5 +-- 7 files changed, 55 insertions(+), 44 deletions(-) create mode 100644 .python-version diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index e73e0df2a..9001ca86f 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -19,7 +19,7 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: selfdrive/test/docker_build.sh base - RUN: docker run --shm-size 1.5G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c + RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical diff --git a/.python-version b/.python-version new file mode 100644 index 000000000..0c7d5f5f5 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.11.4 diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index 2c5f9a035..0789a39c3 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -13,7 +13,7 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 COPY tools/install_ubuntu_dependencies.sh /tmp/tools/ -RUN INSTALL_EXTRA_PACKAGES=no INSTALL_DEADSNAKES_PPA=yes /tmp/tools/install_ubuntu_dependencies.sh && \ +RUN INSTALL_EXTRA_PACKAGES=no /tmp/tools/install_ubuntu_dependencies.sh && \ rm -rf /var/lib/apt/lists/* /tmp/* && \ cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \ rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp @@ -64,16 +64,19 @@ RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER $USER ENV POETRY_VIRTUALENVS_CREATE=false -ENV VIRTUAL_ENV_ROOT="/home/$USER/venv" -ENV PATH="$VIRTUAL_ENV_ROOT/bin:$PATH" +ENV PYENV_VERSION=3.11.4 +ENV PYENV_ROOT="/home/$USER/pyenv" +ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" -COPY --chown=$USER pyproject.toml poetry.lock /tmp/ +COPY --chown=$USER pyproject.toml poetry.lock .python-version /tmp/ COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/ RUN cd /tmp && \ tools/install_python_dependencies.sh && \ rm -rf /tmp/* && \ - rm -rf /home/$USER/.cache + rm -rf /home/$USER/.cache && \ + find /home/$USER/pyenv -type d -name ".git" | xargs rm -rf && \ + rm -rf /home/$USER/pyenv/versions/3.11.4/lib/python3.11/test USER root RUN sudo git config --global --add safe.directory /tmp/openpilot diff --git a/selfdrive/test/ci_shell.sh b/selfdrive/test/ci_shell.sh index 1f3fa1f65..a5ff714b2 100755 --- a/selfdrive/test/ci_shell.sh +++ b/selfdrive/test/ci_shell.sh @@ -11,7 +11,6 @@ fi docker run \ -it \ - --shm-size=100m \ --rm \ --volume $OP_ROOT:$OP_ROOT \ --workdir $PWD \ diff --git a/tools/install_python_dependencies.sh b/tools/install_python_dependencies.sh index eaa32a0a4..df815b582 100755 --- a/tools/install_python_dependencies.sh +++ b/tools/install_python_dependencies.sh @@ -10,18 +10,50 @@ if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then RC_FILE="$HOME/.bash_profile" fi +if ! command -v "pyenv" > /dev/null 2>&1; then + echo "pyenv install ..." + curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash + PYENV_PATH_SETUP="export PATH=\$HOME/.pyenv/bin:\$HOME/.pyenv/shims:\$PATH" +fi + +if [ -z "$PYENV_SHELL" ] || [ -n "$PYENV_PATH_SETUP" ]; then + echo "pyenvrc setup ..." + cat < "${HOME}/.pyenvrc" +if [ -z "\$PYENV_ROOT" ]; then + $PYENV_PATH_SETUP + export PYENV_ROOT="\$HOME/.pyenv" + eval "\$(pyenv init -)" + eval "\$(pyenv virtualenv-init -)" +fi +EOF + + SOURCE_PYENVRC="source ~/.pyenvrc" + if ! grep "^$SOURCE_PYENVRC$" $RC_FILE > /dev/null; then + printf "\n$SOURCE_PYENVRC\n" >> $RC_FILE + fi + + eval "$SOURCE_PYENVRC" + # $(pyenv init -) produces a function which is broken on bash 3.2 which ships on macOS + if [ $(uname) == "Darwin" ]; then + unset -f pyenv + fi +fi + export MAKEFLAGS="-j$(nproc)" - +PYENV_PYTHON_VERSION=$(cat $ROOT/.python-version) +if ! pyenv prefix ${PYENV_PYTHON_VERSION} &> /dev/null; then + # no pyenv update on mac + if [ "$(uname)" == "Linux" ]; then + echo "pyenv update ..." + pyenv update + fi + echo "python ${PYENV_PYTHON_VERSION} install ..." + CONFIGURE_OPTS="--enable-shared" pyenv install -f ${PYENV_PYTHON_VERSION} +fi +eval "$(pyenv init --path)" echo "update pip" -if [ ! -z "$VIRTUAL_ENV_ROOT" ] || [ ! -z "$INSTALL_DEADSNAKES_PPA" ] ; then - if [ -z "$VIRTUAL_ENV_ROOT" ]; then - export VIRTUAL_ENV_ROOT="venv" - fi - python3 -m venv --system-site-packages $VIRTUAL_ENV_ROOT - source $VIRTUAL_ENV_ROOT/bin/activate -fi pip install pip==24.0 pip install poetry==1.7.0 @@ -39,6 +71,7 @@ poetry self add poetry-dotenv-plugin@^0.1.0 echo "pip packages install..." poetry install --no-cache --no-root +pyenv rehash [ -n "$POETRY_VIRTUALENVS_CREATE" ] && RUN="" || RUN="poetry run" diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index 2469168c7..1f8ef24ea 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -99,39 +99,13 @@ function install_ubuntu_lts_latest_requirements() { # Install Ubuntu 20.04 packages function install_ubuntu_focal_requirements() { install_ubuntu_common_requirements - install_deadsnakes_ppa + $SUDO apt-get install -y --no-install-recommends \ libavresample-dev \ qt5-default \ python-dev } -# Remove once on Ubuntu 24.04 -function install_deadsnakes_ppa(){ - if [[ -z "$INSTALL_DEADSNAKES_PPA" ]]; then - read -p "Do you want to use deadsnakes python@3.11? [Y/n]: " -n 1 -r - echo "" - if [[ $REPLY =~ ^[Yy]$ ]]; then - INSTALL_DEADSNAKES_PPA="yes" - fi - fi - if [[ "$INSTALL_DEADSNAKES_PPA" == "yes" ]]; then - # The reinstall ensures that apt_pkg.cpython-35m-x86_64-linux-gnu.so exists - # by reinstalling python3-minimal since it's not present in /usr/lib/python3/dist-packages. - $SUDO apt install -y --no-install-recommends --reinstall python3-minimal - $SUDO apt-get install -y --no-install-recommends python3-apt software-properties-common - $SUDO add-apt-repository ppa:deadsnakes/ppa - $SUDO apt-get install -y --no-install-recommends \ - python3.11-dev \ - python3.11 \ - python3.11-venv \ - python3.11-distutils \ - python3-pip - $SUDO update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 20 - curl -sS https://bootstrap.pypa.io/get-pip.py | python3.11 - fi -} - # Detect OS using /etc/os-release file if [ -f "/etc/os-release" ]; then source /etc/os-release diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index b02186685..d26ec3cfe 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -6,7 +6,7 @@ if [ -z "$SKIP_PROMPT" ]; then echo "--------------- macOS support ---------------" echo "Running openpilot natively on macOS is not officially supported." echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues." - echo + echo echo "Check out devcontainers for a seamless experience (see tools/README.md)." echo "-------------------------------------------------" echo -n "Are you sure you want to continue? [y/N] " @@ -59,7 +59,8 @@ brew "libusb" brew "libtool" brew "llvm" brew "openssl@3.0" -brew "python@3.11" +brew "pyenv" +brew "pyenv-virtualenv" brew "qt@5" brew "zeromq" cask "gcc-arm-embedded" From d6a738bef7b8d8cfacfe8f7edf9fc01ba435f05a Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Mon, 27 May 2024 12:22:41 -0400 Subject: [PATCH 095/220] tools/simulator: Remove superseded build script for sim docker (#32546) * remove * add those back --- tools/sim/build_container.sh | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100755 tools/sim/build_container.sh diff --git a/tools/sim/build_container.sh b/tools/sim/build_container.sh deleted file mode 100755 index 451277d59..000000000 --- a/tools/sim/build_container.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $DIR/../../ - -docker pull ghcr.io/commaai/openpilot-base:latest -docker build \ - --cache-from ghcr.io/commaai/openpilot-sim:latest \ - -t ghcr.io/commaai/openpilot-sim:latest \ - -f tools/sim/Dockerfile.sim . From 30792577cd6c65c243f22bf1013a012e22b1da38 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 27 May 2024 10:38:53 -0700 Subject: [PATCH 096/220] [bot] Bump submodules (#32549) bump submodules Co-authored-by: Vehicle Researcher --- opendbc | 2 +- panda | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc b/opendbc index d53c8f558..9a92d7a23 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit d53c8f558cc4861ce6563498a3663ee9b57daf4b +Subproject commit 9a92d7a232e3abe54c501e01c960462dd04588ea diff --git a/panda b/panda index cade0d5e7..d37d25e05 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit cade0d5e75cdd6a659e1ded21a45d8f3c6c62c18 +Subproject commit d37d25e0575f9f76d3ab0aaded832646ddc6459d From 521ee46c4704057365a6e08c4571a6eafd5d8dde Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 28 May 2024 00:01:31 -0500 Subject: [PATCH 097/220] [bot] Fingerprints: add missing FW versions from new users (#32552) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index eb9602bcc..178905458 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -145,6 +145,7 @@ FW_VERSIONS = { b'68413871AE ', b'68413871AH ', b'68413871AI ', + b'68413873AH ', b'68413873AI ', b'68443120AE ', b'68443123AC ', @@ -165,6 +166,7 @@ FW_VERSIONS = { b'68414271AC', b'68414271AD', b'68414275AC', + b'68414275AD', b'68443154AB', b'68443155AC', b'68443158AB', From 6b3d2b5a80c61e83a925ff28cc2394f9a9c0a996 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 29 May 2024 03:02:15 +0800 Subject: [PATCH 098/220] cabana: fix panda stream issues (#32537) fix segfault --- tools/cabana/streams/abstractstream.h | 5 +++++ tools/cabana/streams/livestream.cc | 9 +++++++- tools/cabana/streams/livestream.h | 1 + tools/cabana/streams/pandastream.cc | 31 +++++++++++++++++--------- tools/cabana/streams/pandastream.h | 5 +++-- tools/cabana/streams/socketcanstream.h | 1 + tools/cabana/streamselector.cc | 5 +++-- tools/cabana/streamselector.h | 2 ++ 8 files changed, 44 insertions(+), 15 deletions(-) diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 3d63ee49b..cfd423b36 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -64,6 +64,7 @@ public: AbstractStream(QObject *parent); virtual ~AbstractStream() {} virtual void start() = 0; + virtual void stop() {} virtual bool liveStreaming() const { return true; } virtual void seekTo(double ts) {} virtual QString routeName() const = 0; @@ -128,11 +129,15 @@ private: }; class AbstractOpenStreamWidget : public QWidget { + Q_OBJECT public: AbstractOpenStreamWidget(AbstractStream **stream, QWidget *parent = nullptr) : stream(stream), QWidget(parent) {} virtual bool open() = 0; virtual QString title() = 0; +signals: + void enableOpenButton(bool); + protected: AbstractStream **stream = nullptr; }; diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 4e1f6d77d..d9d96e23b 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -42,6 +42,10 @@ LiveStream::LiveStream(QObject *parent) : AbstractStream(parent) { QObject::connect(stream_thread, &QThread::finished, stream_thread, &QThread::deleteLater); } +LiveStream::~LiveStream() { + stop(); +} + void LiveStream::startUpdateTimer() { update_timer.stop(); update_timer.start(1000.0 / settings.fps, this); @@ -55,11 +59,14 @@ void LiveStream::start() { begin_date_time = QDateTime::currentDateTime(); } -LiveStream::~LiveStream() { +void LiveStream::stop() { + if (!stream_thread) return; + update_timer.stop(); stream_thread->requestInterruption(); stream_thread->quit(); stream_thread->wait(); + stream_thread = nullptr; } // called in streamThread diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 7a0f8cd83..9ca7e8d74 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -14,6 +14,7 @@ public: LiveStream(QObject *parent); virtual ~LiveStream(); void start() override; + void stop() override; inline QDateTime beginDateTime() const { return begin_date_time; } inline double routeStartTime() const override { return begin_event_ts / 1e9; } void setSpeed(float speed) override { speed_ = speed; } diff --git a/tools/cabana/streams/pandastream.cc b/tools/cabana/streams/pandastream.cc index 308391a10..030783a89 100644 --- a/tools/cabana/streams/pandastream.cc +++ b/tools/cabana/streams/pandastream.cc @@ -6,12 +6,17 @@ #include #include #include +#include -PandaStream::PandaStream(QObject *parent, PandaStreamConfig config_) : config(config_), LiveStream(parent) {} +PandaStream::PandaStream(QObject *parent, PandaStreamConfig config_) : config(config_), LiveStream(parent) { + if (!connect()) { + throw std::runtime_error("Failed to connect to panda"); + } +} bool PandaStream::connect() { try { - qDebug() << "Connecting to panda with serial" << config.serial; + qDebug() << "Connecting to panda " << config.serial; panda.reset(new Panda(config.serial.toStdString())); config.bus_config.resize(3); qDebug() << "Connected"; @@ -80,6 +85,13 @@ AbstractOpenStreamWidget *PandaStream::widget(AbstractStream **stream) { OpenPandaWidget::OpenPandaWidget(AbstractStream **stream) : AbstractOpenStreamWidget(stream) { form_layout = new QFormLayout(this); + if (can && dynamic_cast(can) != nullptr) { + form_layout->addWidget(new QLabel(tr("Already connected to %1.").arg(can->routeName()))); + form_layout->addWidget(new QLabel("Close the current connection via [File menu -> Close Stream] before connecting to another Panda.")); + QTimer::singleShot(0, [this]() { emit enableOpenButton(false); }); + return; + } + QHBoxLayout *serial_layout = new QHBoxLayout(); serial_layout->addWidget(serial_edit = new QComboBox()); @@ -116,6 +128,7 @@ void OpenPandaWidget::buildConfigForm() { Panda panda(serial.toStdString()); has_fd = (panda.hw_type == cereal::PandaState::PandaType::RED_PANDA) || (panda.hw_type == cereal::PandaState::PandaType::RED_PANDA_V2); } catch (const std::exception& e) { + qDebug() << "failed to open panda" << serial; has_panda = false; } } @@ -170,13 +183,11 @@ void OpenPandaWidget::buildConfigForm() { } bool OpenPandaWidget::open() { - if (!config.serial.isEmpty()) { - auto panda_stream = std::make_unique(qApp, config); - if (panda_stream->connect()) { - *stream = panda_stream.release(); - return true; - } + try { + *stream = new PandaStream(qApp, config); + return true; + } catch (std::exception &e) { + QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to connect to panda: '%1'").arg(e.what())); + return false; } - QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to connect to panda")); - return false; } diff --git a/tools/cabana/streams/pandastream.h b/tools/cabana/streams/pandastream.h index ce0adfc9f..c50407be1 100644 --- a/tools/cabana/streams/pandastream.h +++ b/tools/cabana/streams/pandastream.h @@ -21,13 +21,14 @@ class PandaStream : public LiveStream { Q_OBJECT public: PandaStream(QObject *parent, PandaStreamConfig config_ = {}); - bool connect(); + ~PandaStream() { stop(); } static AbstractOpenStreamWidget *widget(AbstractStream **stream); inline QString routeName() const override { - return QString("Live Streaming From Panda %1").arg(config.serial); + return QString("Panda: %1").arg(config.serial); } protected: + bool connect(); void streamThread() override; std::unique_ptr panda; diff --git a/tools/cabana/streams/socketcanstream.h b/tools/cabana/streams/socketcanstream.h index e0fb826ac..952f1aaa5 100644 --- a/tools/cabana/streams/socketcanstream.h +++ b/tools/cabana/streams/socketcanstream.h @@ -17,6 +17,7 @@ class SocketCanStream : public LiveStream { Q_OBJECT public: SocketCanStream(QObject *parent, SocketCanStreamConfig config_ = {}); + ~SocketCanStream() { stop(); } static AbstractOpenStreamWidget *widget(AbstractStream **stream); static bool available(); diff --git a/tools/cabana/streamselector.cc b/tools/cabana/streamselector.cc index d12f1a5df..209b577c9 100644 --- a/tools/cabana/streamselector.cc +++ b/tools/cabana/streamselector.cc @@ -1,6 +1,5 @@ #include "tools/cabana/streamselector.h" -#include #include #include #include @@ -31,7 +30,7 @@ StreamSelector::StreamSelector(AbstractStream **stream, QWidget *parent) : QDial line->setFrameStyle(QFrame::HLine | QFrame::Sunken); layout->addWidget(line); - auto btn_box = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel); + btn_box = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel); layout->addWidget(btn_box); addStreamWidget(ReplayStream::widget(stream)); @@ -60,4 +59,6 @@ StreamSelector::StreamSelector(AbstractStream **stream, QWidget *parent) : QDial void StreamSelector::addStreamWidget(AbstractOpenStreamWidget *w) { tab->addTab(w, w->title()); + auto open_btn = btn_box->button(QDialogButtonBox::Open); + QObject::connect(w, &AbstractOpenStreamWidget::enableOpenButton, open_btn, &QPushButton::setEnabled); } diff --git a/tools/cabana/streamselector.h b/tools/cabana/streamselector.h index 19b438d55..a702fc76a 100644 --- a/tools/cabana/streamselector.h +++ b/tools/cabana/streamselector.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -17,4 +18,5 @@ public: private: QLineEdit *dbc_file; QTabWidget *tab; + QDialogButtonBox *btn_box; }; From a2931d1956addab1e4c2dbc52b11d7d2e9199043 Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Tue, 28 May 2024 14:45:17 -0700 Subject: [PATCH 099/220] CI: add devcontainer-rebuild workflow (#32564) * add devcontainer-rebuild workflow * add shell * add shell on ifs * use scripts/retry.sh --- .github/workflows/tools_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 224b0c9d5..b3cfd56d1 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -73,7 +73,7 @@ jobs: - name: Setup Dev Container CLI run: npm install -g @devcontainers/cli - name: Build dev container image - run: devcontainer build --workspace-folder . + run: ./scripts/retry.sh devcontainer build --workspace-folder . - name: Run dev container run: | mkdir -p /tmp/devcontainer_scons_cache/ From 325dcec06b5662b6b4c0f8903f0a7ea064fa4b7f Mon Sep 17 00:00:00 2001 From: kacperhq Date: Wed, 29 May 2024 00:27:08 +0200 Subject: [PATCH 100/220] KIA SPORTAGE 5th HEV 2022 EUR fingerprint (#32558) Update fingerprints.py KIA Sportage 5th GEN EUR ver --- selfdrive/car/hyundai/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 4518f8b04..8525d3eca 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -1042,6 +1042,7 @@ FW_VERSIONS = { b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1060 665', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663', + b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1070 690', ], From a16fbdae3890b0e547f0113497ff8f713bd2b07b Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 29 May 2024 15:43:55 -0700 Subject: [PATCH 101/220] dmonitoringd: set invalid if missing dependence(s) (#32569) * no step but still send * no this * update diff --- selfdrive/monitoring/dmonitoringd.py | 8 +++++--- selfdrive/monitoring/helpers.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/selfdrive/monitoring/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py index e572bf5bd..80af7b71d 100755 --- a/selfdrive/monitoring/dmonitoringd.py +++ b/selfdrive/monitoring/dmonitoringd.py @@ -20,14 +20,16 @@ def dmonitoringd_thread(): # 20Hz <- dmonitoringmodeld while True: sm.update() - if (not sm.updated['driverStateV2']) or (not sm.all_checks()): + if not sm.updated['driverStateV2']: # iterate when model has new output continue - DM.run_step(sm) + valid = sm.all_checks() + if valid: + DM.run_step(sm) # publish - dat = DM.get_state_packet() + dat = DM.get_state_packet(valid=valid) pm.send('driverMonitoringState', dat) # load live always-on toggle diff --git a/selfdrive/monitoring/helpers.py b/selfdrive/monitoring/helpers.py index 347cb245d..dfb35182b 100644 --- a/selfdrive/monitoring/helpers.py +++ b/selfdrive/monitoring/helpers.py @@ -368,9 +368,9 @@ class DriverMonitoring: self.current_events.add(alert) - def get_state_packet(self): + def get_state_packet(self, valid=True): # build driverMonitoringState packet - dat = messaging.new_message('driverMonitoringState', valid=True) + dat = messaging.new_message('driverMonitoringState', valid=valid) dat.driverMonitoringState = { "events": self.current_events.to_msg(), "faceDetected": self.face_detected, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 4fec7453f..0a9a54325 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -dbf5b05ff480145a79b5941e360d0698b70979cd \ No newline at end of file +87aa5052e36d5cf83698b1eb6e50aef5c86df8ca \ No newline at end of file From 5f778c0d3a740b271d10b10842406a97bd27d959 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 30 May 2024 10:04:03 +0800 Subject: [PATCH 102/220] common/prefix.h: Fix incomplete path cleanup on exit (#32559) --- common/prefix.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/prefix.h b/common/prefix.h index f5abe14b2..11d0bc106 100644 --- a/common/prefix.h +++ b/common/prefix.h @@ -5,6 +5,7 @@ #include "common/params.h" #include "common/util.h" +#include "system/hardware/hw.h" class OpenpilotPrefix { public: @@ -25,6 +26,10 @@ public: system(util::string_format("rm %s -rf", real_path.c_str()).c_str()); unlink(param_path.c_str()); } + if (getenv("COMMA_CACHE") == nullptr) { + system(util::string_format("rm %s -rf", Path::download_cache_root().c_str()).c_str()); + } + system(util::string_format("rm %s -rf", Path::comma_home().c_str()).c_str()); system(util::string_format("rm %s -rf", msgq_path.c_str()).c_str()); unsetenv("OPENPILOT_PREFIX"); } From c2f55a2600d6981c1f84360f7c64bbb7a893d25c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 30 May 2024 01:52:43 -0700 Subject: [PATCH 103/220] map window: log style load errors (#32573) log errors --- selfdrive/ui/qt/maps/map.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index 5f178e9f8..bb66f0869 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -5,6 +5,7 @@ #include +#include "common/swaglog.h" #include "selfdrive/ui/qt/maps/map_helpers.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/ui.h" @@ -262,6 +263,10 @@ void MapWindow::initializeGL() { loaded_once = true; } }); + + QObject::connect(m_map.data(), &QMapLibre::Map::mapLoadingFailed, [=](QMapLibre::Map::MapLoadingFailure err_code, const QString &reason) { + LOGE("Map loading failed with %d: '%s'\n", err_code, reason.toStdString().c_str()); + }); } void MapWindow::paintGL() { From 57d64279bdd0a8935586d7f58b68edaf793a73ed Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 30 May 2024 02:08:31 -0700 Subject: [PATCH 104/220] ui: re-generate JWT on valid system time (#32571) * revert me * Revert "revert me" This reverts commit 17d815ddfc9a18f7fb9f39f89ec8b4481389b339. * duh we have timed! * clean up * use clocks * re-initialize map on SSL handshake failure (time) * this is fine, takes some time to init * fix * log errors like map renderer * more clean up full message is "loading style failed: SSL handshake failed" * MOAR * we still can't swap the token live * mbgl has its own retries that never work, don't reinit multiple times at once * simpler * more * whoops * this works * fix from merge * rm * fix cmt * only an issue calling the function inside itself --- selfdrive/ui/qt/maps/map.cc | 8 ++++++++ selfdrive/ui/qt/maps/map.h | 1 + selfdrive/ui/ui.cc | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index bb66f0869..490eb118c 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -119,6 +119,14 @@ void MapWindow::updateState(const UIState &s) { const SubMaster &sm = *(s.sm); update(); + // on rising edge of a valid system time, reinitialize the map to set a new token + if (sm.valid("clocks") && !prev_time_valid) { + LOGW("Time is now valid, reinitializing map"); + m_settings.setApiKey(get_mapbox_token()); + initializeGL(); + } + prev_time_valid = sm.valid("clocks"); + if (sm.updated("liveLocationKalman")) { auto locationd_location = sm["liveLocationKalman"].getLiveLocationKalman(); auto locationd_pos = locationd_location.getPositionGeodetic(); diff --git a/selfdrive/ui/qt/maps/map.h b/selfdrive/ui/qt/maps/map.h index 8193d5572..31a44f27b 100644 --- a/selfdrive/ui/qt/maps/map.h +++ b/selfdrive/ui/qt/maps/map.h @@ -51,6 +51,7 @@ private: void setError(const QString &err_str); bool loaded_once = false; + bool prev_time_valid = true; // Panning QPointF m_lastPos; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 0ff4f3111..c70b7594c 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -249,7 +249,7 @@ UIState::UIState(QObject *parent) : QObject(parent) { sm = std::make_unique>({ "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "driverStateV2", - "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "uiPlan", + "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "uiPlan", "clocks", }); Params params; From aa081f574833bcb1db4c234b9ee3d5bcd303a6de Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Thu, 30 May 2024 14:25:21 -0400 Subject: [PATCH 105/220] Simulator: update MetaDrive to latest (#32576) * bump metadrive * comment --- poetry.lock | 20 +++++++++++-------- pyproject.toml | 3 ++- .../sim/bridge/metadrive/metadrive_process.py | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/poetry.lock b/poetry.lock index 01ec394f2..23b2eb7b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "aiohttp" @@ -2247,18 +2247,16 @@ version = "0.4.2.3" description = "An open-ended driving simulator with infinite scenes" optional = false python-versions = ">=3.6, <3.12" -files = [ - {file = "metadrive-simulator-0.4.2.3.tar.gz", hash = "sha256:bcda7d07146128161b0bc2cc337e01612b9222202706370043b52f7936a8a277"}, - {file = "metadrive_simulator-0.4.2.3-py3-none-any.whl", hash = "sha256:f6fff20b931bb956c55e0e81bf1f6b641169a84a4c853435a8b26bd51c8e9876"}, -] +files = [] +develop = false [package.dependencies] filelock = "*" geopandas = "*" -gymnasium = ">=0.28,<0.29" +gymnasium = ">=0.28" lxml = "*" matplotlib = "*" -numpy = ">=1.21.6,<=1.24.2" +numpy = ">=1.21.6" opencv-python = "*" panda3d = "1.10.13" panda3d-gltf = "0.13" @@ -2281,6 +2279,12 @@ cuda = ["PyOpenGL (==3.1.6)", "PyOpenGL-accelerate (==3.1.6)", "cuda-python (==1 gym = ["gym (>=0.19.0,<=0.26.0)"] ros = ["zmq"] +[package.source] +type = "git" +url = "https://github.com/metadriverse/metadrive.git" +reference = "233a3a1698be7038ec3dd050ca10b547b4b3324c" +resolved_reference = "233a3a1698be7038ec3dd050ca10b547b4b3324c" + [[package]] name = "mouseinfo" version = "0.1.3" @@ -8037,4 +8041,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "1b15d2bb9465282294cd503c019a7d023f16dbb3e44ddde7b9899c45195c6cb8" +content-hash = "ac6ceb0682848e6c5e39110842e8d96fdc98b15037c56491a7fc1e03b7b89cbd" diff --git a/pyproject.toml b/pyproject.toml index da7f1021e..d7145b10a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -140,7 +140,8 @@ inputs = "*" Jinja2 = "*" lru-dict = "*" matplotlib = "*" -metadrive-simulator = { version = "0.4.2.3", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies +# No release for this fix https://github.com/metadriverse/metadrive/issues/632. Pinned to this commit until next release +metadrive-simulator = {git = "https://github.com/metadriverse/metadrive.git", rev ="233a3a1698be7038ec3dd050ca10b547b4b3324c", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies mpld3 = "*" mypy = "*" myst-parser = "*" diff --git a/tools/sim/bridge/metadrive/metadrive_process.py b/tools/sim/bridge/metadrive/metadrive_process.py index 2b9203c30..38c13a143 100644 --- a/tools/sim/bridge/metadrive/metadrive_process.py +++ b/tools/sim/bridge/metadrive/metadrive_process.py @@ -88,7 +88,7 @@ def metadrive_process(dual_camera: bool, config: dict, camera_array, wide_camera cam.get_cam().reparentTo(env.vehicle.origin) cam.get_cam().setPos(C3_POSITION) cam.get_cam().setHpr(C3_HPR) - img = cam.perceive(clip=False) + img = cam.perceive(to_float=False) if type(img) != np.ndarray: img = img.get() # convert cupy array to numpy return img From 984ad8833aedf20c5cad14996c5e5cafc95fe3fa Mon Sep 17 00:00:00 2001 From: William Stairs Date: Fri, 31 May 2024 05:35:19 +0100 Subject: [PATCH 106/220] Add Chassis for VW Arteon Shooting Brake 2020-2023 (#32579) * Added Arteon "3H" chassis code for Shooting Brake to VWCarDocs. * Added new engine and transmission FW to Volkswagen fingerprints.py for Arteon Mk1. * Apply suggestions from code review * updates docs --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 3 ++- selfdrive/car/volkswagen/values.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 899c6f821..26b7fe203 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. -# 287 Supported Cars +# 288 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -263,6 +263,7 @@ A supported vehicle is one that just works when you install a comma device. All |Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index eb537575f..4d317176b 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -214,10 +214,11 @@ class CAR(Platforms): VWCarDocs("Volkswagen Arteon 2018-23", video_link="https://youtu.be/FAomFKPFlDA"), VWCarDocs("Volkswagen Arteon R 2020-23", video_link="https://youtu.be/FAomFKPFlDA"), VWCarDocs("Volkswagen Arteon eHybrid 2020-23", video_link="https://youtu.be/FAomFKPFlDA"), + VWCarDocs("Volkswagen Arteon Shooting Brake 2020-23", video_link="https://youtu.be/FAomFKPFlDA"), VWCarDocs("Volkswagen CC 2018-22", video_link="https://youtu.be/FAomFKPFlDA"), ], VolkswagenCarSpecs(mass=1733, wheelbase=2.84), - chassis_codes={"AN"}, + chassis_codes={"AN", "3H"}, wmis={WMI.VOLKSWAGEN_EUROPE_CAR}, ) VOLKSWAGEN_ATLAS_MK1 = VolkswagenMQBPlatformConfig( From 0a43d82428d03662a3a439f7ec5ada7afc39b7a2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 30 May 2024 22:20:04 -0700 Subject: [PATCH 107/220] fw_versions debug: match online vin retry --- selfdrive/car/fw_versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index f2aff2e6f..fef3c52d3 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -374,7 +374,7 @@ if __name__ == "__main__": t = time.time() print("Getting vin...") set_obd_multiplexing(params, True) - vin_rx_addr, vin_rx_bus, vin = get_vin(logcan, sendcan, (0, 1), retry=10, debug=args.debug) + vin_rx_addr, vin_rx_bus, vin = get_vin(logcan, sendcan, (0, 1), debug=args.debug) print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}') print(f"Getting VIN took {time.time() - t:.3f} s") print() From f887b8703cfdb764a5f16d624bd4ce8380054a23 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 30 May 2024 23:08:14 -0700 Subject: [PATCH 108/220] add Hyundai CAN FD fingerprinting note --- selfdrive/car/hyundai/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 72513c849..9b01a2e12 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -648,6 +648,8 @@ PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps] # TODO: there are date codes in the ABS firmware versions in hex DATE_FW_ECUS = [Ecu.fwdCamera] +# Note: an ECU on CAN FD cars may sometimes send 0x30080aaaaaaaaaaa (flow control continue) while we +# are attempting to query ECUs. This currently does not seem to affect fingerprinting from the camera FW_QUERY_CONFIG = FwQueryConfig( requests=[ # TODO: add back whitelists From 8f4b00c263e1942c6a6eed9d24297dff44e7f48f Mon Sep 17 00:00:00 2001 From: cl0cks4fe <108313040+cl0cks4fe@users.noreply.github.com> Date: Fri, 31 May 2024 13:43:12 -0700 Subject: [PATCH 109/220] cache get_torque_params (#32560) * cache get_torque_params * switch to cache * Update selfdrive/car/interfaces.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/interfaces.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 982d987d6..a9ff1eedd 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -6,6 +6,7 @@ from abc import abstractmethod, ABC from enum import StrEnum from typing import Any, NamedTuple from collections.abc import Callable +from functools import cache from cereal import car from openpilot.common.basedir import BASEDIR @@ -43,6 +44,7 @@ class LatControlInputs(NamedTuple): TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.LateralTorqueTuning, float, float, bool, bool], float] +@cache def get_torque_params(candidate): with open(TORQUE_SUBSTITUTE_PATH, 'rb') as f: sub = tomllib.load(f) From 30d5edb205b4153e891936b4f7b6f6a39b961a08 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 31 May 2024 16:20:59 -0700 Subject: [PATCH 110/220] Update RELEASES.md --- RELEASES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index da22a87a4..971ba7867 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,9 +1,9 @@ -Version 0.9.7 (2024-05-XX) +Version 0.9.7 (2024-06-11) ======================== * New driving model * Adjust driving personality with the follow distance button -* Support for hybrid variants of supported Ford models * Added toggle to enable driver monitoring even when openpilot is not engaged +* Support for hybrid variants of supported Ford models * Fingerprinting without the OBD-II port on all cars Version 0.9.6 (2024-02-27) From 9908b729c8af1c608ddd9f2b3d0b1b50a58f39de Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 1 Jun 2024 12:40:53 +0800 Subject: [PATCH 111/220] api: cache RSA private key (#32566) --- selfdrive/ui/qt/api.cc | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/selfdrive/ui/qt/api.cc b/selfdrive/ui/qt/api.cc index 0e321d4e1..6889b40e5 100644 --- a/selfdrive/ui/qt/api.cc +++ b/selfdrive/ui/qt/api.cc @@ -1,6 +1,5 @@ #include "selfdrive/ui/qt/api.h" -#include #include #include @@ -8,38 +7,41 @@ #include #include #include -#include #include #include +#include #include -#include "common/params.h" #include "common/util.h" #include "system/hardware/hw.h" #include "selfdrive/ui/qt/util.h" namespace CommaApi { -QByteArray rsa_sign(const QByteArray &data) { - static std::string key = util::read_file(Path::rsa_file()); - if (key.empty()) { - qDebug() << "No RSA private key found, please run manager.py or registration.py"; - return {}; +RSA *get_rsa_private_key() { + static std::unique_ptr rsa_private(nullptr, RSA_free); + if (!rsa_private) { + FILE *fp = fopen(Path::rsa_file().c_str(), "rb"); + if (!fp) { + qDebug() << "No RSA private key found, please run manager.py or registration.py"; + return nullptr; + } + rsa_private.reset(PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)); + fclose(fp); } + return rsa_private.get(); +} - BIO* mem = BIO_new_mem_buf(key.data(), key.size()); - assert(mem); - RSA* rsa_private = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL); - assert(rsa_private); - auto sig = QByteArray(); - sig.resize(RSA_size(rsa_private)); +QByteArray rsa_sign(const QByteArray &data) { + RSA *rsa_private = get_rsa_private_key(); + if (!rsa_private) return {}; + + QByteArray sig(RSA_size(rsa_private), Qt::Uninitialized); unsigned int sig_len; int ret = RSA_sign(NID_sha256, (unsigned char*)data.data(), data.size(), (unsigned char*)sig.data(), &sig_len, rsa_private); assert(ret == 1); - assert(sig_len == sig.size()); - BIO_free(mem); - RSA_free(rsa_private); + assert(sig.size() == sig_len); return sig; } @@ -57,9 +59,7 @@ QString create_jwt(const QJsonObject &payloads, int expiry) { QJsonDocument(payload).toJson(QJsonDocument::Compact).toBase64(b64_opts); auto hash = QCryptographicHash::hash(jwt.toUtf8(), QCryptographicHash::Sha256); - auto sig = rsa_sign(hash); - jwt += '.' + sig.toBase64(b64_opts); - return jwt; + return jwt + "." + rsa_sign(hash).toBase64(b64_opts); } } // namespace CommaApi From 63f55f4915ebb3763cc6bc9adaba52a77467ff23 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 31 May 2024 22:28:03 -0700 Subject: [PATCH 112/220] debug FW fingerprinting: live support (#32585) * live debug! * clean up --- selfdrive/debug/debug_fw_fingerprinting_offline.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/selfdrive/debug/debug_fw_fingerprinting_offline.py b/selfdrive/debug/debug_fw_fingerprinting_offline.py index 8ae9d6d34..3df292473 100755 --- a/selfdrive/debug/debug_fw_fingerprinting_offline.py +++ b/selfdrive/debug/debug_fw_fingerprinting_offline.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 import argparse +from openpilot.tools.lib.live_logreader import live_logreader from openpilot.tools.lib.logreader import LogReader, ReadMode from panda.python import uds -def main(route: str, addrs: list[int]): +def main(route: str | None, addrs: list[int]): """ TODO: - highlight TX vs RX clearly @@ -13,7 +14,10 @@ def main(route: str, addrs: list[int]): - print as fixed width table, easier to read """ - lr = LogReader(route, default_mode=ReadMode.RLOG, sort_by_time=True) + if route is None: + lr = live_logreader() + else: + lr = LogReader(route, default_mode=ReadMode.RLOG, sort_by_time=True) start_mono_time = None prev_mono_time = 0 @@ -28,7 +32,7 @@ def main(route: str, addrs: list[int]): if msg.which() in ("can", 'sendcan'): for can in getattr(msg, msg.which()): - if can.address in addrs: + if can.address in addrs or not len(addrs): if msg.logMonoTime != prev_mono_time: print() prev_mono_time = msg.logMonoTime @@ -38,8 +42,8 @@ def main(route: str, addrs: list[int]): if __name__ == "__main__": parser = argparse.ArgumentParser(description='View back and forth ISO-TP communication between various ECUs given an address') - parser.add_argument('route', help='Route name') - parser.add_argument('addrs', nargs='*', help='List of tx address to view (0x7e0 for engine)') + parser.add_argument('route', nargs='?', help='Route name, live if not specified') + parser.add_argument('--addrs', nargs='*', default=[], help='List of tx address to view (0x7e0 for engine)') args = parser.parse_args() addrs = [int(addr, base=16) if addr.startswith('0x') else int(addr) for addr in args.addrs] From a21f773366333427f50f8f2ad2358203e70eff9f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Jun 2024 14:23:48 -0700 Subject: [PATCH 113/220] no lfs in release --- release/build_devel.sh | 8 +++++++- release/release_files.py | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/release/build_devel.sh b/release/build_devel.sh index 18d99bb1c..7fce11ca7 100755 --- a/release/build_devel.sh +++ b/release/build_devel.sh @@ -48,7 +48,6 @@ cp -pR --parents $(./release/release_files.py) $TARGET_DIR/ # in the directory cd $TARGET_DIR rm -f panda/board/obj/panda.bin.signed -git submodule status # include source commit hash and build date in commit GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD) @@ -64,6 +63,13 @@ date: $DATETIME master commit: $GIT_HASH " +# should be no submodules or LFS files +git submodule status +if [ ! -z "$(git lfs ls-files)" ]; then + echo "LFS files detected!" + exit 1 +fi + # ensure files are within GitHub's limit BIG_FILES="$(find . -type f -not -path './.git/*' -size +95M)" if [ ! -z "$BIG_FILES" ]; then diff --git a/release/release_files.py b/release/release_files.py index bf6cd56a9..23e56d354 100755 --- a/release/release_files.py +++ b/release/release_files.py @@ -27,6 +27,10 @@ blacklist = [ ".devcontainer/", "Darwin/", ".vscode", + + # no LFS + ".lfsconfig", + ".gitattributes", ] # gets you through the blacklist From 54116569c3448b6044c271f529d60210ea0222da Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Jun 2024 15:05:07 -0700 Subject: [PATCH 114/220] build_release fixups --- release/build_release.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/release/build_release.sh b/release/build_release.sh index c2745ea28..b68ae455c 100755 --- a/release/build_release.sh +++ b/release/build_release.sh @@ -1,4 +1,6 @@ -#!/usr/bin/bash -e +#!/usr/bin/bash +set -e +set -x # git diff --name-status origin/release3-staging | grep "^A" | less @@ -29,7 +31,7 @@ git checkout --orphan $RELEASE_BRANCH # do the files copy echo "[-] copying files T=$SECONDS" cd $SOURCE_DIR -cp -pR --parents $(./release/release_files.py) $TARGET_DIR/ +cp -pR --parents $(./release/release_files.py) $BUILD_DIR/ # in the directory cd $BUILD_DIR @@ -46,7 +48,7 @@ git commit -a -m "openpilot v$VERSION release" # Build export PYTHONPATH="$BUILD_DIR" -scons -j$(nproc) +scons -j$(nproc) --minimal # release panda fw CERT=/data/pandaextra/certs/release RELEASE=1 scons -j$(nproc) panda/ From 7de9a3693ffc7626111fdf388b18be84ed22598a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Jun 2024 15:16:09 -0700 Subject: [PATCH 115/220] more release files --- release/release_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/release_files.py b/release/release_files.py index 23e56d354..f312b50a2 100755 --- a/release/release_files.py +++ b/release/release_files.py @@ -54,7 +54,7 @@ whitelist = [ "tinygrad_repo/tinygrad/runtime/ops_disk.py", "tinygrad_repo/tinygrad/runtime/ops_gpu.py", "tinygrad_repo/tinygrad/shape/*", - "tinygrad_repo/tinygrad/*.py", + "tinygrad_repo/tinygrad/.*.py", ] if __name__ == "__main__": From ce2a686b9751296e4e7207fd6a16b2d1b34d6ef4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 1 Jun 2024 16:04:04 -0700 Subject: [PATCH 116/220] add body teleop to release --- release/release_files.py | 1 + 1 file changed, 1 insertion(+) diff --git a/release/release_files.py b/release/release_files.py index f312b50a2..a6fb7d648 100755 --- a/release/release_files.py +++ b/release/release_files.py @@ -36,6 +36,7 @@ blacklist = [ # gets you through the blacklist whitelist = [ "tools/lib/", + "tools/bodyteleop/", "tinygrad_repo/openpilot/compile2.py", "tinygrad_repo/extra/onnx.py", From 00b10f3d9ad03a6695446aab7b3a34d86229549a Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Sun, 2 Jun 2024 14:53:32 -0700 Subject: [PATCH 117/220] `pytest`: discover `openpilot/` (#32561) * pytest: discover everything in openpilot/ * ignore process replay * remove --ignore=openpilot/ * ignore directories in root * remove skip in selfdrive/test/process_replay * use openpilot directory * set openpilot directory for test_translations * omit generated config.py files * run ci * cd into openpilot for test_translation * && * remove rm main_test_en command * remove echo * increase shm-size to 2G * remove rm * test only cpp_files that are test_*.cc~ * add process_replay test skip * use addopts in pyproject to ignore test_processes * try --rootdir for pytest * cleanups / add rootdir in PYTEST env * add rm create_test_translations * revert poetry.lock * simplify * no regen! --------- Co-authored-by: Adeeb Shihadeh --- .github/workflows/selfdrive_tests.yaml | 2 +- pyproject.toml | 34 ++++++++------------------ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 9001ca86f..bc2338238 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -19,7 +19,7 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: selfdrive/test/docker_build.sh base - RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c + RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical diff --git a/pyproject.toml b/pyproject.toml index d7145b10a..312e760b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,8 +9,8 @@ Homepage = "https://comma.ai" [tool.pytest.ini_options] minversion = "6.0" -addopts = "--ignore=openpilot/ --ignore=cereal/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=teleoprtc_repo/ -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" -cpp_files = "test_*" +addopts = "--ignore=selfdrive/test/process_replay/test_processes.py --ignore=selfdrive/test/process_replay/test_regen.py -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" +cpp_files = "test_*.cc" cpp_harness = "selfdrive/test/cpp_harness.py" python_files = "test_*.py" #timeout = "30" # you get this long by default @@ -19,28 +19,10 @@ markers = [ "tici: tests that are only meant to run on the C3/C3X", ] testpaths = [ - "common", - "selfdrive/boardd", - "selfdrive/car", - "selfdrive/controls", - "selfdrive/locationd", - "selfdrive/monitoring", - "selfdrive/navd/tests", - "selfdrive/test/longitudinal_maneuvers", - "selfdrive/test/process_replay/test_fuzzy.py", - "system/updated", - "system/thermald", - "system/athena", - "system/camerad", - "system/hardware/tici", - "system/loggerd", - "system/proclogd", - "system/tests", - "system/ubloxd", - "system/webrtc", - "tools/lib/tests", - "tools/replay", - "tools/cabana" + "tools/", + "common/", + "system/", + "selfdrive/", ] [tool.mypy] @@ -227,6 +209,10 @@ lint.flake8-implicit-str-concat.allow-multiline=false "unittest".msg = "Use pytest" [tool.coverage.run] +omit = [ + "config.py", + "config-3.py" +] concurrency = ["multiprocessing", "thread"] [tool.ruff.format] quote-style = "preserve" From f717e1e4e6cd8dbc787d2b8260a6635dda23dc16 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:05:15 -0400 Subject: [PATCH 118/220] tools/rerun: streaming to one Viewer from multiple processes (#32595) * one spawn only * one blueprint * comment --- tools/rerun/run.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tools/rerun/run.py b/tools/rerun/run.py index 8a002f68b..1c3c0a59e 100755 --- a/tools/rerun/run.py +++ b/tools/rerun/run.py @@ -39,6 +39,7 @@ def log_msg(msg, parent_key=''): pass # Not a plottable value def createBlueprint(): + blueprint = None timeSeriesViews = [] for topic in sorted(SERVICE_LIST.keys()): timeSeriesViews.append(rrb.TimeSeriesView(name=topic, origin=f"/{topic}/", visible=False)) @@ -51,9 +52,12 @@ def log_thumbnail(thumbnailMsg): bytesImgData = thumbnailMsg.get('thumbnail') rr.log("/thumbnail", rr.ImageEncoded(contents=bytesImgData)) -def process(blueprint, lr): +@rr.shutdown_at_exit +def process(lr): + rr.init("rerun_test") + rr.connect() + ret = [] - rr.init("rerun_test", spawn=True, default_blueprint=blueprint) for msg in lr: ret.append(msg) rr.set_time_nanos("TIMELINE", msg.logMonoTime) @@ -75,8 +79,11 @@ if __name__ == '__main__': args = parser.parse_args() - route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip() blueprint = createBlueprint() + rr.init("rerun_test", default_blueprint=blueprint) + rr.spawn(connect=False) # child processes stream data to Viewer + + route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip() print("Getting route log paths") lr = LogReader(route_or_segment_name) - lr.run_across_segments(NUM_CPUS, partial(process, blueprint)) + lr.run_across_segments(NUM_CPUS, partial(process)) From 1e70b23855a50e645325edf6f9548b0de73abe8d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 3 Jun 2024 13:52:45 +0800 Subject: [PATCH 119/220] LongitudinalPlanner: replace hardcoded length with ModelConstants.IDX_N (#32597) replace hardcoded length --- selfdrive/controls/lib/longitudinal_planner.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 9113bb5a9..ff5f901b5 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -62,9 +62,9 @@ class LongitudinalPlanner: @staticmethod def parse_model(model_msg, model_error): - if (len(model_msg.position.x) == 33 and - len(model_msg.velocity.x) == 33 and - len(model_msg.acceleration.x) == 33): + if (len(model_msg.position.x) == ModelConstants.IDX_N and + len(model_msg.velocity.x) == ModelConstants.IDX_N and + len(model_msg.acceleration.x) == ModelConstants.IDX_N): x = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.position.x) - model_error * T_IDXS_MPC v = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.velocity.x) - model_error a = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.acceleration.x) From 544b554c6997e2e02e99ab5275fc49e02ad0a5bc Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:24:03 -0700 Subject: [PATCH 120/220] [bot] Bump submodules (#32602) bump submodules Co-authored-by: Vehicle Researcher --- cereal | 2 +- panda | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cereal b/cereal index 51cbf6294..d0ceac712 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 51cbf6294efb356347b2c18b3df9904d11a7ff43 +Subproject commit d0ceac712f531c125923cbdc4ec7bedbdc5a7baf diff --git a/panda b/panda index d37d25e05..59d5be937 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit d37d25e0575f9f76d3ab0aaded832646ddc6459d +Subproject commit 59d5be937e40b8d93e9ebb79b33c65961a01de97 From 7c4b7ce799f7de15384231552c8fef1f9227292a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 3 Jun 2024 14:11:51 -0700 Subject: [PATCH 121/220] [bot] Fingerprints: add missing FW versions from CAN fingerprinting cars (#32604) Export fingerprints --- selfdrive/car/hyundai/fingerprints.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 8525d3eca..5f57f7154 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -135,9 +135,11 @@ FW_VERSIONS = { b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7200 ', b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7500 ', b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7000 ', + b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7100 ', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7310 4APEC101', + b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7510 4APEC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7560 4APEC101', ], (Ecu.fwdCamera, 0x7c4, None): [ @@ -146,6 +148,7 @@ FW_VERSIONS = { b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.01 95740-G2600 190819', b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.03 95740-G2500 190516', b'\xf1\x00AEE MFC AT EUR RHD 1.00 1.01 95740-G2600 190819', + b'\xf1\x00AEE MFC AT USA LHD 1.00 1.01 95740-G2600 190819', ], }, CAR.HYUNDAI_IONIQ_EV_LTD: { @@ -1039,10 +1042,10 @@ FW_VERSIONS = { CAR.KIA_SPORTAGE_5TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NQ5 FR_CMR AT AUS RHD 1.00 1.00 99211-P1040 663', + b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663', b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1060 665', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663', - b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1070 690', ], From c59887c8109dd8d33ea2e7169995184fbe38cc3a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 3 Jun 2024 15:48:56 -0700 Subject: [PATCH 122/220] test_*.py files are no longer executable (#32610) * test_*.py files are no longer executable * cleanup empty lines * update precommit * fixme * enable * build --- .github/workflows/selfdrive_tests.yaml | 4 +++- .pre-commit-config.yaml | 4 ++-- common/transformations/tests/test_coordinates.py | 2 -- common/transformations/tests/test_orientation.py | 2 -- selfdrive/boardd/tests/test_boardd_loopback.py | 1 - selfdrive/boardd/tests/test_boardd_spi.py | 1 - selfdrive/boardd/tests/test_pandad.py | 1 - selfdrive/car/ford/tests/test_ford.py | 1 - selfdrive/car/gm/tests/test_gm.py | 1 - selfdrive/car/honda/tests/test_honda.py | 1 - selfdrive/car/hyundai/tests/test_hyundai.py | 1 - selfdrive/car/tests/test_can_fingerprint.py | 1 - selfdrive/car/tests/test_car_interfaces.py | 1 - selfdrive/car/tests/test_docs.py | 1 - selfdrive/car/tests/test_fingerprints.py | 1 - selfdrive/car/tests/test_fw_fingerprint.py | 1 - selfdrive/car/tests/test_lateral_limits.py | 1 - selfdrive/car/tests/test_models.py | 1 - selfdrive/car/tests/test_platform_configs.py | 2 -- selfdrive/car/toyota/tests/test_toyota.py | 1 - selfdrive/car/volkswagen/tests/test_volkswagen.py | 1 - selfdrive/controls/lib/tests/test_alertmanager.py | 1 - selfdrive/controls/lib/tests/test_latcontrol.py | 1 - selfdrive/controls/lib/tests/test_vehicle_model.py | 1 - selfdrive/controls/tests/test_alerts.py | 1 - selfdrive/controls/tests/test_cruise_speed.py | 1 - selfdrive/controls/tests/test_following_distance.py | 1 - selfdrive/controls/tests/test_leads.py | 1 - selfdrive/controls/tests/test_state_machine.py | 2 -- selfdrive/debug/test_fw_query_on_routes.py | 1 - selfdrive/locationd/test/test_calibrationd.py | 1 - selfdrive/locationd/test/test_locationd.py | 1 - selfdrive/locationd/test/test_locationd_scenarios.py | 1 - selfdrive/modeld/tests/test_modeld.py | 1 - selfdrive/monitoring/test_monitoring.py | 1 - selfdrive/navd/tests/test_map_renderer.py | 1 - selfdrive/navd/tests/test_navd.py | 1 - selfdrive/test/longitudinal_maneuvers/test_longitudinal.py | 1 - selfdrive/test/process_replay/test_fuzzy.py | 1 - selfdrive/test/process_replay/test_imgproc.py | 1 - selfdrive/test/process_replay/test_processes.py | 1 - selfdrive/test/process_replay/test_regen.py | 2 -- selfdrive/test/test_onroad.py | 1 - selfdrive/test/test_time_to_onroad.py | 1 - selfdrive/test/test_updated.py | 1 - selfdrive/ui/tests/test_soundd.py | 2 -- selfdrive/ui/tests/test_translations.py | 1 - system/athena/tests/test_athenad.py | 1 - system/athena/tests/test_athenad_ping.py | 1 - system/athena/tests/test_registration.py | 1 - system/camerad/test/test_camerad.py | 1 - system/camerad/test/test_exposure.py | 1 - system/hardware/tici/tests/test_agnos_updater.py | 1 - system/hardware/tici/tests/test_amplifier.py | 1 - system/hardware/tici/tests/test_hardware.py | 1 - system/hardware/tici/tests/test_power_draw.py | 1 - system/loggerd/tests/test_deleter.py | 1 - system/loggerd/tests/test_encoder.py | 1 - system/loggerd/tests/test_loggerd.py | 1 - system/loggerd/tests/test_uploader.py | 1 - system/manager/test/test_manager.py | 1 - system/qcomgpsd/tests/test_qcomgpsd.py | 1 - system/sensord/tests/test_sensord.py | 1 - system/tests/test_logmessaged.py | 1 - system/thermald/tests/test_fan_controller.py | 1 - system/thermald/tests/test_power_monitoring.py | 1 - system/ubloxd/tests/test_pigeond.py | 1 - system/updated/casync/tests/test_casync.py | 1 - system/webrtc/tests/test_stream_session.py | 1 - system/webrtc/tests/test_webrtcd.py | 1 - third_party/acados/acados_template/gnsf/__init__.py | 1 - tools/car_porting/test_car_model.py | 1 - tools/lib/tests/test_caching.py | 1 - tools/lib/tests/test_logreader.py | 1 - tools/lib/tests/test_readers.py | 1 - tools/lib/tests/test_route_library.py | 1 - tools/plotjuggler/test_plotjuggler.py | 1 - tools/sim/tests/test_metadrive_bridge.py | 1 - 78 files changed, 5 insertions(+), 85 deletions(-) mode change 100755 => 100644 common/transformations/tests/test_coordinates.py mode change 100755 => 100644 common/transformations/tests/test_orientation.py mode change 100755 => 100644 selfdrive/boardd/tests/test_boardd_loopback.py mode change 100755 => 100644 selfdrive/boardd/tests/test_boardd_spi.py mode change 100755 => 100644 selfdrive/boardd/tests/test_pandad.py mode change 100755 => 100644 selfdrive/car/ford/tests/test_ford.py mode change 100755 => 100644 selfdrive/car/gm/tests/test_gm.py mode change 100755 => 100644 selfdrive/car/honda/tests/test_honda.py mode change 100755 => 100644 selfdrive/car/hyundai/tests/test_hyundai.py mode change 100755 => 100644 selfdrive/car/tests/test_can_fingerprint.py mode change 100755 => 100644 selfdrive/car/tests/test_car_interfaces.py mode change 100755 => 100644 selfdrive/car/tests/test_docs.py mode change 100755 => 100644 selfdrive/car/tests/test_fingerprints.py mode change 100755 => 100644 selfdrive/car/tests/test_fw_fingerprint.py mode change 100755 => 100644 selfdrive/car/tests/test_lateral_limits.py mode change 100755 => 100644 selfdrive/car/tests/test_models.py mode change 100755 => 100644 selfdrive/car/tests/test_platform_configs.py mode change 100755 => 100644 selfdrive/car/toyota/tests/test_toyota.py mode change 100755 => 100644 selfdrive/car/volkswagen/tests/test_volkswagen.py mode change 100755 => 100644 selfdrive/controls/lib/tests/test_alertmanager.py mode change 100755 => 100644 selfdrive/controls/lib/tests/test_latcontrol.py mode change 100755 => 100644 selfdrive/controls/lib/tests/test_vehicle_model.py mode change 100755 => 100644 selfdrive/controls/tests/test_alerts.py mode change 100755 => 100644 selfdrive/controls/tests/test_cruise_speed.py mode change 100755 => 100644 selfdrive/controls/tests/test_following_distance.py mode change 100755 => 100644 selfdrive/controls/tests/test_leads.py mode change 100755 => 100644 selfdrive/controls/tests/test_state_machine.py mode change 100755 => 100644 selfdrive/debug/test_fw_query_on_routes.py mode change 100755 => 100644 selfdrive/locationd/test/test_calibrationd.py mode change 100755 => 100644 selfdrive/locationd/test/test_locationd.py mode change 100755 => 100644 selfdrive/locationd/test/test_locationd_scenarios.py mode change 100755 => 100644 selfdrive/modeld/tests/test_modeld.py mode change 100755 => 100644 selfdrive/monitoring/test_monitoring.py mode change 100755 => 100644 selfdrive/navd/tests/test_map_renderer.py mode change 100755 => 100644 selfdrive/navd/tests/test_navd.py mode change 100755 => 100644 selfdrive/test/longitudinal_maneuvers/test_longitudinal.py mode change 100755 => 100644 selfdrive/test/process_replay/test_fuzzy.py mode change 100755 => 100644 selfdrive/test/process_replay/test_imgproc.py mode change 100755 => 100644 selfdrive/test/process_replay/test_processes.py mode change 100755 => 100644 selfdrive/test/process_replay/test_regen.py mode change 100755 => 100644 selfdrive/test/test_onroad.py mode change 100755 => 100644 selfdrive/test/test_time_to_onroad.py mode change 100755 => 100644 selfdrive/test/test_updated.py mode change 100755 => 100644 selfdrive/ui/tests/test_soundd.py mode change 100755 => 100644 selfdrive/ui/tests/test_translations.py mode change 100755 => 100644 system/athena/tests/test_athenad.py mode change 100755 => 100644 system/athena/tests/test_athenad_ping.py mode change 100755 => 100644 system/athena/tests/test_registration.py mode change 100755 => 100644 system/camerad/test/test_camerad.py mode change 100755 => 100644 system/camerad/test/test_exposure.py mode change 100755 => 100644 system/hardware/tici/tests/test_agnos_updater.py mode change 100755 => 100644 system/hardware/tici/tests/test_amplifier.py mode change 100755 => 100644 system/hardware/tici/tests/test_hardware.py mode change 100755 => 100644 system/hardware/tici/tests/test_power_draw.py mode change 100755 => 100644 system/loggerd/tests/test_deleter.py mode change 100755 => 100644 system/loggerd/tests/test_encoder.py mode change 100755 => 100644 system/loggerd/tests/test_loggerd.py mode change 100755 => 100644 system/loggerd/tests/test_uploader.py mode change 100755 => 100644 system/manager/test/test_manager.py mode change 100755 => 100644 system/qcomgpsd/tests/test_qcomgpsd.py mode change 100755 => 100644 system/sensord/tests/test_sensord.py mode change 100755 => 100644 system/tests/test_logmessaged.py mode change 100755 => 100644 system/thermald/tests/test_fan_controller.py mode change 100755 => 100644 system/thermald/tests/test_power_monitoring.py mode change 100755 => 100644 system/ubloxd/tests/test_pigeond.py mode change 100755 => 100644 system/updated/casync/tests/test_casync.py mode change 100755 => 100644 system/webrtc/tests/test_stream_session.py mode change 100755 => 100644 system/webrtc/tests/test_webrtcd.py mode change 100755 => 100644 tools/car_porting/test_car_model.py mode change 100755 => 100644 tools/lib/tests/test_caching.py mode change 100755 => 100644 tools/lib/tests/test_logreader.py mode change 100755 => 100644 tools/lib/tests/test_readers.py mode change 100755 => 100644 tools/lib/tests/test_route_library.py mode change 100755 => 100644 tools/plotjuggler/test_plotjuggler.py mode change 100755 => 100644 tools/sim/tests/test_metadrive_bridge.py diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index bc2338238..9392b9b8d 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -116,6 +116,8 @@ jobs: submodules: true - uses: ./.github/workflows/setup-pre-commit - uses: ./.github/workflows/setup-with-retry + - name: Build openpilot + run: ${{ env.RUN }} "scons -j$(nproc)" - name: pre-commit timeout-minutes: 4 run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all && chmod -R 777 /tmp/pre-commit" @@ -143,7 +145,7 @@ jobs: $PYTEST --timeout 60 -m 'not slow' && \ ./selfdrive/ui/tests/create_test_translations.sh && \ QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \ - ./selfdrive/ui/tests/test_translations.py" + pytest ./selfdrive/ui/tests/test_translations.py" - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v4 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 28f8acd6e..68d303cd6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -86,8 +86,8 @@ repos: hooks: - id: test_translations name: test translations - entry: selfdrive/ui/tests/test_translations.py - language: script + entry: pytest selfdrive/ui/tests/test_translations.py + language: system pass_filenames: false files: '^selfdrive/ui/translations/' - repo: https://github.com/python-poetry/poetry diff --git a/common/transformations/tests/test_coordinates.py b/common/transformations/tests/test_coordinates.py old mode 100755 new mode 100644 index 41076d9b3..11a6bf70e --- a/common/transformations/tests/test_coordinates.py +++ b/common/transformations/tests/test_coordinates.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import numpy as np import openpilot.common.transformations.coordinates as coord diff --git a/common/transformations/tests/test_orientation.py b/common/transformations/tests/test_orientation.py old mode 100755 new mode 100644 index 695642774..55fbc6581 --- a/common/transformations/tests/test_orientation.py +++ b/common/transformations/tests/test_orientation.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import numpy as np from openpilot.common.transformations.orientation import euler2quat, quat2euler, euler2rot, rot2euler, \ diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py old mode 100755 new mode 100644 index fa9eb957c..9bb3a12e9 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import copy import random diff --git a/selfdrive/boardd/tests/test_boardd_spi.py b/selfdrive/boardd/tests/test_boardd_spi.py old mode 100755 new mode 100644 index d384caadd..b4f4ea137 --- a/selfdrive/boardd/tests/test_boardd_spi.py +++ b/selfdrive/boardd/tests/test_boardd_spi.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import time import numpy as np diff --git a/selfdrive/boardd/tests/test_pandad.py b/selfdrive/boardd/tests/test_pandad.py old mode 100755 new mode 100644 index 581b9813a..5c74b40ce --- a/selfdrive/boardd/tests/test_pandad.py +++ b/selfdrive/boardd/tests/test_pandad.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import pytest import time diff --git a/selfdrive/car/ford/tests/test_ford.py b/selfdrive/car/ford/tests/test_ford.py old mode 100755 new mode 100644 index 72dd69980..b1a19017d --- a/selfdrive/car/ford/tests/test_ford.py +++ b/selfdrive/car/ford/tests/test_ford.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import random from collections.abc import Iterable diff --git a/selfdrive/car/gm/tests/test_gm.py b/selfdrive/car/gm/tests/test_gm.py old mode 100755 new mode 100644 index 389d0636c..a0a4a94ff --- a/selfdrive/car/gm/tests/test_gm.py +++ b/selfdrive/car/gm/tests/test_gm.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from parameterized import parameterized from openpilot.selfdrive.car.gm.fingerprints import FINGERPRINTS diff --git a/selfdrive/car/honda/tests/test_honda.py b/selfdrive/car/honda/tests/test_honda.py old mode 100755 new mode 100644 index 54d177d2e..b8ad7872b --- a/selfdrive/car/honda/tests/test_honda.py +++ b/selfdrive/car/honda/tests/test_honda.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import re from openpilot.selfdrive.car.honda.fingerprints import FW_VERSIONS diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py old mode 100755 new mode 100644 index db2110b0d..4d31d7d15 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from hypothesis import settings, given, strategies as st import pytest diff --git a/selfdrive/car/tests/test_can_fingerprint.py b/selfdrive/car/tests/test_can_fingerprint.py old mode 100755 new mode 100644 index bb585d567..f236986d8 --- a/selfdrive/car/tests/test_can_fingerprint.py +++ b/selfdrive/car/tests/test_can_fingerprint.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from parameterized import parameterized from cereal import log, messaging diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py old mode 100755 new mode 100644 index 618bcd962..19096c23e --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import math import hypothesis.strategies as st diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py old mode 100755 new mode 100644 index 0ed95e18f..40ad07b28 --- a/selfdrive/car/tests/test_docs.py +++ b/selfdrive/car/tests/test_docs.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from collections import defaultdict import os import pytest diff --git a/selfdrive/car/tests/test_fingerprints.py b/selfdrive/car/tests/test_fingerprints.py old mode 100755 new mode 100644 index 34f30bc70..6575d3e5c --- a/selfdrive/car/tests/test_fingerprints.py +++ b/selfdrive/car/tests/test_fingerprints.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import sys diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py old mode 100755 new mode 100644 index 230e6f10e..f87297254 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import random import time diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py old mode 100755 new mode 100644 index a478bc601..39cdb9a74 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from collections import defaultdict import importlib from parameterized import parameterized_class diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py old mode 100755 new mode 100644 index 8807db69d..b5d75e665 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import capnp import os import importlib diff --git a/selfdrive/car/tests/test_platform_configs.py b/selfdrive/car/tests/test_platform_configs.py old mode 100755 new mode 100644 index 217189255..31e4be4fe --- a/selfdrive/car/tests/test_platform_configs.py +++ b/selfdrive/car/tests/test_platform_configs.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - from openpilot.selfdrive.car.values import PLATFORMS diff --git a/selfdrive/car/toyota/tests/test_toyota.py b/selfdrive/car/toyota/tests/test_toyota.py old mode 100755 new mode 100644 index ef49e0055..0217a0fbc --- a/selfdrive/car/toyota/tests/test_toyota.py +++ b/selfdrive/car/toyota/tests/test_toyota.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from hypothesis import given, settings, strategies as st from cereal import car diff --git a/selfdrive/car/volkswagen/tests/test_volkswagen.py b/selfdrive/car/volkswagen/tests/test_volkswagen.py old mode 100755 new mode 100644 index 561d28b9f..000257810 --- a/selfdrive/car/volkswagen/tests/test_volkswagen.py +++ b/selfdrive/car/volkswagen/tests/test_volkswagen.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import random import re diff --git a/selfdrive/controls/lib/tests/test_alertmanager.py b/selfdrive/controls/lib/tests/test_alertmanager.py old mode 100755 new mode 100644 index c234cc49d..8b9c18a9d --- a/selfdrive/controls/lib/tests/test_alertmanager.py +++ b/selfdrive/controls/lib/tests/test_alertmanager.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import random from openpilot.selfdrive.controls.lib.events import Alert, EVENTS diff --git a/selfdrive/controls/lib/tests/test_latcontrol.py b/selfdrive/controls/lib/tests/test_latcontrol.py old mode 100755 new mode 100644 index b731bbd95..81411edec --- a/selfdrive/controls/lib/tests/test_latcontrol.py +++ b/selfdrive/controls/lib/tests/test_latcontrol.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from parameterized import parameterized from cereal import car, log diff --git a/selfdrive/controls/lib/tests/test_vehicle_model.py b/selfdrive/controls/lib/tests/test_vehicle_model.py old mode 100755 new mode 100644 index 2efcf2fbb..4d0e41805 --- a/selfdrive/controls/lib/tests/test_vehicle_model.py +++ b/selfdrive/controls/lib/tests/test_vehicle_model.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import math diff --git a/selfdrive/controls/tests/test_alerts.py b/selfdrive/controls/tests/test_alerts.py old mode 100755 new mode 100644 index e29a6322a..38dc04594 --- a/selfdrive/controls/tests/test_alerts.py +++ b/selfdrive/controls/tests/test_alerts.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import copy import json import os diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py old mode 100755 new mode 100644 index 6c46285e8..8f451a49b --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import itertools import numpy as np diff --git a/selfdrive/controls/tests/test_following_distance.py b/selfdrive/controls/tests/test_following_distance.py old mode 100755 new mode 100644 index 89a575a9a..0fd543dd6 --- a/selfdrive/controls/tests/test_following_distance.py +++ b/selfdrive/controls/tests/test_following_distance.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import itertools from parameterized import parameterized_class diff --git a/selfdrive/controls/tests/test_leads.py b/selfdrive/controls/tests/test_leads.py old mode 100755 new mode 100644 index f4e97725f..f1f4449af --- a/selfdrive/controls/tests/test_leads.py +++ b/selfdrive/controls/tests/test_leads.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import cereal.messaging as messaging from openpilot.selfdrive.test.process_replay import replay_process_with_name diff --git a/selfdrive/controls/tests/test_state_machine.py b/selfdrive/controls/tests/test_state_machine.py old mode 100755 new mode 100644 index b92724ce4..b6ec512dc --- a/selfdrive/controls/tests/test_state_machine.py +++ b/selfdrive/controls/tests/test_state_machine.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - from cereal import car, log from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car.car_helpers import interfaces diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py old mode 100755 new mode 100644 index e338110a7..73c913858 --- a/selfdrive/debug/test_fw_query_on_routes.py +++ b/selfdrive/debug/test_fw_query_on_routes.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # type: ignore from collections import defaultdict diff --git a/selfdrive/locationd/test/test_calibrationd.py b/selfdrive/locationd/test/test_calibrationd.py old mode 100755 new mode 100644 index 598d5d2d5..df61b6a7c --- a/selfdrive/locationd/test/test_calibrationd.py +++ b/selfdrive/locationd/test/test_calibrationd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import random import numpy as np diff --git a/selfdrive/locationd/test/test_locationd.py b/selfdrive/locationd/test/test_locationd.py old mode 100755 new mode 100644 index f88f423cf..74ac7d296 --- a/selfdrive/locationd/test/test_locationd.py +++ b/selfdrive/locationd/test/test_locationd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import json import random diff --git a/selfdrive/locationd/test/test_locationd_scenarios.py b/selfdrive/locationd/test/test_locationd_scenarios.py old mode 100755 new mode 100644 index be95c6fff..ca52bffee --- a/selfdrive/locationd/test/test_locationd_scenarios.py +++ b/selfdrive/locationd/test/test_locationd_scenarios.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import numpy as np from collections import defaultdict diff --git a/selfdrive/modeld/tests/test_modeld.py b/selfdrive/modeld/tests/test_modeld.py old mode 100755 new mode 100644 index 5cbdbc2bb..413057931 --- a/selfdrive/modeld/tests/test_modeld.py +++ b/selfdrive/modeld/tests/test_modeld.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import numpy as np import random diff --git a/selfdrive/monitoring/test_monitoring.py b/selfdrive/monitoring/test_monitoring.py old mode 100755 new mode 100644 index a960a379e..f750437dc --- a/selfdrive/monitoring/test_monitoring.py +++ b/selfdrive/monitoring/test_monitoring.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import numpy as np from cereal import car, log diff --git a/selfdrive/navd/tests/test_map_renderer.py b/selfdrive/navd/tests/test_map_renderer.py old mode 100755 new mode 100644 index 52b594a57..6d66528ae --- a/selfdrive/navd/tests/test_map_renderer.py +++ b/selfdrive/navd/tests/test_map_renderer.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import time import numpy as np import os diff --git a/selfdrive/navd/tests/test_navd.py b/selfdrive/navd/tests/test_navd.py old mode 100755 new mode 100644 index 3d899ba28..b6580acff --- a/selfdrive/navd/tests/test_navd.py +++ b/selfdrive/navd/tests/test_navd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import json import random import numpy as np diff --git a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py old mode 100755 new mode 100644 index 0ad6d6d4f..62a95babe --- a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py +++ b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import itertools from parameterized import parameterized_class diff --git a/selfdrive/test/process_replay/test_fuzzy.py b/selfdrive/test/process_replay/test_fuzzy.py old mode 100755 new mode 100644 index 6bcc94911..c802d9c57 --- a/selfdrive/test/process_replay/test_fuzzy.py +++ b/selfdrive/test/process_replay/test_fuzzy.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import copy from hypothesis import given, HealthCheck, Phase, settings import hypothesis.strategies as st diff --git a/selfdrive/test/process_replay/test_imgproc.py b/selfdrive/test/process_replay/test_imgproc.py old mode 100755 new mode 100644 index 036f21b9e..27d0541a5 --- a/selfdrive/test/process_replay/test_imgproc.py +++ b/selfdrive/test/process_replay/test_imgproc.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import numpy as np import hashlib diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py old mode 100755 new mode 100644 index 533ab125f..ae844ac9b --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import argparse import concurrent.futures import os diff --git a/selfdrive/test/process_replay/test_regen.py b/selfdrive/test/process_replay/test_regen.py old mode 100755 new mode 100644 index c27d9e8f7..17fefcb49 --- a/selfdrive/test/process_replay/test_regen.py +++ b/selfdrive/test/process_replay/test_regen.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - from parameterized import parameterized from openpilot.selfdrive.test.process_replay.regen import regen_segment, DummyFrameReader diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py old mode 100755 new mode 100644 index 8b60b9650..2e2b40d03 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import bz2 import math import json diff --git a/selfdrive/test/test_time_to_onroad.py b/selfdrive/test/test_time_to_onroad.py old mode 100755 new mode 100644 index 11de5283b..e08d0e676 --- a/selfdrive/test/test_time_to_onroad.py +++ b/selfdrive/test/test_time_to_onroad.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import pytest import time diff --git a/selfdrive/test/test_updated.py b/selfdrive/test/test_updated.py old mode 100755 new mode 100644 index 12619d424..f8eae9482 --- a/selfdrive/test/test_updated.py +++ b/selfdrive/test/test_updated.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import datetime import os import pytest diff --git a/selfdrive/ui/tests/test_soundd.py b/selfdrive/ui/tests/test_soundd.py old mode 100755 new mode 100644 index d15a6c183..468bc92cc --- a/selfdrive/ui/tests/test_soundd.py +++ b/selfdrive/ui/tests/test_soundd.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - from cereal import car from cereal import messaging from cereal.messaging import SubMaster, PubMaster diff --git a/selfdrive/ui/tests/test_translations.py b/selfdrive/ui/tests/test_translations.py old mode 100755 new mode 100644 index 57de069d0..0967152fa --- a/selfdrive/ui/tests/test_translations.py +++ b/selfdrive/ui/tests/test_translations.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import json import os diff --git a/system/athena/tests/test_athenad.py b/system/athena/tests/test_athenad.py old mode 100755 new mode 100644 index 895cd8eb5..48519a0ff --- a/system/athena/tests/test_athenad.py +++ b/system/athena/tests/test_athenad.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest from functools import wraps import json diff --git a/system/athena/tests/test_athenad_ping.py b/system/athena/tests/test_athenad_ping.py old mode 100755 new mode 100644 index 4fda13dfe..73fe7783a --- a/system/athena/tests/test_athenad_ping.py +++ b/system/athena/tests/test_athenad_ping.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import subprocess import threading diff --git a/system/athena/tests/test_registration.py b/system/athena/tests/test_registration.py old mode 100755 new mode 100644 index 85c065c1b..4f663fbc0 --- a/system/athena/tests/test_registration.py +++ b/system/athena/tests/test_registration.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import json from Crypto.PublicKey import RSA from pathlib import Path diff --git a/system/camerad/test/test_camerad.py b/system/camerad/test/test_camerad.py old mode 100755 new mode 100644 index dcc982563..ada959489 --- a/system/camerad/test/test_camerad.py +++ b/system/camerad/test/test_camerad.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import time import numpy as np diff --git a/system/camerad/test/test_exposure.py b/system/camerad/test/test_exposure.py old mode 100755 new mode 100644 index 36e8522b1..dbe6f3d88 --- a/system/camerad/test/test_exposure.py +++ b/system/camerad/test/test_exposure.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import time import numpy as np diff --git a/system/hardware/tici/tests/test_agnos_updater.py b/system/hardware/tici/tests/test_agnos_updater.py old mode 100755 new mode 100644 index 462cf6cb5..a1bbd363f --- a/system/hardware/tici/tests/test_agnos_updater.py +++ b/system/hardware/tici/tests/test_agnos_updater.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import json import os import requests diff --git a/system/hardware/tici/tests/test_amplifier.py b/system/hardware/tici/tests/test_amplifier.py old mode 100755 new mode 100644 index dfba84b94..3f75436db --- a/system/hardware/tici/tests/test_amplifier.py +++ b/system/hardware/tici/tests/test_amplifier.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import time import random diff --git a/system/hardware/tici/tests/test_hardware.py b/system/hardware/tici/tests/test_hardware.py old mode 100755 new mode 100644 index 49d4ac769..30eed7e0d --- a/system/hardware/tici/tests/test_hardware.py +++ b/system/hardware/tici/tests/test_hardware.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import time import numpy as np diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py old mode 100755 new mode 100644 index 1fe063c8e..866f7d118 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from collections import defaultdict, deque import pytest import time diff --git a/system/loggerd/tests/test_deleter.py b/system/loggerd/tests/test_deleter.py old mode 100755 new mode 100644 index 3ba6ad403..6222ea253 --- a/system/loggerd/tests/test_deleter.py +++ b/system/loggerd/tests/test_deleter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import time import threading from collections import namedtuple diff --git a/system/loggerd/tests/test_encoder.py b/system/loggerd/tests/test_encoder.py old mode 100755 new mode 100644 index ddf074d3b..7289d9ede --- a/system/loggerd/tests/test_encoder.py +++ b/system/loggerd/tests/test_encoder.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import math import os import pytest diff --git a/system/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py old mode 100755 new mode 100644 index d3789badb..882ce99ed --- a/system/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import numpy as np import os import re diff --git a/system/loggerd/tests/test_uploader.py b/system/loggerd/tests/test_uploader.py old mode 100755 new mode 100644 index c0a9770e5..659119828 --- a/system/loggerd/tests/test_uploader.py +++ b/system/loggerd/tests/test_uploader.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import time import threading diff --git a/system/manager/test/test_manager.py b/system/manager/test/test_manager.py old mode 100755 new mode 100644 index af8397b24..e5960d111 --- a/system/manager/test/test_manager.py +++ b/system/manager/test/test_manager.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import pytest import signal diff --git a/system/qcomgpsd/tests/test_qcomgpsd.py b/system/qcomgpsd/tests/test_qcomgpsd.py old mode 100755 new mode 100644 index 33d6e5b78..ef23737dd --- a/system/qcomgpsd/tests/test_qcomgpsd.py +++ b/system/qcomgpsd/tests/test_qcomgpsd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import pytest import json diff --git a/system/sensord/tests/test_sensord.py b/system/sensord/tests/test_sensord.py old mode 100755 new mode 100644 index aed3b07b3..1871012dd --- a/system/sensord/tests/test_sensord.py +++ b/system/sensord/tests/test_sensord.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import pytest import time diff --git a/system/tests/test_logmessaged.py b/system/tests/test_logmessaged.py old mode 100755 new mode 100644 index f8c5be09b..3baf5300c --- a/system/tests/test_logmessaged.py +++ b/system/tests/test_logmessaged.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import glob import os import time diff --git a/system/thermald/tests/test_fan_controller.py b/system/thermald/tests/test_fan_controller.py old mode 100755 new mode 100644 index 5c858132a..ffbf180ac --- a/system/thermald/tests/test_fan_controller.py +++ b/system/thermald/tests/test_fan_controller.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest from openpilot.system.thermald.fan_controller import TiciFanController diff --git a/system/thermald/tests/test_power_monitoring.py b/system/thermald/tests/test_power_monitoring.py old mode 100755 new mode 100644 index 0795a29c8..95166094b --- a/system/thermald/tests/test_power_monitoring.py +++ b/system/thermald/tests/test_power_monitoring.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest from openpilot.common.params import Params diff --git a/system/ubloxd/tests/test_pigeond.py b/system/ubloxd/tests/test_pigeond.py old mode 100755 new mode 100644 index cd3ad9305..202820e41 --- a/system/ubloxd/tests/test_pigeond.py +++ b/system/ubloxd/tests/test_pigeond.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import time diff --git a/system/updated/casync/tests/test_casync.py b/system/updated/casync/tests/test_casync.py old mode 100755 new mode 100644 index 29cf78f0f..bc171e743 --- a/system/updated/casync/tests/test_casync.py +++ b/system/updated/casync/tests/test_casync.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import os import pathlib diff --git a/system/webrtc/tests/test_stream_session.py b/system/webrtc/tests/test_stream_session.py old mode 100755 new mode 100644 index d8defab13..fa22915db --- a/system/webrtc/tests/test_stream_session.py +++ b/system/webrtc/tests/test_stream_session.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import asyncio import json # for aiortc and its dependencies diff --git a/system/webrtc/tests/test_webrtcd.py b/system/webrtc/tests/test_webrtcd.py old mode 100755 new mode 100644 index b0bc7b196..309058fb7 --- a/system/webrtc/tests/test_webrtcd.py +++ b/system/webrtc/tests/test_webrtcd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import pytest import asyncio import json diff --git a/third_party/acados/acados_template/gnsf/__init__.py b/third_party/acados/acados_template/gnsf/__init__.py index 8b1378917..e69de29bb 100644 --- a/third_party/acados/acados_template/gnsf/__init__.py +++ b/third_party/acados/acados_template/gnsf/__init__.py @@ -1 +0,0 @@ - diff --git a/tools/car_porting/test_car_model.py b/tools/car_porting/test_car_model.py old mode 100755 new mode 100644 index cf0be1a80..b96f81075 --- a/tools/car_porting/test_car_model.py +++ b/tools/car_porting/test_car_model.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import argparse import sys import unittest # noqa: TID251 diff --git a/tools/lib/tests/test_caching.py b/tools/lib/tests/test_caching.py old mode 100755 new mode 100644 index 32f55df5d..2bb63b4dc --- a/tools/lib/tests/test_caching.py +++ b/tools/lib/tests/test_caching.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import http.server import os import shutil diff --git a/tools/lib/tests/test_logreader.py b/tools/lib/tests/test_logreader.py old mode 100755 new mode 100644 index 58d22a07e..6bc7ba877 --- a/tools/lib/tests/test_logreader.py +++ b/tools/lib/tests/test_logreader.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import capnp import contextlib import io diff --git a/tools/lib/tests/test_readers.py b/tools/lib/tests/test_readers.py old mode 100755 new mode 100644 index f92554872..624531a1a --- a/tools/lib/tests/test_readers.py +++ b/tools/lib/tests/test_readers.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import pytest import requests import tempfile diff --git a/tools/lib/tests/test_route_library.py b/tools/lib/tests/test_route_library.py old mode 100755 new mode 100644 index 8f75fa19c..491bb8132 --- a/tools/lib/tests/test_route_library.py +++ b/tools/lib/tests/test_route_library.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python from collections import namedtuple from openpilot.tools.lib.route import SegmentName diff --git a/tools/plotjuggler/test_plotjuggler.py b/tools/plotjuggler/test_plotjuggler.py old mode 100755 new mode 100644 index b9a55297e..a2c509f94 --- a/tools/plotjuggler/test_plotjuggler.py +++ b/tools/plotjuggler/test_plotjuggler.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import glob import signal diff --git a/tools/sim/tests/test_metadrive_bridge.py b/tools/sim/tests/test_metadrive_bridge.py old mode 100755 new mode 100644 index f06110184..8849e901c --- a/tools/sim/tests/test_metadrive_bridge.py +++ b/tools/sim/tests/test_metadrive_bridge.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import pytest import warnings From 69f57fb6a890ed17b7ed8e908a870354e5d5d55b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 3 Jun 2024 17:05:06 -0700 Subject: [PATCH 123/220] boardd: check CAN in SPI test (#32400) * test * little more --------- Co-authored-by: Comma Device --- .../boardd/tests/test_boardd_loopback.py | 2 ++ selfdrive/boardd/tests/test_boardd_spi.py | 36 +++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index 9bb3a12e9..3f5cc5a74 100644 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -8,6 +8,7 @@ from pprint import pprint import cereal.messaging as messaging from cereal import car, log +from openpilot.common.retry import retry from openpilot.common.params import Params from openpilot.common.timeout import Timeout from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp @@ -16,6 +17,7 @@ from openpilot.system.hardware import TICI from openpilot.selfdrive.test.helpers import phone_only, with_processes +@retry(attempts=3) def setup_boardd(num_pandas): params = Params() params.put_bool("IsOnroad", False) diff --git a/selfdrive/boardd/tests/test_boardd_spi.py b/selfdrive/boardd/tests/test_boardd_spi.py index b4f4ea137..3bb41155d 100644 --- a/selfdrive/boardd/tests/test_boardd_spi.py +++ b/selfdrive/boardd/tests/test_boardd_spi.py @@ -2,12 +2,13 @@ import os import time import numpy as np import pytest +import random import cereal.messaging as messaging from cereal.services import SERVICE_LIST from openpilot.system.hardware import HARDWARE from openpilot.selfdrive.test.helpers import phone_only, with_processes -from openpilot.selfdrive.boardd.tests.test_boardd_loopback import setup_boardd +from openpilot.selfdrive.boardd.tests.test_boardd_loopback import setup_boardd, send_random_can_messages @pytest.mark.tici @@ -18,6 +19,7 @@ class TestBoarddSpi: pytest.skip("only for spi pandas") os.environ['STARTED'] = '1' os.environ['BOARDD_LOOPBACK'] = '1' + #os.environ['SPI_ERR_PROB'] = '-1' os.environ['SPI_ERR_PROB'] = '0.001' @phone_only @@ -25,30 +27,48 @@ class TestBoarddSpi: def test_spi_corruption(self, subtests): setup_boardd(1) + sendcan = messaging.pub_sock('sendcan') socks = {s: messaging.sub_sock(s, conflate=False, timeout=100) for s in ('can', 'pandaStates', 'peripheralState')} time.sleep(2) for s in socks.values(): messaging.drain_sock_raw(s) + total_recv_count = 0 + total_sent_count = 0 + sent_msgs = {bus: list() for bus in range(3)} + st = time.monotonic() ts = {s: list() for s in socks.keys()} for _ in range(20): + # send some CAN messages + sent = send_random_can_messages(sendcan, random.randrange(2, 20)) + for k, v in sent.items(): + sent_msgs[k].extend(list(v)) + total_sent_count += len(v) + for service, sock in socks.items(): for m in messaging.drain_sock(sock): ts[service].append(m.logMonoTime) # sanity check for corruption - assert m.valid + assert m.valid or (service == "can") if service == "can": - assert len(m.can) == 0 + for msg in m.can: + if msg.src > 4: + continue + key = (msg.address, msg.dat) + assert key in sent_msgs[msg.src], f"got unexpected msg: {msg.src=} {msg.address=} {msg.dat=}" + # TODO: enable this + #sent_msgs[msg.src].remove(key) + total_recv_count += 1 elif service == "pandaStates": assert len(m.pandaStates) == 1 ps = m.pandaStates[0] - assert ps.uptime < 100 + assert ps.uptime < 1000 assert ps.pandaType == "tres" assert ps.ignitionLine assert not ps.ignitionCan - assert ps.voltage < 14000 + assert 4000 < ps.voltage < 14000 elif service == "peripheralState": ps = m.peripheralState assert ps.pandaType == "tres" @@ -66,6 +86,10 @@ class TestBoarddSpi: with subtests.test(msg="timing check", service=service): edt = 1e3 / SERVICE_LIST[service].frequency assert edt*0.9 < np.mean(dts) < edt*1.1 - assert np.max(dts) < edt*3 + assert np.max(dts) < edt*20 assert np.min(dts) < edt assert len(dts) >= ((et-0.5)*SERVICE_LIST[service].frequency*0.8) + + with subtests.test(msg="CAN traffic"): + print(f"Sent {total_sent_count} CAN messages, got {total_recv_count} back. {total_recv_count/total_sent_count:.2%} received") + assert total_recv_count > 20 From 57a976118638be4868fd969ea7dfe5e66b7516f2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 3 Jun 2024 17:17:02 -0700 Subject: [PATCH 124/220] add pytest-repeat (#32612) --- poetry.lock | 3047 ++++++++++++++++++++++++------------------------ pyproject.toml | 1 + 2 files changed, 1536 insertions(+), 1512 deletions(-) diff --git a/poetry.lock b/poetry.lock index 23b2eb7b8..062d14fdc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -112,39 +112,42 @@ ifaddr = ">=0.2.0" [[package]] name = "aiortc" -version = "1.8.0" +version = "1.9.0" description = "An implementation of WebRTC and ORTC" optional = false python-versions = ">=3.8" files = [ - {file = "aiortc-1.8.0-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ac0bc48c9f98a744f6696be287b0403648deb3e20bd7f8fa91eb841e1c6c4e8d"}, - {file = "aiortc-1.8.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:639afa23b7d5c6f7d4f3f7af5fadb9cc67c82d56e17840b4433d2e5f73958bb5"}, - {file = "aiortc-1.8.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:173dcfa6f0e989f65eb9d38f151d8834677df0f696f9f4ad925ee9795e914eaf"}, - {file = "aiortc-1.8.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b453def215c246486747e8ba5c1307a538071d6bfbb2a4e74ebfef583771a429"}, - {file = "aiortc-1.8.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22efeb53dab9eb58a1a6c2dcdeb72ae526de0a2b30334fc40782341df92a657d"}, - {file = "aiortc-1.8.0-cp38-abi3-win32.whl", hash = "sha256:4ec0c5c284c3345a9d994253ced4ad909acf9e375271a7ff01db165b09890ce8"}, - {file = "aiortc-1.8.0-cp38-abi3-win_amd64.whl", hash = "sha256:76454c55a59441a76f6ab7cd1218454389520d6a3cc9b0d13d428f6a3f2ebbcc"}, - {file = "aiortc-1.8.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b0eb1342595e386befcad56cd0f91cd5cd16daa7612ffc5c8abf7e5b58e529f5"}, - {file = "aiortc-1.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cbbdf78ac55e05d838fe4de326ed095ca6df1cd10d571958d2ef8f23792203b"}, - {file = "aiortc-1.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bb565acb623474d8052926f2ee768dbf1f87a71d271df78482319c0bec7c817"}, - {file = "aiortc-1.8.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd50def722eb6b999ebc831eca7bea79019d2eda71dc79f4219a9ab19d65c961"}, - {file = "aiortc-1.8.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4054f42f9ef875c67e38c0e86532e85e7ba528957052bc3d99e7c7caf273c456"}, - {file = "aiortc-1.8.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ef40f132262a670169121b888a448e1973e892f1ed8a5f5980ab05a12ee78a32"}, - {file = "aiortc-1.8.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e53d9f999104a2438c0c23f2cbc991c5e15e46c0fe71476d60c222b62e4c5a70"}, - {file = "aiortc-1.8.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a1ef2e0d657aaca42106558c7c8d6e84c7088d0b70bc1fe3f93c555c242e38"}, - {file = "aiortc-1.8.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:454012e08c9ef5027c2543d4e97b6f1323ce027ec395202478a7e431b2519c5b"}, - {file = "aiortc-1.8.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09dd2fad7a52f8fc66c86cdd2dd4d281b9815afd996e41301dd2706ccd57438a"}, - {file = "aiortc-1.8.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d669b635bbd8cf76fce63d3ceb83da5b219cea8bae4b566233f68618e69446cb"}, - {file = "aiortc-1.8.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ccc4da8821e7ecdd2179bc5eb7fd5f12e50db8fc6affdbc8baa55f3f14dd377"}, - {file = "aiortc-1.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29ba65bcb4c4cd1b25109d1e7ee5cf303654b757a3b7b59a28e162953e5f6c36"}, - {file = "aiortc-1.8.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1be4571e70e15b443f5b9ae651e24ac9dafb8b9abc1cdeb14e5f4bf028639944"}, - {file = "aiortc-1.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2e20fe3cb4a8b6db4f5e8f625ff1eb9dafc67b7c0c9a0cb9969b646570aebd34"}, - {file = "aiortc-1.8.0.tar.gz", hash = "sha256:2363c08d1d2cb3aaed563c1fb256f5dae9f3ba75b70ad5e5df6d448504122591"}, + {file = "aiortc-1.9.0-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e3e67c1970c2cffacac53c8f161df264efc62b22721c64a621940935028ee087"}, + {file = "aiortc-1.9.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d893cb3d4ffa0ff4f9bb03a88f0a700cdbcd4c0dc060a46c59a27ccd1c890663"}, + {file = "aiortc-1.9.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:176b4eb38d833667f87cf719a7a3e105e25a35b138b30893294418c1c96e38db"}, + {file = "aiortc-1.9.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44b610f36b8d17123855dfbe915fa6874201765b8a2c7fd9cf72d14cf417740"}, + {file = "aiortc-1.9.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55505adb31d56cba19a1ef8ad6aa9b727ccdba2a83bfbfb4aa79ef3c472026a6"}, + {file = "aiortc-1.9.0-cp38-abi3-win32.whl", hash = "sha256:680b703e35870e301535c930bfe32e7d012224a91ce51531aba45a3124ef07cc"}, + {file = "aiortc-1.9.0-cp38-abi3-win_amd64.whl", hash = "sha256:de5e7020cfc2d2d9fb95690926ff2e3b3c30cd4f5f5bc68d5b6756a8eebb686e"}, + {file = "aiortc-1.9.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34c516ae4e70e8f64494305057af09311444325722fe6938ec38dd1e111adca9"}, + {file = "aiortc-1.9.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:40e61c1b84914d6f4c2968ff49353a22eed9419de74b151237cdb71af431209c"}, + {file = "aiortc-1.9.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1924e130a441507b1315956aff05c504a274f1a09802def225d0f3a3d1870320"}, + {file = "aiortc-1.9.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb62950e396c311e398925149fa76bc90b8d6525b4eccf28cba704e7ded8bf5"}, + {file = "aiortc-1.9.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5234177e8d3126a0190ed9b6f8d0288daedcc0158c45cc279b4e6ac7d97f43f8"}, + {file = "aiortc-1.9.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0e31575eb050aa68e0ea4c519aef101770b2297954f49e64a5c3d73ef27702ea"}, + {file = "aiortc-1.9.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:33018ce36186142e8a5eccca53189ff30c6d48d3d4d0c3df952fbf80f59f17d7"}, + {file = "aiortc-1.9.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d8cec50d8dcb1ea089378f885cb780357842ac39b7cb0e9361e5143c0126ecc"}, + {file = "aiortc-1.9.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8f73ee2d738208c10bb9be8bd2dc0d7da7621de1bbd5ab709216dfa681f4585"}, + {file = "aiortc-1.9.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84f16cb2a654d4e5018c8aba45e77882c75bf50c6af4eee3048ddb35af7f0c8f"}, + {file = "aiortc-1.9.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23df191d42b2937214263471a796502fcb8f86980e6b676aedbd188107e2a11d"}, + {file = "aiortc-1.9.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:9e7bf1c892f7b0a474e85f7e2c462775dbb5a79d6bd6450cf0d0784804629020"}, + {file = "aiortc-1.9.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bc9692a1b67f4eea8d3f22785b6ac9bc9c3d98478fd2326f99247ebf432b05d1"}, + {file = "aiortc-1.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4d0321824d24e3db918d2e494d44f2bc4467c8abd70646bbd57a5a5a49b72583"}, + {file = "aiortc-1.9.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7eeabe29472c9e3bb73fb58d5ad3b017269046d43189532e6ec64359c5697b8"}, + {file = "aiortc-1.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51f030e175569962df436d61953162da7a7c5e3d691adec660b5eee72dbba56"}, + {file = "aiortc-1.9.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:928f136647e609eca0028f7aaf3812fff4e3a4e0fe78abdc19dd0786e65ffac8"}, + {file = "aiortc-1.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1107acead0fa97e2f039d3cf00179a8b12b35822372b922f6b9f007145b171d3"}, + {file = "aiortc-1.9.0.tar.gz", hash = "sha256:03faa76d76ef0e5989ac10386898b029369756102217230e2fcd4b029c50b303"}, ] [package.dependencies] aioice = ">=0.9.0,<1.0.0" -av = ">=9.0.0,<12.0.0" +av = ">=9.0.0,<13.0.0" cffi = ">=1.0.0" cryptography = ">=42.0.0" google-crc32c = ">=1.1" @@ -201,56 +204,60 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "av" -version = "11.0.0" +version = "12.1.0" description = "Pythonic bindings for FFmpeg's libraries." optional = false python-versions = ">=3.8" files = [ - {file = "av-11.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a01f13b37eb6d181e03bbbbda29093fe2d68f10755795188220acdc89560ec27"}, - {file = "av-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2236faee1b5d71dff3cdef81ef6eec22cc8b71dbfb45eb037e6437fe80f24e7"}, - {file = "av-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40543a08e5c84aecd2bc84da5d43548743201897f0ba21bf5ae3a4dcddefca2b"}, - {file = "av-11.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2907376884d956376aaf3bc1905fa4e0dcb9ba4e0d183e519392a19d89317d1b"}, - {file = "av-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8d5581dcdc81cd601e3ce036809f14da82c46ff187bcefe981ec819390e0ab0"}, - {file = "av-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:150490f2a62cfa470f3cb60f3a0060ff93afd807e2b7b3b0eeeb5a992eb8d67b"}, - {file = "av-11.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d9bac0de62f09e2cb4e2132b5a46a89bc31c898189aa285b484c17351d991afe"}, - {file = "av-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2122ff8bdace4ce50207920f37de472517921e2ca1f0503464f748fdb8e20506"}, - {file = "av-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:527d840697fee6ad4cf47eba987eaf30cd76bd96b2d20eaa907e166b9b8065c8"}, - {file = "av-11.0.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abeaedddfca9101886eb6fc47318c5f5ece8480d330d73aacf6917d7421981a2"}, - {file = "av-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13790fbb889b955baf885fe3761e923e85537ef414173465ec293177cedb7b99"}, - {file = "av-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc27e27f52480287f44226ad4ae3eb53346bf027959d0f00a9154530bd98b371"}, - {file = "av-11.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:892583e2c6b8c2500e5d24310f499caefcdaa2e48c8f7169ad41041aaaf4da11"}, - {file = "av-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6943679d70a9f4de974049e7ae2cf0b20afe0d7ddab650526c02a6cf9adcd08f"}, - {file = "av-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6d73b038ccf1df5c16bc643eee5c694fb7732e09375e2f4903c1f4ce90dfb72"}, - {file = "av-11.0.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c83422db3333e97b9680700df5185139352fc3a568b14179da3bdcbeb2f0e91b"}, - {file = "av-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8413900f6a3639e0088c018a3a516a1656d4d16799e7aa759a16ddf3bd268e2b"}, - {file = "av-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:908e49ee336223801d8f2f7dca5a1deb64e9d8256138b8e7a79013b682a6ebb5"}, - {file = "av-11.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:82411ae4a562da07b76028d2f349fb0e6a86aa78ad2b18d2d7bf5b06b17fba14"}, - {file = "av-11.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:621104bd63e38fa4eca554da3722b1aac329619de39152f27eec8999acc72342"}, - {file = "av-11.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:442878990c094455a16c10127edcc54bc4e78d355e6a13ad2a27608b0ecda38f"}, - {file = "av-11.0.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:658199c92987dc72511f5ee8ade62faef6234b7a04c8b5788de99e366be5e073"}, - {file = "av-11.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4b381665c49267b46f87297573898b85e5c41384750fee2e70267fbc4ba318"}, - {file = "av-11.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:60de14f71293e36ca4e297cc8a8460f0cf74f38a201694f3c6fc7f40301582f2"}, - {file = "av-11.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a90f04af96374dab94028a7471597bdfcf03083338b9be2eb8ca4805a8ec7ab5"}, - {file = "av-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8821ab2d23e4cb5c8abea6b08d2b1bfceca6af2d88fab1d1dc1b3ec7b34933c7"}, - {file = "av-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a92342ed307eeaf9509a6b0f3bafd4337c4880c851b50acc18df48c625b63b6"}, - {file = "av-11.0.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe3502975bc844f5d432c1f24d331bf6ef3e05532ebf06f7ed08b60719b8ea5"}, - {file = "av-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c278b3a4fd111b4c9190abe6b1a5ca358d5f91e851d470b62577b957e0187b09"}, - {file = "av-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:478aa1d54fbc3058ea65ff41086b6adbe1326b456a027d2f3b59dbe60b4ac2ca"}, - {file = "av-11.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e8df10bb2d56a981d02a8a0b41491912b76dad06305d174a2575ef55ad451100"}, - {file = "av-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b30c51e597785a89241bd61865faff2dbd3327856a8285a1e120dbf60e18348b"}, - {file = "av-11.0.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8b8bd92edb096699b306e7b090ad096925ca3bdae6f89656f023fa2a2da627d"}, - {file = "av-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9383af733abfc44f6fc29307a6c922fbf671ee343dc97b78b74eac6a2346a46d"}, - {file = "av-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a9df4a60579198b560f641cdfe4c2139948a70193ddc096b275f2cf6d94e3e04"}, - {file = "av-11.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8ae5f7ae0a7093fb813686d4aa4c554531f80a28480427f5c155da51b747eff0"}, - {file = "av-11.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50fb7d606f8236891d773c701d5650b93af8dbf78eeaac36fc7e1f7f64a9d664"}, - {file = "av-11.0.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:543e0f9bf6ff02dedbe66d906fbc89c8907c80a8ea7413fc3fed68ce4a6e9b44"}, - {file = "av-11.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:daa279c884457ab194ce78bdd89c0aa391af733da95fb3258d4c6eb8c258299a"}, - {file = "av-11.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1aacc21f4cf96447117a61edfb776afb73186750a5e08a21484ddfc3599aefb5"}, - {file = "av-11.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2568b38eef777b916a5d02e42b8f67f92e12023531239ddd32e1ca4f3cdf8c5b"}, - {file = "av-11.0.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:747c6d347e27c59cc2e78c9c505d23cd88eceff0cc9386be73693ae9009a577c"}, - {file = "av-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbd8f4941b9d3450eff40003b9b9d904667aec7ab085fa31f0f9bca32d755e0"}, - {file = "av-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f39c1244ba0cf185b2722aeec116b8a98a2ee5728ce687cec0bda60ee0360dfc"}, - {file = "av-11.0.0.tar.gz", hash = "sha256:48223f000a252070f8e700ff634bb7fb3aa1b7bc7e450373029fbdd6f369ac31"}, + {file = "av-12.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0df2ad330ccf63ed8192d637306f13123cdf1c06717168d1de8b9a084d62f70"}, + {file = "av-12.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e66ad48dc3f618cf4a75cc14dd7e119d1151ff3c13b9b064014c79bad20df85"}, + {file = "av-12.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0e8fbbe3cffd04dcbfaf7f9e0469c8c9d3ae962728487aae0dbbac9ebb62567"}, + {file = "av-12.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c24d21b116e3af45e2f4b3a7ff1c96ae9a266bcde33a689ace0c52888e74d9"}, + {file = "av-12.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eff59d1eb0ba263e9efe8e460ca239c6ee2285f1b92c6b3c64f002c1b2ffd56"}, + {file = "av-12.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:09f8bd1fd124e389a266c770d209b5b4333f69c4b5a66b9aa2d09a561b0b54ab"}, + {file = "av-12.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e4c409639699d75e85a5b4b9fbb0538388bb009c8b426f7976b218731815e645"}, + {file = "av-12.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f624a61d8062bb7128a4b0af018ef5c7642acff2af7cea1bb6cc5aa663954b77"}, + {file = "av-12.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73c61635e959dd50857f1ae3ad28984ce813688262672a5188376686dd293333"}, + {file = "av-12.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f8dcf20ecdfed62cb8b31790d3f394c76f05d5d58d5cc516f7b37c8608b78e2"}, + {file = "av-12.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebb11aba1ef2acb945713be5f4f7a359439230dc566243c354dddb2b06361367"}, + {file = "av-12.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a309994db77f632b606fe22c5bac03302e3dbe48d53c195abc435ccc56192746"}, + {file = "av-12.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:08401e59a9e33a42511d28cf1fdc570c31d3416426a2d73f4f4aaaaca5945c54"}, + {file = "av-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:efd45e3aa1e478ccbaafd84baf7d95d660b9cef30d850816129fd37d76813589"}, + {file = "av-12.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ab553ce72c631477181d6c08c6e710afa44fa3452e61b82d9a75be07b1b2fef"}, + {file = "av-12.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:555f3240306ff02169ff209b152f97b071b57957868c3004c65e25c28130d593"}, + {file = "av-12.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07706499489f2047b54a4675dd04e2cf88322caef904b7b6eb03f480e682cf15"}, + {file = "av-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:f669f5fb2515e9a4c9ee05b24ffbe3168d33c241bda93c84c8e384ca682a5cde"}, + {file = "av-12.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:876302ee793a457a03c4faa8281012671bb52dec843062bec59d6f0ae3735ba6"}, + {file = "av-12.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e6ad88e1e61e65c69d92ff1db8826686f913f147b427c99aa3202b027e766128"}, + {file = "av-12.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49a8f88b26d3d25140633a8ec48328a9467bbe001d01c54472394484cdb60b10"}, + {file = "av-12.1.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97873f344344b9b6aef786b22b57fb42c6eaa4ea0798d2020c5ed061f29ab3d6"}, + {file = "av-12.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdf4c54354580abbea9390e23a471a346e9a4b4ca19c6929ad11a59d525e2ad3"}, + {file = "av-12.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:dc1a82e7d43495be6d34b50fd917989a72de7c3a7434d8ec72af0952c1ad4ea3"}, + {file = "av-12.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41d13494401bd3968255f7f9af2af203c30b684efc5a7ed92ebe9ec37f9f9264"}, + {file = "av-12.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc36f7b74e88db8e73fa69dc869331da74abc4f034ecd55f85f6232fcdddca60"}, + {file = "av-12.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff7a43ce921f2cc3c794810b148c4fa2cfd7ff10f4404072c94cf57b39b13d"}, + {file = "av-12.1.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce02915698d605c19c372314b7894033a451e838300d0a45c2708a550044e2d1"}, + {file = "av-12.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eadd5c7c374c9ff889a9116802cdda7ef9d574b623338f4045effc0f3f3c2cbc"}, + {file = "av-12.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:f32893849fe34300f3cec51c4ae71c45b0acac448d36336d3452a5bb4f7e11bf"}, + {file = "av-12.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a0a2a8693fdaa3bbb00255cda388f110f7a0b00817470a8cd8f1aa5c8dcbc3c9"}, + {file = "av-12.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:615f440856cbc5b96b8ae52c75ba722f082b898c3ab837eae024a06a0914e8a6"}, + {file = "av-12.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257fe519b0ffb4e900b737515137fb9ae0490edca7d70818b6c71c3cd79994ca"}, + {file = "av-12.1.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04afe8f9005bb42f95717bcfbb22a8950b4b942a862444edb1f0bab71ea702e9"}, + {file = "av-12.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63cbeaedc0184094b7d36bd4267cd61e6c69c18cb3464cc726ce6a8a438ac87a"}, + {file = "av-12.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0a0e056baa87037f932d12de3d3f258cbc4284d18d85099ccd845b333ac1bb91"}, + {file = "av-12.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7d549c2e6e9035022ea2280b781150a8c81acc4a03c69bde20b2f53262041a88"}, + {file = "av-12.1.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b1e02715cbb985b0efe6b6aaf134f9d1fee760822a07fd19e995a8e461909f4"}, + {file = "av-12.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b348264ba26152d7b06f2aaf0b2a11c90b13c628a447f6daa2a6770b9443fb0"}, + {file = "av-12.1.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6a3b3e4138cd1977f14e3d16c5f89979de8efa251d7558e2dc10a51cfcc0100"}, + {file = "av-12.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:105b017958eb5b6a128a5399200a4ec2b1040c2047e0b5f5e3714cd64fe7046e"}, + {file = "av-12.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:00596e53db3082193142e32fbdf47349724221de117645b0ed8fcaaec508adf4"}, + {file = "av-12.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed7c48d2d79961d70ea59f44fcff453bb2444a152793f80d2ceaa17af4331b9c"}, + {file = "av-12.1.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d2c486adf83fc5b8e444efcc32f3eef27eefd6d0966ef68607d41205adcd8ec0"}, + {file = "av-12.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abe9475dd2c8bea47338d5e90d6a45a28930d0fe3820ed2d3d09dfbb3316d476"}, + {file = "av-12.1.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0130a8391aa258eee60da3c09d69eb5c9480f14a9f1b1b5312336bac879edd2a"}, + {file = "av-12.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669f206cfdd5696d0edf2c81c5d220acc40b4153b71cf6662618c376e00b6d3a"}, + {file = "av-12.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e322533f585c2e8df07aa708c594fcb67f5f27a2f8b4107a7e6a6f90606190c7"}, + {file = "av-12.1.0.tar.gz", hash = "sha256:67adab9fdabcb8a86bd542787196580e38ed4132331ee9e82234b23cea9546b3"}, ] [[package]] @@ -400,13 +407,13 @@ numpy = "*" [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -756,63 +763,63 @@ test = ["pytest", "pytest-timeout"] [[package]] name = "coverage" -version = "7.5.1" +version = "7.5.3" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e"}, - {file = "coverage-7.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b0ceee8147444347da6a66be737c9d78f3353b0681715b668b72e79203e4a"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a9ca3f2fae0088c3c71d743d85404cec8df9be818a005ea065495bedc33da35"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd215c0c7d7aab005221608a3c2b46f58c0285a819565887ee0b718c052aa4e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4bf0655ab60d754491004a5efd7f9cccefcc1081a74c9ef2da4735d6ee4a6223"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61c4bf1ba021817de12b813338c9be9f0ad5b1e781b9b340a6d29fc13e7c1b5e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db66fc317a046556a96b453a58eced5024af4582a8dbdc0c23ca4dbc0d5b3146"}, - {file = "coverage-7.5.1-cp310-cp310-win32.whl", hash = "sha256:b016ea6b959d3b9556cb401c55a37547135a587db0115635a443b2ce8f1c7228"}, - {file = "coverage-7.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:df4e745a81c110e7446b1cc8131bf986157770fa405fe90e15e850aaf7619bc8"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, - {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, - {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, - {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, - {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, - {file = "coverage-7.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2213def81a50519d7cc56ed643c9e93e0247f5bbe0d1247d15fa520814a7cd7"}, - {file = "coverage-7.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5037f8fcc2a95b1f0e80585bd9d1ec31068a9bcb157d9750a172836e98bc7a90"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3721c2c9e4c4953a41a26c14f4cef64330392a6d2d675c8b1db3b645e31f0e"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca498687ca46a62ae590253fba634a1fe9836bc56f626852fb2720f334c9e4e5"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cdcbc320b14c3e5877ee79e649677cb7d89ef588852e9583e6b24c2e5072661"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:57e0204b5b745594e5bc14b9b50006da722827f0b8c776949f1135677e88d0b8"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fe7502616b67b234482c3ce276ff26f39ffe88adca2acf0261df4b8454668b4"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9e78295f4144f9dacfed4f92935fbe1780021247c2fabf73a819b17f0ccfff8d"}, - {file = "coverage-7.5.1-cp38-cp38-win32.whl", hash = "sha256:1434e088b41594baa71188a17533083eabf5609e8e72f16ce8c186001e6b8c41"}, - {file = "coverage-7.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:0646599e9b139988b63704d704af8e8df7fa4cbc4a1f33df69d97f36cb0a38de"}, - {file = "coverage-7.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4cc37def103a2725bc672f84bd939a6fe4522310503207aae4d56351644682f1"}, - {file = "coverage-7.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc0b4d8bfeabd25ea75e94632f5b6e047eef8adaed0c2161ada1e922e7f7cece"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d0a0f5e06881ecedfe6f3dd2f56dcb057b6dbeb3327fd32d4b12854df36bf26"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9735317685ba6ec7e3754798c8871c2f49aa5e687cc794a0b1d284b2389d1bd5"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d21918e9ef11edf36764b93101e2ae8cc82aa5efdc7c5a4e9c6c35a48496d601"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3e757949f268364b96ca894b4c342b41dc6f8f8b66c37878aacef5930db61be"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:79afb6197e2f7f60c4824dd4b2d4c2ec5801ceb6ba9ce5d2c3080e5660d51a4f"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1d0d98d95dd18fe29dc66808e1accf59f037d5716f86a501fc0256455219668"}, - {file = "coverage-7.5.1-cp39-cp39-win32.whl", hash = "sha256:1cc0fe9b0b3a8364093c53b0b4c0c2dd4bb23acbec4c9240b5f284095ccf7981"}, - {file = "coverage-7.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:dde0070c40ea8bb3641e811c1cfbf18e265d024deff6de52c5950677a8fb1e0f"}, - {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, - {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, + {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, + {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, + {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, + {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, + {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, + {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, + {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, + {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, + {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, + {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, + {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, + {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, + {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, + {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, ] [package.extras] @@ -1152,53 +1159,53 @@ files = [ [[package]] name = "fonttools" -version = "4.52.1" +version = "4.53.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.52.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:67a30b872e79577e5319ce660ede4a5131fa8a45de76e696746545e17db4437f"}, - {file = "fonttools-4.52.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a5bff35738f8f6607c4303561ee1d1e5f64d5b14cf3c472d3030566c82e763"}, - {file = "fonttools-4.52.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c9622593dfff042480a1b7e5b72c4d7dc00b96d2b4f98b0bf8acf071087e0db"}, - {file = "fonttools-4.52.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33cfc9fe27af5e113d157d5147e24fc8e5bda3c5aadb55bea9847ec55341ce30"}, - {file = "fonttools-4.52.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa5bec5027d947ee4b2242caecf7dc6e4ea03833e92e9b5211ebb6ab4eede8b2"}, - {file = "fonttools-4.52.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:10e44bf8e5654050a332a79285bacd6bd3069084540aec46c0862391147a1daa"}, - {file = "fonttools-4.52.1-cp310-cp310-win32.whl", hash = "sha256:7fba390ac2ca18ebdd456f3a9acfb4557d6dcb2eaba5cc3eadce01003892a770"}, - {file = "fonttools-4.52.1-cp310-cp310-win_amd64.whl", hash = "sha256:15df3517eb95035422a5c953ca19aac99913c16aa0e4ef061aeaef5f3bcaf369"}, - {file = "fonttools-4.52.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40730aab9cf42286f314b985b483eea574f1bcf3a23e28223084cbb9e256457c"}, - {file = "fonttools-4.52.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a19bc2be3af5b22ff5c7fe858c380862e31052c74f62e2c6d565ed0855bed7a6"}, - {file = "fonttools-4.52.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f859066d8afde53f2ddabcd0705061e6d9d9868757c6ae28abe49bc885292df4"}, - {file = "fonttools-4.52.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74cd3e3e9ba501e87a391b62e91f7b1610e8b3f3d706a368e5aee51614c1674e"}, - {file = "fonttools-4.52.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:958957b81418647f66820480363cb617ba6b5bcf189ec6c4cea307d051048545"}, - {file = "fonttools-4.52.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56addf1f995d94dad13aaaf56eb6def3d9ca97c2fada5e27af8190b3141e8633"}, - {file = "fonttools-4.52.1-cp311-cp311-win32.whl", hash = "sha256:fea5456b2af42db8ecb1a6c2f144655ca6dcdcebd970f3145c56e668084ded7e"}, - {file = "fonttools-4.52.1-cp311-cp311-win_amd64.whl", hash = "sha256:228faab7638cd726cdde5e2ec9ee10f780fbf9de9aa38d7f1e56a270437dff36"}, - {file = "fonttools-4.52.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7c6aeb0d53e2ea92009b11c3d4ad9c03d0ecdfe602d547bed8537836e464f51e"}, - {file = "fonttools-4.52.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e871123d12c92e2c9bda6369b69ce2da9cef40b119cc340451e413e90355fa38"}, - {file = "fonttools-4.52.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ff8857dc9bb3e407c25aef3e025409cfbb23adb646a835636bebb1bdfc27a41"}, - {file = "fonttools-4.52.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7685fdc6e23267844eef2b9af585d7f171cca695e4eb369d7682544c3e2e1123"}, - {file = "fonttools-4.52.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1e1b2774485fbbb41a1beccc913b9c6f7971f78da61dd34207b9acc3cc2963e"}, - {file = "fonttools-4.52.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1e2c415160397fd6ed3964155aeec4bfefceeee365ab17161a5b3fe3f8dab077"}, - {file = "fonttools-4.52.1-cp312-cp312-win32.whl", hash = "sha256:3ba2c4647e7decfb8e9cd346661c7d151dae1fba23d37b48bcf5fa8351f7b8c8"}, - {file = "fonttools-4.52.1-cp312-cp312-win_amd64.whl", hash = "sha256:d39b926f14a2f7a7f92ded7d266b18f0108d867364769ab59da88ac2fa90d288"}, - {file = "fonttools-4.52.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6e58d8097a269b6c43ec0abb3fa8d6c350ff0c7dfd23fc14d004610df88a4bb3"}, - {file = "fonttools-4.52.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:20f0fc969817c50539dc919ed8c4aef4de28c2d6e0111a064112301f157aede4"}, - {file = "fonttools-4.52.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d62e84d38969491c6c1f6fe3dd63108e99d02de01bb3d98c160a5d4d24120910"}, - {file = "fonttools-4.52.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8eb5a389bbdee6f4c422881de422ee0e7efdfcd9310b13d540b12aa8ae2c9e7b"}, - {file = "fonttools-4.52.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0caf05c969cbde6729dd97b64bea445ee152bb19215d5886f7b93bd0fb455468"}, - {file = "fonttools-4.52.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:df08bee1dd29a767311b50c62c0cfe4d72ae8c793e567d4c60b8c16c7c63a4f0"}, - {file = "fonttools-4.52.1-cp38-cp38-win32.whl", hash = "sha256:82ffcf4782ceda09842b5b7875b36834c15d7cc0d5dd3d23a658ee9cf8819cd6"}, - {file = "fonttools-4.52.1-cp38-cp38-win_amd64.whl", hash = "sha256:26b43bab5a3bce55ed4d9699b16568795eef5597d154f52dcabef5b4804c4b21"}, - {file = "fonttools-4.52.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e8dbc13c4bc12e60df1b1f5e484112a5e96a6e8bba995e2965988ad73c5ea1b"}, - {file = "fonttools-4.52.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7352ba2226e45e8fba11c3fb416363faf1b06f3f2e80d07d2930401265f3bf9c"}, - {file = "fonttools-4.52.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8834d43763e9e92349ce8bb25dfb612aef6691eefefad885212d5e8f36a94a4"}, - {file = "fonttools-4.52.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee2a8c1101d06cc8fca7851dceb67afd53dd6fc0288bacaa632e647bc5afff58"}, - {file = "fonttools-4.52.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a99b738227c0f6f2bbe381b45804a7c46653c95b9d7bf13f6f02884bc87e4930"}, - {file = "fonttools-4.52.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:75aa00a16b9a64d1550e2e70d3582c7fe1ef18560e0cf066a4087fe6d11908a2"}, - {file = "fonttools-4.52.1-cp39-cp39-win32.whl", hash = "sha256:c2f09b4aa699cfed4bbebc1829c5f044b41976707dac9230ed00d5a9fc6452c1"}, - {file = "fonttools-4.52.1-cp39-cp39-win_amd64.whl", hash = "sha256:78ea6e0d4c89f8e216995923b854dd10bd09e48d3a5a3ccb48bb68f436a409ad"}, - {file = "fonttools-4.52.1-py3-none-any.whl", hash = "sha256:faf5c83f83f7ddebdafdb453d02efdbea7fb494080d7a8d45a8a20db06ea8da5"}, - {file = "fonttools-4.52.1.tar.gz", hash = "sha256:8c9204435aa6e5e9479a5ba4e669f05dea28b0c61958e0c0923cb164296d9329"}, + {file = "fonttools-4.53.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:52a6e0a7a0bf611c19bc8ec8f7592bdae79c8296c70eb05917fd831354699b20"}, + {file = "fonttools-4.53.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:099634631b9dd271d4a835d2b2a9e042ccc94ecdf7e2dd9f7f34f7daf333358d"}, + {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e40013572bfb843d6794a3ce076c29ef4efd15937ab833f520117f8eccc84fd6"}, + {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715b41c3e231f7334cbe79dfc698213dcb7211520ec7a3bc2ba20c8515e8a3b5"}, + {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74ae2441731a05b44d5988d3ac2cf784d3ee0a535dbed257cbfff4be8bb49eb9"}, + {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:95db0c6581a54b47c30860d013977b8a14febc206c8b5ff562f9fe32738a8aca"}, + {file = "fonttools-4.53.0-cp310-cp310-win32.whl", hash = "sha256:9cd7a6beec6495d1dffb1033d50a3f82dfece23e9eb3c20cd3c2444d27514068"}, + {file = "fonttools-4.53.0-cp310-cp310-win_amd64.whl", hash = "sha256:daaef7390e632283051e3cf3e16aff2b68b247e99aea916f64e578c0449c9c68"}, + {file = "fonttools-4.53.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a209d2e624ba492df4f3bfad5996d1f76f03069c6133c60cd04f9a9e715595ec"}, + {file = "fonttools-4.53.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f520d9ac5b938e6494f58a25c77564beca7d0199ecf726e1bd3d56872c59749"}, + {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eceef49f457253000e6a2d0f7bd08ff4e9fe96ec4ffce2dbcb32e34d9c1b8161"}, + {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1f3e34373aa16045484b4d9d352d4c6b5f9f77ac77a178252ccbc851e8b2ee"}, + {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:28d072169fe8275fb1a0d35e3233f6df36a7e8474e56cb790a7258ad822b6fd6"}, + {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a2a6ba400d386e904fd05db81f73bee0008af37799a7586deaa4aef8cd5971e"}, + {file = "fonttools-4.53.0-cp311-cp311-win32.whl", hash = "sha256:bb7273789f69b565d88e97e9e1da602b4ee7ba733caf35a6c2affd4334d4f005"}, + {file = "fonttools-4.53.0-cp311-cp311-win_amd64.whl", hash = "sha256:9fe9096a60113e1d755e9e6bda15ef7e03391ee0554d22829aa506cdf946f796"}, + {file = "fonttools-4.53.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d8f191a17369bd53a5557a5ee4bab91d5330ca3aefcdf17fab9a497b0e7cff7a"}, + {file = "fonttools-4.53.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93156dd7f90ae0a1b0e8871032a07ef3178f553f0c70c386025a808f3a63b1f4"}, + {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bff98816cb144fb7b85e4b5ba3888a33b56ecef075b0e95b95bcd0a5fbf20f06"}, + {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:973d030180eca8255b1bce6ffc09ef38a05dcec0e8320cc9b7bcaa65346f341d"}, + {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4ee5a24e281fbd8261c6ab29faa7fd9a87a12e8c0eed485b705236c65999109"}, + {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd5bc124fae781a4422f61b98d1d7faa47985f663a64770b78f13d2c072410c2"}, + {file = "fonttools-4.53.0-cp312-cp312-win32.whl", hash = "sha256:a239afa1126b6a619130909c8404070e2b473dd2b7fc4aacacd2e763f8597fea"}, + {file = "fonttools-4.53.0-cp312-cp312-win_amd64.whl", hash = "sha256:45b4afb069039f0366a43a5d454bc54eea942bfb66b3fc3e9a2c07ef4d617380"}, + {file = "fonttools-4.53.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:93bc9e5aaa06ff928d751dc6be889ff3e7d2aa393ab873bc7f6396a99f6fbb12"}, + {file = "fonttools-4.53.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2367d47816cc9783a28645bc1dac07f8ffc93e0f015e8c9fc674a5b76a6da6e4"}, + {file = "fonttools-4.53.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:907fa0b662dd8fc1d7c661b90782ce81afb510fc4b7aa6ae7304d6c094b27bce"}, + {file = "fonttools-4.53.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e0ad3c6ea4bd6a289d958a1eb922767233f00982cf0fe42b177657c86c80a8f"}, + {file = "fonttools-4.53.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:73121a9b7ff93ada888aaee3985a88495489cc027894458cb1a736660bdfb206"}, + {file = "fonttools-4.53.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ee595d7ba9bba130b2bec555a40aafa60c26ce68ed0cf509983e0f12d88674fd"}, + {file = "fonttools-4.53.0-cp38-cp38-win32.whl", hash = "sha256:fca66d9ff2ac89b03f5aa17e0b21a97c21f3491c46b583bb131eb32c7bab33af"}, + {file = "fonttools-4.53.0-cp38-cp38-win_amd64.whl", hash = "sha256:31f0e3147375002aae30696dd1dc596636abbd22fca09d2e730ecde0baad1d6b"}, + {file = "fonttools-4.53.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d6166192dcd925c78a91d599b48960e0a46fe565391c79fe6de481ac44d20ac"}, + {file = "fonttools-4.53.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef50ec31649fbc3acf6afd261ed89d09eb909b97cc289d80476166df8438524d"}, + {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f193f060391a455920d61684a70017ef5284ccbe6023bb056e15e5ac3de11d1"}, + {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9f09ff17f947392a855e3455a846f9855f6cf6bec33e9a427d3c1d254c712f"}, + {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c555e039d268445172b909b1b6bdcba42ada1cf4a60e367d68702e3f87e5f64"}, + {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a4788036201c908079e89ae3f5399b33bf45b9ea4514913f4dbbe4fac08efe0"}, + {file = "fonttools-4.53.0-cp39-cp39-win32.whl", hash = "sha256:d1a24f51a3305362b94681120c508758a88f207fa0a681c16b5a4172e9e6c7a9"}, + {file = "fonttools-4.53.0-cp39-cp39-win_amd64.whl", hash = "sha256:1e677bfb2b4bd0e5e99e0f7283e65e47a9814b0486cb64a41adf9ef110e078f2"}, + {file = "fonttools-4.53.0-py3-none-any.whl", hash = "sha256:6b4f04b1fbc01a3569d63359f2227c89ab294550de277fd09d8fca6185669fa4"}, + {file = "fonttools-4.53.0.tar.gz", hash = "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002"}, ] [package.extras] @@ -1416,34 +1423,33 @@ testing = ["pytest"] [[package]] name = "gymnasium" -version = "0.28.1" +version = "0.29.1" description = "A standard API for reinforcement learning and a diverse set of reference environments (formerly Gym)." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "gymnasium-0.28.1-py3-none-any.whl", hash = "sha256:7bc9a5bce1022f997d1dbc152fc91d1ac977bad9cc7794cdc25437010867cabf"}, - {file = "gymnasium-0.28.1.tar.gz", hash = "sha256:4c2c745808792c8f45c6e88ad0a5504774394e0c126f6e3db555e720d3da6f24"}, + {file = "gymnasium-0.29.1-py3-none-any.whl", hash = "sha256:61c3384b5575985bb7f85e43213bcb40f36fcdff388cae6bc229304c71f2843e"}, + {file = "gymnasium-0.29.1.tar.gz", hash = "sha256:1a532752efcb7590478b1cc7aa04f608eb7a2fdad5570cd217b66b6a35274bb1"}, ] [package.dependencies] cloudpickle = ">=1.2.0" farama-notifications = ">=0.0.1" -jax-jumpy = ">=1.0.0" numpy = ">=1.21.0" typing-extensions = ">=4.3.0" [package.extras] accept-rom-license = ["autorom[accept-rom-license] (>=0.4.2,<0.5.0)"] -all = ["box2d-py (==2.3.5)", "imageio (>=2.14.1)", "jax (==0.3.24)", "jaxlib (==0.3.24)", "lz4 (>=3.1.0)", "matplotlib (>=3.0)", "moviepy (>=1.0.0)", "mujoco (>=2.3.2)", "mujoco-py (>=2.1,<2.2)", "opencv-python (>=3.0)", "pygame (==2.1.3)", "shimmy[atari] (>=0.1.0,<1.0)", "swig (==4.*)", "torch (>=1.0.0)"] +all = ["box2d-py (==2.3.5)", "cython (<3)", "imageio (>=2.14.1)", "jax (>=0.4.0)", "jaxlib (>=0.4.0)", "lz4 (>=3.1.0)", "matplotlib (>=3.0)", "moviepy (>=1.0.0)", "mujoco (>=2.3.3)", "mujoco-py (>=2.1,<2.2)", "opencv-python (>=3.0)", "pygame (>=2.1.3)", "shimmy[atari] (>=0.1.0,<1.0)", "swig (==4.*)", "torch (>=1.0.0)"] atari = ["shimmy[atari] (>=0.1.0,<1.0)"] -box2d = ["box2d-py (==2.3.5)", "pygame (==2.1.3)", "swig (==4.*)"] -classic-control = ["pygame (==2.1.3)", "pygame (==2.1.3)"] -jax = ["jax (==0.3.24)", "jaxlib (==0.3.24)"] -mujoco = ["imageio (>=2.14.1)", "mujoco (>=2.3.2)"] -mujoco-py = ["mujoco-py (>=2.1,<2.2)", "mujoco-py (>=2.1,<2.2)"] +box2d = ["box2d-py (==2.3.5)", "pygame (>=2.1.3)", "swig (==4.*)"] +classic-control = ["pygame (>=2.1.3)", "pygame (>=2.1.3)"] +jax = ["jax (>=0.4.0)", "jaxlib (>=0.4.0)"] +mujoco = ["imageio (>=2.14.1)", "mujoco (>=2.3.3)"] +mujoco-py = ["cython (<3)", "cython (<3)", "mujoco-py (>=2.1,<2.2)", "mujoco-py (>=2.1,<2.2)"] other = ["lz4 (>=3.1.0)", "matplotlib (>=3.0)", "moviepy (>=1.0.0)", "opencv-python (>=3.0)", "torch (>=1.0.0)"] -testing = ["pytest (==7.1.3)", "scipy (==1.7.3)"] -toy-text = ["pygame (==2.1.3)", "pygame (==2.1.3)"] +testing = ["pytest (==7.1.3)", "scipy (>=1.7.3)"] +toy-text = ["pygame (>=2.1.3)", "pygame (>=2.1.3)"] [[package]] name = "h3" @@ -1643,24 +1649,6 @@ files = [ [package.dependencies] six = "*" -[[package]] -name = "jax-jumpy" -version = "1.0.0" -description = "Common backend for Jax or Numpy." -optional = false -python-versions = ">=3.7" -files = [ - {file = "jax-jumpy-1.0.0.tar.gz", hash = "sha256:195fb955cc4c2b7f0b1453e3cb1fb1c414a51a407ffac7a51e69a73cb30d59ad"}, - {file = "jax_jumpy-1.0.0-py3-none-any.whl", hash = "sha256:ab7e01454bba462de3c4d098e3e585c302a8f06bc36d9182ab4e7e4aa7067c5e"}, -] - -[package.dependencies] -numpy = ">=1.18.0" - -[package.extras] -jax = ["jax (>=0.3.24)", "jaxlib (>=0.3.24)"] -testing = ["pytest (==7.1.3)"] - [[package]] name = "jinja2" version = "3.1.4" @@ -2569,53 +2557,58 @@ icu = ["PyICU (>=1.0.0)"] [[package]] name = "nodeenv" -version = "1.8.0" +version = "1.9.0" description = "Node.js virtual environment builder" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "nodeenv-1.9.0-py2.py3-none-any.whl", hash = "sha256:508ecec98f9f3330b636d4448c0f1a56fc68017c68f1e7857ebc52acf0eb879a"}, + {file = "nodeenv-1.9.0.tar.gz", hash = "sha256:07f144e90dae547bf0d4ee8da0ee42664a42a04e02ed68e06324348dafe4bdb1"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "numpy" -version = "1.24.2" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, - {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, - {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, - {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, - {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, - {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, - {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, - {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, - {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, - {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, - {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] @@ -2731,18 +2724,17 @@ sympy = "*" [[package]] name = "opencv-python" -version = "4.9.0.80" +version = "4.10.0.82" description = "Wrapper package for OpenCV python bindings." optional = false python-versions = ">=3.6" files = [ - {file = "opencv-python-4.9.0.80.tar.gz", hash = "sha256:1a9f0e6267de3a1a1db0c54213d022c7c8b5b9ca4b580e80bdc58516c922c9e1"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:7e5f7aa4486651a6ebfa8ed4b594b65bd2d2f41beeb4241a3e4b1b85acbbbadb"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:71dfb9555ccccdd77305fc3dcca5897fbf0cf28b297c51ee55e079c065d812a3"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b34a52e9da36dda8c151c6394aed602e4b17fa041df0b9f5b93ae10b0fcca2a"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4088cab82b66a3b37ffc452976b14a3c599269c247895ae9ceb4066d8188a57"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-win32.whl", hash = "sha256:dcf000c36dd1651118a2462257e3a9e76db789a78432e1f303c7bac54f63ef6c"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl", hash = "sha256:3f16f08e02b2a2da44259c7cc712e779eff1dd8b55fdb0323e8cab09548086c0"}, + {file = "opencv-python-4.10.0.82.tar.gz", hash = "sha256:dbc021eaa310c4145c47cd648cb973db69bb5780d6e635386cd53d3ea76bd2d5"}, + {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:e6be19a0615aa8c4e0d34e0c7b133e26e386f4b7e9b557b69479104ab2c133ec"}, + {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b49e530f7fd86f671514b39ffacdf5d14ceb073bc79d0de46bbb6b0cad78eaf"}, + {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955c5ce8ac90c9e4636ad7f5c0d9c75b80abbe347182cfd09b0e3eec6e50472c"}, + {file = "opencv_python-4.10.0.82-cp37-abi3-win32.whl", hash = "sha256:ff54adc9e4daaf438e669664af08bec4a268c7b7356079338b8e4fae03810f2c"}, + {file = "opencv_python-4.10.0.82-cp37-abi3-win_amd64.whl", hash = "sha256:2e3c2557b176f1e528417520a52c0600a92c1bb1c359f3df8e6411ab4293f065"}, ] [package.dependencies] @@ -2750,18 +2742,17 @@ numpy = {version = ">=1.23.5", markers = "python_version >= \"3.11\""} [[package]] name = "opencv-python-headless" -version = "4.9.0.80" +version = "4.10.0.82" description = "Wrapper package for OpenCV python bindings." optional = false python-versions = ">=3.6" files = [ - {file = "opencv-python-headless-4.9.0.80.tar.gz", hash = "sha256:71a4cd8cf7c37122901d8e81295db7fb188730e33a0e40039a4e59c1030b0958"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:2ea8a2edc4db87841991b2fbab55fc07b97ecb602e0f47d5d485bd75cee17c1a"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:e0ee54e27be493e8f7850847edae3128e18b540dac1d7b2e4001b8944e11e1c6"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57ce2865e8fec431c6f97a81e9faaf23fa5be61011d0a75ccf47a3c0d65fa73d"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:976656362d68d9f40a5c66f83901430538002465f7db59142784f3893918f3df"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-win32.whl", hash = "sha256:11e3849d83e6651d4e7699aadda9ec7ed7c38957cbbcb99db074f2a2d2de9670"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-win_amd64.whl", hash = "sha256:a8056c2cb37cd65dfcdf4153ca16f7362afcf3a50d600d6bb69c660fc61ee29c"}, + {file = "opencv-python-headless-4.10.0.82.tar.gz", hash = "sha256:de9e742c1b9540816fbd115b0b03841d41ed0c65566b0d7a5371f98b131b7e6d"}, + {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:977a5fd21e1fe0d3d2134887db4441f8725abeae95150126302f31fcd9f548fa"}, + {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4ec6755838b0be12510bfc9ffb014779c612418f11f4f7e6f505c36124a3aa"}, + {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a37fa5276967ecf6eb297295b16b28b7a2eb3b568ca0ee469fb1a5954de298"}, + {file = "opencv_python_headless-4.10.0.82-cp37-abi3-win32.whl", hash = "sha256:94736e9b322d13db4768fd35588ad5e8995e78e207263076bfbee18aac835ad5"}, + {file = "opencv_python_headless-4.10.0.82-cp37-abi3-win_amd64.whl", hash = "sha256:c1822fa23d1641c0249ed5eb906f4c385f7959ff1bd601a776d56b0c18914af4"}, ] [package.dependencies] @@ -3639,2762 +3630,2780 @@ files = [ [[package]] name = "pyobjc" -version = "10.2" +version = "10.3" description = "Python<->ObjC Interoperability Module" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-10.2-py3-none-any.whl", hash = "sha256:976c8f8af49a91195307b3efbc2d63517be63aae2b4b3689dcff4f317669c23a"}, - {file = "pyobjc-10.2.tar.gz", hash = "sha256:bfea9891750ce3af6439ee102e8e417917f1a7ed7fc4f54b5da9d7457fbb7fc6"}, + {file = "pyobjc-10.3-py3-none-any.whl", hash = "sha256:80068513b43c4a7950d41931f2fb53599ddfefd7e3961976cb8a65a01d2bb2d7"}, + {file = "pyobjc-10.3.tar.gz", hash = "sha256:4af8a73bf5d73fc62f6cceb8826d6fc86db63017bf75450140a4fa7ec263db6b"}, ] [package.dependencies] -pyobjc-core = "10.2" -pyobjc-framework-Accessibility = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-Accounts = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-AddressBook = "10.2" -pyobjc-framework-AdServices = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-AdSupport = {version = "10.2", markers = "platform_release >= \"18.0\""} -pyobjc-framework-AppleScriptKit = "10.2" -pyobjc-framework-AppleScriptObjC = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-ApplicationServices = "10.2" -pyobjc-framework-AppTrackingTransparency = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-AudioVideoBridging = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-AuthenticationServices = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-AutomaticAssessmentConfiguration = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-Automator = "10.2" -pyobjc-framework-AVFoundation = {version = "10.2", markers = "platform_release >= \"11.0\""} -pyobjc-framework-AVKit = {version = "10.2", markers = "platform_release >= \"13.0\""} -pyobjc-framework-AVRouting = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-BackgroundAssets = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-BrowserEngineKit = {version = "10.2", markers = "platform_release >= \"23.4\""} -pyobjc-framework-BusinessChat = {version = "10.2", markers = "platform_release >= \"18.0\""} -pyobjc-framework-CalendarStore = {version = "10.2", markers = "platform_release >= \"9.0\""} -pyobjc-framework-CallKit = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-CFNetwork = "10.2" -pyobjc-framework-Cinematic = {version = "10.2", markers = "platform_release >= \"23.0\""} -pyobjc-framework-ClassKit = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-CloudKit = {version = "10.2", markers = "platform_release >= \"14.0\""} -pyobjc-framework-Cocoa = "10.2" -pyobjc-framework-Collaboration = {version = "10.2", markers = "platform_release >= \"9.0\""} -pyobjc-framework-ColorSync = {version = "10.2", markers = "platform_release >= \"17.0\""} -pyobjc-framework-Contacts = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-ContactsUI = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-CoreAudio = "10.2" -pyobjc-framework-CoreAudioKit = "10.2" -pyobjc-framework-CoreBluetooth = {version = "10.2", markers = "platform_release >= \"14.0\""} -pyobjc-framework-CoreData = "10.2" -pyobjc-framework-CoreHaptics = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-CoreLocation = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-CoreMedia = {version = "10.2", markers = "platform_release >= \"11.0\""} -pyobjc-framework-CoreMediaIO = {version = "10.2", markers = "platform_release >= \"11.0\""} -pyobjc-framework-CoreMIDI = "10.2" -pyobjc-framework-CoreML = {version = "10.2", markers = "platform_release >= \"17.0\""} -pyobjc-framework-CoreMotion = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-CoreServices = "10.2" -pyobjc-framework-CoreSpotlight = {version = "10.2", markers = "platform_release >= \"17.0\""} -pyobjc-framework-CoreText = "10.2" -pyobjc-framework-CoreWLAN = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-CryptoTokenKit = {version = "10.2", markers = "platform_release >= \"14.0\""} -pyobjc-framework-DataDetection = {version = "10.2", markers = "platform_release >= \"21.0\""} -pyobjc-framework-DeviceCheck = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-DictionaryServices = {version = "10.2", markers = "platform_release >= \"9.0\""} -pyobjc-framework-DiscRecording = "10.2" -pyobjc-framework-DiscRecordingUI = "10.2" -pyobjc-framework-DiskArbitration = "10.2" -pyobjc-framework-DVDPlayback = "10.2" -pyobjc-framework-EventKit = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-ExceptionHandling = "10.2" -pyobjc-framework-ExecutionPolicy = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-ExtensionKit = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-ExternalAccessory = {version = "10.2", markers = "platform_release >= \"17.0\""} -pyobjc-framework-FileProvider = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-FileProviderUI = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-FinderSync = {version = "10.2", markers = "platform_release >= \"14.0\""} -pyobjc-framework-FSEvents = {version = "10.2", markers = "platform_release >= \"9.0\""} -pyobjc-framework-GameCenter = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-GameController = {version = "10.2", markers = "platform_release >= \"13.0\""} -pyobjc-framework-GameKit = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-GameplayKit = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-HealthKit = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-ImageCaptureCore = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-InputMethodKit = {version = "10.2", markers = "platform_release >= \"9.0\""} -pyobjc-framework-InstallerPlugins = "10.2" -pyobjc-framework-InstantMessage = {version = "10.2", markers = "platform_release >= \"9.0\""} -pyobjc-framework-Intents = {version = "10.2", markers = "platform_release >= \"16.0\""} -pyobjc-framework-IntentsUI = {version = "10.2", markers = "platform_release >= \"21.0\""} -pyobjc-framework-IOBluetooth = "10.2" -pyobjc-framework-IOBluetoothUI = "10.2" -pyobjc-framework-IOSurface = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-iTunesLibrary = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-KernelManagement = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-LatentSemanticMapping = "10.2" -pyobjc-framework-LaunchServices = "10.2" -pyobjc-framework-libdispatch = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-libxpc = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-LinkPresentation = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-LocalAuthentication = {version = "10.2", markers = "platform_release >= \"14.0\""} -pyobjc-framework-LocalAuthenticationEmbeddedUI = {version = "10.2", markers = "platform_release >= \"21.0\""} -pyobjc-framework-MailKit = {version = "10.2", markers = "platform_release >= \"21.0\""} -pyobjc-framework-MapKit = {version = "10.2", markers = "platform_release >= \"13.0\""} -pyobjc-framework-MediaAccessibility = {version = "10.2", markers = "platform_release >= \"13.0\""} -pyobjc-framework-MediaLibrary = {version = "10.2", markers = "platform_release >= \"13.0\""} -pyobjc-framework-MediaPlayer = {version = "10.2", markers = "platform_release >= \"16.0\""} -pyobjc-framework-MediaToolbox = {version = "10.2", markers = "platform_release >= \"13.0\""} -pyobjc-framework-Metal = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-MetalFX = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-MetalKit = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-MetalPerformanceShaders = {version = "10.2", markers = "platform_release >= \"17.0\""} -pyobjc-framework-MetalPerformanceShadersGraph = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-MetricKit = {version = "10.2", markers = "platform_release >= \"21.0\""} -pyobjc-framework-MLCompute = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-ModelIO = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-MultipeerConnectivity = {version = "10.2", markers = "platform_release >= \"14.0\""} -pyobjc-framework-NaturalLanguage = {version = "10.2", markers = "platform_release >= \"18.0\""} -pyobjc-framework-NetFS = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-Network = {version = "10.2", markers = "platform_release >= \"18.0\""} -pyobjc-framework-NetworkExtension = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-NotificationCenter = {version = "10.2", markers = "platform_release >= \"14.0\""} -pyobjc-framework-OpenDirectory = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-OSAKit = "10.2" -pyobjc-framework-OSLog = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-PassKit = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-PencilKit = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-PHASE = {version = "10.2", markers = "platform_release >= \"21.0\""} -pyobjc-framework-Photos = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-PhotosUI = {version = "10.2", markers = "platform_release >= \"15.0\""} -pyobjc-framework-PreferencePanes = "10.2" -pyobjc-framework-PubSub = {version = "10.2", markers = "platform_release >= \"9.0\" and platform_release < \"18.0\""} -pyobjc-framework-PushKit = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-Quartz = "10.2" -pyobjc-framework-QuickLookThumbnailing = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-ReplayKit = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-SafariServices = {version = "10.2", markers = "platform_release >= \"16.0\""} -pyobjc-framework-SafetyKit = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-SceneKit = {version = "10.2", markers = "platform_release >= \"11.0\""} -pyobjc-framework-ScreenCaptureKit = {version = "10.2", markers = "platform_release >= \"21.4\""} -pyobjc-framework-ScreenSaver = "10.2" -pyobjc-framework-ScreenTime = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-ScriptingBridge = {version = "10.2", markers = "platform_release >= \"9.0\""} -pyobjc-framework-SearchKit = "10.2" -pyobjc-framework-Security = "10.2" -pyobjc-framework-SecurityFoundation = "10.2" -pyobjc-framework-SecurityInterface = "10.2" -pyobjc-framework-SensitiveContentAnalysis = {version = "10.2", markers = "platform_release >= \"23.0\""} -pyobjc-framework-ServiceManagement = {version = "10.2", markers = "platform_release >= \"10.0\""} -pyobjc-framework-SharedWithYou = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-SharedWithYouCore = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-ShazamKit = {version = "10.2", markers = "platform_release >= \"21.0\""} -pyobjc-framework-Social = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-SoundAnalysis = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-Speech = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-SpriteKit = {version = "10.2", markers = "platform_release >= \"13.0\""} -pyobjc-framework-StoreKit = {version = "10.2", markers = "platform_release >= \"11.0\""} -pyobjc-framework-Symbols = {version = "10.2", markers = "platform_release >= \"23.0\""} -pyobjc-framework-SyncServices = "10.2" -pyobjc-framework-SystemConfiguration = "10.2" -pyobjc-framework-SystemExtensions = {version = "10.2", markers = "platform_release >= \"19.0\""} -pyobjc-framework-ThreadNetwork = {version = "10.2", markers = "platform_release >= \"22.0\""} -pyobjc-framework-UniformTypeIdentifiers = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-UserNotifications = {version = "10.2", markers = "platform_release >= \"18.0\""} -pyobjc-framework-UserNotificationsUI = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-VideoSubscriberAccount = {version = "10.2", markers = "platform_release >= \"18.0\""} -pyobjc-framework-VideoToolbox = {version = "10.2", markers = "platform_release >= \"12.0\""} -pyobjc-framework-Virtualization = {version = "10.2", markers = "platform_release >= \"20.0\""} -pyobjc-framework-Vision = {version = "10.2", markers = "platform_release >= \"17.0\""} -pyobjc-framework-WebKit = "10.2" +pyobjc-core = "10.3" +pyobjc-framework-Accessibility = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-Accounts = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-AddressBook = "10.3" +pyobjc-framework-AdServices = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-AdSupport = {version = "10.3", markers = "platform_release >= \"18.0\""} +pyobjc-framework-AppleScriptKit = "10.3" +pyobjc-framework-AppleScriptObjC = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-ApplicationServices = "10.3" +pyobjc-framework-AppTrackingTransparency = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-AudioVideoBridging = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-AuthenticationServices = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-AutomaticAssessmentConfiguration = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-Automator = "10.3" +pyobjc-framework-AVFoundation = {version = "10.3", markers = "platform_release >= \"11.0\""} +pyobjc-framework-AVKit = {version = "10.3", markers = "platform_release >= \"13.0\""} +pyobjc-framework-AVRouting = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-BackgroundAssets = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-BrowserEngineKit = {version = "10.3", markers = "platform_release >= \"23.4\""} +pyobjc-framework-BusinessChat = {version = "10.3", markers = "platform_release >= \"18.0\""} +pyobjc-framework-CalendarStore = {version = "10.3", markers = "platform_release >= \"9.0\""} +pyobjc-framework-CallKit = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-CFNetwork = "10.3" +pyobjc-framework-Cinematic = {version = "10.3", markers = "platform_release >= \"23.0\""} +pyobjc-framework-ClassKit = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-CloudKit = {version = "10.3", markers = "platform_release >= \"14.0\""} +pyobjc-framework-Cocoa = "10.3" +pyobjc-framework-Collaboration = {version = "10.3", markers = "platform_release >= \"9.0\""} +pyobjc-framework-ColorSync = {version = "10.3", markers = "platform_release >= \"17.0\""} +pyobjc-framework-Contacts = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-ContactsUI = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-CoreAudio = "10.3" +pyobjc-framework-CoreAudioKit = "10.3" +pyobjc-framework-CoreBluetooth = {version = "10.3", markers = "platform_release >= \"14.0\""} +pyobjc-framework-CoreData = "10.3" +pyobjc-framework-CoreHaptics = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-CoreLocation = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-CoreMedia = {version = "10.3", markers = "platform_release >= \"11.0\""} +pyobjc-framework-CoreMediaIO = {version = "10.3", markers = "platform_release >= \"11.0\""} +pyobjc-framework-CoreMIDI = "10.3" +pyobjc-framework-CoreML = {version = "10.3", markers = "platform_release >= \"17.0\""} +pyobjc-framework-CoreMotion = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-CoreServices = "10.3" +pyobjc-framework-CoreSpotlight = {version = "10.3", markers = "platform_release >= \"17.0\""} +pyobjc-framework-CoreText = "10.3" +pyobjc-framework-CoreWLAN = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-CryptoTokenKit = {version = "10.3", markers = "platform_release >= \"14.0\""} +pyobjc-framework-DataDetection = {version = "10.3", markers = "platform_release >= \"21.0\""} +pyobjc-framework-DeviceCheck = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-DictionaryServices = {version = "10.3", markers = "platform_release >= \"9.0\""} +pyobjc-framework-DiscRecording = "10.3" +pyobjc-framework-DiscRecordingUI = "10.3" +pyobjc-framework-DiskArbitration = "10.3" +pyobjc-framework-DVDPlayback = "10.3" +pyobjc-framework-EventKit = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-ExceptionHandling = "10.3" +pyobjc-framework-ExecutionPolicy = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-ExtensionKit = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-ExternalAccessory = {version = "10.3", markers = "platform_release >= \"17.0\""} +pyobjc-framework-FileProvider = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-FileProviderUI = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-FinderSync = {version = "10.3", markers = "platform_release >= \"14.0\""} +pyobjc-framework-FSEvents = {version = "10.3", markers = "platform_release >= \"9.0\""} +pyobjc-framework-GameCenter = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-GameController = {version = "10.3", markers = "platform_release >= \"13.0\""} +pyobjc-framework-GameKit = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-GameplayKit = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-HealthKit = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-ImageCaptureCore = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-InputMethodKit = {version = "10.3", markers = "platform_release >= \"9.0\""} +pyobjc-framework-InstallerPlugins = "10.3" +pyobjc-framework-InstantMessage = {version = "10.3", markers = "platform_release >= \"9.0\""} +pyobjc-framework-Intents = {version = "10.3", markers = "platform_release >= \"16.0\""} +pyobjc-framework-IntentsUI = {version = "10.3", markers = "platform_release >= \"21.0\""} +pyobjc-framework-IOBluetooth = "10.3" +pyobjc-framework-IOBluetoothUI = "10.3" +pyobjc-framework-IOSurface = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-iTunesLibrary = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-KernelManagement = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-LatentSemanticMapping = "10.3" +pyobjc-framework-LaunchServices = "10.3" +pyobjc-framework-libdispatch = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-libxpc = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-LinkPresentation = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-LocalAuthentication = {version = "10.3", markers = "platform_release >= \"14.0\""} +pyobjc-framework-LocalAuthenticationEmbeddedUI = {version = "10.3", markers = "platform_release >= \"21.0\""} +pyobjc-framework-MailKit = {version = "10.3", markers = "platform_release >= \"21.0\""} +pyobjc-framework-MapKit = {version = "10.3", markers = "platform_release >= \"13.0\""} +pyobjc-framework-MediaAccessibility = {version = "10.3", markers = "platform_release >= \"13.0\""} +pyobjc-framework-MediaLibrary = {version = "10.3", markers = "platform_release >= \"13.0\""} +pyobjc-framework-MediaPlayer = {version = "10.3", markers = "platform_release >= \"16.0\""} +pyobjc-framework-MediaToolbox = {version = "10.3", markers = "platform_release >= \"13.0\""} +pyobjc-framework-Metal = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-MetalFX = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-MetalKit = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-MetalPerformanceShaders = {version = "10.3", markers = "platform_release >= \"17.0\""} +pyobjc-framework-MetalPerformanceShadersGraph = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-MetricKit = {version = "10.3", markers = "platform_release >= \"21.0\""} +pyobjc-framework-MLCompute = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-ModelIO = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-MultipeerConnectivity = {version = "10.3", markers = "platform_release >= \"14.0\""} +pyobjc-framework-NaturalLanguage = {version = "10.3", markers = "platform_release >= \"18.0\""} +pyobjc-framework-NetFS = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-Network = {version = "10.3", markers = "platform_release >= \"18.0\""} +pyobjc-framework-NetworkExtension = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-NotificationCenter = {version = "10.3", markers = "platform_release >= \"14.0\""} +pyobjc-framework-OpenDirectory = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-OSAKit = "10.3" +pyobjc-framework-OSLog = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-PassKit = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-PencilKit = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-PHASE = {version = "10.3", markers = "platform_release >= \"21.0\""} +pyobjc-framework-Photos = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-PhotosUI = {version = "10.3", markers = "platform_release >= \"15.0\""} +pyobjc-framework-PreferencePanes = "10.3" +pyobjc-framework-PubSub = {version = "10.3", markers = "platform_release >= \"9.0\" and platform_release < \"18.0\""} +pyobjc-framework-PushKit = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-Quartz = "10.3" +pyobjc-framework-QuickLookThumbnailing = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-ReplayKit = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-SafariServices = {version = "10.3", markers = "platform_release >= \"16.0\""} +pyobjc-framework-SafetyKit = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-SceneKit = {version = "10.3", markers = "platform_release >= \"11.0\""} +pyobjc-framework-ScreenCaptureKit = {version = "10.3", markers = "platform_release >= \"21.4\""} +pyobjc-framework-ScreenSaver = "10.3" +pyobjc-framework-ScreenTime = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-ScriptingBridge = {version = "10.3", markers = "platform_release >= \"9.0\""} +pyobjc-framework-SearchKit = "10.3" +pyobjc-framework-Security = "10.3" +pyobjc-framework-SecurityFoundation = "10.3" +pyobjc-framework-SecurityInterface = "10.3" +pyobjc-framework-SensitiveContentAnalysis = {version = "10.3", markers = "platform_release >= \"23.0\""} +pyobjc-framework-ServiceManagement = {version = "10.3", markers = "platform_release >= \"10.0\""} +pyobjc-framework-SharedWithYou = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-SharedWithYouCore = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-ShazamKit = {version = "10.3", markers = "platform_release >= \"21.0\""} +pyobjc-framework-Social = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-SoundAnalysis = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-Speech = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-SpriteKit = {version = "10.3", markers = "platform_release >= \"13.0\""} +pyobjc-framework-StoreKit = {version = "10.3", markers = "platform_release >= \"11.0\""} +pyobjc-framework-Symbols = {version = "10.3", markers = "platform_release >= \"23.0\""} +pyobjc-framework-SyncServices = "10.3" +pyobjc-framework-SystemConfiguration = "10.3" +pyobjc-framework-SystemExtensions = {version = "10.3", markers = "platform_release >= \"19.0\""} +pyobjc-framework-ThreadNetwork = {version = "10.3", markers = "platform_release >= \"22.0\""} +pyobjc-framework-UniformTypeIdentifiers = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-UserNotifications = {version = "10.3", markers = "platform_release >= \"18.0\""} +pyobjc-framework-UserNotificationsUI = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-VideoSubscriberAccount = {version = "10.3", markers = "platform_release >= \"18.0\""} +pyobjc-framework-VideoToolbox = {version = "10.3", markers = "platform_release >= \"12.0\""} +pyobjc-framework-Virtualization = {version = "10.3", markers = "platform_release >= \"20.0\""} +pyobjc-framework-Vision = {version = "10.3", markers = "platform_release >= \"17.0\""} +pyobjc-framework-WebKit = "10.3" [package.extras] -allbindings = ["pyobjc-core (==10.2)", "pyobjc-framework-AVFoundation (==10.2)", "pyobjc-framework-AVKit (==10.2)", "pyobjc-framework-AVRouting (==10.2)", "pyobjc-framework-Accessibility (==10.2)", "pyobjc-framework-Accounts (==10.2)", "pyobjc-framework-AdServices (==10.2)", "pyobjc-framework-AdSupport (==10.2)", "pyobjc-framework-AddressBook (==10.2)", "pyobjc-framework-AppTrackingTransparency (==10.2)", "pyobjc-framework-AppleScriptKit (==10.2)", "pyobjc-framework-AppleScriptObjC (==10.2)", "pyobjc-framework-ApplicationServices (==10.2)", "pyobjc-framework-AudioVideoBridging (==10.2)", "pyobjc-framework-AuthenticationServices (==10.2)", "pyobjc-framework-AutomaticAssessmentConfiguration (==10.2)", "pyobjc-framework-Automator (==10.2)", "pyobjc-framework-BackgroundAssets (==10.2)", "pyobjc-framework-BrowserEngineKit (==10.2)", "pyobjc-framework-BusinessChat (==10.2)", "pyobjc-framework-CFNetwork (==10.2)", "pyobjc-framework-CalendarStore (==10.2)", "pyobjc-framework-CallKit (==10.2)", "pyobjc-framework-Cinematic (==10.2)", "pyobjc-framework-ClassKit (==10.2)", "pyobjc-framework-CloudKit (==10.2)", "pyobjc-framework-Cocoa (==10.2)", "pyobjc-framework-Collaboration (==10.2)", "pyobjc-framework-ColorSync (==10.2)", "pyobjc-framework-Contacts (==10.2)", "pyobjc-framework-ContactsUI (==10.2)", "pyobjc-framework-CoreAudio (==10.2)", "pyobjc-framework-CoreAudioKit (==10.2)", "pyobjc-framework-CoreBluetooth (==10.2)", "pyobjc-framework-CoreData (==10.2)", "pyobjc-framework-CoreHaptics (==10.2)", "pyobjc-framework-CoreLocation (==10.2)", "pyobjc-framework-CoreMIDI (==10.2)", "pyobjc-framework-CoreML (==10.2)", "pyobjc-framework-CoreMedia (==10.2)", "pyobjc-framework-CoreMediaIO (==10.2)", "pyobjc-framework-CoreMotion (==10.2)", "pyobjc-framework-CoreServices (==10.2)", "pyobjc-framework-CoreSpotlight (==10.2)", "pyobjc-framework-CoreText (==10.2)", "pyobjc-framework-CoreWLAN (==10.2)", "pyobjc-framework-CryptoTokenKit (==10.2)", "pyobjc-framework-DVDPlayback (==10.2)", "pyobjc-framework-DataDetection (==10.2)", "pyobjc-framework-DeviceCheck (==10.2)", "pyobjc-framework-DictionaryServices (==10.2)", "pyobjc-framework-DiscRecording (==10.2)", "pyobjc-framework-DiscRecordingUI (==10.2)", "pyobjc-framework-DiskArbitration (==10.2)", "pyobjc-framework-EventKit (==10.2)", "pyobjc-framework-ExceptionHandling (==10.2)", "pyobjc-framework-ExecutionPolicy (==10.2)", "pyobjc-framework-ExtensionKit (==10.2)", "pyobjc-framework-ExternalAccessory (==10.2)", "pyobjc-framework-FSEvents (==10.2)", "pyobjc-framework-FileProvider (==10.2)", "pyobjc-framework-FileProviderUI (==10.2)", "pyobjc-framework-FinderSync (==10.2)", "pyobjc-framework-GameCenter (==10.2)", "pyobjc-framework-GameController (==10.2)", "pyobjc-framework-GameKit (==10.2)", "pyobjc-framework-GameplayKit (==10.2)", "pyobjc-framework-HealthKit (==10.2)", "pyobjc-framework-IOBluetooth (==10.2)", "pyobjc-framework-IOBluetoothUI (==10.2)", "pyobjc-framework-IOSurface (==10.2)", "pyobjc-framework-ImageCaptureCore (==10.2)", "pyobjc-framework-InputMethodKit (==10.2)", "pyobjc-framework-InstallerPlugins (==10.2)", "pyobjc-framework-InstantMessage (==10.2)", "pyobjc-framework-Intents (==10.2)", "pyobjc-framework-IntentsUI (==10.2)", "pyobjc-framework-KernelManagement (==10.2)", "pyobjc-framework-LatentSemanticMapping (==10.2)", "pyobjc-framework-LaunchServices (==10.2)", "pyobjc-framework-LinkPresentation (==10.2)", "pyobjc-framework-LocalAuthentication (==10.2)", "pyobjc-framework-LocalAuthenticationEmbeddedUI (==10.2)", "pyobjc-framework-MLCompute (==10.2)", "pyobjc-framework-MailKit (==10.2)", "pyobjc-framework-MapKit (==10.2)", "pyobjc-framework-MediaAccessibility (==10.2)", "pyobjc-framework-MediaLibrary (==10.2)", "pyobjc-framework-MediaPlayer (==10.2)", "pyobjc-framework-MediaToolbox (==10.2)", "pyobjc-framework-Metal (==10.2)", "pyobjc-framework-MetalFX (==10.2)", "pyobjc-framework-MetalKit (==10.2)", "pyobjc-framework-MetalPerformanceShaders (==10.2)", "pyobjc-framework-MetalPerformanceShadersGraph (==10.2)", "pyobjc-framework-MetricKit (==10.2)", "pyobjc-framework-ModelIO (==10.2)", "pyobjc-framework-MultipeerConnectivity (==10.2)", "pyobjc-framework-NaturalLanguage (==10.2)", "pyobjc-framework-NetFS (==10.2)", "pyobjc-framework-Network (==10.2)", "pyobjc-framework-NetworkExtension (==10.2)", "pyobjc-framework-NotificationCenter (==10.2)", "pyobjc-framework-OSAKit (==10.2)", "pyobjc-framework-OSLog (==10.2)", "pyobjc-framework-OpenDirectory (==10.2)", "pyobjc-framework-PHASE (==10.2)", "pyobjc-framework-PassKit (==10.2)", "pyobjc-framework-PencilKit (==10.2)", "pyobjc-framework-Photos (==10.2)", "pyobjc-framework-PhotosUI (==10.2)", "pyobjc-framework-PreferencePanes (==10.2)", "pyobjc-framework-PubSub (==10.2)", "pyobjc-framework-PushKit (==10.2)", "pyobjc-framework-Quartz (==10.2)", "pyobjc-framework-QuickLookThumbnailing (==10.2)", "pyobjc-framework-ReplayKit (==10.2)", "pyobjc-framework-SafariServices (==10.2)", "pyobjc-framework-SafetyKit (==10.2)", "pyobjc-framework-SceneKit (==10.2)", "pyobjc-framework-ScreenCaptureKit (==10.2)", "pyobjc-framework-ScreenSaver (==10.2)", "pyobjc-framework-ScreenTime (==10.2)", "pyobjc-framework-ScriptingBridge (==10.2)", "pyobjc-framework-SearchKit (==10.2)", "pyobjc-framework-Security (==10.2)", "pyobjc-framework-SecurityFoundation (==10.2)", "pyobjc-framework-SecurityInterface (==10.2)", "pyobjc-framework-SensitiveContentAnalysis (==10.2)", "pyobjc-framework-ServiceManagement (==10.2)", "pyobjc-framework-SharedWithYou (==10.2)", "pyobjc-framework-SharedWithYouCore (==10.2)", "pyobjc-framework-ShazamKit (==10.2)", "pyobjc-framework-Social (==10.2)", "pyobjc-framework-SoundAnalysis (==10.2)", "pyobjc-framework-Speech (==10.2)", "pyobjc-framework-SpriteKit (==10.2)", "pyobjc-framework-StoreKit (==10.2)", "pyobjc-framework-Symbols (==10.2)", "pyobjc-framework-SyncServices (==10.2)", "pyobjc-framework-SystemConfiguration (==10.2)", "pyobjc-framework-SystemExtensions (==10.2)", "pyobjc-framework-ThreadNetwork (==10.2)", "pyobjc-framework-UniformTypeIdentifiers (==10.2)", "pyobjc-framework-UserNotifications (==10.2)", "pyobjc-framework-UserNotificationsUI (==10.2)", "pyobjc-framework-VideoSubscriberAccount (==10.2)", "pyobjc-framework-VideoToolbox (==10.2)", "pyobjc-framework-Virtualization (==10.2)", "pyobjc-framework-Vision (==10.2)", "pyobjc-framework-WebKit (==10.2)", "pyobjc-framework-iTunesLibrary (==10.2)", "pyobjc-framework-libdispatch (==10.2)", "pyobjc-framework-libxpc (==10.2)"] +allbindings = ["pyobjc-core (==10.3)", "pyobjc-framework-AVFoundation (==10.3)", "pyobjc-framework-AVKit (==10.3)", "pyobjc-framework-AVRouting (==10.3)", "pyobjc-framework-Accessibility (==10.3)", "pyobjc-framework-Accounts (==10.3)", "pyobjc-framework-AdServices (==10.3)", "pyobjc-framework-AdSupport (==10.3)", "pyobjc-framework-AddressBook (==10.3)", "pyobjc-framework-AppTrackingTransparency (==10.3)", "pyobjc-framework-AppleScriptKit (==10.3)", "pyobjc-framework-AppleScriptObjC (==10.3)", "pyobjc-framework-ApplicationServices (==10.3)", "pyobjc-framework-AudioVideoBridging (==10.3)", "pyobjc-framework-AuthenticationServices (==10.3)", "pyobjc-framework-AutomaticAssessmentConfiguration (==10.3)", "pyobjc-framework-Automator (==10.3)", "pyobjc-framework-BackgroundAssets (==10.3)", "pyobjc-framework-BrowserEngineKit (==10.3)", "pyobjc-framework-BusinessChat (==10.3)", "pyobjc-framework-CFNetwork (==10.3)", "pyobjc-framework-CalendarStore (==10.3)", "pyobjc-framework-CallKit (==10.3)", "pyobjc-framework-Cinematic (==10.3)", "pyobjc-framework-ClassKit (==10.3)", "pyobjc-framework-CloudKit (==10.3)", "pyobjc-framework-Cocoa (==10.3)", "pyobjc-framework-Collaboration (==10.3)", "pyobjc-framework-ColorSync (==10.3)", "pyobjc-framework-Contacts (==10.3)", "pyobjc-framework-ContactsUI (==10.3)", "pyobjc-framework-CoreAudio (==10.3)", "pyobjc-framework-CoreAudioKit (==10.3)", "pyobjc-framework-CoreBluetooth (==10.3)", "pyobjc-framework-CoreData (==10.3)", "pyobjc-framework-CoreHaptics (==10.3)", "pyobjc-framework-CoreLocation (==10.3)", "pyobjc-framework-CoreMIDI (==10.3)", "pyobjc-framework-CoreML (==10.3)", "pyobjc-framework-CoreMedia (==10.3)", "pyobjc-framework-CoreMediaIO (==10.3)", "pyobjc-framework-CoreMotion (==10.3)", "pyobjc-framework-CoreServices (==10.3)", "pyobjc-framework-CoreSpotlight (==10.3)", "pyobjc-framework-CoreText (==10.3)", "pyobjc-framework-CoreWLAN (==10.3)", "pyobjc-framework-CryptoTokenKit (==10.3)", "pyobjc-framework-DVDPlayback (==10.3)", "pyobjc-framework-DataDetection (==10.3)", "pyobjc-framework-DeviceCheck (==10.3)", "pyobjc-framework-DictionaryServices (==10.3)", "pyobjc-framework-DiscRecording (==10.3)", "pyobjc-framework-DiscRecordingUI (==10.3)", "pyobjc-framework-DiskArbitration (==10.3)", "pyobjc-framework-EventKit (==10.3)", "pyobjc-framework-ExceptionHandling (==10.3)", "pyobjc-framework-ExecutionPolicy (==10.3)", "pyobjc-framework-ExtensionKit (==10.3)", "pyobjc-framework-ExternalAccessory (==10.3)", "pyobjc-framework-FSEvents (==10.3)", "pyobjc-framework-FileProvider (==10.3)", "pyobjc-framework-FileProviderUI (==10.3)", "pyobjc-framework-FinderSync (==10.3)", "pyobjc-framework-GameCenter (==10.3)", "pyobjc-framework-GameController (==10.3)", "pyobjc-framework-GameKit (==10.3)", "pyobjc-framework-GameplayKit (==10.3)", "pyobjc-framework-HealthKit (==10.3)", "pyobjc-framework-IOBluetooth (==10.3)", "pyobjc-framework-IOBluetoothUI (==10.3)", "pyobjc-framework-IOSurface (==10.3)", "pyobjc-framework-ImageCaptureCore (==10.3)", "pyobjc-framework-InputMethodKit (==10.3)", "pyobjc-framework-InstallerPlugins (==10.3)", "pyobjc-framework-InstantMessage (==10.3)", "pyobjc-framework-Intents (==10.3)", "pyobjc-framework-IntentsUI (==10.3)", "pyobjc-framework-KernelManagement (==10.3)", "pyobjc-framework-LatentSemanticMapping (==10.3)", "pyobjc-framework-LaunchServices (==10.3)", "pyobjc-framework-LinkPresentation (==10.3)", "pyobjc-framework-LocalAuthentication (==10.3)", "pyobjc-framework-LocalAuthenticationEmbeddedUI (==10.3)", "pyobjc-framework-MLCompute (==10.3)", "pyobjc-framework-MailKit (==10.3)", "pyobjc-framework-MapKit (==10.3)", "pyobjc-framework-MediaAccessibility (==10.3)", "pyobjc-framework-MediaLibrary (==10.3)", "pyobjc-framework-MediaPlayer (==10.3)", "pyobjc-framework-MediaToolbox (==10.3)", "pyobjc-framework-Metal (==10.3)", "pyobjc-framework-MetalFX (==10.3)", "pyobjc-framework-MetalKit (==10.3)", "pyobjc-framework-MetalPerformanceShaders (==10.3)", "pyobjc-framework-MetalPerformanceShadersGraph (==10.3)", "pyobjc-framework-MetricKit (==10.3)", "pyobjc-framework-ModelIO (==10.3)", "pyobjc-framework-MultipeerConnectivity (==10.3)", "pyobjc-framework-NaturalLanguage (==10.3)", "pyobjc-framework-NetFS (==10.3)", "pyobjc-framework-Network (==10.3)", "pyobjc-framework-NetworkExtension (==10.3)", "pyobjc-framework-NotificationCenter (==10.3)", "pyobjc-framework-OSAKit (==10.3)", "pyobjc-framework-OSLog (==10.3)", "pyobjc-framework-OpenDirectory (==10.3)", "pyobjc-framework-PHASE (==10.3)", "pyobjc-framework-PassKit (==10.3)", "pyobjc-framework-PencilKit (==10.3)", "pyobjc-framework-Photos (==10.3)", "pyobjc-framework-PhotosUI (==10.3)", "pyobjc-framework-PreferencePanes (==10.3)", "pyobjc-framework-PubSub (==10.3)", "pyobjc-framework-PushKit (==10.3)", "pyobjc-framework-Quartz (==10.3)", "pyobjc-framework-QuickLookThumbnailing (==10.3)", "pyobjc-framework-ReplayKit (==10.3)", "pyobjc-framework-SafariServices (==10.3)", "pyobjc-framework-SafetyKit (==10.3)", "pyobjc-framework-SceneKit (==10.3)", "pyobjc-framework-ScreenCaptureKit (==10.3)", "pyobjc-framework-ScreenSaver (==10.3)", "pyobjc-framework-ScreenTime (==10.3)", "pyobjc-framework-ScriptingBridge (==10.3)", "pyobjc-framework-SearchKit (==10.3)", "pyobjc-framework-Security (==10.3)", "pyobjc-framework-SecurityFoundation (==10.3)", "pyobjc-framework-SecurityInterface (==10.3)", "pyobjc-framework-SensitiveContentAnalysis (==10.3)", "pyobjc-framework-ServiceManagement (==10.3)", "pyobjc-framework-SharedWithYou (==10.3)", "pyobjc-framework-SharedWithYouCore (==10.3)", "pyobjc-framework-ShazamKit (==10.3)", "pyobjc-framework-Social (==10.3)", "pyobjc-framework-SoundAnalysis (==10.3)", "pyobjc-framework-Speech (==10.3)", "pyobjc-framework-SpriteKit (==10.3)", "pyobjc-framework-StoreKit (==10.3)", "pyobjc-framework-Symbols (==10.3)", "pyobjc-framework-SyncServices (==10.3)", "pyobjc-framework-SystemConfiguration (==10.3)", "pyobjc-framework-SystemExtensions (==10.3)", "pyobjc-framework-ThreadNetwork (==10.3)", "pyobjc-framework-UniformTypeIdentifiers (==10.3)", "pyobjc-framework-UserNotifications (==10.3)", "pyobjc-framework-UserNotificationsUI (==10.3)", "pyobjc-framework-VideoSubscriberAccount (==10.3)", "pyobjc-framework-VideoToolbox (==10.3)", "pyobjc-framework-Virtualization (==10.3)", "pyobjc-framework-Vision (==10.3)", "pyobjc-framework-WebKit (==10.3)", "pyobjc-framework-iTunesLibrary (==10.3)", "pyobjc-framework-libdispatch (==10.3)", "pyobjc-framework-libxpc (==10.3)"] [[package]] name = "pyobjc-core" -version = "10.2" +version = "10.3" description = "Python<->ObjC Interoperability Module" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-core-10.2.tar.gz", hash = "sha256:0153206e15d0e0d7abd53ee8a7fbaf5606602a032e177a028fc8589516a8771c"}, - {file = "pyobjc_core-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8eab50ce7f17017a0f1d68c3b7e88bb1bb033415fdff62b8e0a9ee4ab72f242"}, - {file = "pyobjc_core-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f2115971463073426ab926416e17e5c16de5b90d1a1f2a2d8724637eb1c21308"}, - {file = "pyobjc_core-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a70546246177c23acb323c9324330e37638f1a0a3d13664abcba3bb75e43012c"}, - {file = "pyobjc_core-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a9b5a215080d13bd7526031d21d5eb27a410780878d863f486053a0eba7ca9a5"}, - {file = "pyobjc_core-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:eb1ab700a44bcc4ceb125091dfaae0b998b767b49990df5fdc83eb58158d8e3f"}, - {file = "pyobjc_core-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9a7163aff9c47d654f835f80361c1b112886ec754800d34e75d1e02ff52c3d7"}, + {file = "pyobjc_core-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:713dd174e3fd4bfb975949d7314c778d02909d5c017497408d8eedcedab73a42"}, + {file = "pyobjc_core-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eca0c6d3923e8f5c4a86831e446f2995958525ff0c6a01f6f4fa8de0cb25c8a"}, + {file = "pyobjc_core-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:50dfe3bd7295f04445cf3134113578678a188ca4fb0869e821369a2d288492dc"}, + {file = "pyobjc_core-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:13511c0ab3235486d4560e9923ed96db76357e7c7e70e0629fee9425b0a8d901"}, + {file = "pyobjc_core-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a7e3a0625f9370ef86a2529be0d22dd3dc48326a7a28113bc6f24d4bf866d076"}, + {file = "pyobjc_core-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7a17321d2e226ca43a8f70f8bc823cfaa58ff9d9cdedcd16708d4eec9ca808b2"}, + {file = "pyobjc_core-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5c2bfb2f9fcb9f291a64041a336aab1b34a20dbbf4f77fca3057a7d8ef9ce9c5"}, + {file = "pyobjc_core-10.3.tar.gz", hash = "sha256:875f2555b51a8a36cafbdb7d5d36f3452287a81bd5d7dc09aa6c309d638a9275"}, ] [[package]] name = "pyobjc-framework-accessibility" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Accessibility on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Accessibility-10.2.tar.gz", hash = "sha256:275c9ac0df1350bf751dbddc81d98f7702cf03ad66e0271876cef9aa70ca5c24"}, - {file = "pyobjc_framework_Accessibility-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c801ad06fadc17f281102408d8a98a844739b3496b9799e2cef2b630a8bec312"}, - {file = "pyobjc_framework_Accessibility-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:861c6f7683c1bd769df85e677905a051f17f01a99a59cbba63b68c2f4bf46066"}, - {file = "pyobjc_framework_Accessibility-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:7e0a716b0cc89fbfb68d4ac0eba4bbd9c50a092255efa2794c4bb93b27b05b98"}, + {file = "pyobjc_framework_Accessibility-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6affccae6d0cd6f1061954c9a5c3341f6db3a2358fefa64117ccefd444d2a985"}, + {file = "pyobjc_framework_Accessibility-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:523e031fcb4e06270212c24b93de19df66287fe77bec3d03a27dc1c888da7992"}, + {file = "pyobjc_framework_Accessibility-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b119e3bf3c5173358797d4ed2fddf554b498dd623def8dd2925f7ac27a548655"}, + {file = "pyobjc_framework_accessibility-10.3.tar.gz", hash = "sha256:5be6f066582b4eda8e0c6ffac7d19c9f01835c036f16bed81211c9c7dece9f67"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-accounts" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Accounts on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Accounts-10.2.tar.gz", hash = "sha256:40c8d7299b58b2300db0a6189a7c7056d38385e58700cb40137a744bb03708b7"}, - {file = "pyobjc_framework_Accounts-10.2-py2.py3-none-any.whl", hash = "sha256:9616c8c27f08baadfeea7c27fb1efac043e0785fbbbfbe05f20021402ac5295f"}, + {file = "pyobjc_framework_Accounts-10.3-py2.py3-none-any.whl", hash = "sha256:09f311f689676805b98e8c848df582ab8a6f2ec30cd2eabfa453340b2f813abe"}, + {file = "pyobjc_framework_accounts-10.3.tar.gz", hash = "sha256:a84a84e82536054403bcf1a990755897d2011848e13377faaedca1333c58d418"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-addressbook" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AddressBook on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AddressBook-10.2.tar.gz", hash = "sha256:d6969fcbde1d78ec9fa0ebcefc2f453090e35d7590c4b4baf62174e060de6bce"}, - {file = "pyobjc_framework_AddressBook-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6558b05e9d40a7f40650cddde9b71cb6fb536edf891985c977d4abc626f07a63"}, - {file = "pyobjc_framework_AddressBook-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c57347c04b11310f980e3d6cadc84ebc701d2216853108f9b708c03b0d295a59"}, - {file = "pyobjc_framework_AddressBook-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ba6eff580e4764dc9616b73cf4794cd44b4389b98f95696bac0bb5190f6a1211"}, + {file = "pyobjc_framework_AddressBook-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3e383caa4af01522cad1336b67339e50786887ce9e5c0a1ccfbcd4949f1930"}, + {file = "pyobjc_framework_AddressBook-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7403df85c541fc2b8569c21fa148a5cf56faff2763466600a7a4953e858ceaed"}, + {file = "pyobjc_framework_AddressBook-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d26655504b723cbf2e9efcd76f937bbe4afe5ce107ec158f96aec9dfd925a2d5"}, + {file = "pyobjc_framework_addressbook-10.3.tar.gz", hash = "sha256:e9488b4fede12f6bbd6215ab3478699c94a257b31983f665ce3cfa76d8249f1d"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-adservices" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AdServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AdServices-10.2.tar.gz", hash = "sha256:76eafba018c819c1770f88daa68d25fc5f06dc93a9f5e369d329d0f341dec3af"}, - {file = "pyobjc_framework_AdServices-10.2-py2.py3-none-any.whl", hash = "sha256:b03fcd460b632fc1b3fd8275060255e518933d1d0da06d6eda9b128b4e2999ec"}, + {file = "pyobjc_framework_AdServices-10.3-py2.py3-none-any.whl", hash = "sha256:a3d8ed85beb1f75335fb5598eb0d63a76390099bb09735b8a5b37908ddd6ad40"}, + {file = "pyobjc_framework_adservices-10.3.tar.gz", hash = "sha256:c3b8a874a77a346b34439d8fcc6e37fa59836130160a58e848af2b222f476fe5"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-adsupport" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AdSupport on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AdSupport-10.2.tar.gz", hash = "sha256:1eb76dc039d081e6d25b4fd334a3987bd9f73527a17844c421bcc8289dd16968"}, - {file = "pyobjc_framework_AdSupport-10.2-py2.py3-none-any.whl", hash = "sha256:4883ac30f1d78d764b57aacb46af78018f2302b9f7e8f4e1fccb25c3cb44ab74"}, + {file = "pyobjc_framework_AdSupport-10.3-py2.py3-none-any.whl", hash = "sha256:e68b2bfcf095fd291fe04b6626d26dc60c17c9e37418b30f977e79a42567d415"}, + {file = "pyobjc_framework_adsupport-10.3.tar.gz", hash = "sha256:fe04f5bdab7d1f56c9c97fadea619576d62774bffb418832b97c9e17ef7cab01"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-applescriptkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AppleScriptKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AppleScriptKit-10.2.tar.gz", hash = "sha256:871452c17b15ce33337cd7ebd293fe31daef9f02f16ebb649efc36165cfb02da"}, - {file = "pyobjc_framework_AppleScriptKit-10.2-py2.py3-none-any.whl", hash = "sha256:15af7d97f017563ff3771127a2b7c515496aa6083497415cbe8c27dd5811c50f"}, + {file = "pyobjc_framework_AppleScriptKit-10.3-py2.py3-none-any.whl", hash = "sha256:93f25fe54cf5ea0b389956c3ab7061181373db7aec8beccbc376d0c9e116dc71"}, + {file = "pyobjc_framework_applescriptkit-10.3.tar.gz", hash = "sha256:d6a99ad673ed1feaccc41aa0e082526026b7b43e6b37a018c123577513965767"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-applescriptobjc" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AppleScriptObjC on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AppleScriptObjC-10.2.tar.gz", hash = "sha256:71f90e41be6beb392a833d915d3af13d10526bfb29bf35cb9af1578b5ec52566"}, - {file = "pyobjc_framework_AppleScriptObjC-10.2-py2.py3-none-any.whl", hash = "sha256:41156fcc36acc3ca7bd0a62af47af4ab8089330c6072db6047b91b52f815f049"}, + {file = "pyobjc_framework_AppleScriptObjC-10.3-py2.py3-none-any.whl", hash = "sha256:97e171fda7473ec09788531b840fd19b26ab64fc8d44dbdf4ec70da2127304c6"}, + {file = "pyobjc_framework_applescriptobjc-10.3.tar.gz", hash = "sha256:9f7fad7bd4f6e4b90800ac87a4f4260e44fd78e052a0c24bef90b797b9cf4159"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-applicationservices" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ApplicationServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ApplicationServices-10.2.tar.gz", hash = "sha256:f83d6ed3320afb6648be6defafe0f05bac00d0281fc84ee4766ff977309b659f"}, - {file = "pyobjc_framework_ApplicationServices-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2aebfed888f9bcb4f11d93f9ef9a76d561e92848dcb6011da5d5e9d3593371be"}, - {file = "pyobjc_framework_ApplicationServices-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:edfd3153e64ee9573bcff7ccaa1fbbbd6964658f187464c461ad34f24552bc85"}, - {file = "pyobjc_framework_ApplicationServices-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d2c89b246c19a041221ff36e9121c92e86a4422016f809a40f5ce3d647882d9"}, - {file = "pyobjc_framework_ApplicationServices-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee1e69947f31aad5fdec44921ce37f7f921faf50a0ceb27ed40b6d54f4b15d0e"}, - {file = "pyobjc_framework_ApplicationServices-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:101f5b09d71e55bd39e6e91f0787433805d422622336b72fde969a7c54528045"}, - {file = "pyobjc_framework_ApplicationServices-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a3ef00c9aea09c5ef5840b8749d0753249869bc30e124145b763cd0b4b81155"}, + {file = "pyobjc_framework_ApplicationServices-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6beb4565b5fa17f45828e2957161d4f6991f7bea5da6c44e268d96a7d103bfa7"}, + {file = "pyobjc_framework_ApplicationServices-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe18f999755e15f2c7bc459860e4aac9a78b84208eb1751cbaef83e6ac9f6765"}, + {file = "pyobjc_framework_ApplicationServices-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9cd2b5bae9e0517b453aac7fc15143e9ac5ea607ad6a8fa56d31b58555403bba"}, + {file = "pyobjc_framework_ApplicationServices-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:ea7db447abef7deb8233da00204bc5e76e695e504dcf7ad765c7b5d04d164188"}, + {file = "pyobjc_framework_ApplicationServices-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9381d3c3ad04063d460b5aa9edd8bb1234350833b4decb8dd3df3feefc19c62f"}, + {file = "pyobjc_framework_ApplicationServices-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:cbc55594468cab4df4314b956a0ab9b92395460ede76f874991d6219038c8e2a"}, + {file = "pyobjc_framework_ApplicationServices-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cba0a07176a30b1e3961842195bad2f079f80ec57872d52d705910e18eb23e26"}, + {file = "pyobjc_framework_applicationservices-10.3.tar.gz", hash = "sha256:36ca55df6a9552b7404e1a0799797c15db47faf608050024a898d50d2b1f4351"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreText = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreText = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-apptrackingtransparency" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AppTrackingTransparency on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AppTrackingTransparency-10.2.tar.gz", hash = "sha256:2eb7276fc70c676562e33c3f7b2fe254175236f968516c63cc8507f325ac56db"}, - {file = "pyobjc_framework_AppTrackingTransparency-10.2-py2.py3-none-any.whl", hash = "sha256:de140b6b6ca1df928d13d986b093f19b8be0c9ab7c42f4121bdbf58f5c69df48"}, + {file = "pyobjc_framework_AppTrackingTransparency-10.3-py2.py3-none-any.whl", hash = "sha256:10774b1e288ee303813f5736569a5f7522c8cde0ad5d787a36f9d4f89da6e2d7"}, + {file = "pyobjc_framework_apptrackingtransparency-10.3.tar.gz", hash = "sha256:8917c06633b9b5b5317945edfbc7064679f096651ae847fd4d186734a256eaac"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-audiovideobridging" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AudioVideoBridging on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AudioVideoBridging-10.2.tar.gz", hash = "sha256:94d77284aae3a151124aa170074c2902537f540debb076376d49f5ee54fb9ce1"}, - {file = "pyobjc_framework_AudioVideoBridging-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:180e0d1862ba7748a8e4dff0bfeb5dc162bc4d7b0c0888a333f11dbf2569af74"}, - {file = "pyobjc_framework_AudioVideoBridging-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1d68f51143e8da14940ea54edd1236e5cd229dcbc83350551945df285b482704"}, - {file = "pyobjc_framework_AudioVideoBridging-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e0bd4ed2f8a16795b1b46ea9bed746995044f2cd6afb808018ac9c1549dc60b4"}, - {file = "pyobjc_framework_AudioVideoBridging-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2300d1c9ac22cfa8ef80a86dcdf3bc0be1cfa26a61c560f976fbcd0abfb4f13c"}, - {file = "pyobjc_framework_AudioVideoBridging-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a5d48b8192385ef2e0bea47c7b65ca1e0d06d1bdc4a7da59f3d1df3932c5f11c"}, - {file = "pyobjc_framework_AudioVideoBridging-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3883a0f76187a120ad1478f674be245d2949d1bae436d697786ad4086d878b18"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b29110d34e79a7ff275628246237de1f497e88db954c0763d1da19874e136639"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:21761c9f69813d95243c9ecfa68161468a48cf2eae3bff982c568458f369de52"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4683c2f919161178210292f3aff8bf664d402325452be4a7fae419cc02e3f976"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:8688210459c3fe3883131c6d91d3ee5e821488215398dd1e3513ca472cc3f335"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4bd821fe8da7ee329f96900645515d23689eaea4799ebb4738ab1e0e9fe68d00"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:f58c46deb3c75c3c35904ab300986863f0ee0f494919b7bc0f92c6d40873d7e0"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5cbe0382f874fd277704b7a539cc401fe915ecdde75e67c719c3e45aef55f911"}, + {file = "pyobjc_framework_audiovideobridging-10.3.tar.gz", hash = "sha256:0125620773157566c34038318b064def855ae096ac601e4482882277e4d913e6"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-authenticationservices" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AuthenticationServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AuthenticationServices-10.2.tar.gz", hash = "sha256:1be0f05458c4ebfc3e018cb59b4a8bd9022c42b18fea449b0fbf5def0b5f7ef7"}, - {file = "pyobjc_framework_AuthenticationServices-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c797abcd8fb1d9f0f48849093fcbf480814256fca9f1a835445f551a369541e2"}, - {file = "pyobjc_framework_AuthenticationServices-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cf172a06ffab3faa98a95041ce5205ec6c516b59513390d48cfafe17ff4add08"}, - {file = "pyobjc_framework_AuthenticationServices-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3d6b81342caa28dbdc44c3f32820958e0b3865bd3e5bac7ba5ce9efc293e0d75"}, + {file = "pyobjc_framework_AuthenticationServices-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6598252867b6578d8f5c6f987299aadcdaa36095c15439318011fb7b3c2e9334"}, + {file = "pyobjc_framework_AuthenticationServices-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cb9d0154a15a8509bb0c4be32138b852802bcf0ad362fe9907038cfe37c5f9b7"}, + {file = "pyobjc_framework_AuthenticationServices-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4f8a1e45db6e61d6e0a18e3182e07cac7e9c09b2b0c5909a74c465938d3cbab5"}, + {file = "pyobjc_framework_authenticationservices-10.3.tar.gz", hash = "sha256:2cbb41260156dc5d2423fd9e3573c04117eca91f765b3c8f9268360d97253a7e"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-automaticassessmentconfiguration" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AutomaticAssessmentConfiguration on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AutomaticAssessmentConfiguration-10.2.tar.gz", hash = "sha256:ead3f75200ad74dd013b4a6372054b84b2adeacdac656ca31e763e42fb76cf7b"}, - {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f4a60e1f1dae0d8d9223cb09c945aeb5688c09b3dffa9c6e9457981b05902874"}, - {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1ca34d71b7def8bf4e820e0ee64cae0d732309c6ddc126699a5bbd0c5719dc48"}, - {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:cb3242e2943768e02208c13b4eef47068f0e1ff8ad5572fabfaef7964737daaa"}, + {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fca0e66a78daa4605b056c54a3aadc10772d7d942b3fbc77d1a12fcc5d454bc"}, + {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2af49bd323db3d94421364e2f89bcb38511dcf3bd36688c852ea49619caed9db"}, + {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:03e506e574b75aac0a82d783376b4e2ff1519c31e14dd2b0a978595e27149d0c"}, + {file = "pyobjc_framework_automaticassessmentconfiguration-10.3.tar.gz", hash = "sha256:e31b4f0e4127b5e82f77c7fac73d8168e12df02176ab38b220683c375b8a884f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-automator" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Automator on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Automator-10.2.tar.gz", hash = "sha256:fb753e5bd40bfe720fa9e60e2ea5a1777b4c92082ffeba42b4055cdd56cb022d"}, - {file = "pyobjc_framework_Automator-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0034f9e64c3e77b8e1adc54170868954af67b50457b768982de705d8cd170792"}, - {file = "pyobjc_framework_Automator-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e3b66af8ecd2effca8d51b512518137173b026ab13c30dbdac3d0d7ee059fc48"}, - {file = "pyobjc_framework_Automator-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d7f26be322fee0476125bfb2658a08db81b705ce0e8880e91c627562419a9821"}, + {file = "pyobjc_framework_Automator-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0e63a47fd3a89334de05246e4594f33af13b495ad2b4523a5fa18db445d1015f"}, + {file = "pyobjc_framework_Automator-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:efff1edede64731581026ec4b3f89ec624f1a7fe8652ae435b7a8090ba2e8f47"}, + {file = "pyobjc_framework_Automator-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c303f65a16a09f70bf2b52e0b41270329422c2d8e07c7d4bf16146b4c5db60d7"}, + {file = "pyobjc_framework_automator-10.3.tar.gz", hash = "sha256:18dc4792774e0a7e13c5df62212b73af8fa78a40414f3422e52919145a7a9180"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-avfoundation" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AVFoundation on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AVFoundation-10.2.tar.gz", hash = "sha256:4d394014f2477c0c6a596dbb01ef5d92944058d0e0d954ce6121a676ae9395ce"}, - {file = "pyobjc_framework_AVFoundation-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5f20c11a8870d7d58f0e4f20f918e45e922520aa5c9dbee61dc59ca4bc4bd26d"}, - {file = "pyobjc_framework_AVFoundation-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:283355d1f96c184e5f5f479870eb3bf510747307697616737bbc5d224af3abcb"}, - {file = "pyobjc_framework_AVFoundation-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:a63a4e26c088023b0b1cb29d7da2c2246aa8eca2b56767fe1cc36a18c6fb650b"}, + {file = "pyobjc_framework_AVFoundation-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2692fc423a1fcbcb3f8355d8217d9258cf27c0b2ef6c2362829fdc0b65f262c4"}, + {file = "pyobjc_framework_AVFoundation-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:4a54fc6e34a6045b4b6050699d4724bdb7f1ae8e6355c9646e262db3f9b31dfa"}, + {file = "pyobjc_framework_AVFoundation-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:56989f914e463340eb7d51db63a10dd6b5b5204bb1da528a0602d80072d56788"}, + {file = "pyobjc_framework_avfoundation-10.3.tar.gz", hash = "sha256:0bcccca344f7708416c7d910daab2a7b7f05c51f0efb4eec1860a01ed4862af2"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreAudio = ">=10.2" -pyobjc-framework-CoreMedia = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreAudio = ">=10.3" +pyobjc-framework-CoreMedia = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-avkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AVKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AVKit-10.2.tar.gz", hash = "sha256:6497a5109a29235a7fd8bddcb6d79bd495ccd9373b41e84ca3f012a642e5b880"}, - {file = "pyobjc_framework_AVKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:480766be9da6bb1a6272a4f13f6a327ec952fe1cd41eb0e7c3a07abb07a3491f"}, - {file = "pyobjc_framework_AVKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c9cfdc9ef8f7c9abe53841e8e548b2671f0a425ce9e0e4961314f5d080401e68"}, - {file = "pyobjc_framework_AVKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ff811fc88fb9d676a4892adea21a1a82384777af53153c74bb829501721f3374"}, + {file = "pyobjc_framework_AVKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:56555ea3b415c929d0111db2b52961b01bbb6e105d3bf75d9ff84ab1399cf4c9"}, + {file = "pyobjc_framework_AVKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:420e09834e862a13dc0a93debd0a493775bd99ba1a8f7262531d02d755a584d6"}, + {file = "pyobjc_framework_AVKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:de1b117de0490018058c0e159b771bd5e908ac876fe53622a6d1e019f0f99415"}, + {file = "pyobjc_framework_avkit-10.3.tar.gz", hash = "sha256:5b9ab88fde35d45e495efab95ba1fdb1c83f63c35ba71cf2a7312efb9467f0ba"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-avrouting" -version = "10.2" +version = "10.3" description = "Wrappers for the framework AVRouting on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-AVRouting-10.2.tar.gz", hash = "sha256:133d646cf36cfa329c2b3a060c7b81368a95bfbb24f30e2bae2804be65b93ec9"}, - {file = "pyobjc_framework_AVRouting-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1f72c23e92981311e218a04f3cfcd0ef4c3a93058af6e0042c7cf835320300cc"}, - {file = "pyobjc_framework_AVRouting-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a91d65fda866e64bd249c0f11017d0d9f569b3e9d6d159c38e64e1b144a04d85"}, - {file = "pyobjc_framework_AVRouting-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3357ed6b9bf583ded7eee4531ac1854c6e1cdfe91a278f2dec18593d2381d488"}, + {file = "pyobjc_framework_AVRouting-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f9f1ebc5161758522a0da9336df8f893f0dce50ca130fcf95f222b30f016b51f"}, + {file = "pyobjc_framework_AVRouting-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b071da24ef134447dab23b80f2e6affd3bf2765ecb3633074a5e8724eee2b57c"}, + {file = "pyobjc_framework_AVRouting-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:73ba803f2a448a3af4e7a666998d13aa6200a0812fe7a19d51ef2e1e63b4fdc5"}, + {file = "pyobjc_framework_avrouting-10.3.tar.gz", hash = "sha256:1fa5c727ee8d6903625f5a946c43c53e96b78ec24e96f11b5bf12288e5726365"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-backgroundassets" -version = "10.2" +version = "10.3" description = "Wrappers for the framework BackgroundAssets on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-BackgroundAssets-10.2.tar.gz", hash = "sha256:97ad7b0c693e406950c0c4af2edc9320eac9aef7fdf33274903f526b4682fcb7"}, - {file = "pyobjc_framework_BackgroundAssets-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a71de388248ed05eda85abc440dbe3f04ff39567745785df25b1d5316b2aa9f1"}, - {file = "pyobjc_framework_BackgroundAssets-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:476a7fc80a4083405c82b0bb0d8551cccd10f998a2a9d35c8eab76c82915d25e"}, - {file = "pyobjc_framework_BackgroundAssets-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:9c8721ea4695f1cd5f1f7d6b2a70b3e2b9cefe484289b7427cfda5d23b48e7b6"}, + {file = "pyobjc_framework_BackgroundAssets-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:83c66c350122cbb25d56ddc27a036eb7046eeb9d0411f3bf40b2b76bb0a55e8a"}, + {file = "pyobjc_framework_BackgroundAssets-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1307c0fc2616b5fbf214dd6c906e0da10d8bb25874ec6e8a41d14c7e146d0265"}, + {file = "pyobjc_framework_BackgroundAssets-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6a5ab8be15c98368e60eae602c01baea291c0b05075d89ae6faeb9e48f287c4f"}, + {file = "pyobjc_framework_backgroundassets-10.3.tar.gz", hash = "sha256:4ba4a0a2d5f657ea4f27962686e5eb725408912a1aa3846afafe626653c722d6"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-browserenginekit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework BrowserEngineKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-BrowserEngineKit-10.2.tar.gz", hash = "sha256:a47648e62d3482d39179ffe51543322817dd7a639cef9dcd555dfcc7d6a6497f"}, - {file = "pyobjc_framework_BrowserEngineKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:98563b461e2c96ad387abe1885e91f7bc0686868b39c273774e087bbf1b500ac"}, - {file = "pyobjc_framework_BrowserEngineKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5eb3d8f9e198aaeb01a4a85aa739624942c39b626400d232271d632f1ee30e09"}, - {file = "pyobjc_framework_BrowserEngineKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6824c528e10da1b560d83f55e258232b8916d49d12a578dd00d3ec4e702d3011"}, + {file = "pyobjc_framework_BrowserEngineKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:799551f5a432a1389bb73b5d580c55d0a75cdedee3fb093fd28164e30fe20f2b"}, + {file = "pyobjc_framework_BrowserEngineKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0a97c27c8a973131d69ef197d6168cd6e0464bc7005fa67a6d14e1fb09d29020"}, + {file = "pyobjc_framework_BrowserEngineKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3836d388413a047bdadfe7cc5350c1c8c6a89514e6e73334519ee967dbaa6e0e"}, + {file = "pyobjc_framework_browserenginekit-10.3.tar.gz", hash = "sha256:730e0c0b8c741f93a74aaba1dca53743922f0e43bbed0c94831bf18dc5683a5b"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreAudio = ">=10.2" -pyobjc-framework-CoreMedia = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreAudio = ">=10.3" +pyobjc-framework-CoreMedia = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-businesschat" -version = "10.2" +version = "10.3" description = "Wrappers for the framework BusinessChat on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-BusinessChat-10.2.tar.gz", hash = "sha256:44ecf240da59ce36f2d75d1ed9f58e05f2df46b9b1989ee0cc184a46c779fb4e"}, - {file = "pyobjc_framework_BusinessChat-10.2-py2.py3-none-any.whl", hash = "sha256:aa51d4d0b3b3eb050242e0d0e48b29e020ccfeb82a39c0d3a2289512734f53e4"}, + {file = "pyobjc_framework_BusinessChat-10.3-py2.py3-none-any.whl", hash = "sha256:d5e16558060059784e65e1fd96c7ff52a6bb531179d5e5f55882060adb5f6e6f"}, + {file = "pyobjc_framework_businesschat-10.3.tar.gz", hash = "sha256:a320db015134b7cd200d1ec31ab3edb5c1361eef7dc0232d896da9a292015f80"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-calendarstore" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CalendarStore on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CalendarStore-10.2.tar.gz", hash = "sha256:131c14faa227a251d7254afd9c00fef203361dd76224d9700ba5e99682e191d8"}, - {file = "pyobjc_framework_CalendarStore-10.2-py2.py3-none-any.whl", hash = "sha256:e289236df651953a41be8ee4ce548f477a6ab8e90aa8bbd73f46ad29032ff13f"}, + {file = "pyobjc_framework_CalendarStore-10.3-py2.py3-none-any.whl", hash = "sha256:ad3aeea3183f172ac2fbcf8bebdbc4b805664b04922b0c162ab0bd2ccff6bcca"}, + {file = "pyobjc_framework_calendarstore-10.3.tar.gz", hash = "sha256:67f9d202adfc1cddb05552a9f7e1e13bf5e7db401df259105a35070d0c17ea61"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-callkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CallKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CallKit-10.2.tar.gz", hash = "sha256:45cd81a5b6b0107ba56e26d8e54e852b8a15b3487b7291b5818e10e94beee6d0"}, - {file = "pyobjc_framework_CallKit-10.2-py2.py3-none-any.whl", hash = "sha256:f3f26c877743a340718e0647ccee4604f9d87aa8ad5c3268c794d94f6f9246ee"}, + {file = "pyobjc_framework_CallKit-10.3-py2.py3-none-any.whl", hash = "sha256:5a54438c22e66328b6cf3a12e138f5531fef5772bb0c8d542848ad21f0d87857"}, + {file = "pyobjc_framework_callkit-10.3.tar.gz", hash = "sha256:8ba5d5174c9090fa6befe2e0840575ff3fff83fb47629047ed1ccf54991e0972"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-cfnetwork" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CFNetwork on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CFNetwork-10.2.tar.gz", hash = "sha256:18ebd22c645b5b77c1df6d973a91cc035ddd4666346912b2a0c847803c23f4d4"}, - {file = "pyobjc_framework_CFNetwork-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6050428c99505e09db1fe5d0eafaaca4ead407ffaaab8a5c1e5ec09e7ad31053"}, - {file = "pyobjc_framework_CFNetwork-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f7a305d7f94a11dd32d3ab9159cde1f9655f107282373841668624b124935af8"}, - {file = "pyobjc_framework_CFNetwork-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:41a211b934afebbc9dd9ce76cb5c2862244a699a41badb660ab46c198414c4cb"}, + {file = "pyobjc_framework_CFNetwork-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c52c47463d1e58c56f9d84bb29374ec71ec0b06f68cdb7359ae33c1572a39adc"}, + {file = "pyobjc_framework_CFNetwork-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f73e6da65867a498303ef315f1182b6e88ceca78c03424e17b7a43bbe0199d58"}, + {file = "pyobjc_framework_CFNetwork-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0e1c060b64e865e88af6fd60965f3fc16f31516e2235025e46e985a55c780b6c"}, + {file = "pyobjc_framework_cfnetwork-10.3.tar.gz", hash = "sha256:9dd4700f88575dce21b0827fde79ac29580f0f4f99a725aa910b9aaad47e0b63"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-cinematic" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Cinematic on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Cinematic-10.2.tar.gz", hash = "sha256:514effad241be5c8df4ef870683fa1387909970a7f7d8bbf343c06e840931854"}, - {file = "pyobjc_framework_Cinematic-10.2-py2.py3-none-any.whl", hash = "sha256:962af237b284605ecd30d584d2d7fb75fda40e429327578de5d651644d0316da"}, + {file = "pyobjc_framework_Cinematic-10.3-py2.py3-none-any.whl", hash = "sha256:2705fe6893bf8ac9c836dc5a10abe781e3e00af9b4b6c72eb455a0bee30b1deb"}, + {file = "pyobjc_framework_cinematic-10.3.tar.gz", hash = "sha256:17cfae0f02b382b9a9f69128279cb5c156b1dfbd205a7f87941a28bf9fd72c37"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-AVFoundation = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreMedia = ">=10.2" -pyobjc-framework-Metal = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-AVFoundation = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreMedia = ">=10.3" +pyobjc-framework-Metal = ">=10.3" [[package]] name = "pyobjc-framework-classkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ClassKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ClassKit-10.2.tar.gz", hash = "sha256:252e47e3284491e48000d4d87948b31e396aaa78eaf2447ba03a71f4b97cb989"}, - {file = "pyobjc_framework_ClassKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9d5f69e7bba660ca989e699d4b38a93db7ee3f8cff45e67a23fb852ac3caab49"}, - {file = "pyobjc_framework_ClassKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e1acc7231ef030125eaf7302f324909c56ba1c58ff91f4e160b6632938db64df"}, - {file = "pyobjc_framework_ClassKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:87158ca3d7cd78c50af353c23f32e1e8eb0adec47dc15fa4e4d777017d308b80"}, + {file = "pyobjc_framework_ClassKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:06b9a516cbdb6d1a18971a872f2a1306b19e3eb6c2ffb1b1fd54f7bcebc2aaf0"}, + {file = "pyobjc_framework_ClassKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:14f2ccd96c893b7f9ad852c19320eeaed09928a4d6a747aaadab136cf13f6fee"}, + {file = "pyobjc_framework_ClassKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5e2b21fa1f6ec371d6fbc25c044c084537823330314d527eac087fb1827ace3d"}, + {file = "pyobjc_framework_classkit-10.3.tar.gz", hash = "sha256:95279d5e21d2f6298b2956d46213c6ec2acf3762e6e1b62ba6b5c240274de5c4"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-cloudkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CloudKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CloudKit-10.2.tar.gz", hash = "sha256:497a0dda5f5a9aafc795e1941ef3e3662c2f3240096ce68893d0d5de6d54a474"}, - {file = "pyobjc_framework_CloudKit-10.2-py2.py3-none-any.whl", hash = "sha256:32bd77c2b9109113b2321feb6ed6d754af99df6569d953371f1547123be80467"}, + {file = "pyobjc_framework_CloudKit-10.3-py2.py3-none-any.whl", hash = "sha256:cad1645304336e5fafe9ffca3398bf8592c3b477b3ebb3c94c75b47a085d9dde"}, + {file = "pyobjc_framework_cloudkit-10.3.tar.gz", hash = "sha256:72e2dd2f5ea91c4a1dc45e50eac8566ba85f196a7aa14c159c6f079fcb2e67e7"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Accounts = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreData = ">=10.2" -pyobjc-framework-CoreLocation = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Accounts = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreData = ">=10.3" +pyobjc-framework-CoreLocation = ">=10.3" [[package]] name = "pyobjc-framework-cocoa" -version = "10.2" +version = "10.3" description = "Wrappers for the Cocoa frameworks on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Cocoa-10.2.tar.gz", hash = "sha256:6383141379636b13855dca1b39c032752862b829f93a49d7ddb35046abfdc035"}, - {file = "pyobjc_framework_Cocoa-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9227b4f271fda2250f5a88cbc686ff30ae02c0f923bb7854bb47972397496b2"}, - {file = "pyobjc_framework_Cocoa-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6a6042b7703bdc33b7491959c715c1e810a3f8c7a560c94b36e00ef321480797"}, - {file = "pyobjc_framework_Cocoa-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:18886d5013cd7dc7ecd6e0df5134c767569b5247fc10a5e293c72ee3937b217b"}, - {file = "pyobjc_framework_Cocoa-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ecf01400ee698d2e0ff4c907bcf9608d9d710e97203fbb97b37d208507a9362"}, - {file = "pyobjc_framework_Cocoa-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0def036a7b24e3ae37a244c77bec96b7c9c8384bf6bb4d33369f0a0c8807a70d"}, - {file = "pyobjc_framework_Cocoa-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f47ecc393bc1019c4b47e8653207188df784ac006ad54d8c2eb528906ff7013"}, + {file = "pyobjc_framework_Cocoa-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:745fcd99cc9ca1827a5b6fa2127d12023428f8ce2047afefc57b1e69f185750f"}, + {file = "pyobjc_framework_Cocoa-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:116b79be8e9756047a9b6f90d2f08c0e640ff86fcea85ca553dbbb4b121b390f"}, + {file = "pyobjc_framework_Cocoa-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:08ccc260d3481ddf03784f7dcf2cc7a4e9d8f1ecdf727cb4f80cde7b88416c39"}, + {file = "pyobjc_framework_Cocoa-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:277f5e4d4fab0d431cb5f07fc161a3076cb365099977e748c6a255e94eaad137"}, + {file = "pyobjc_framework_Cocoa-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:008e5ca144a378513ee5f8c5a9009e8b4401ec09edda3648b01f8d8b640b3152"}, + {file = "pyobjc_framework_Cocoa-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:3c3f9806aa04dc1cd08e18a98a97629f0d0581fa0d6a71e739934f02e8b1a8df"}, + {file = "pyobjc_framework_Cocoa-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb89620f96d5d0d52a158faeab1b568bed6fa6d0c4f883198e60e60a14db1360"}, + {file = "pyobjc_framework_cocoa-10.3.tar.gz", hash = "sha256:d39f90ffe04143911060c392e62b9514f14caaba119657d6e2b8b197af49e117"}, ] [package.dependencies] -pyobjc-core = ">=10.2" +pyobjc-core = ">=10.3" [[package]] name = "pyobjc-framework-collaboration" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Collaboration on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Collaboration-10.2.tar.gz", hash = "sha256:32e3a7fe8447f38fd3be5ea1fe9c1e52efef3889f4bd5781dffa3c5fa044fe20"}, - {file = "pyobjc_framework_Collaboration-10.2-py2.py3-none-any.whl", hash = "sha256:239a0505d702d49b5c3f0a3524531f9be63d599ea2cd3cbb5953147b34dbdcc1"}, + {file = "pyobjc_framework_Collaboration-10.3-py2.py3-none-any.whl", hash = "sha256:ebc711c769ed01382fe2f0335aeed57336e8ea6d352ba2ea514387e37e14325a"}, + {file = "pyobjc_framework_collaboration-10.3.tar.gz", hash = "sha256:b07f2b722bb6db94efe32007227d927d50c8ec43114fec31224da703de991bd4"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-colorsync" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ColorSync on Mac OS X" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ColorSync-10.2.tar.gz", hash = "sha256:108105c281b375dff7d226fcc3f860621a4880dcbab711660b74dc458a506231"}, - {file = "pyobjc_framework_ColorSync-10.2-py2.py3-none-any.whl", hash = "sha256:2fcc68eb6fa6300d34b95b1da1cc8d244f6999aed4b83099a3323d32e0349f98"}, + {file = "pyobjc_framework_ColorSync-10.3-py2.py3-none-any.whl", hash = "sha256:4cf483c9c370fda6ea621d7110b676321511c41b52e4ad33e94c98ebadee0094"}, + {file = "pyobjc_framework_colorsync-10.3.tar.gz", hash = "sha256:27990cde04b111087659507b270bbc788b36b693d1dc95be44e469e78f86e2b4"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-contacts" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Contacts on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Contacts-10.2.tar.gz", hash = "sha256:5a9de975f41c7dac3c219b4c60cd08b8ba385685db7997c8622f19e0a43e6857"}, - {file = "pyobjc_framework_Contacts-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b5ff801009c9346927b7efc82434ac14a0c2798bd018daf1e7d8aad74484b490"}, - {file = "pyobjc_framework_Contacts-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:52dd5e4b4574b2438420a56867ca2069e29414087dc27ad03e7c46d536f1e641"}, - {file = "pyobjc_framework_Contacts-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:8a387c47e90c74a3e6f4bc81187f1fde18a020bb1d08067497a0c35f462299f9"}, + {file = "pyobjc_framework_Contacts-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:fe73800104eea8d358dc89f68742bcb65cacbb7e7f3b7caafcdd669b13861057"}, + {file = "pyobjc_framework_Contacts-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:77b2efeaf48b1c1ec5a1aec78323842ae23c774b71aa22a306d66b583b1368fd"}, + {file = "pyobjc_framework_Contacts-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0747f0ff0a49daca0c3ddff28bafe6579bdaaa75eeb4d5a97603e204afc8cf84"}, + {file = "pyobjc_framework_contacts-10.3.tar.gz", hash = "sha256:ca2c9a28bcdb3e0bb0dded2a1a34824c0ec64145e4cdd36b0c8e1edcf8ef0e1f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-contactsui" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ContactsUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ContactsUI-10.2.tar.gz", hash = "sha256:2dd5f1993c36caf13527de0890c6c49c08a339e58bc3b3fa303d5a04b672b418"}, - {file = "pyobjc_framework_ContactsUI-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c8af8b52853ba2a09664dad40255613f01089c9bc77e5316b29d27c65603863c"}, - {file = "pyobjc_framework_ContactsUI-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:47a8fd0aa5cb680b0ba0f1fdd37f56525729e5ed998df2a312e9f81feea8fbb0"}, - {file = "pyobjc_framework_ContactsUI-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0575650e6e5985950bcd424da0b50e981ea5e6819d1c6fbccb075585e424e121"}, + {file = "pyobjc_framework_ContactsUI-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:78497fbb5b3b65b7318680f988919f7862e28ea1da8257a5a068623caeb42675"}, + {file = "pyobjc_framework_ContactsUI-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c5439b1db545c533c3a9578ed2dee39a98c553c7395c9b3ac20e089b1806a312"}, + {file = "pyobjc_framework_ContactsUI-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ba1315b9519930870adb506cb180e967266f30503e645b4974729fdf774a9d1e"}, + {file = "pyobjc_framework_contactsui-10.3.tar.gz", hash = "sha256:312af2525a5a4e45f23c2d9b3817d8ad5bb2395c44f18be3d692ce16e8fe2bb5"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Contacts = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Contacts = ">=10.3" [[package]] name = "pyobjc-framework-coreaudio" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreAudio on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreAudio-10.2.tar.gz", hash = "sha256:5e97ae7a65be85aee83aef004b31146c5fbf28325d870362959f7312b303fb67"}, - {file = "pyobjc_framework_CoreAudio-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:65ce01a9963692d9cf94aef36d8e342eb2e75b855a2f362f9cbcef9f3782a690"}, - {file = "pyobjc_framework_CoreAudio-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:22b5017ed340f9d3137baacb5f0c2354266017a4ed21890a795a0667788fc0cd"}, - {file = "pyobjc_framework_CoreAudio-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32608ce881b5e6a7cb332c2732762fa93829ac495c5344c33e8e8b72a2431b23"}, - {file = "pyobjc_framework_CoreAudio-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5182342257be1cdaa64bc38045cd81aca5b60bb86a9444194adbff58706ce91"}, - {file = "pyobjc_framework_CoreAudio-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:94ec138f95801019ec7f3e7010ad6f2c575aea69d2428aa9f5b159bf0355034a"}, - {file = "pyobjc_framework_CoreAudio-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:04ad3dddff27cb65d31a432aa1aa6290ff5d82a54bc5825da44ed7d80bcdb925"}, + {file = "pyobjc_framework_CoreAudio-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce7223a0b0295442a6ffc49c03bae555907ebf4d266ca89446be7db705d17845"}, + {file = "pyobjc_framework_CoreAudio-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40b7236da5349e892fd57e9a777f068c25659ee832c5c3f938acb65be9e3fe80"}, + {file = "pyobjc_framework_CoreAudio-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:17bc91198166232a77c935f449b77d9b72ef742638478ab8e2e92740995041e1"}, + {file = "pyobjc_framework_CoreAudio-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:3444691c03c096902601a52bcf5b985e54d12fea7d9d8f53968a86998876468d"}, + {file = "pyobjc_framework_CoreAudio-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01e21d0352b46ac49b3154f4557d23ec391687f621d210d59f7283855229d1bb"}, + {file = "pyobjc_framework_CoreAudio-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:ed9883f42a001c5795d5e04bb57788acf57700769a31d922b7b1be936757c1b3"}, + {file = "pyobjc_framework_CoreAudio-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2d6d278bb83687dec413f43c568e3ccfea2f1192b53e1f7252bd6bb4fa0a992a"}, + {file = "pyobjc_framework_coreaudio-10.3.tar.gz", hash = "sha256:658af891719c3c60d1e36f77662eaa80f63ecaaabbf029f90f107bc1fc86b9b6"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coreaudiokit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreAudioKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreAudioKit-10.2.tar.gz", hash = "sha256:38dfafba8eddb655aac352a967c0e713a90e10a4dd40d4ea1abbb4db01c5d33f"}, - {file = "pyobjc_framework_CoreAudioKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:aede4cd58a67008b014757178a01b984ee585cc055133a9eb8f10b310d764de8"}, - {file = "pyobjc_framework_CoreAudioKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:4fb992025df80b8799fbd1605b0dd4b4b3f6b467c375a16da1b286f6ac2e2854"}, - {file = "pyobjc_framework_CoreAudioKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:28f17803e5eaf35a73caa327cbd0c857efbfdea57307637a60ff8309834b7a95"}, + {file = "pyobjc_framework_CoreAudioKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:25006ba6109d79532926f9b8c590d386bd2375f411f6adc97f6bb4903a6d78b5"}, + {file = "pyobjc_framework_CoreAudioKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f3f08f32eec59f80784929a372c7bdc4e1c5d4b41cd2889f4fa7af50369854aa"}, + {file = "pyobjc_framework_CoreAudioKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:47b743bdd2ec3d8fec9d6bb7ad08918af016ab8fa55f90808d12427a4b973b4a"}, + {file = "pyobjc_framework_coreaudiokit-10.3.tar.gz", hash = "sha256:7a17534f08a8426e26ee3eec9f80f22aa5be3d6114687344f7545176abd4a705"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreAudio = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreAudio = ">=10.3" [[package]] name = "pyobjc-framework-corebluetooth" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreBluetooth on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreBluetooth-10.2.tar.gz", hash = "sha256:fb69d2c61082935b2b12827c1ba4bb22146eb3d251695fa1d58bbd5835260729"}, - {file = "pyobjc_framework_CoreBluetooth-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6e118f08ae08289195841e0066389632206b68a8377ac384b30ac0c7e262b779"}, - {file = "pyobjc_framework_CoreBluetooth-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:411de4f937264b5e2935be25b78362c58118e2ab9f6a7af4d4d005813c458354"}, - {file = "pyobjc_framework_CoreBluetooth-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:81da4426a492089f9dd9ca50814766101f97574675782f7be7ce1a63197d497a"}, + {file = "pyobjc_framework_CoreBluetooth-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1da6f13386165f28a55d71ba73fc93e3a731023cd83cbb0846f43aff7135856a"}, + {file = "pyobjc_framework_CoreBluetooth-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:d96c721409979953353e006596f8d646ae35f3a463b2545a4d0083244a81f2a9"}, + {file = "pyobjc_framework_CoreBluetooth-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:439abd4edcbd6f091f4a885afe01f322ca4c879e6eb0edda869f359c5979fef9"}, + {file = "pyobjc_framework_corebluetooth-10.3.tar.gz", hash = "sha256:7ca00c8f96517b4421162846b5f66369360e4523ca917c6e0507d051381fb466"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coredata" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreData on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreData-10.2.tar.gz", hash = "sha256:0260bbf8f4ce6071749686fdc079618b3bd2b07976db7db4c864ecc62316bb3b"}, - {file = "pyobjc_framework_CoreData-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:41a22fe04544ba35e82232d89ad751b452c2314f07df6c72129a5ad6c3e4cbec"}, - {file = "pyobjc_framework_CoreData-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c29c6dce8ce155e15e960b9c542618516923c3ef55a50bf98ec95e60afe0aa3d"}, - {file = "pyobjc_framework_CoreData-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:cd7c419d9067ce9a9f83f6abd3c072caeb3aa20091f779881375067f7c1c417b"}, + {file = "pyobjc_framework_CoreData-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:218b64c79a6d2402852c763dd1accff2113ef206676b2b5a0027e875978cc56f"}, + {file = "pyobjc_framework_CoreData-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1fdb6d56d2902b9cafaeec8cc8fc0ea9b98c49abef59ac4afdb37e9672b9bd1a"}, + {file = "pyobjc_framework_CoreData-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:65de27fadc762d72efd559e1e92f5a98831e492500b6dc0ca405810afd5b72aa"}, + {file = "pyobjc_framework_coredata-10.3.tar.gz", hash = "sha256:1101f071d2e4485fcf3a41ec524cc27e4d0e86b19a03cca19a287ad5cbd1ca31"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-corehaptics" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreHaptics on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreHaptics-10.2.tar.gz", hash = "sha256:7b98bd70b63506aef63401a6e03f67391d7582f39fbe8aa7bb7258dd66ab0e55"}, - {file = "pyobjc_framework_CoreHaptics-10.2-py2.py3-none-any.whl", hash = "sha256:c67fae4b543fc070cece622cfe5803796016a36d1020812428e0f22e5f5674aa"}, + {file = "pyobjc_framework_CoreHaptics-10.3-py2.py3-none-any.whl", hash = "sha256:48077361a913ef7e9927c0110255c29ba58576a33f31276ac53eed18c50b13da"}, + {file = "pyobjc_framework_corehaptics-10.3.tar.gz", hash = "sha256:59cbdda7c4c77556377e97d47887385f9d641278015118c533165f8dd540910a"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-corelocation" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreLocation on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreLocation-10.2.tar.gz", hash = "sha256:59497cc210023479e03191495c880e61fb6f44ad6c435ed1c8dd8def39f3aada"}, - {file = "pyobjc_framework_CoreLocation-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c2e02352a4dfbc090cebc9c0d3716470031e584d4d33f22d97307f04c23ef01f"}, - {file = "pyobjc_framework_CoreLocation-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f7eda101abb366be52d2fd85e15c79fdf0b9f64de9aab87dc0577653375595de"}, - {file = "pyobjc_framework_CoreLocation-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:8f67af17b8267aa2a066684b518e66bbe7fee9651b779e372d6286d65914df82"}, + {file = "pyobjc_framework_CoreLocation-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7bb5bc7835783f20a7262956a276526bc58bd74c1445a1272158c40704ebe3c1"}, + {file = "pyobjc_framework_CoreLocation-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f0de20706d176d118c65b551857d93c2f825a1ebe6aafedaebcae25bde61d917"}, + {file = "pyobjc_framework_CoreLocation-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:80f35e370a047bf67dffb6986adbd5f4dc80301760634722f9375fd2a69d0632"}, + {file = "pyobjc_framework_corelocation-10.3.tar.gz", hash = "sha256:0c48a19d253ac5746327a2bb12216d91972dc409809982f5bc8c03a301baebae"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coremedia" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreMedia on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreMedia-10.2.tar.gz", hash = "sha256:d726d86636217eaa135e5626d05c7eb0f9b4529ce1ed504e08069fe1e0421483"}, - {file = "pyobjc_framework_CoreMedia-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0c91037fd4f9995021be9e849f1d7ac74579291d0130ad6898e3cb1940f870e1"}, - {file = "pyobjc_framework_CoreMedia-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63ed4f6dbe33e5f3d5293a78674329cb516a256df34ef92e7c1fefacdb5c32db"}, - {file = "pyobjc_framework_CoreMedia-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7fa13166a14d384bb6442e5f635310dd075c2a4b3b3bd67ac63b1e2e1fd2d65e"}, - {file = "pyobjc_framework_CoreMedia-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd7da9da1fad7168a63466d5c267dea8bce706808557baa960b6a931010dca48"}, - {file = "pyobjc_framework_CoreMedia-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:c48c7f0c3709a900cd11002018950a72626af39a096d1001bb9a871574db794f"}, - {file = "pyobjc_framework_CoreMedia-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d3e86d03c6d7909058b8f1b8e54d9b5d93679049c7980eb0a5d930a5a63410e0"}, + {file = "pyobjc_framework_CoreMedia-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:29d365c3eb9b3d40168c17f55df193c8b1db08668911c78a74d58d3f90ba4881"}, + {file = "pyobjc_framework_CoreMedia-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:efc4f40a216e7a3503ff1f047124ffa3ebbc7d7574128c361ae0c7189aed58d4"}, + {file = "pyobjc_framework_CoreMedia-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:88e934d2231febcfa049a274a6d4db86987c986958adffa5cd972c2b25b7cddf"}, + {file = "pyobjc_framework_CoreMedia-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:52de7b47a04743e12617f9de17216590ff6c5120f610bf962d7851f449309632"}, + {file = "pyobjc_framework_CoreMedia-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b1a93d2535b9f41fbd03a10dc15ea13a8675cae408f18122acce9e10e2e3a2c2"}, + {file = "pyobjc_framework_CoreMedia-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:2567dfafc595c92f5e7c1cd52fd49d7edb6f581a6eb9ae3929d195458097d62f"}, + {file = "pyobjc_framework_CoreMedia-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ee5e0ea21cc43d584cdaf304e5b34b1bf34279e787fc1751bb78cfceada464e"}, + {file = "pyobjc_framework_coremedia-10.3.tar.gz", hash = "sha256:91e9752da6dd04a21349fc5a640c4665357fbcdba45f4800bb634b466fd05173"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coremediaio" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreMediaIO on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreMediaIO-10.2.tar.gz", hash = "sha256:12f9fd93e610e61258f1acb023b868ed196e9444c69e38dfd314f8c256d07c9e"}, - {file = "pyobjc_framework_CoreMediaIO-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4ede4da59fa2a611b4a9d5a532e0c09731f448186af6cc957ab733b388f86d5b"}, - {file = "pyobjc_framework_CoreMediaIO-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:184854c2ebc3d12466ad39e640b5f3d2bdb3792d8675c83f499bb48b078d3d91"}, - {file = "pyobjc_framework_CoreMediaIO-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:aa9418277d16a1d5c0b576ad8a35f8e239d3461da60bb296df310090147331f7"}, + {file = "pyobjc_framework_CoreMediaIO-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:25b7359a195e4e9339744d835290a9232a783bc03eb4b21dfe5076e56fde5d05"}, + {file = "pyobjc_framework_CoreMediaIO-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0fdcd3332de8942a39181eca08ac42ab71296275305ca76c9fbdeed9ac020d1c"}, + {file = "pyobjc_framework_CoreMediaIO-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e78950d9d0fa6bcca95fd4f414824da3b722e501be1b2c519d557b69b03dadaf"}, + {file = "pyobjc_framework_coremediaio-10.3.tar.gz", hash = "sha256:d136225bf4fdae1b3962b0b163733e06ff104fd55c424424bdaa93d5acb7507b"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coremidi" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreMIDI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreMIDI-10.2.tar.gz", hash = "sha256:8168cb1e57e5dbc31648cd68d9afe3306cd2751de03275ef5f7f9b6483f17c07"}, - {file = "pyobjc_framework_CoreMIDI-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:809a79fbf384df94884dfddcab4dad3e68eba9e85591f7b55d24f4af2fb8db94"}, - {file = "pyobjc_framework_CoreMIDI-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a48176d5f49f9e893f5a7ac86f7cd7ee63b66dc7941ef74c04876f87a1ae3475"}, - {file = "pyobjc_framework_CoreMIDI-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:cce95647865c7f374d3c9cf853a3a8a44ae06fda6fa2e65fc7ad6450dc60e50f"}, + {file = "pyobjc_framework_CoreMIDI-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1a1950ad4effaa46fde70b3c08331ba105b244b3ffb49fb44bf13590883d5af7"}, + {file = "pyobjc_framework_CoreMIDI-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0eda91893eeb21e25e3750a86f2d995d101cb0aa2d3a6620ada7ffbe866592ca"}, + {file = "pyobjc_framework_CoreMIDI-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b9cb89bc18165114a9675891586ca30d572270219b170619ac89f6313a68598d"}, + {file = "pyobjc_framework_coremidi-10.3.tar.gz", hash = "sha256:dd863a02a7cde849fdf1406bc604c86ce03812063fbc3fbb524f77e2b220a145"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coreml" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreML on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreML-10.2.tar.gz", hash = "sha256:a1d7743a91160d096ccd3f5f5d824dafdd6b99d0c4342e8c18852333c9b3318e"}, - {file = "pyobjc_framework_CoreML-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ab99248b8ace0bebb11d15eb4094d8017093ebf76dadf828e324cacc9f1866f1"}, - {file = "pyobjc_framework_CoreML-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:074b81c0e0e4177d33b2da8267d377fb7842b47eb7b977bb07d674b9b05c32b5"}, - {file = "pyobjc_framework_CoreML-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:baedffd5ab34dc0294c2c30ad1b5bcff175957f51f107b1f9f8b20f80e15cc9c"}, + {file = "pyobjc_framework_CoreML-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1c2427c9d0150cc270aef9385cfa6dcd47f0264847c07c96aca6f14d3b5015f8"}, + {file = "pyobjc_framework_CoreML-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:403754cd9f5bafdddab8d7227dedc79c4bcbe19887e333103e35a25d3ec2452e"}, + {file = "pyobjc_framework_CoreML-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3e468ca8f2e2430cc4b7e87bb42d5caa15a58f9f9d3df682dc1ac029cfc54113"}, + {file = "pyobjc_framework_coreml-10.3.tar.gz", hash = "sha256:37f86fbf7cf90809a43ad81a8fc31190175b9b78e792351817d124c3daf1302a"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coremotion" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreMotion on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreMotion-10.2.tar.gz", hash = "sha256:1e1827f2f811ada123dd42809bc86f04a4c1ae3cec619ccf0f05a9387412bec1"}, - {file = "pyobjc_framework_CoreMotion-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:804abc6b22db933e7fb7ba3e60b30f4c60e8921f8bb5790c3612375f7b4a6f03"}, - {file = "pyobjc_framework_CoreMotion-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:76d5a2ed1cba375e3c423887bd93bbaab849c7a961156c5cead8e1429c26c24d"}, - {file = "pyobjc_framework_CoreMotion-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c0a8022dca1404795e93cd7317bca9f8ad601f3ecec7bed71312d80adad296e4"}, - {file = "pyobjc_framework_CoreMotion-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b727d5301ec386b8aa94de69a9257a412a4edbd69ca394d76b83d9f2bec6bc96"}, - {file = "pyobjc_framework_CoreMotion-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7e4571a08475428a8171a237284036a990011f212497f141222d281fa7e2ca5c"}, - {file = "pyobjc_framework_CoreMotion-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bef81c52af0d1be75b3bd7514d5f9ef7c6e868f385f0dd8c28ad62e5d3faeeb6"}, + {file = "pyobjc_framework_CoreMotion-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7457a9167f70e5e41055663364431bb66c0995bbf4078183323b0f7492d6f62f"}, + {file = "pyobjc_framework_CoreMotion-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d0e03179739670d0c1a4a7b50a2b652163c16e8ef3a0e88962179430058abbc9"}, + {file = "pyobjc_framework_CoreMotion-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:eaa3fa5638717011f0eb64e2b1e8354574b363780efadd37bdd6490f0a0fa1ca"}, + {file = "pyobjc_framework_CoreMotion-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:f924079954b0035ff95e943c88964879c0cfd35f59b285586fc1034f421c8060"}, + {file = "pyobjc_framework_CoreMotion-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:379f74023ce989df59df8d4fe6a6ff0e6ac5e081ae45ab457c173b301e9a2f87"}, + {file = "pyobjc_framework_CoreMotion-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:39734bd0a2fe727208ecd795edc75ae85cca5745297c7783fd0d9fefd0b8e16d"}, + {file = "pyobjc_framework_CoreMotion-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:731e556f2ba5f24d941d5b36f9c4282e26f78794dc80c4de37dbfd12492dc83f"}, + {file = "pyobjc_framework_coremotion-10.3.tar.gz", hash = "sha256:981c395ba01b5e9cfe1474d8f180b9ccf42b35cf45ed8159b1ee4d1e4bd33721"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coreservices" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreServices-10.2.tar.gz", hash = "sha256:90fa09e68e840fdd229b33354f4b2e55e9f95a221fcc30612f4bd92cdc530518"}, - {file = "pyobjc_framework_CoreServices-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2b0c6142490c7099c5be0a2fa10b1816e4280bc04ac4e5a4a9af17a9c2006482"}, - {file = "pyobjc_framework_CoreServices-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c2c05674d9d142abc62fcc8e39c8484bdcdfd3ad8a17f009b8aa7c631e227571"}, - {file = "pyobjc_framework_CoreServices-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f87ad202d896e596b31c98a9d0378b2e6d2e6732a2dfc7b82ceae4c70863364d"}, + {file = "pyobjc_framework_CoreServices-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:73b72eb37f7f1ee6f0dd4741adc56549806501c023b50d1425cf0765163caf3f"}, + {file = "pyobjc_framework_CoreServices-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:002139b8bcbb268eaf37c9055efdc9f70d6eab3bc7d36d169162968eff10aaf4"}, + {file = "pyobjc_framework_CoreServices-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:13e4c1a0cd54a557267a86deb47a8c8bc24ef2a4f1b427c2ddc4852f830c96ff"}, + {file = "pyobjc_framework_coreservices-10.3.tar.gz", hash = "sha256:a7c38090c26a2e1b600fb31c3b056ef60e86bacfbb26ecfbcdd997ed61b1cdc8"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-FSEvents = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-FSEvents = ">=10.3" [[package]] name = "pyobjc-framework-corespotlight" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreSpotlight on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreSpotlight-10.2.tar.gz", hash = "sha256:bc4ac490953db29f6a58bc6fca6f819f8a810d0bb15d5f067451b3a8cad1cb50"}, - {file = "pyobjc_framework_CoreSpotlight-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f69dc88ddfa116262009b15ac302b880aef2dad878bf472cbf574f4473f4b059"}, - {file = "pyobjc_framework_CoreSpotlight-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:09912188648e658a0f579bbfd2cf6765afb8e0f466ee666e24019cc9931b6bc5"}, - {file = "pyobjc_framework_CoreSpotlight-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:75ba49ee4bfdbf4df733bc8c508b4417f47c442a56b83ffe5527e76e1c5bad67"}, + {file = "pyobjc_framework_CoreSpotlight-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:34497a442230e6f98e99374ba5b0694aa36ae730aece3869c022953e54554876"}, + {file = "pyobjc_framework_CoreSpotlight-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ce50141e3b0225d79ec39c99cd1fd5ba71fc02c83e4b87b39a98c6abe1b8764c"}, + {file = "pyobjc_framework_CoreSpotlight-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:07df5335405ccb55a12a44fe9bb7c3104068b5f9340ced6dd0e47a7098fa18c3"}, + {file = "pyobjc_framework_corespotlight-10.3.tar.gz", hash = "sha256:532340debec937393569d27f8f28af16fc46270e47299dad63634e05b58161da"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-coretext" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreText on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreText-10.2.tar.gz", hash = "sha256:59ef8ca8d88bb53ce9980dda0b8094daa3e2dabe355847365ba965ff0b49f961"}, - {file = "pyobjc_framework_CoreText-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:44052f752f42b62d342fa8aced5d1b8928831e70830eccddc594726d40500d5c"}, - {file = "pyobjc_framework_CoreText-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0bc278f509a3fd3eea89124d81e77de11af10167c0df0d0cc15a369f060465a0"}, - {file = "pyobjc_framework_CoreText-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7b819119dc859e49c0ce9040ae09d6a3bd66658003793f486ef5a21e46a2d34f"}, - {file = "pyobjc_framework_CoreText-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2719c57ff08af6e4fdcddd0fa5eda56113808a1690c3325f1c6926740817f9a1"}, - {file = "pyobjc_framework_CoreText-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:8239ce92f9496587a60fc1bfd4994136832bad99405bb45572f92d960cbe746e"}, - {file = "pyobjc_framework_CoreText-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:80a1d207fcdb2999841daa430c83d760ac1a3f2f65c605949fc5ff789425b1f6"}, + {file = "pyobjc_framework_CoreText-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6d68d8a4cd2e86a1a6fb748beea20ae5256221ec282c69becb16334ae293c17e"}, + {file = "pyobjc_framework_CoreText-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb7d4e89d7f6d579ec807542cebe815e62fe37a473342c8f026b6b048260d591"}, + {file = "pyobjc_framework_CoreText-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:bc4a53c6e82606e24d4e096f4c503c78ec0171f67cd3214c571ff443c6edaa8f"}, + {file = "pyobjc_framework_CoreText-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:4c2c407a24aa44acc3495098e394e33a332e3ae03d68cc6a045f94ad0a6c51e7"}, + {file = "pyobjc_framework_CoreText-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a43f90662021248c6c9e31a9d9d75a33b9eecb738075998798926ceb5c243455"}, + {file = "pyobjc_framework_CoreText-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:bddc0f7f72a92747d783cecd0a51eb1936d73dd77a5d1de48317d4a7e1293c98"}, + {file = "pyobjc_framework_CoreText-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8a697a4bbd51a45bb1c74baa3f83fd224c01e6352528b1c2485a01359785e695"}, + {file = "pyobjc_framework_coretext-10.3.tar.gz", hash = "sha256:d1c5f4345783451314f6f9725f0d020d02f112eaa8acd2cd15c27ca8e7639a64"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-corewlan" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CoreWLAN on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CoreWLAN-10.2.tar.gz", hash = "sha256:f47dcf735145eb2f817db5c2134321a7cfb9274a634161ff3069617fd2afff42"}, - {file = "pyobjc_framework_CoreWLAN-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8dc102d7d08437b5421856ae8aac32e3e9846e546c1742e4d57343abd694688f"}, - {file = "pyobjc_framework_CoreWLAN-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:85bcf84fd38a2e949760dda3201f13f8bef73b341a623f6736834b7420386f16"}, - {file = "pyobjc_framework_CoreWLAN-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ada346a6da1075e16bf5f022ccad488632fe6de972d2d925616add87e3eb9fad"}, + {file = "pyobjc_framework_CoreWLAN-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:485ea9c1cbddf8f3d76b162fd1498a5ac882294cb5699d978e3e7e083951cebb"}, + {file = "pyobjc_framework_CoreWLAN-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8ca8fdf5d7d8a1fe96c673c377d8788780d61380565c16a2508736435e0c1a61"}, + {file = "pyobjc_framework_CoreWLAN-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1a41570f7d9c2d298430abb6ee9b631cbbacafca9989627ddb8e8bd97de414d1"}, + {file = "pyobjc_framework_corewlan-10.3.tar.gz", hash = "sha256:1ddc4d9bf0a02f3a8cd2add8721edcc5595dde0660ca02746db3cc0ce2b0af9e"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-cryptotokenkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework CryptoTokenKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-CryptoTokenKit-10.2.tar.gz", hash = "sha256:c0adfde2d53da7df1f8827bdf0cbf4419590151dd1041711ab2f66a32bd986f5"}, - {file = "pyobjc_framework_CryptoTokenKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:89264d38ca58e8b5a586a3c13260d490ee2cdc9c1498211a804cec67f7659cd7"}, - {file = "pyobjc_framework_CryptoTokenKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e13d92966273420a154cde6694b4bc7dd3dc7679e93d651534dcf2b0c5246546"}, - {file = "pyobjc_framework_CryptoTokenKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:a56af323d597332090a0787c00d16c40152c62cb278d951a59723006cd3e10de"}, + {file = "pyobjc_framework_CryptoTokenKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9809ea10b0987d01f08d7948cd577a0dbc38f82d400270d8ff5903671bf99ab"}, + {file = "pyobjc_framework_CryptoTokenKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7272b025e56b5623994a629fd67c56ac84ec79976fe198640778f5b92b259c95"}, + {file = "pyobjc_framework_CryptoTokenKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:38d03fbd3348c471e201ea542b170bb633122e05dfb269b17e1d89ea01af2e0e"}, + {file = "pyobjc_framework_cryptotokenkit-10.3.tar.gz", hash = "sha256:d810a0f72cfe0a03ea57ce5efa9b44f1cbf73ea924431710338df8424a0ac4cf"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-datadetection" -version = "10.2" +version = "10.3" description = "Wrappers for the framework DataDetection on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-DataDetection-10.2.tar.gz", hash = "sha256:9532bb697b96ec4ffc04310550bf21c45c8494fc07d8067fc41cbfd94c8ba27d"}, - {file = "pyobjc_framework_DataDetection-10.2-py2.py3-none-any.whl", hash = "sha256:4435ebaa3b3fa3de855690469fefd2d8a3568f702f51540707efaf4363ec94aa"}, + {file = "pyobjc_framework_DataDetection-10.3-py2.py3-none-any.whl", hash = "sha256:50d5c2f6856251ca33d8d82545c2c9f57742f6623857855b1a9e5e52c2dbcef0"}, + {file = "pyobjc_framework_datadetection-10.3.tar.gz", hash = "sha256:eb3f1e8383affbc594b161dd5c73d398a553f03af837eaef13a81fcc6690637f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-devicecheck" -version = "10.2" +version = "10.3" description = "Wrappers for the framework DeviceCheck on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-DeviceCheck-10.2.tar.gz", hash = "sha256:f620ede18e12dd36d92f24d1a68278821bcf7aeaea6577993fbfb328c118569d"}, - {file = "pyobjc_framework_DeviceCheck-10.2-py2.py3-none-any.whl", hash = "sha256:c9c87ae40af41c4c296af40317018732bba85e589111f5286b2f136f022c8ecd"}, + {file = "pyobjc_framework_DeviceCheck-10.3-py2.py3-none-any.whl", hash = "sha256:a1982656616dfb4749d0dfb58e8ecc99f382599e678d66c6b3f5da87486dc499"}, + {file = "pyobjc_framework_devicecheck-10.3.tar.gz", hash = "sha256:e75e2261f61686a4590bdceef43357d8ba972b61e34ad9d0c2bf9dd07c405360"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-dictionaryservices" -version = "10.2" +version = "10.3" description = "Wrappers for the framework DictionaryServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-DictionaryServices-10.2.tar.gz", hash = "sha256:858b4edce36dfbb0f906f17c6aac1aae06350d508cf0b295949113ebf383bfb4"}, - {file = "pyobjc_framework_DictionaryServices-10.2-py2.py3-none-any.whl", hash = "sha256:39b577b35c52a033cbac030df1fdcd16fb109144e8c59cb2044a13fcd803ab49"}, + {file = "pyobjc_framework_DictionaryServices-10.3-py2.py3-none-any.whl", hash = "sha256:8ed612ff352f943cd9f7f5b77bd1d9da76e8ba2a852eb43c97cbfa692c506396"}, + {file = "pyobjc_framework_dictionaryservices-10.3.tar.gz", hash = "sha256:07ef0bc72a79f9634cd32f2fcd6299b60ae3b0c57e123fa36d298e9390f88351"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-CoreServices = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-CoreServices = ">=10.3" [[package]] name = "pyobjc-framework-discrecording" -version = "10.2" +version = "10.3" description = "Wrappers for the framework DiscRecording on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-DiscRecording-10.2.tar.gz", hash = "sha256:9670018a0970553882feb10e066585ad791c502539712f4117bad4a6647c79b3"}, - {file = "pyobjc_framework_DiscRecording-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:cbf0d9904a24bece47a71b56f87090a769e96338c0acb3f33385c3e584ed1c96"}, - {file = "pyobjc_framework_DiscRecording-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0a7d9980ab9f59903d60d09172de4085028bbb97a63112f78b9cca0051a73639"}, - {file = "pyobjc_framework_DiscRecording-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:8a6512d0b7e61064ca167ca0a9c95a3f49f8fa7216fe5e1d77eab01ce56a9414"}, + {file = "pyobjc_framework_DiscRecording-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4059e53356d0c52c8913fe63b440dcfa94312c6d10d0f4473f32a0f32859cab6"}, + {file = "pyobjc_framework_DiscRecording-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:739a8d2463af29f498f7c119084c379d2aa22bb07af837f0a0fe9e4508e7d1de"}, + {file = "pyobjc_framework_DiscRecording-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0d74a12e75699d99bc4ed3cdc1c06ae8ae31fe15ec3899d238963404bcd0cd43"}, + {file = "pyobjc_framework_discrecording-10.3.tar.gz", hash = "sha256:f56e054af941feafa9b8599dd2e399460d31b96a9ead11ea794057531ed8623d"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-discrecordingui" -version = "10.2" +version = "10.3" description = "Wrappers for the framework DiscRecordingUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-DiscRecordingUI-10.2.tar.gz", hash = "sha256:afda9756a8f9e8ce1f83930eca3b1a263a29f48c1618269457f4aba63fc1644f"}, - {file = "pyobjc_framework_DiscRecordingUI-10.2-py2.py3-none-any.whl", hash = "sha256:e0423c548851cd9eb4ad7e9e085da4db2cde2420e1f3e05d46e649498edf97d8"}, + {file = "pyobjc_framework_DiscRecordingUI-10.3-py2.py3-none-any.whl", hash = "sha256:65d49b052c1c200b450607f72defa854863a5d8cae21d52acef7099c779d5b27"}, + {file = "pyobjc_framework_discrecordingui-10.3.tar.gz", hash = "sha256:374b4ab5b09f45667f610e2b10a88a7874cff713fba97e46f3dac5c4f324be4b"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-DiscRecording = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-DiscRecording = ">=10.3" [[package]] name = "pyobjc-framework-diskarbitration" -version = "10.2" +version = "10.3" description = "Wrappers for the framework DiskArbitration on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-DiskArbitration-10.2.tar.gz", hash = "sha256:25b74db4f39a7128599e153533db0f88c680ad55f366c5ab6a6d7dede96eeb57"}, - {file = "pyobjc_framework_DiskArbitration-10.2-py2.py3-none-any.whl", hash = "sha256:dd14eb448865ca4c49e15a543f748f1ef6501ea0044eaa2cf04860547205c84f"}, + {file = "pyobjc_framework_DiskArbitration-10.3-py2.py3-none-any.whl", hash = "sha256:cd59193185f064df2a5bb4d79b337efffec81059ff6049b183b72fe287b5c867"}, + {file = "pyobjc_framework_diskarbitration-10.3.tar.gz", hash = "sha256:e02f6b52d6bdce90e151a77cf1e2c41e9d704608a7c8a049d079a78bc1bf1c80"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-dvdplayback" -version = "10.2" +version = "10.3" description = "Wrappers for the framework DVDPlayback on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-DVDPlayback-10.2.tar.gz", hash = "sha256:0869a6e8da1c2d93713699785b4f0bbe5dd1b2820a0ff4a6adf06227b1bb96ac"}, - {file = "pyobjc_framework_DVDPlayback-10.2-py2.py3-none-any.whl", hash = "sha256:f3fb90eb3d616290d2ab652214ce682130cd19d1fd3205def6ab0ba295535dd9"}, + {file = "pyobjc_framework_DVDPlayback-10.3-py2.py3-none-any.whl", hash = "sha256:7d3e2aec568910deb7e9661185ff55e101726280f90a567d93d2cc40de0c24a9"}, + {file = "pyobjc_framework_dvdplayback-10.3.tar.gz", hash = "sha256:0db8a36223e1471cfabe3ee2767e81cac2686ac178fa9549fafa43a2def664a5"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-eventkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Accounts on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-EventKit-10.2.tar.gz", hash = "sha256:13c8262344f06096514d1e72d3c026fa4002d917846ce81217d4258acd861324"}, - {file = "pyobjc_framework_EventKit-10.2-py2.py3-none-any.whl", hash = "sha256:c9afa63fc2924281fdf1ef6c86cc2ba01b7b84a8545a826ddd89e4abd7077e81"}, + {file = "pyobjc_framework_EventKit-10.3-py2.py3-none-any.whl", hash = "sha256:8644a1547b1d1a012306abbc6c5693d3302b98bb5b1098fb81e060885995bc70"}, + {file = "pyobjc_framework_eventkit-10.3.tar.gz", hash = "sha256:a9c7609e6b800d5378bd0fa05e19de878c000882a6b0c9ad716684fa0ca7bff8"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-exceptionhandling" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ExceptionHandling on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ExceptionHandling-10.2.tar.gz", hash = "sha256:cf4cd143c24504d66ef9d4e67b4b88e2ac892716e6ead2aa9585a7d39278d943"}, - {file = "pyobjc_framework_ExceptionHandling-10.2-py2.py3-none-any.whl", hash = "sha256:fd7dfc197c29ccf187718dbb0b1dcd966a8c04ee6549ee9472959912e76a0609"}, + {file = "pyobjc_framework_ExceptionHandling-10.3-py2.py3-none-any.whl", hash = "sha256:5b5148bf5cbf70acc3713e5b8feef4fda3d8b1a9c515b1478143fa65cd6efc0f"}, + {file = "pyobjc_framework_exceptionhandling-10.3.tar.gz", hash = "sha256:7f3d4bca9dd23b1b10ed6174fe39e4c92368bb7e2a85fd237de37196a78dc8c4"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-executionpolicy" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ExecutionPolicy on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ExecutionPolicy-10.2.tar.gz", hash = "sha256:8976c35a58c2e51d6574123ecfcd58459bbdb32b3992716119a3c001d3cc2bcf"}, - {file = "pyobjc_framework_ExecutionPolicy-10.2-py2.py3-none-any.whl", hash = "sha256:4d95d55f82a15286035bb5bc01b339d6c36103a1cbf7d6a3d7a9feac71663626"}, + {file = "pyobjc_framework_ExecutionPolicy-10.3-py2.py3-none-any.whl", hash = "sha256:6798cd17078d8a65544367243a432e54947c312885c7b0adf0f5fefe4f156b92"}, + {file = "pyobjc_framework_executionpolicy-10.3.tar.gz", hash = "sha256:16dcde7e8c81af347892b943f9e22633aebe772510bfcea19d688baac5cc1414"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-extensionkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ExtensionKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ExtensionKit-10.2.tar.gz", hash = "sha256:343c17ec1696947cde6764b32f741d00d7424a620cdbaa91d9bcf47025b77718"}, - {file = "pyobjc_framework_ExtensionKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:69981d3a0f7146b57b16f1132c114419a2b89fa201677c7e240f861bc7e56670"}, - {file = "pyobjc_framework_ExtensionKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:30fa27de3f97436c867ca3e89d8e95f141337a9377f71be3c8a036795b5557fb"}, - {file = "pyobjc_framework_ExtensionKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:09e1402c9fd7c6fcacd662caa2198d79342b812665980fd9a66e906743bddf69"}, + {file = "pyobjc_framework_ExtensionKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:84d4bd8c753a4c532dd5553e6d2d9900e6b534bff6b8b2f09b55fb85bc13896f"}, + {file = "pyobjc_framework_ExtensionKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:28b4979a1f373b70d0f00e5ed1187d1f28861199373bed607c868c06e634d0cb"}, + {file = "pyobjc_framework_ExtensionKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:65ed21df1e0aabf615be87d3cc985d761ffe88e77ba5e99db214bc48a100c483"}, + {file = "pyobjc_framework_extensionkit-10.3.tar.gz", hash = "sha256:928b7e5e1a1c5bb80b6e7c0b1fda0dda88ea212d15372f3ead7404283138b159"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-externalaccessory" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ExternalAccessory on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ExternalAccessory-10.2.tar.gz", hash = "sha256:e62af0029b2fd7e07c17a4abe52b20495dba05cba45d7e901acbd43ad19c4cc3"}, - {file = "pyobjc_framework_ExternalAccessory-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b279672b05f0f8a11201a5ed8754bcea5b8d3e6226ec16c6b59127e2c6e25259"}, - {file = "pyobjc_framework_ExternalAccessory-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5fbe16bb4831a30659cba6a53b77dca94b72ff12bfd318c76f118f39557427c5"}, - {file = "pyobjc_framework_ExternalAccessory-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f446ce468a369650c4c49947bb7329c58c68cd44aee801506e60be1f26cd6265"}, + {file = "pyobjc_framework_ExternalAccessory-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:833dc91f933f40ef2e54fcaad4328154d1cedde46a289dcecf59ba87554fd344"}, + {file = "pyobjc_framework_ExternalAccessory-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c04f1470aa59c9930d732c04872aa44bd0a0ea6414c5d330e51fd323538f4675"}, + {file = "pyobjc_framework_ExternalAccessory-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b597b2c5c1dbf775cfaa60407bce7c0a7ecdfb40ccd9b0c03413c250b607ae20"}, + {file = "pyobjc_framework_externalaccessory-10.3.tar.gz", hash = "sha256:fa481f7171f7d42bb77e1d5d525798dfed6b6d89e4a789c0d252d9319b13e3b1"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-fileprovider" -version = "10.2" +version = "10.3" description = "Wrappers for the framework FileProvider on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-FileProvider-10.2.tar.gz", hash = "sha256:1accc2965c59395152d04b2f4a096cb4a5364bca8094695ce2b60d2f794bff74"}, - {file = "pyobjc_framework_FileProvider-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e69d294b0ac9fdcafb28fbb1b9770e1e851cc5467dc0ae1d7b182882ce16d1d"}, - {file = "pyobjc_framework_FileProvider-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1d5cc02d43f2c6851934c8208cd4a66ad007daf0db673f72d1938677c90b1208"}, - {file = "pyobjc_framework_FileProvider-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0ae00a293e3ac511cc9eb54ee05b67583ea35d490b47f23f448a3da6652c189b"}, - {file = "pyobjc_framework_FileProvider-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fab7da3c7961e77b09f34cb71a876205ea8d73f9d10d5db78080f7282dd5066f"}, - {file = "pyobjc_framework_FileProvider-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:5d2b581c8cb1c15304676f5a77c42e430aaad886ac92d8b2d4e5cec57cb86be3"}, - {file = "pyobjc_framework_FileProvider-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c471c0d27d9d6a7bba3d06f679f14ac8d719ed3660d9a8e6788a31e1521e71d"}, + {file = "pyobjc_framework_FileProvider-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed3171ca16e0cdeb5d76e557efc622ec30768a236ef3a4eb4245fd2444fd4e3b"}, + {file = "pyobjc_framework_FileProvider-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6fb9753039e37e4762fb42d1f29bf335f56323186913189109480cf849481ff6"}, + {file = "pyobjc_framework_FileProvider-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0c7253a92ed6b739a8cc92f1d874acf9323190a11c3271907cb8446619fa7b66"}, + {file = "pyobjc_framework_FileProvider-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:9991c333d3f7bd0c940c7363a6ab93eeb11cbe5b8795ccf6cfeb80b8197f9758"}, + {file = "pyobjc_framework_FileProvider-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b454f39902b88f840b4042752925e412e0e68ed3f95997ddd0d451481e42e22"}, + {file = "pyobjc_framework_FileProvider-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:16afd455c1a654562bc01ab2d62b4499ebb419991c45142aceb1663dccb375b5"}, + {file = "pyobjc_framework_FileProvider-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bf96275c3d8536af578984b8d2c638362680fb66452a58ba000977da6342a180"}, + {file = "pyobjc_framework_fileprovider-10.3.tar.gz", hash = "sha256:d0def20f2de25465b2d9090ef86063719736ef3e568bf7b2e7e9c3bd2c1fcbec"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-fileproviderui" -version = "10.2" +version = "10.3" description = "Wrappers for the framework FileProviderUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-FileProviderUI-10.2.tar.gz", hash = "sha256:a22204c1fad818e4c8d94ecb544fec59387e01a0074cbe2ca6e58de1a12c157e"}, - {file = "pyobjc_framework_FileProviderUI-10.2-py2.py3-none-any.whl", hash = "sha256:5fac2067c09a23a436708e05d71faf65d64f4c36b45ad254617720b1a682aad6"}, + {file = "pyobjc_framework_FileProviderUI-10.3-py2.py3-none-any.whl", hash = "sha256:b11c922e017c3e11e957b459f3741331ddf3b4403aab7a9a477cfbab40c23e0e"}, + {file = "pyobjc_framework_fileproviderui-10.3.tar.gz", hash = "sha256:44dd84dcdcf187fd45ce34bacacb0eb6797f41767e663675eb37ec25bb2c8544"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-FileProvider = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-FileProvider = ">=10.3" [[package]] name = "pyobjc-framework-findersync" -version = "10.2" +version = "10.3" description = "Wrappers for the framework FinderSync on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-FinderSync-10.2.tar.gz", hash = "sha256:5ecbe9bf7fe77f28204fbe358ee541fdd2786fc076a631c4f11b74377d60ea05"}, - {file = "pyobjc_framework_FinderSync-10.2-py2.py3-none-any.whl", hash = "sha256:11d569492efe74a52883e6086038ca9d5a712a08db828f3ca43c03e756013801"}, + {file = "pyobjc_framework_FinderSync-10.3-py2.py3-none-any.whl", hash = "sha256:50c0f0da42ecb10174969d41d23051ab0c6a605086e05d9de17f7cd2dcb9e0d8"}, + {file = "pyobjc_framework_findersync-10.3.tar.gz", hash = "sha256:1b15d4aa42d636968a243832777c39c944844a1d7da435da28c9d0a4f78beec8"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-fsevents" -version = "10.2" +version = "10.3" description = "Wrappers for the framework FSEvents on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-FSEvents-10.2.tar.gz", hash = "sha256:3a75f38bb1d5d2cf6a0d3e92801b3510f32e96cf6443d81b9dd92a84d72eff0a"}, - {file = "pyobjc_framework_FSEvents-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:129f9654ab9074eff29ccb8dd09625e3740058744a38f9776d0349387f518715"}, - {file = "pyobjc_framework_FSEvents-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c71699f24482d99ee8f6b7a8d36c4c294655c670d8cbd0f3c6f146a2fda6283c"}, - {file = "pyobjc_framework_FSEvents-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:a0ff7bb8c1a357181345ff3a90b7f808cd55c4757df60c723541f0f469323190"}, + {file = "pyobjc_framework_FSEvents-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:160483598a4bef081f0acfcfdb51d62eedb07c81adb7614206ffa712b7552256"}, + {file = "pyobjc_framework_FSEvents-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8ca91bc2c90df83438ee839ab8b97d148626c1dba5830f753ff07198923e83bd"}, + {file = "pyobjc_framework_FSEvents-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e987588a3f9d011ea27a5895b7bc3753b052d19ea6e7392b56644ab72f550b34"}, + {file = "pyobjc_framework_fsevents-10.3.tar.gz", hash = "sha256:46fe0220e54f4d2f375d2b98d292d10ad188a797973cf60b64b24336fd1160ad"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-gamecenter" -version = "10.2" +version = "10.3" description = "Wrappers for the framework GameCenter on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-GameCenter-10.2.tar.gz", hash = "sha256:43341b428cad2e50710cb974728924280e520e04ae9f750bc7beda5006457ae3"}, - {file = "pyobjc_framework_GameCenter-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f14ad00713519b508f4c956a8212bff01f6b6279b2a76e87d99a18262e61dfda"}, - {file = "pyobjc_framework_GameCenter-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b52932e90c6b6d90ce8c895b0ac878dc4e639d493724a5789fc990e1efec3d05"}, - {file = "pyobjc_framework_GameCenter-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:dc9de1b3d0db1921fb197ad964226ebc271744aee0cc792f9fe66afaf92b24f0"}, + {file = "pyobjc_framework_GameCenter-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:875fb445aa7916088ffbb556fad915b023978e6dbc56efed054e92bed21acff3"}, + {file = "pyobjc_framework_GameCenter-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9a498dd05ccaf8ddec5e118a1e2142025e5bb29c42fb6c1b3d2918ff77d39252"}, + {file = "pyobjc_framework_GameCenter-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c7701fa23009d04385584b88b9fa6ed248781a1d652d34761169fee807277d61"}, + {file = "pyobjc_framework_gamecenter-10.3.tar.gz", hash = "sha256:6719c88a40ff9958ae836d4da65c81ce61adb5c614f13f3e1849282f7d31c571"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-gamecontroller" -version = "10.2" +version = "10.3" description = "Wrappers for the framework GameController on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-GameController-10.2.tar.gz", hash = "sha256:81ad502346904995ec04b0580bab94ab32ca847fad06bca88cdf2ec6222b80ae"}, - {file = "pyobjc_framework_GameController-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:47e6dfcf10353a17adcfa7649d0f5d0cba4d4dc3ce3a66826d873574ae2afcb1"}, - {file = "pyobjc_framework_GameController-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8ef6fcb5308c1c31d1de3969165a13750b74f52c80249b722383307fc558edff"}, - {file = "pyobjc_framework_GameController-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:89a7aac243b0347c3ef10fc2bcedcb1b2ae9eb14daabccb3f3cfe1cf12c7e572"}, + {file = "pyobjc_framework_GameController-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a75fcde32187cbcddbc7d0513fd9030e4f97ae9b1515af93a404b0d6be3c08f3"}, + {file = "pyobjc_framework_GameController-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:eadfa2e9c2243eb6e8be4a8ca13fe63aad1e1d96fe9b43d62dc5cb3eff46e8fa"}, + {file = "pyobjc_framework_GameController-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:25010deb72f07978bf343f371237244e35f22f8c494542e14e2c4da0e08841bf"}, + {file = "pyobjc_framework_gamecontroller-10.3.tar.gz", hash = "sha256:dc85c473cafb46ba72cf91e1dadd428f26564c4e331d107b01f78ad450fa74c6"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-gamekit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework GameKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-GameKit-10.2.tar.gz", hash = "sha256:0ef877db88e8888ecf682b09b9fb1ee6b879f23d521ce3a738a1b0fb2b885974"}, - {file = "pyobjc_framework_GameKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c23025087bec023a37fe0c84fcdc592cdc100d9187b49250446587f09571dbeb"}, - {file = "pyobjc_framework_GameKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6867159762db0a72046abe42df8dff080620c2f9cdf20927445eec28f3f04124"}, - {file = "pyobjc_framework_GameKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e7d91d28c4c8d240f0fbab80f84545efbeeb5a42db4c6fbd4ccb1f3face88c9c"}, + {file = "pyobjc_framework_GameKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b997b024f8fbb5bd2d423399d3926fd2fb2e22c162d7f2f49e2616e452b36dfa"}, + {file = "pyobjc_framework_GameKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c289aba92513c3e1c2b3fad33ef32eacb6d987bc08252e5a3e4e6253b7e5ab63"}, + {file = "pyobjc_framework_GameKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:414e3a5c0c3d4cfa7e749fba0f2e83a3ffd29dd4ba87d2e30903780a120fb100"}, + {file = "pyobjc_framework_gamekit-10.3.tar.gz", hash = "sha256:c1aabd78057a95955ccccd8553a13ea554ce1ee2e6fdf5d270f1f5c404f38066"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-gameplaykit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework GameplayKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-GameplayKit-10.2.tar.gz", hash = "sha256:068ee6f3586f4033d25ed3b0451eab8f388b2970be1dfbe39be01accca7a9b2e"}, - {file = "pyobjc_framework_GameplayKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c9e87b8221a74599c813640b823f3a2546aa6076b04087f26fd3ecc8c78cbe01"}, - {file = "pyobjc_framework_GameplayKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a1f81c969347d63a1200818ae12350ad39353e85842f34040b9d997e55f7ec89"}, - {file = "pyobjc_framework_GameplayKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f438c4b98e1d00dec84fedc8796761063e99814f913151441bc7147ac8b23068"}, + {file = "pyobjc_framework_GameplayKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:908e79ef67328c6dea5175896f9a94bf40f4bec185866ec5a0e0936466706487"}, + {file = "pyobjc_framework_GameplayKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a19405a1b3e7a6bd96bbda80208b37c9b261970cd2268b114d256db8113c6316"}, + {file = "pyobjc_framework_GameplayKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d247b11e30f4db7e1c0d1c6430f92afd6fa87ccd70e6ff61e5a4929b7fa33e7d"}, + {file = "pyobjc_framework_gameplaykit-10.3.tar.gz", hash = "sha256:3e0a52b2e7e271e28cb26391e3dd96760a21f8b36124a4c4224a8219d7b783c6"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-SpriteKit = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-SpriteKit = ">=10.3" [[package]] name = "pyobjc-framework-healthkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework HealthKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-HealthKit-10.2.tar.gz", hash = "sha256:abcc4e6bd0e11eace7257887958b6cc5332f8aad4efa6b94e930425016540789"}, - {file = "pyobjc_framework_HealthKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:093687705413b88efe47097f09c7be84b6ccbb7ec0f9b943b4ad19fe9fbdc01c"}, - {file = "pyobjc_framework_HealthKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1fb83b08ed28b9adc9a8a2379dbf5f7515e01009160a86847e1a5f71b491a49c"}, - {file = "pyobjc_framework_HealthKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b84d3857c54076a63feea7072ecf98d925f68f96413ca40164d04b2fd865a4dc"}, + {file = "pyobjc_framework_HealthKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d7267d490329e62a733e50f37a4b5fdb98db8353425f2d193ba3117a80bf9f84"}, + {file = "pyobjc_framework_HealthKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:db1bc0574c32f639ca830fec3885c4774642015b086855a1147c8b2244246e54"}, + {file = "pyobjc_framework_HealthKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:aa51fe233fc95da5b2c0c2726ba5d9c83e5c95312208c033d530ecde9fc75888"}, + {file = "pyobjc_framework_healthkit-10.3.tar.gz", hash = "sha256:ae964ed3d6a2250235bba6f1fcf465d54d9c10854322e82a64b0e06505c264fb"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-imagecapturecore" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ImageCaptureCore on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ImageCaptureCore-10.2.tar.gz", hash = "sha256:68f1f96982282e786c9c387c177c3b14202d560d68000136562eba1ed3f45a6e"}, - {file = "pyobjc_framework_ImageCaptureCore-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:69c19e235de32bc707a622fd2865fa53f6e7692b52851d559ea0c23664ee7665"}, - {file = "pyobjc_framework_ImageCaptureCore-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3bdbae9adf6456b4b4e2847135e5da214516545638dd715f01573ec6b6324af6"}, - {file = "pyobjc_framework_ImageCaptureCore-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:46b90bc950646b69b416949bb50ee7d2189b42b7aa77692e01d7c1b4062ddc19"}, + {file = "pyobjc_framework_ImageCaptureCore-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:097fb42cc33e9deb84d2afba2f701757a831f31fd031dd4426b6357d20959496"}, + {file = "pyobjc_framework_ImageCaptureCore-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:02c2a1a8aacddd4b2b3842b4b389a8956ceaf26d0a965ece3e9bdca62a3cf8dd"}, + {file = "pyobjc_framework_ImageCaptureCore-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c80fbec0f6f0d7c39f11c0827bc1546badca66c2110e9923bde21b12e531d7da"}, + {file = "pyobjc_framework_imagecapturecore-10.3.tar.gz", hash = "sha256:649fb5676ceb76254c4a3782ac05bdc6c30f4fd69f58652727a4732921e07d64"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-inputmethodkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework InputMethodKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-InputMethodKit-10.2.tar.gz", hash = "sha256:294cf2c50cdbb4cdc8f06946924a01faf45a7356ef86652d73c1f310fc1ce99f"}, - {file = "pyobjc_framework_InputMethodKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f8bcb156dcd1dc77826f720ff70f9a12c72ad45e97d4faa7ca88e85fc2d7843a"}, - {file = "pyobjc_framework_InputMethodKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:d96a18dd92dc19f631ed50c524355ab29f79975e081f516ad3cea2d902a277e7"}, - {file = "pyobjc_framework_InputMethodKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:fdea1320a3cf6e409ab8f602b90b167110f7ca58f44f95a52f188c6f59f08753"}, + {file = "pyobjc_framework_InputMethodKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:456b2601bf5e0e2b015f146cb4b9ee2083c0891df4b6e4508bbbf9b7d4f1ba2a"}, + {file = "pyobjc_framework_InputMethodKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3a19b34a229a338b1d6496813feb804079b3c84e29556977c43ef861d0540bac"}, + {file = "pyobjc_framework_InputMethodKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5d04033b886c2cb6c2696216ad7d25da67d58890bdec602d25c6b7f2db6317da"}, + {file = "pyobjc_framework_inputmethodkit-10.3.tar.gz", hash = "sha256:e38844bb93276758334f8fbe09e668da12d697e83b4c925850bf0ae7bc9decab"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-installerplugins" -version = "10.2" +version = "10.3" description = "Wrappers for the framework InstallerPlugins on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-InstallerPlugins-10.2.tar.gz", hash = "sha256:001e9ec6489e49fc22bbec1ef050518213292e8d56239ed004f98ed038b164e2"}, - {file = "pyobjc_framework_InstallerPlugins-10.2-py2.py3-none-any.whl", hash = "sha256:754b8fdf462b6e568f30249255af50f9bd3ac90edacfe6e02d0fe77f276c049b"}, + {file = "pyobjc_framework_InstallerPlugins-10.3-py2.py3-none-any.whl", hash = "sha256:1b577fb5ebe9d4651807798efb056d4cc2a43959bb680a53cdfe25cb185152d5"}, + {file = "pyobjc_framework_installerplugins-10.3.tar.gz", hash = "sha256:69f902733f6e8086c0fa18e6b23a604a759c7d65a7de66a331148afda5f120ec"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-instantmessage" -version = "10.2" +version = "10.3" description = "Wrappers for the framework InstantMessage on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-InstantMessage-10.2.tar.gz", hash = "sha256:4aa7627697fa57120594477f1f287bc41836ec7a4107215d3060c26416cf72c9"}, - {file = "pyobjc_framework_InstantMessage-10.2-py2.py3-none-any.whl", hash = "sha256:65db5cb1f163700a6cb915506f8f7ae2f28d8d3f6464f7b122b0535b1694859a"}, + {file = "pyobjc_framework_InstantMessage-10.3-py2.py3-none-any.whl", hash = "sha256:27e17102aff08bd7016ac092597fd515e690e97ff179fbba8c92f5d1fdd3bf74"}, + {file = "pyobjc_framework_instantmessage-10.3.tar.gz", hash = "sha256:f88992c2ce71efa147d3809d5a0d8a422643e657281c5c72840ad9de5edce732"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-intents" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Intents on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Intents-10.2.tar.gz", hash = "sha256:ec27d5d19212fcec180ff04e2bc617fee0a018e2eaf29b2590c5512da167aa6a"}, - {file = "pyobjc_framework_Intents-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6a4e2ba2b5319c15ceeabdfd06f258789174e7e31011a24eab489d685066ed69"}, - {file = "pyobjc_framework_Intents-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9a3c08ec0dd199305989786e6e3c68d27f40b9eae3050bbf0207f053190f3513"}, - {file = "pyobjc_framework_Intents-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3dc9233522564ea8850a02961398a591446e0a0a0e63cd42cf7820daa0242f6a"}, + {file = "pyobjc_framework_Intents-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f68e0fee12cd47c539655a6e5be219c43592e6579542c5059d7ef211f0d4ad04"}, + {file = "pyobjc_framework_Intents-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9d6e972ed2fc5f87dd28313e32fdea137588100a8c9baca645fd53f87cea7541"}, + {file = "pyobjc_framework_Intents-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:9542e410767899ac4723079875e9c3305efccb8266a145711b73e783d8f04c32"}, + {file = "pyobjc_framework_intents-10.3.tar.gz", hash = "sha256:03faf5c52eb8e069fb72065f7a772d51e669a1e3be1d74810a69e05bc2ff7326"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-intentsui" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Intents on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-IntentsUI-10.2.tar.gz", hash = "sha256:4b9ca6f868b6cb7945ef4c285e73d220433efc35dfcad6b4a356bfce55e96c09"}, - {file = "pyobjc_framework_IntentsUI-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ec579d0f25cba0e1225f7690f52ed092bef5e01962fbe83ffbb70ec39861674"}, - {file = "pyobjc_framework_IntentsUI-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:91331fec42522596500bd0a580c633b7b84831c6316b2ec7458425d60b37da9e"}, - {file = "pyobjc_framework_IntentsUI-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:81f9d337473b3cb51f2aa4aa98156d6e294778d24fe011f41f0123b2676d824c"}, - {file = "pyobjc_framework_IntentsUI-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1c52fa06e8d65a003e384afcc1322051f2fbbfeac2c91ab852b407c552fd5652"}, - {file = "pyobjc_framework_IntentsUI-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:c514ecef1277ff00c07f78f7890e3a6cbe3c8fe44184f2f6da1a7b4b32851605"}, - {file = "pyobjc_framework_IntentsUI-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:22c40c11d5de5a866a5db2b4ba57e9663e79180c323928709eced30c5c03ac81"}, + {file = "pyobjc_framework_IntentsUI-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a25e9cbee40b404299194c3d94895760a9983db6ddafd11124d00905cb9bfe3e"}, + {file = "pyobjc_framework_IntentsUI-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1a27bf62bec02fe499918baefee4418207d138bca83327a3cdd775078c3d06e2"}, + {file = "pyobjc_framework_IntentsUI-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:eb94c897a006bcb11f8c1d521650d11674b3e3a20e8a07ace70fe4994cba5975"}, + {file = "pyobjc_framework_IntentsUI-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:d78ed0172745840561583127c4ae6786670de05aca385ffee167f15354e879a1"}, + {file = "pyobjc_framework_IntentsUI-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81dd968167c3b4a76e55f89b642e7d18dfab0267b2aa8528d7f8d4ac4d64e6ff"}, + {file = "pyobjc_framework_IntentsUI-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:82830c3bfae58f78b085c1c98258db7fb8774f69abf2e56b1b76a20cd23293cb"}, + {file = "pyobjc_framework_IntentsUI-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7d3f575c728688191a197d127940da1171fe91d902d366b9e9570d6dc927c0a"}, + {file = "pyobjc_framework_intentsui-10.3.tar.gz", hash = "sha256:1e791ecef111ba21ce03f779e8d39da5214b6921a2f6625247ee1247e09261be"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Intents = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Intents = ">=10.3" [[package]] name = "pyobjc-framework-iobluetooth" -version = "10.2" +version = "10.3" description = "Wrappers for the framework IOBluetooth on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-IOBluetooth-10.2.tar.gz", hash = "sha256:8c4d6a82d0f550c84dce72188369adb9347ad6ee1c8adef996ee1a8c376c51ee"}, - {file = "pyobjc_framework_IOBluetooth-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:15e8a35431740d3e4ee484d4af01afef0b6b8aee2bdfe7b6dbe6cf7c7cc563fa"}, - {file = "pyobjc_framework_IOBluetooth-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:03ee5ecc3a2d2f6a0b4de9b36bc1c56f820624e8176abca0014c9ef3c86b0cd0"}, - {file = "pyobjc_framework_IOBluetooth-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b91c0b370047b386e9b333ba3c12ac121089fa94291c721e8b1ad6945b5763dd"}, + {file = "pyobjc_framework_IOBluetooth-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a55ae467d77ef1482ce93ed0d0847ea86e466b2278b13929ec26cd8a8a609207"}, + {file = "pyobjc_framework_IOBluetooth-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8d671c767fea4e128a38136a24ef1f17a9df96b4578f8d6e56a4752c7b1a6e3c"}, + {file = "pyobjc_framework_IOBluetooth-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:001743ad0dc32a19ccd39d3352adf376f624e51d06d79b7ee9583a9c7090450f"}, + {file = "pyobjc_framework_iobluetooth-10.3.tar.gz", hash = "sha256:49ffbe7464684008b162c3dc025c39b8b943b505e300fc185966c567d7e8f284"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-iobluetoothui" -version = "10.2" +version = "10.3" description = "Wrappers for the framework IOBluetoothUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-IOBluetoothUI-10.2.tar.gz", hash = "sha256:ed9f4cb62eeda769b3f530ce396fd332f82441c5d22b9cf7b58058670c262d10"}, - {file = "pyobjc_framework_IOBluetoothUI-10.2-py2.py3-none-any.whl", hash = "sha256:f833efa3b1636f7a6cf8b5b2d25fc566757c2c7c06ee7945023aeb992493d96e"}, + {file = "pyobjc_framework_IOBluetoothUI-10.3-py2.py3-none-any.whl", hash = "sha256:4ad16ce48e34b5af186d3b528147e34f772ff5818aa8284390070d3b45cdbf05"}, + {file = "pyobjc_framework_iobluetoothui-10.3.tar.gz", hash = "sha256:9ab371ff6ce1a4f7b3706acc3b430e697aa8816808899e3a709f5504b8c3d36c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-IOBluetooth = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-IOBluetooth = ">=10.3" [[package]] name = "pyobjc-framework-iosurface" -version = "10.2" +version = "10.3" description = "Wrappers for the framework IOSurface on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-IOSurface-10.2.tar.gz", hash = "sha256:f1412c2f029aa1d60add57abefe63ea4116b990892ef7530ae27a974efafdb42"}, - {file = "pyobjc_framework_IOSurface-10.2-py2.py3-none-any.whl", hash = "sha256:b571335a2150e865828d3e52e2a742531499c88dd85215c14d07e68e9bed70a7"}, + {file = "pyobjc_framework_IOSurface-10.3-py2.py3-none-any.whl", hash = "sha256:ed016eeb0fb6b176a002a37da968bee9770ce764e11299dbbef9386a2dd746af"}, + {file = "pyobjc_framework_iosurface-10.3.tar.gz", hash = "sha256:bbb3acb6417e729f27bc4fed1286436aab9242ba750cc61e39cf6994ad26fecc"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-ituneslibrary" -version = "10.2" +version = "10.3" description = "Wrappers for the framework iTunesLibrary on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-iTunesLibrary-10.2.tar.gz", hash = "sha256:c60d1dc9eabb28b036b766b89ea7d18198e21deb8925fc5a5753777c905ecddf"}, - {file = "pyobjc_framework_iTunesLibrary-10.2-py2.py3-none-any.whl", hash = "sha256:4e6cf6073a902f77e0b0c33d2d52e3ab3f0c869cb339b7685b5e7f079df8ef4e"}, + {file = "pyobjc_framework_iTunesLibrary-10.3-py2.py3-none-any.whl", hash = "sha256:3cf1062f5e95aa1c2641743fee6d48bcf73235955d40ca843c728690f46f590e"}, + {file = "pyobjc_framework_ituneslibrary-10.3.tar.gz", hash = "sha256:ac4978becfaa69cdb8e6ba2900965bb86dedb1610262acd993cf58dc7d8d33f3"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-kernelmanagement" -version = "10.2" +version = "10.3" description = "Wrappers for the framework KernelManagement on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-KernelManagement-10.2.tar.gz", hash = "sha256:effd1d3230c8a3b8628e7fd315f0aac10fbf1ea99f2ed923999cb1ab787c317a"}, - {file = "pyobjc_framework_KernelManagement-10.2-py2.py3-none-any.whl", hash = "sha256:d8dca9dc1f756bfa894a32f56857ecefb4d188aec590433ee302529261dffb68"}, + {file = "pyobjc_framework_KernelManagement-10.3-py2.py3-none-any.whl", hash = "sha256:87998385a4ba9d7c69afc361aa081f8b980fe14dca0ef04f74a97eb13b133a1b"}, + {file = "pyobjc_framework_kernelmanagement-10.3.tar.gz", hash = "sha256:9619677c9976a9428f0913420c0e939a17f1fa809855bbc3d9bb6a989729d49e"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-latentsemanticmapping" -version = "10.2" +version = "10.3" description = "Wrappers for the framework LatentSemanticMapping on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-LatentSemanticMapping-10.2.tar.gz", hash = "sha256:eb3ddd5e04c39b0151a64bd356f7de3c66062257e3802e8abea7a882e972ff21"}, - {file = "pyobjc_framework_LatentSemanticMapping-10.2-py2.py3-none-any.whl", hash = "sha256:dadd4352b9af681dd85d04712a6cf1d2c574acbf0b8178c35f42231ec8c5a6d1"}, + {file = "pyobjc_framework_LatentSemanticMapping-10.3-py2.py3-none-any.whl", hash = "sha256:fac29c9f90271299fdc6d0f79cd20cbccda2e65d25ebe8eb94b5de16283cf517"}, + {file = "pyobjc_framework_latentsemanticmapping-10.3.tar.gz", hash = "sha256:a3d633158ac9c416617fbe0a64a672c0a56167714774675b7c374d1e712efc5a"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-launchservices" -version = "10.2" +version = "10.3" description = "Wrappers for the framework LaunchServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-LaunchServices-10.2.tar.gz", hash = "sha256:d9f78d702dea13a363de8a7c1c382e1ca872993980c164781cb2758ee49353d2"}, - {file = "pyobjc_framework_LaunchServices-10.2-py2.py3-none-any.whl", hash = "sha256:15b7c96e3059550c218ed5cb5de11dddc7aae21c67c0808b130a5d49b8f4cc0f"}, + {file = "pyobjc_framework_LaunchServices-10.3-py2.py3-none-any.whl", hash = "sha256:2969eed89464e49a38bf1c80829cf0c721ea8bf2e75e67985748bdfb2ba03937"}, + {file = "pyobjc_framework_launchservices-10.3.tar.gz", hash = "sha256:b28b605ed6d5626ce0e48520444cf131d6596ee51b1af56596c0bbe2d1ef996a"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-CoreServices = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-CoreServices = ">=10.3" [[package]] name = "pyobjc-framework-libdispatch" -version = "10.2" +version = "10.3" description = "Wrappers for libdispatch on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-libdispatch-10.2.tar.gz", hash = "sha256:ae17602efbe628fa0432bcf436ee8137d2239a70669faefad420cd527e3ad567"}, - {file = "pyobjc_framework_libdispatch-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:955d3e3e5ee74f6707ab06cc76ad3fae27e78c180dea13f1b85e2659f9135889"}, - {file = "pyobjc_framework_libdispatch-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:011736d708067d9b21a4722bae0ed776cbf84c8625fc81648de26228ca093f6b"}, - {file = "pyobjc_framework_libdispatch-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:28c2a2ab2b4d2930f7c7865ad96c1157ad50ac93c58ffff64d889f769917a280"}, - {file = "pyobjc_framework_libdispatch-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6cb0879e1f6773ad0bbeb82d495ad0d76d8c24b196a314ac9a6eab8eed1736e0"}, - {file = "pyobjc_framework_libdispatch-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:aa921cd469a1c2e20d8ba9118989fe4e827cbb98e947fd11ae0392f36db3afcc"}, - {file = "pyobjc_framework_libdispatch-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f3d57d24f81878d1b5dcb00a13f85465ede5b91589394f4f1b9dcf312f3bd99"}, + {file = "pyobjc_framework_libdispatch-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6845f7dcb13cd24e921eed2c9cf5087ce138f69089a05ba0bf9ac9e2d5294930"}, + {file = "pyobjc_framework_libdispatch-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e49c4e6614f53a9c89f0e79abbee3cdcdd6426dd213780ebb9e3eeeb02088c3"}, + {file = "pyobjc_framework_libdispatch-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e71d7bad62be682718035d384aefc7603ec1f350ee7992cf89a3eff797f6e371"}, + {file = "pyobjc_framework_libdispatch-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:df656b26e04bc489f76f96d1748f3349a9fb0a5f6dcd8f0ca686b0bf1c89641f"}, + {file = "pyobjc_framework_libdispatch-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2da791f1515c64c40e2e4de552933f77fdcced8321afa1511eae7c35c0f31a30"}, + {file = "pyobjc_framework_libdispatch-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:c1f46c4dc4816274c890822bb809462cbe8c46b27be24cceb4fa0902b85e8ec0"}, + {file = "pyobjc_framework_libdispatch-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1d47e167bd6e246a1f5c9c780955d5b08ed049f0d71af23314f81715d0e98500"}, + {file = "pyobjc_framework_libdispatch-10.3.tar.gz", hash = "sha256:1f0aa2a1900788368bc8370a631d7ee83e18cd3cacc32bbfb2b3653d9d93d892"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-libxpc" -version = "10.2" +version = "10.3" description = "Wrappers for xpc on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-libxpc-10.2.tar.gz", hash = "sha256:04deac1f9dbd1c19c10d175846017f8e8e51d2b52a2674482638d6b289e883a6"}, - {file = "pyobjc_framework_libxpc-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b57089f792d51ad687c9933dd2d3669cd5e6f84d1f9213738ecc5833dba9aa8c"}, - {file = "pyobjc_framework_libxpc-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e31cb4f7fdb76defc53fe0b56c3f1db953c1dcf3519093835527f270c37315c3"}, - {file = "pyobjc_framework_libxpc-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:978cc2a9cc668e0c4aef13af81cec6129e7b98877b44c952232c0083a8fd352e"}, - {file = "pyobjc_framework_libxpc-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5dd057a556398b48982fdae84f8e08ee9b69b6e5918b6782bd842ef9ad97820d"}, - {file = "pyobjc_framework_libxpc-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:df394dc08eab33430f565a2252906f27cd4f7c41fd431f75b4ae35d3a76f4eab"}, - {file = "pyobjc_framework_libxpc-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fd3608a32ebe65253c24b7590ad96977135aa847dd188e4c2168f0da9e74e47"}, + {file = "pyobjc_framework_libxpc-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b64eef0b36efccf926e529f0cfd55d416fee667ee71371679cba8675959947"}, + {file = "pyobjc_framework_libxpc-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:af837591e4a2cd5dfbf37017c92d4f30b448293fe56a7ac10e1033d5aaf692a3"}, + {file = "pyobjc_framework_libxpc-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c10a1a8a5863099b163e71f808c7d42d6e052611e5851924e13ab260fab12b36"}, + {file = "pyobjc_framework_libxpc-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:ff4a24534e7fc6b5da6af2503afc76d33bc8148693f04d9585a1f1062171e21f"}, + {file = "pyobjc_framework_libxpc-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c406f029c57ccead3b0bb53fb20046cbf72552fb3b06e922893cffa2a84b54f3"}, + {file = "pyobjc_framework_libxpc-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7717d83d440d66742d153d081bb52bf8493fce7db21debace77b87012df21bde"}, + {file = "pyobjc_framework_libxpc-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fafaf57f13eb3fe09dd1f93cc7895d2b50178933f2e163fe9abb06940f553d00"}, + {file = "pyobjc_framework_libxpc-10.3.tar.gz", hash = "sha256:b69f3e73ecca92e07ded276544f8cae15f915fda314144dda18fadc7f2f127b9"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-linkpresentation" -version = "10.2" +version = "10.3" description = "Wrappers for the framework LinkPresentation on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-LinkPresentation-10.2.tar.gz", hash = "sha256:4ccae5f593b58dfe9cb422645e0ccf5adab906ec008d3e20eb710cd62bbb4717"}, - {file = "pyobjc_framework_LinkPresentation-10.2-py2.py3-none-any.whl", hash = "sha256:1cada96d3eb03e51e1bbb7e7c10b9c08c80fd098132541b4e992234fe43cfa37"}, + {file = "pyobjc_framework_LinkPresentation-10.3-py2.py3-none-any.whl", hash = "sha256:180cf53bc4149c5873ef9d6c93026ce73c5ae8b522fb7e38850c94243d9879af"}, + {file = "pyobjc_framework_linkpresentation-10.3.tar.gz", hash = "sha256:9a5696d126ded58cf9362b19e8846c51c70ee17d546d3be55ff4d279f791aaf1"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-localauthentication" -version = "10.2" +version = "10.3" description = "Wrappers for the framework LocalAuthentication on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-LocalAuthentication-10.2.tar.gz", hash = "sha256:26e899e8b4a90632958eb323abbc06d7b55c64d894d4530a9cc92d49dc115a7e"}, - {file = "pyobjc_framework_LocalAuthentication-10.2-py2.py3-none-any.whl", hash = "sha256:442f6cae70300f29c9133ed7f2e01c294976b9aae55fe180c64983d5dee62254"}, + {file = "pyobjc_framework_LocalAuthentication-10.3-py2.py3-none-any.whl", hash = "sha256:d8dbf68c2073cd5cd3894d6d73f3538bb35afccde4273cdeac45ad1489691c17"}, + {file = "pyobjc_framework_localauthentication-10.3.tar.gz", hash = "sha256:073716dacdc1d8ca28db778ea133c9a4bff8678af9a6066a2a7e7043dc0e0169"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Security = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Security = ">=10.3" [[package]] name = "pyobjc-framework-localauthenticationembeddedui" -version = "10.2" +version = "10.3" description = "Wrappers for the framework LocalAuthenticationEmbeddedUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-LocalAuthenticationEmbeddedUI-10.2.tar.gz", hash = "sha256:52acdef34ea38d1381a95de15b19c9543a607aeff11db603371d0224917a8830"}, - {file = "pyobjc_framework_LocalAuthenticationEmbeddedUI-10.2-py2.py3-none-any.whl", hash = "sha256:eafbbc321082ff012cdb14e38abae7ced94c6d962cb64af43d6d515da976e175"}, + {file = "pyobjc_framework_LocalAuthenticationEmbeddedUI-10.3-py2.py3-none-any.whl", hash = "sha256:481592e8a3ec90f51ff334509d65a5bdb22b07c01239ee47029f9cb78d2bbdd8"}, + {file = "pyobjc_framework_localauthenticationembeddedui-10.3.tar.gz", hash = "sha256:fdd6edc4a286f943d372d4aacc9587284c07efc3df19a6f8642cfff91cb74ba2"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-LocalAuthentication = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-LocalAuthentication = ">=10.3" [[package]] name = "pyobjc-framework-mailkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MailKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MailKit-10.2.tar.gz", hash = "sha256:8d8fceff5498df0cfa630b7088814f8daa8a25794a36d4b57cfde8c2c14cdc70"}, - {file = "pyobjc_framework_MailKit-10.2-py2.py3-none-any.whl", hash = "sha256:d8bc9e6649e7e500d2d4d4ab288304846d9bfa06952ebeee621fe095dc2f51eb"}, + {file = "pyobjc_framework_MailKit-10.3-py2.py3-none-any.whl", hash = "sha256:4865846f1c6b655901c3248eb2b7ea9115f023a93144ceeb07e67ee9f8229d0c"}, + {file = "pyobjc_framework_mailkit-10.3.tar.gz", hash = "sha256:e097f8db128f927ac2860696cc3326213203526bea070de82aca4e5117c409d4"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-mapkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MapKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MapKit-10.2.tar.gz", hash = "sha256:35dfe7aa5ec9e51abc47d6ceb0f83d3c2b5876258591a568e85e2db8218427c4"}, - {file = "pyobjc_framework_MapKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ce322299b04eef212706185764771041a1220f7a611606e33f95ac355d913238"}, - {file = "pyobjc_framework_MapKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:339a8c8181047fc9eb612eb47c51f017423a6b074e2a4838cd6b06e36af6c160"}, - {file = "pyobjc_framework_MapKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:85a110693198798234d3edbd3b606d9d9c9b4817e4ed70d2b2e18357422783c6"}, + {file = "pyobjc_framework_MapKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:290ce559818baaea69a94817239fef6c211d0d5428ad2d9e31e6aabc06079b11"}, + {file = "pyobjc_framework_MapKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1ed74fc8a5e5989c902c304f6e5ccff7b21f871234ff3797b5903ae00de2e0f4"}, + {file = "pyobjc_framework_MapKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c9f92577550b3cebb61d40755ac3f2946be47d47a2449472495c1589ed0df3a7"}, + {file = "pyobjc_framework_mapkit-10.3.tar.gz", hash = "sha256:321cc41a26df1e4d9676d4c7df5f83ea9239b56da66f4fed077ce8949ae9e315"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreLocation = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreLocation = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-mediaaccessibility" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MediaAccessibility on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MediaAccessibility-10.2.tar.gz", hash = "sha256:acce0baf11270c9276a219f5a0dfb6d8241e01ac775144bfe3a83e088dcd1308"}, - {file = "pyobjc_framework_MediaAccessibility-10.2-py2.py3-none-any.whl", hash = "sha256:55dbf7519028fadf3ac6cb1ef185156f6df649655075a015cf87cee370255e82"}, + {file = "pyobjc_framework_MediaAccessibility-10.3-py2.py3-none-any.whl", hash = "sha256:95b2368b0f0ca17a618d687225d6faf1254b7819cf8762572561ef7986c1025f"}, + {file = "pyobjc_framework_mediaaccessibility-10.3.tar.gz", hash = "sha256:03d7aa15ae9a19b582003144dec91c3d99aa563a58328d559fe1f03b95cfa234"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-medialibrary" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MediaLibrary on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MediaLibrary-10.2.tar.gz", hash = "sha256:b3e1bd3e70f0013bbaccd0b43727a0f16ecf23f7d708ca81b8474faaa1f8e8fc"}, - {file = "pyobjc_framework_MediaLibrary-10.2-py2.py3-none-any.whl", hash = "sha256:98b9687f1399365889529c337d99d7f19edf3a94beb05884cf15a29f4fc178af"}, + {file = "pyobjc_framework_MediaLibrary-10.3-py2.py3-none-any.whl", hash = "sha256:2fa66b8f60aa4dc63ae064555a28bbd247842d5b867de218d1dff43ae6c71357"}, + {file = "pyobjc_framework_medialibrary-10.3.tar.gz", hash = "sha256:5084a082758e9e616789c603da539acfe12d681bb3b633041f53b035797e116f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-mediaplayer" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MediaPlayer on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MediaPlayer-10.2.tar.gz", hash = "sha256:4b6d296b084e01fb6e5c782b7b6308077db09f4051f50b0a6c3298ffbd1f1d70"}, - {file = "pyobjc_framework_MediaPlayer-10.2-py2.py3-none-any.whl", hash = "sha256:c501ea19380bfbf6b04fbe909fcfe9a78c5ff2a9b58dae87be259066b1ae3521"}, + {file = "pyobjc_framework_MediaPlayer-10.3-py2.py3-none-any.whl", hash = "sha256:82882aa1e901741e9b976f143cb576668845d45c2a0f51c8d5721c35700f0406"}, + {file = "pyobjc_framework_mediaplayer-10.3.tar.gz", hash = "sha256:b7571fbec3fecf9333e9c0c1a4b21a8c1c6ac4f776d431c3d0f2468ff96595ce"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-AVFoundation = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-AVFoundation = ">=10.3" [[package]] name = "pyobjc-framework-mediatoolbox" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MediaToolbox on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MediaToolbox-10.2.tar.gz", hash = "sha256:614ec0a28c810395274aa1d5348a447f67bae4629a3a8372d14162f38e2fc597"}, - {file = "pyobjc_framework_MediaToolbox-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca7443bca94dfd9863d5290d2680247b7d577cf031dcfc854c414e5fdd9cdb03"}, - {file = "pyobjc_framework_MediaToolbox-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c34dca15560507286eb9ef045d6234ac1db1e50f22c63397662155a7f01ea9ac"}, - {file = "pyobjc_framework_MediaToolbox-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:696d6cadbb643f98750f5a791663ca264f0a0f4db2aeec7c8cf59c02face1683"}, + {file = "pyobjc_framework_MediaToolbox-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fb293ab6085277b151a289b1fb3f6eec4c0214e2147d3fbeb0a8d9a666808d2"}, + {file = "pyobjc_framework_MediaToolbox-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a7c692ac7dcab5c83c4a01db83400f06ea2c46bb3940ee477d0002a2cc824c6f"}, + {file = "pyobjc_framework_MediaToolbox-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4b0b40879ac673b7211fe6e4363bdf0628ce3dab38d47b94bc83043d155063f5"}, + {file = "pyobjc_framework_mediatoolbox-10.3.tar.gz", hash = "sha256:d63da415403ebb759b604adbefd3abe37ac68c5a301faf2eb8d934a85e3b7d26"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-metal" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Metal on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Metal-10.2.tar.gz", hash = "sha256:652050cf9f5627dba36b31ad134e56c49040d0dcfaf93a7026018ef17330a01e"}, - {file = "pyobjc_framework_Metal-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c68e4025c52e8c8b0fa584abeb058debe49ac3174e8c421408bf873e5951fd02"}, - {file = "pyobjc_framework_Metal-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:49f333f41556f08e28750bb4e09a7053ac55434f4a29a3e228ed4fd9bae8f57d"}, - {file = "pyobjc_framework_Metal-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0cb39a4f4a70f45f88f79c3641b00b6db0c9b9ed90bee21840a725a8d7c7eaca"}, + {file = "pyobjc_framework_Metal-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7a724a98fa6972e237c5aeaee8314b68e8716ff725790587760b1fe0f700e2e7"}, + {file = "pyobjc_framework_Metal-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1c5df37c7e02a29e1b27081bcba7fa86523fce6eddaca08f6935659a2419fd3d"}, + {file = "pyobjc_framework_Metal-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:88989bf43f1443d68fd4692e224cebd68aef6215d0a92e0606c644c2a193ec51"}, + {file = "pyobjc_framework_metal-10.3.tar.gz", hash = "sha256:f137fb82175bf477e56de5c788e96caa2ad1f83b65a4fc374f9dbd1f1f9e91cc"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-metalfx" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MetalFX on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MetalFX-10.2.tar.gz", hash = "sha256:d98a0fd1f0d2d3ea54efa768e6817a8773566c820ae7a3a23497e1c492e11da7"}, - {file = "pyobjc_framework_MetalFX-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e7f1b50316db47ffb1e9505726dfe5bf552f32188d21b6ef979078fec9f58077"}, - {file = "pyobjc_framework_MetalFX-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:526687ac36b71b9822613bf552bff99930ee2620414b0b932f5e0d327d62809e"}, - {file = "pyobjc_framework_MetalFX-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:a8c78a8f9c3ee59cb5ba96e4db56c3ab8cc78860f9d42ca5732168d8691cb17b"}, + {file = "pyobjc_framework_MetalFX-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:980d113befb87cc04d59e821a7a9c8e3f938e2350a644a272132aef964f5d14c"}, + {file = "pyobjc_framework_MetalFX-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9fb93254978f105dd2f3781f8319131a8164c34b90dbf367084beb5fcef11b63"}, + {file = "pyobjc_framework_MetalFX-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:bcf5e8d550e47d5d4aadd7661ea17853ad91e5645aae8674ad4837d649b4b865"}, + {file = "pyobjc_framework_metalfx-10.3.tar.gz", hash = "sha256:a0235e213e7b54db43d2690062d1d938cbe8f3923abd2a61e8b91cf35b57a639"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Metal = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Metal = ">=10.3" [[package]] name = "pyobjc-framework-metalkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MetalKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MetalKit-10.2.tar.gz", hash = "sha256:42fc61371d49c2b86828d2a668b7badb2418c0ecce7595fce790830607bd8040"}, - {file = "pyobjc_framework_MetalKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:abcdabdad3d9810730c67f493b70139254f7438ebba0149b5dcd848384a08a85"}, - {file = "pyobjc_framework_MetalKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7990b05194919d187a6af8be7fe51007ab666cfdb3512b6fb022da9049d9957d"}, - {file = "pyobjc_framework_MetalKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c26c2e2965ae6547edecbc8e250117401c26f62f9a55e351eca42f2e557721e7"}, + {file = "pyobjc_framework_MetalKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3c5c1e84984d4d8788cdd08eb7c5db8c75a96fbdda72f4ab66d19eb525d9f76a"}, + {file = "pyobjc_framework_MetalKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f8cb173e0fa120f1858cf0ef05ca61f07e84c9636ffe3cd6a34c12d92a511ca9"}, + {file = "pyobjc_framework_MetalKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1426937d86371d9b2371027f70f282e896e39e63a0d6486f0ba7984dfd0b6766"}, + {file = "pyobjc_framework_metalkit-10.3.tar.gz", hash = "sha256:de8cfbc63531e574bc3fef34960590820b3e7ead2efa48a6295c4a7eea20a9d9"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Metal = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Metal = ">=10.3" [[package]] name = "pyobjc-framework-metalperformanceshaders" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MetalPerformanceShaders on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MetalPerformanceShaders-10.2.tar.gz", hash = "sha256:66e6f671279b1f7edbaed1bea8ab1eb57f617e000c1e871c190b60ad60c1d727"}, - {file = "pyobjc_framework_MetalPerformanceShaders-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a65c201921fffb992955aa143ffcb36be3e7c5aee86334941d3214428f0c7ad8"}, - {file = "pyobjc_framework_MetalPerformanceShaders-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9fd437d0b1a83a3bdc866727ba17a00b49ee239205b2d14b617f5ca4f566c4f7"}, - {file = "pyobjc_framework_MetalPerformanceShaders-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0f862a65ffc0159e6b9ad46115b8d7ecbce5f56fe920c709b943982d4a70d63c"}, + {file = "pyobjc_framework_MetalPerformanceShaders-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3b71ad3993d18564e5566e48c782a06eb4315af9e03c64f8ef6fd20d09d8783e"}, + {file = "pyobjc_framework_MetalPerformanceShaders-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2ea02d5c65a4cda05a66ce7f5642ff3c3942e9a305abbc30a2a3770fdd02d4d3"}, + {file = "pyobjc_framework_MetalPerformanceShaders-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:7cd0e7d0e10f3a2619fc13653eab142c18168fd05718ee0d459a8cb54b68b576"}, + {file = "pyobjc_framework_metalperformanceshaders-10.3.tar.gz", hash = "sha256:602bdc6c2ac75c330897f473661b52cfb1bed32d606a351962fd36180bf09001"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Metal = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Metal = ">=10.3" [[package]] name = "pyobjc-framework-metalperformanceshadersgraph" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MetalPerformanceShadersGraph on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MetalPerformanceShadersGraph-10.2.tar.gz", hash = "sha256:4fffad1c37e700fc38b2ca8eb006d7532b3b5cb700580ce7dfd31af35e0fb6e8"}, - {file = "pyobjc_framework_MetalPerformanceShadersGraph-10.2-py2.py3-none-any.whl", hash = "sha256:7fedd831f9fc58708f6b01888abd42a2f08151c86db47280fe47be0f709811bf"}, + {file = "pyobjc_framework_MetalPerformanceShadersGraph-10.3-py2.py3-none-any.whl", hash = "sha256:afb9d542458d98402546700a844b0b93877a71988b3fc4e56109065d2a7652b6"}, + {file = "pyobjc_framework_metalperformanceshadersgraph-10.3.tar.gz", hash = "sha256:fbb3b6f5f91fb4419e7e3023c7b8729eae42aca0d48b2bb985f96af6718ae4a6"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-MetalPerformanceShaders = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-MetalPerformanceShaders = ">=10.3" [[package]] name = "pyobjc-framework-metrickit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MetricKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MetricKit-10.2.tar.gz", hash = "sha256:14cb02fd8fc338f6f15df5fd14c95419871b768cc8f5f71b1e0e99fde46b4712"}, - {file = "pyobjc_framework_MetricKit-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:585a494a5126c5481afc34ac5bfdc28a1a2b7044d8b0e3427fbd5313e72c59fb"}, - {file = "pyobjc_framework_MetricKit-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b330ccffa45f4ccf2fc23c73112bf3b652515eb025fddeb3e2c81ca25f1a168"}, - {file = "pyobjc_framework_MetricKit-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fc336ff6db376bff4cab0bd7db962aae1ff11f4584026cd5c4d3f66283018ce7"}, - {file = "pyobjc_framework_MetricKit-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d1403302d753686b49aa0d6fc0a4c05e6ead18aa1b9de9668322fd0e81c51f"}, - {file = "pyobjc_framework_MetricKit-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:82b01a838203000c262f9f52420b1387850505f0a7b742b29a73cc8c6a9e0c25"}, - {file = "pyobjc_framework_MetricKit-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:79971789bff04540200bd443ec3c6ae13f83eea827d2dab0f33bc9c6e6af9ab0"}, + {file = "pyobjc_framework_MetricKit-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6944badc0ea077a1f2e9c9e16137293534a1566e2a2f411ab861d4d21090b2a8"}, + {file = "pyobjc_framework_MetricKit-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a18d89bf6583ea70aa67bc964a48e6c57a12470c5ed2eb0ef1b797368eeba3aa"}, + {file = "pyobjc_framework_MetricKit-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c5fce19ea55a0ef4da7b597626c76553b69b2ca2c87fa33811752e52d8db012d"}, + {file = "pyobjc_framework_MetricKit-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:7a065292b8331bc5fe2e736ebf39ff9edde9fe32994eb32b4987b901d756b36e"}, + {file = "pyobjc_framework_MetricKit-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c6b369b7a0daeb75bc40d05a527953f77162499a25c6fa6b59719ddd4490a556"}, + {file = "pyobjc_framework_MetricKit-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:13c6fd6110e640fee48ad72d0965eabc5049038cf70c3fc1157cd57a9b6812fb"}, + {file = "pyobjc_framework_MetricKit-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:21ad79f98474da198003e32de23a66f10d819e9e572f86ed81d7588ba4e72824"}, + {file = "pyobjc_framework_metrickit-10.3.tar.gz", hash = "sha256:0daaca29f60f0806e3f2a08bfe5ee2dfdbb8bf3ad2c7adef50f90cc523f34530"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-mlcompute" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MLCompute on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MLCompute-10.2.tar.gz", hash = "sha256:6f5bff2317b2ae45c092a94a05e7831d0dc7a002fc68b03648abbac5a2ce33a3"}, - {file = "pyobjc_framework_MLCompute-10.2-py2.py3-none-any.whl", hash = "sha256:a191abf1c6aef061b4eab1aa8d4cf886fd6c98e53f6fedcd738ddd904571b933"}, + {file = "pyobjc_framework_MLCompute-10.3-py2.py3-none-any.whl", hash = "sha256:5845c232ac703be2e1cd5139e6e4c758493602562565e9b57cc8aec0e8630583"}, + {file = "pyobjc_framework_mlcompute-10.3.tar.gz", hash = "sha256:551139df816a78d0cdb4e70ddf01cd705ecb4b88ba121baebf4db4297c4ca274"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-modelio" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ModelIO on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ModelIO-10.2.tar.gz", hash = "sha256:8ae1444375260a346d1c77838f84e2c04dfabaf2769b2970a3588becb670431e"}, - {file = "pyobjc_framework_ModelIO-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6d226b059a4c99669ec3dc03c1dde9b0daeba392a198cdb36398394396512a26"}, - {file = "pyobjc_framework_ModelIO-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c2fff57596d54b95507a1c180a6df877e28e561e5e71941619d70ac67d5bec4d"}, - {file = "pyobjc_framework_ModelIO-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e6b119d66cefde55ce63e406c4fd12d626fb017ee88d9e01fdd25434f6ddc831"}, + {file = "pyobjc_framework_ModelIO-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d348fb8fa7339e152059ee08ed5ccb70d75bb92db2c4e60aba2ca8be79640c15"}, + {file = "pyobjc_framework_ModelIO-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3f2534d4a3920a77572acc4a6803f7514eabb6ef780c858ed2b63c2b4af502c7"}, + {file = "pyobjc_framework_ModelIO-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ec49cdf8e17f77c3f76ba3f159c7383778dfdfd73330be92c7136244c875e348"}, + {file = "pyobjc_framework_modelio-10.3.tar.gz", hash = "sha256:851e411bb075e0c7f813ee188610d5b87630f8552393657061bc3de58c20655f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-multipeerconnectivity" -version = "10.2" +version = "10.3" description = "Wrappers for the framework MultipeerConnectivity on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-MultipeerConnectivity-10.2.tar.gz", hash = "sha256:e3c1e5f39715621786f4ad5ecffa2cc9445a218e5ab3e94295c16fbcb754ee5a"}, - {file = "pyobjc_framework_MultipeerConnectivity-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ce68b7b5030e95e78bc94e898adb09f1e3f30c738e7140101146c52c64ff5493"}, - {file = "pyobjc_framework_MultipeerConnectivity-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f158aaaabcfd0d1e6d77585ec24797dbedf6bde640675b26dcfb4e2093d3a0ce"}, - {file = "pyobjc_framework_MultipeerConnectivity-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0e02f9ecdbf2c4aacd5ab8cd019415584bed7fa1656d525c8f841466d6e58993"}, + {file = "pyobjc_framework_MultipeerConnectivity-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8013e0298f7d98cb060ed7ca491ba393999030c589c86900a143cbcc5ba8767f"}, + {file = "pyobjc_framework_MultipeerConnectivity-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6802c1fc6f77cec5f4a117f8b2bcb4c02d8fe8216278e9dbb49df31ee0626a47"}, + {file = "pyobjc_framework_MultipeerConnectivity-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f38409f8b9c6744222c9f5d4a3a0079ca844a9700b2e9e711f150df317147132"}, + {file = "pyobjc_framework_multipeerconnectivity-10.3.tar.gz", hash = "sha256:ee4ab1f39bcb50354602bf05b0064cf4698db95b504551c0beebda554eef5f8f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-naturallanguage" -version = "10.2" +version = "10.3" description = "Wrappers for the framework NaturalLanguage on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-NaturalLanguage-10.2.tar.gz", hash = "sha256:eba7de67bea4a6a071e04e79c8a4de0547c25a09635fe3d4ee6cd58fb6aeaf65"}, - {file = "pyobjc_framework_NaturalLanguage-10.2-py2.py3-none-any.whl", hash = "sha256:0165735973a720f09bd5a2333f32e16aac52332fb595425480d7a2215472d4fb"}, + {file = "pyobjc_framework_NaturalLanguage-10.3-py2.py3-none-any.whl", hash = "sha256:1c002762da454c59b7465d9bec0337c796f4a255e789c37fc091e734b7ee1f60"}, + {file = "pyobjc_framework_naturallanguage-10.3.tar.gz", hash = "sha256:af031d2e3bf184ad3120f15b99cd9219fb5372372024c50e494767b1dbb2dab7"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-netfs" -version = "10.2" +version = "10.3" description = "Wrappers for the framework NetFS on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-NetFS-10.2.tar.gz", hash = "sha256:05de46b15d19abecbb9e7d04745ca27dba9ec121f16ea7bafc9dc87a12c0e828"}, - {file = "pyobjc_framework_NetFS-10.2-py2.py3-none-any.whl", hash = "sha256:e7a84497be6114ea2e47776efda640d9d8becaaa07214d712a204b5d446e3d95"}, + {file = "pyobjc_framework_NetFS-10.3-py2.py3-none-any.whl", hash = "sha256:3b223f96aeb2e3317e11b9f53fbe4d0c06033279bdef5570cb77ca9c12c0a8f4"}, + {file = "pyobjc_framework_netfs-10.3.tar.gz", hash = "sha256:119a6c4080f9a07d0dd5355bd8eeea1272477b8f128c3d532aa04e883763569c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-network" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Network on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Network-10.2.tar.gz", hash = "sha256:b39bc26f89cf9fc56cc9c4a99099aef68c388d45b62dc1ec16772ee290b225d4"}, - {file = "pyobjc_framework_Network-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4f465400cd4402b7495a27de4c9099bcc127afa4d1cb587f75b987750c0ea032"}, - {file = "pyobjc_framework_Network-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:39966aa35d17b00973fa85e334b6360311cfd1a097d26d79b5957bc7cd7fad4a"}, - {file = "pyobjc_framework_Network-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5542660d0c7183dc4599bd20763ed3b59772cf17211ca3720a4175f886a8eada"}, + {file = "pyobjc_framework_Network-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:40ea746241e8199b793389a17ebb4e699e7d9e9fc17407133bb217ea2aff74f4"}, + {file = "pyobjc_framework_Network-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:951dc751a8f8fe62dcc6f888fd3c53be84835815bc0c3989f3bc9203e482c326"}, + {file = "pyobjc_framework_Network-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c029aab42580af9846a5e97d6afe76a97b870254433900faf55b1b726ce91369"}, + {file = "pyobjc_framework_network-10.3.tar.gz", hash = "sha256:34d63495b8e1bfd8008a55299c3b14a743a082bf1cbce25fb741db57284e2bc4"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-networkextension" -version = "10.2" +version = "10.3" description = "Wrappers for the framework NetworkExtension on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-NetworkExtension-10.2.tar.gz", hash = "sha256:14f237bd96a822c55374584e99f2d79581b2d60570f34e4863800f934a44b82d"}, - {file = "pyobjc_framework_NetworkExtension-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:280dc76901628b2c9750766bb2424a29de3f1f49b41e5f29634701cfe0ab0524"}, - {file = "pyobjc_framework_NetworkExtension-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ce6cfdff6f65f512137ee382ba04ee2b52e0fb51deacb651e385daf5349d28b7"}, - {file = "pyobjc_framework_NetworkExtension-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ed2cf32a802ec872466c743013ce9ef17757e89e21a49cbeeeffddfaefb89fc4"}, + {file = "pyobjc_framework_NetworkExtension-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2f4a2ef0ac9619052ec2db1681ed5ce7d568ad0c73f570fb6c119ec33b25fee2"}, + {file = "pyobjc_framework_NetworkExtension-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f5f2e8f23f89d754ac82d7db6b607634bb40c390b8507b0367f94d70493eea3b"}, + {file = "pyobjc_framework_NetworkExtension-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:387e2bb13540d66cdd6222f4e3b44f8fa49525c03ec987acaf26a235393c51ed"}, + {file = "pyobjc_framework_networkextension-10.3.tar.gz", hash = "sha256:0798f951be920e4d3a2867d559ea2b2103f2f6f53c03b53cc752915807fb1887"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-notificationcenter" -version = "10.2" +version = "10.3" description = "Wrappers for the framework NotificationCenter on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-NotificationCenter-10.2.tar.gz", hash = "sha256:3771c7a8b8e839d07c7cb51eef2e83666254bdd88bd873b0ba7e385245cda684"}, - {file = "pyobjc_framework_NotificationCenter-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f982ce1d0916f9ba3322ebbffd9b936b5b9aeb6d8ec21bd2c3c5245c467c1a12"}, - {file = "pyobjc_framework_NotificationCenter-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:dd1d8364d2212a671b2224ab6bf7785ba5b2aae46610ec46ae35d27c4d55cb15"}, - {file = "pyobjc_framework_NotificationCenter-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1e8aaaef40b6c0deaffd979b3741d1f9de7d804995b7b92fa88ba7839615230e"}, + {file = "pyobjc_framework_NotificationCenter-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2ffae68cfe70bf1f1ceee56971fed5f3f1a52ff26a857948923805d4f71b7844"}, + {file = "pyobjc_framework_NotificationCenter-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f3a25f6f7273f875f8e567421708d863a86e6f6f00963c958dfcc31ebbedaed5"}, + {file = "pyobjc_framework_NotificationCenter-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:58627e5236f70cf75ddb75f8ff944749c2b91f89fa7b56a28fe2535192ae831d"}, + {file = "pyobjc_framework_notificationcenter-10.3.tar.gz", hash = "sha256:2a0de17db42fc5a31c097f344ebbe61c3479d7018a6762944d9c387af0e5bf92"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-opendirectory" -version = "10.2" +version = "10.3" description = "Wrappers for the framework OpenDirectory on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-OpenDirectory-10.2.tar.gz", hash = "sha256:ecca3346275e1ee7be812e428da7f243e37258d8152708a2baa246001b7f5996"}, - {file = "pyobjc_framework_OpenDirectory-10.2-py2.py3-none-any.whl", hash = "sha256:7996985a746f4cceee72233eb5671983e9ee9c9bce3fa9c2fd03d65e766a4efd"}, + {file = "pyobjc_framework_OpenDirectory-10.3-py2.py3-none-any.whl", hash = "sha256:5d9770afc8f5f3293a633ead3bd5e5b843262a515dc37fab99808b3fb111548a"}, + {file = "pyobjc_framework_opendirectory-10.3.tar.gz", hash = "sha256:750a74323a6bdd032bba3ea50dc4b442c92682536cb9a456515c48d2c6e30a13"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-osakit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework OSAKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-OSAKit-10.2.tar.gz", hash = "sha256:6efba4a1733e9ab0bf0e7b4f2eb3e0c84b2a4af1b0b4bbc3a310ae041ccaf92d"}, - {file = "pyobjc_framework_OSAKit-10.2-py2.py3-none-any.whl", hash = "sha256:fbad23e47e31d795a005c18a20d84bff68d90d6dd0f87b6a343e46f87c00034a"}, + {file = "pyobjc_framework_OSAKit-10.3-py2.py3-none-any.whl", hash = "sha256:ffa00d345700c3b75ad4fec6b6cc28b2d34a565d4d611df288c708f5837b664e"}, + {file = "pyobjc_framework_osakit-10.3.tar.gz", hash = "sha256:c784228de4d8838e37ef0d01c031879f863c7839493e227ab3bcc877926dd639"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-oslog" -version = "10.2" +version = "10.3" description = "Wrappers for the framework OSLog on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-OSLog-10.2.tar.gz", hash = "sha256:2377637a0de7dd60f610caab4bcd7efa165d23dba4ac896fd542f1fab2fc588a"}, - {file = "pyobjc_framework_OSLog-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ef1ddc15f98243be9b03f4f4bcb839318333fb135842085ba40499a58c8bd342"}, - {file = "pyobjc_framework_OSLog-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7958957503310ec8df90a0a036ae8a075b90610c0b797769ad117bf635b0caa6"}, - {file = "pyobjc_framework_OSLog-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:67796f02b77c1cc893b3f112f88c58714b1e16a38b59bc52748c25798db71c29"}, + {file = "pyobjc_framework_OSLog-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e13e40fb8d014b3668777969cf11e5757721d6e35309d60f2fecf0280181a98"}, + {file = "pyobjc_framework_OSLog-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ffca1c49760eb76022ece753d8646162750939583263e2f55ea6bffea6e03c90"}, + {file = "pyobjc_framework_OSLog-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:14e5efaf7f50607c3c43f3dc9eb2d5b6af56ccf3f22b7f65fd1b92cccb9318e1"}, + {file = "pyobjc_framework_oslog-10.3.tar.gz", hash = "sha256:198a582cdaac5306cd7a6ff8c65047602766b18230a953baf95f9e6120709127"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreMedia = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreMedia = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-passkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework PassKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-PassKit-10.2.tar.gz", hash = "sha256:0c879d632f0f0bf586161a7abbbba3dad9ba9894a3edbce06f4160491c2c134c"}, - {file = "pyobjc_framework_PassKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:15891c8c1e23081961d652946d4750fd3cd1308efc953a1c77713394726798a6"}, - {file = "pyobjc_framework_PassKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:d68061729743be30c66f7eb3cb649850ef12a24b1d1896233036a390e7d69aa7"}, - {file = "pyobjc_framework_PassKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:7290369b34be3317463a32c9e78a0ed734db4793414851a9e73295413cf17317"}, + {file = "pyobjc_framework_PassKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:88a5a3e57337b8ad7c31499844496932ad25a7b175604c605bedfc02912cff89"}, + {file = "pyobjc_framework_PassKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1e215af948065631c0cc752a2ac5fe2df52eba894cd70cc88caf88a5359e5fe1"}, + {file = "pyobjc_framework_PassKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c1e03659e061d29d6a907642cd5e8829b1e67cf7b36ec94e0c32a44a5edb170f"}, + {file = "pyobjc_framework_passkit-10.3.tar.gz", hash = "sha256:9a4464f1a3359ee7bfff8a60c80dddd07b4519082ffe5316ef8532491ea99a9c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-pencilkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework PencilKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-PencilKit-10.2.tar.gz", hash = "sha256:2338ea384b9a9e67a7f34c300a898ccb997bcff9a2a27e5f9bf7642760c016a0"}, - {file = "pyobjc_framework_PencilKit-10.2-py2.py3-none-any.whl", hash = "sha256:d3e605f104548f26c708957ab7939a64147c422c35d45c4ff4c8d01b5c248c4d"}, + {file = "pyobjc_framework_PencilKit-10.3-py2.py3-none-any.whl", hash = "sha256:9c0e3d504b55cf7c8a52e8efcca0188b8f7657108d8ef4e41990e99bb3b8ae43"}, + {file = "pyobjc_framework_pencilkit-10.3.tar.gz", hash = "sha256:dd7c9ef5482c975ad4674ec8e9a547b91fc3095e29343fbdfcfecf1b276d4483"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-phase" -version = "10.2" +version = "10.3" description = "Wrappers for the framework PHASE on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-PHASE-10.2.tar.gz", hash = "sha256:047ba5b7a869ed93c3c7af2cf7e3ffc83299038275d47c8229e7c09006785402"}, - {file = "pyobjc_framework_PHASE-10.2-py2.py3-none-any.whl", hash = "sha256:f29cd40e5be860758d8444e761d43f313915e2750b8b03b8a080dd86260f6f91"}, + {file = "pyobjc_framework_PHASE-10.3-py2.py3-none-any.whl", hash = "sha256:947291b108f95008042fbaf9b967f19726e0b2b521d7e8d57b9411b47f0e2ad1"}, + {file = "pyobjc_framework_phase-10.3.tar.gz", hash = "sha256:f38712f38eedc9da80e5e99665f9a5654031886ffeab03879fbf6cb14c5c40b7"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-AVFoundation = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-AVFoundation = ">=10.3" [[package]] name = "pyobjc-framework-photos" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Photos on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Photos-10.2.tar.gz", hash = "sha256:ba05d1208158e6de6d14782c182991c0d157254be7254b8d3bb0a9a53bf113fb"}, - {file = "pyobjc_framework_Photos-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4f2c2aa73f3ac331a84ee1f7b5e0edc26471776b2de2190640f041e3c1cc8ef3"}, - {file = "pyobjc_framework_Photos-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:17d69ce116a7f7db1d78ed12a8a81bec1b580735ad40611c0037d8c2977b2eb8"}, - {file = "pyobjc_framework_Photos-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e53d0759c26c7eac4ebfc7bd0018dfd7e3be8ab88a042684ee45e9184e0ac90e"}, + {file = "pyobjc_framework_Photos-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:eb921df4c5f61f518c156681131159f1a640d2654d98811a129f3df8eef976a2"}, + {file = "pyobjc_framework_Photos-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ba6b9df97e76d5342298ae93d8c6bb2dc0c9561c8b03efd87499512af962f6f6"}, + {file = "pyobjc_framework_Photos-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:26409575fc656b8967e52efb699c1ef2dab57ea60657dab3b7180515029f485f"}, + {file = "pyobjc_framework_photos-10.3.tar.gz", hash = "sha256:621c058e84df654af49a5cfc1e0799b5de07fb37449d83562ff11c4bb40530eb"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-photosui" -version = "10.2" +version = "10.3" description = "Wrappers for the framework PhotosUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-PhotosUI-10.2.tar.gz", hash = "sha256:d0bbcae82b4cc652bb60d3221c557cc19be62ff430575ec8e6d233beb936f73b"}, - {file = "pyobjc_framework_PhotosUI-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a27607419652b45053e0be5ede2780b48e6a8dded2b365ded1732e80dafacea0"}, - {file = "pyobjc_framework_PhotosUI-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7eddf0343fae6c327a3dc941d0d7b216f5d186edb2e511d7c54668f6ff2be701"}, - {file = "pyobjc_framework_PhotosUI-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d6715ac72c7967761c33502f6cd552534ec0f727f009f22a2c273dc12076d52d"}, + {file = "pyobjc_framework_PhotosUI-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2579e6f77668500ae2621f133ceec5bf5931c908a87d53ecd0a0fca0cf32608f"}, + {file = "pyobjc_framework_PhotosUI-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1e2ead7e15aab8fb34aaa55bbd55faa48b3fbc9cb6994af730fad1fe9e8f229d"}, + {file = "pyobjc_framework_PhotosUI-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:9e50ca9c56187e7394def35c57238b556cb48d61c1c7fb59bc4cd2cee1e2e10b"}, + {file = "pyobjc_framework_photosui-10.3.tar.gz", hash = "sha256:1acc78ac2eaa487a63d1e732f22e7cf9a9e620ed7cac1d10af03ad08f125eb9c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-preferencepanes" -version = "10.2" +version = "10.3" description = "Wrappers for the framework PreferencePanes on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-PreferencePanes-10.2.tar.gz", hash = "sha256:f1fba8727d172a3e9b58d764695702f7752dfb585d0378e588915f3d8363728c"}, - {file = "pyobjc_framework_PreferencePanes-10.2-py2.py3-none-any.whl", hash = "sha256:4da63d42bc2f2de547b6c817236e902ad6155efa05e5305daa38be830b70a19d"}, + {file = "pyobjc_framework_PreferencePanes-10.3-py2.py3-none-any.whl", hash = "sha256:d82b67f9ba6c4f6524dff93f8bf705ff703d281985d42d85d703743ccf89cf5b"}, + {file = "pyobjc_framework_preferencepanes-10.3.tar.gz", hash = "sha256:39b927fe60ff5883b79df7bf25cba2bfd2b13a33153754a3ecd29e1636ec188c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-pubsub" -version = "10.2" +version = "10.3" description = "Wrappers for the framework PubSub on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-PubSub-10.2.tar.gz", hash = "sha256:68ca9701b29c5e87f7837490cad3dab0b6cd539dfaff3ffe84b1f3f1bf4dc764"}, - {file = "pyobjc_framework_PubSub-10.2-py2.py3-none-any.whl", hash = "sha256:b44f7f87de3f92ce9655344c476672f8f7a912f86ab7a615fec30cebbe7a8827"}, + {file = "pyobjc_framework_PubSub-10.3-py2.py3-none-any.whl", hash = "sha256:5da1ab453671d73c801d21e509537492a27d56bd8ea0d4b060a21768594e9ca2"}, + {file = "pyobjc_framework_pubsub-10.3.tar.gz", hash = "sha256:060949b977a647922ca7c92951f0316815a98f54a1293c9733573706907f8041"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-pushkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework PushKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-PushKit-10.2.tar.gz", hash = "sha256:e30fc4926a9fcd3427701e48a8908f72e546720e52b1e0f457ba2fa017974917"}, - {file = "pyobjc_framework_PushKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1015e4473a8eac7eba09902807b8d8edd47c536e3a50a0b3fe7ab7211e454ad8"}, - {file = "pyobjc_framework_PushKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6f68b2630f84dc6d94046f7676d415e5342b2bb3f0368f3b9e81d0c5744c219b"}, - {file = "pyobjc_framework_PushKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5fe75738ea08c05e42460a58acbf0a8af67a3df26ca2a7bddd48d801b00772ed"}, + {file = "pyobjc_framework_PushKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b3ef9d2928d31735c03e909b2a7aabb2b22b4ab962aba15b0c5b1691c5a0197f"}, + {file = "pyobjc_framework_PushKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:262121afe7aa5a44dfcd50b87f0416288907ace5e5dc374fb0cf15ac3c8407ca"}, + {file = "pyobjc_framework_PushKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f98e8abc8e69b48858829f00723c818b579018525cdc89ba7fb2aa8fcbc0f1a1"}, + {file = "pyobjc_framework_pushkit-10.3.tar.gz", hash = "sha256:942d5a77b13cd3f7310cd50ac86fa563c502e5d6a0d4d2eecb3ee67587a8e844"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-quartz" -version = "10.2" +version = "10.3" description = "Wrappers for the Quartz frameworks on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Quartz-10.2.tar.gz", hash = "sha256:9b947e081f5bd6cd01c99ab5d62c36500d2d6e8d3b87421c1cbb7f9c885555eb"}, - {file = "pyobjc_framework_Quartz-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bc0ab739259a717d9d13a739434991b54eb8963ad7c27f9f6d04d68531fb479b"}, - {file = "pyobjc_framework_Quartz-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a74d00e933c1e1a1820839323dc5cf252bee8bb98e2a298d961f7ae7905ce71"}, - {file = "pyobjc_framework_Quartz-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3e8e33246d966c2bd7f5ee2cf3b431582fa434a6ec2b6dbe580045ebf1f55be5"}, - {file = "pyobjc_framework_Quartz-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c6ca490eff1be0dd8dc7726edde79c97e21ec1afcf55f75962a79e27b4eb2961"}, - {file = "pyobjc_framework_Quartz-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d3d54d9fa50de09ee8994248151def58f30b4738eb20755b0bdd5ee1e1f5883d"}, - {file = "pyobjc_framework_Quartz-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:520c8031b2389110f80070b078dde1968caaecb10921f8070046c26132ac9286"}, + {file = "pyobjc_framework_Quartz-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ab809262f8a1a2880a0e9d9e65035992cba684883f422c375bd320848f4e9a43"}, + {file = "pyobjc_framework_Quartz-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2187dd8a8d15fb731c9e3ae24b7311b9e21681a53377650ee6f9b519e1f78432"}, + {file = "pyobjc_framework_Quartz-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:caf489c498b2137bf2909ad19f6461ddfb66106f678694805184daaa0dec7919"}, + {file = "pyobjc_framework_Quartz-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:cca8f2233d93b3b84bca2745ad74b603c23a77c38c1c5847ac590eab0c335fd5"}, + {file = "pyobjc_framework_Quartz-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71d9f590d5842191c68a5a8aee812d5516d61240e5dea8f604d8a9f769bbda4f"}, + {file = "pyobjc_framework_Quartz-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:75094e160492e4724347a7fdde5a6f4c9f186c31d528c247f359e2c1606d9fb2"}, + {file = "pyobjc_framework_Quartz-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:465ae4c1ecceca59831e7698c5fbe62d8e1e987c7fbbb000737954f2085762b9"}, + {file = "pyobjc_framework_quartz-10.3.tar.gz", hash = "sha256:4c4441e5a338ebe2e1d44a3bdf78e6bfb849ac167732814646dc438c3a08f595"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-quicklookthumbnailing" -version = "10.2" +version = "10.3" description = "Wrappers for the framework QuickLookThumbnailing on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-QuickLookThumbnailing-10.2.tar.gz", hash = "sha256:91497a4dc601c99ccc11ad7976ff729b57f724d9eff071bc24c519940d129dca"}, - {file = "pyobjc_framework_QuickLookThumbnailing-10.2-py2.py3-none-any.whl", hash = "sha256:34349ff0b07b39ecfe5757eb80341a45f9d4426558b93946225f8b4fa2781c4c"}, + {file = "pyobjc_framework_QuickLookThumbnailing-10.3-py2.py3-none-any.whl", hash = "sha256:245970d34a6c2faa591a4f597336591867f1f3577b91ba510cfa74461e50a0d3"}, + {file = "pyobjc_framework_quicklookthumbnailing-10.3.tar.gz", hash = "sha256:657793496b4f906d8d651505f049d624e00b9cd4e12af617f3818d5674cef5db"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-replaykit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ReplayKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ReplayKit-10.2.tar.gz", hash = "sha256:12544028e59ef25ea5c96ebd451cee70d1833d6b5991d3a1b324c6d81ecfb49e"}, - {file = "pyobjc_framework_ReplayKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4e34b006879ed2e86df044e3dd36482d78e6297c954aeda29f60f4b9006c8114"}, - {file = "pyobjc_framework_ReplayKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a6e7ae17d41a381d379d10bd240e1681fc83664b89495999a4dd8d0f42d4b542"}, - {file = "pyobjc_framework_ReplayKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3c57b4019563aaae3c37a250d6c064cbcb5c0d3b227b5b4f1e18bf4a1effcf0e"}, + {file = "pyobjc_framework_ReplayKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:429d2b47cd60dd4e7c239ffc3185c93d07f2a78c45b575d0d04af6cafa93e0cc"}, + {file = "pyobjc_framework_ReplayKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0656092eefe1e7484e4f35147d25f037ce22dcbca8ac68489b93fa1827d452d1"}, + {file = "pyobjc_framework_ReplayKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:88e74ce344bf9790d306d30c62789746b5c2fdf8eaf7bf77cfef12961451c9dd"}, + {file = "pyobjc_framework_replaykit-10.3.tar.gz", hash = "sha256:b1c87606d3b90b93d2549b792af2ca1915827788e7c0c3a534df0d068b39c012"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-safariservices" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SafariServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SafariServices-10.2.tar.gz", hash = "sha256:723de09afb718b05d03cbbed42f90d36356294b038ca6422c88d50240047b067"}, - {file = "pyobjc_framework_SafariServices-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2cd4b4210bd3c05d74d41e5bf2760e841289927601184f0e6ca3ef85019aa5dd"}, - {file = "pyobjc_framework_SafariServices-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6c8aa0becaa7d4ce0d0d1ada4e14e1eae2bf8e5be7ef49cc1861a41d3a4eeade"}, - {file = "pyobjc_framework_SafariServices-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:aecc109b096b3e995b896bfb97c09ef156600788e2a46c498bb4e2e355faa2bc"}, + {file = "pyobjc_framework_SafariServices-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7e2bdd40f0399076840e4f95599d409df2ad7be06ef8593cc59cc12c84b39ca6"}, + {file = "pyobjc_framework_SafariServices-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7ed3bc6b71575082f21b6edb6360a3d3093fb2d40d1f57749f4d25264041e394"}, + {file = "pyobjc_framework_SafariServices-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:8c9ff1b7fbcbdabaeabbd9866e89208d7dfde1e125c372d91d047799e0b3682b"}, + {file = "pyobjc_framework_safariservices-10.3.tar.gz", hash = "sha256:678fd2013ed3451b9c249f6515e8cb712f8c68f76050e2e0b8911dcdd1bb1df0"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-safetykit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SafetyKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SafetyKit-10.2.tar.gz", hash = "sha256:b5822cda3b1dc0209fa58027551fa17457763275902c7d42fc23d5b13de9ee67"}, - {file = "pyobjc_framework_SafetyKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:947d42faf40b4ddd71bce75b8b913b7b67e0640fffa508562f4e502ca99426d4"}, - {file = "pyobjc_framework_SafetyKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65feaff614eeacceb8c405030ddd79f8eda2366d2a73f44ea595f48f7969bcf0"}, - {file = "pyobjc_framework_SafetyKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:a6c3201dfb649523fa2f7569ca1274d1322527e210ee19d7c2395d0e3d18e0a2"}, + {file = "pyobjc_framework_SafetyKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:01da686c3be43dece5935b671335f7567ad02490557d72a273465223c7390444"}, + {file = "pyobjc_framework_SafetyKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7439880b24a51f62520e96597b9cd3cf6f987390fb0c7a6d4c1c756b452e3865"}, + {file = "pyobjc_framework_SafetyKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:9c1a74ab089cc953fc385d47ab1bb2b434f6ae3a5c4bca4856a3df5dec2e2989"}, + {file = "pyobjc_framework_safetykit-10.3.tar.gz", hash = "sha256:4d04ff2919b3061c15bd013d87a88bd532cc76cd7a94ab76d70ac8dc5d63022c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-scenekit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SceneKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SceneKit-10.2.tar.gz", hash = "sha256:53d2ffac43684bb7834ae570d3537bd15f2a7711b77cc9e8b7b81f63a697ba03"}, - {file = "pyobjc_framework_SceneKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac80bf8c4cf957add63a0bd2f1811097fb62eafb4fc26192f4087cd7853e85fd"}, - {file = "pyobjc_framework_SceneKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:86c3d23b63b0bb4d8fea370cb08aac778bc3fdb64b639b8b9ea87dacc54fd1cf"}, - {file = "pyobjc_framework_SceneKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:00676f4e11f3069545b07357e51781054ecf4785ed24ea8747515e018db1618c"}, + {file = "pyobjc_framework_SceneKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:95feb8d312ab140b7e064a2792c477a2f366b184bf89a676f134a9b5c8bad391"}, + {file = "pyobjc_framework_SceneKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:40335d7a8a4e20091e3e34958da779b06a91613736521634c3cb00c83c7d9f17"}, + {file = "pyobjc_framework_SceneKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ac8afdfaf8a4b0352ce53228e3088e52813813a3ea92719f17e12f2f49df607f"}, + {file = "pyobjc_framework_scenekit-10.3.tar.gz", hash = "sha256:aeb4182d2a2d3d2887afe4b4f18f44bb64bf89aff62a22e69522b67bdb1fc6eb"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-screencapturekit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ScreenCaptureKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ScreenCaptureKit-10.2.tar.gz", hash = "sha256:86f64377be94db1b95e77ca53301ed94c0a7a82c0251c9e960bcae24b6a5841b"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e15b0af8a1155b7bc975ccd54192c5feae2706a8e17da6effa4273a3302d4dce"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bdcc687d022b8b6264dca74c1f72897c91528b0c701d76f1466faeead8030a11"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f53caee8edca7868449f2cce60574cedea4299c324fa692c944824a627b7b8a4"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4cdd6add328e2318550df325210c83d1de68774a634d3914da2bfbd1cb7d929f"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:e51c6c632b1c6ff773cfcf7d3e2b349693e06d52259b8c8485cfaa6c6cd602b3"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b63d9dc8635e7a3e59163a4abc13a9014de702729a55d290a22518702f4679fc"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11e0804885f3c6d40818a644a2732a1eea8047641b9f6e70cd300f05c5aa5eca"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:496d16ef5fe2ffda8dda6d1d01f9f66e6585194d281fa989dc659646d7661513"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:cbb8583032093e2e1f142c333574d6b9e785aac4186f7f4d25286f0e3545b2f5"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:4885bd0147f08c14430e660280b42bbc00023e5c3ec80605f62f644239a686bd"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6dd224b70f67dda55a53972d6679281d305a787e128206e583ce1ef1acf3c41e"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:136e63f4e1868129cf8f42c81cd84cc03078b098666fb941e068732100563ba9"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa91c9c266d19afbd7e1f2c51015be6d707f645d5a4546ca7d301326a6d18dc"}, + {file = "pyobjc_framework_screencapturekit-10.3.tar.gz", hash = "sha256:96cd9da48212b13c749b9fdfba570c7e374f1cd3b6fa07b89f09c017d3463ca6"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreMedia = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreMedia = ">=10.3" [[package]] name = "pyobjc-framework-screensaver" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ScreenSaver on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ScreenSaver-10.2.tar.gz", hash = "sha256:00c6a312467abb516fd2f19e3166c4609eed939edc0f2c888ccd8c9f0fdd30f1"}, - {file = "pyobjc_framework_ScreenSaver-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:830b2fc85ff7d48824eb6f12100915c2aa480a1a408b53c30f6b81906dc8b1ea"}, - {file = "pyobjc_framework_ScreenSaver-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1cb8a31bd2a0597727553d0459c91803bf02c52ffb5ac94aa5ad484ddc46d88d"}, - {file = "pyobjc_framework_ScreenSaver-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ca00a5c4cd89450e629962bfafe6a4a25b7bae93eb3fdd3ecb314c6c5755cbcf"}, + {file = "pyobjc_framework_ScreenSaver-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9676a820ee37fd570831ff6f55d237e2c7169529dba90efaedc4aca4eb38e687"}, + {file = "pyobjc_framework_ScreenSaver-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c02a8ea32a5361542c7578b836414d08a9f913bdbd1fb3e479be3f55b1f349f3"}, + {file = "pyobjc_framework_ScreenSaver-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:2634591a4c2e689655e3f28023177d36a6e8f287f0b71f51306eab8ebb8ca903"}, + {file = "pyobjc_framework_screensaver-10.3.tar.gz", hash = "sha256:32ad91df0ad95c94f757a48e9338caf92afb90a492e3800de749aa37d4590a63"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-screentime" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ScreenTime on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ScreenTime-10.2.tar.gz", hash = "sha256:fd516f0dd7c16f15ab6ed3eeb8180460136f72b7eaa3d6e849d4a462438bfdf2"}, - {file = "pyobjc_framework_ScreenTime-10.2-py2.py3-none-any.whl", hash = "sha256:43afabfd0fd61eed91f11aba3de95091a4f05d7c7e63341f493026e5ff7b90e4"}, + {file = "pyobjc_framework_ScreenTime-10.3-py2.py3-none-any.whl", hash = "sha256:79447a4513362d38a9fc691ffa45d37a16daa11fc1c89cc1a93ae13dd8198e3d"}, + {file = "pyobjc_framework_screentime-10.3.tar.gz", hash = "sha256:8698e56883fb58402f912e7d90e833c6092d8345fe53683a6f6f90dc739fbc5d"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-scriptingbridge" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ScriptingBridge on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ScriptingBridge-10.2.tar.gz", hash = "sha256:c02d88b4a4d48d54ce2260f5c7e1757e74cd91281352cdd32492a4c7ee4b0e7c"}, - {file = "pyobjc_framework_ScriptingBridge-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:466ad2d483edadf97dc38629c393902a790141547e145e83f6bd34351d10f4c9"}, - {file = "pyobjc_framework_ScriptingBridge-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1e3e0c19afd0f8189ebee5c57ab2b0c177dddccc9b56811c665ec6848007ac6a"}, - {file = "pyobjc_framework_ScriptingBridge-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:560dff883edd251f1e0bf86dde681c1e19845399720fd2434734c91120eafdd0"}, + {file = "pyobjc_framework_ScriptingBridge-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:56c26806bd77d9241773d92f21da6c86eccc82617dc3d4d9f4515e5473d7d253"}, + {file = "pyobjc_framework_ScriptingBridge-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ec2d52aaf0f7dcc07896e0390a37f07bda3f3bfe8ac2f4a26a773409650d5123"}, + {file = "pyobjc_framework_ScriptingBridge-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:19f6a8f5466b65d53f2620f9ef9e9a74a47f23e79ad244efb38fcaf8a3dcb101"}, + {file = "pyobjc_framework_scriptingbridge-10.3.tar.gz", hash = "sha256:d4c33a6c5aca98cae0175821ec8df487d0ed49a8763f046cb0c518d4fe83603f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-searchkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SearchKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SearchKit-10.2.tar.gz", hash = "sha256:c1e16457e727c5282b620d20b2d764352947cd4509966475a874f2750a9c5d11"}, - {file = "pyobjc_framework_SearchKit-10.2-py2.py3-none-any.whl", hash = "sha256:ddd9e2f207ae578f04ec2358fdf485f26978d6de4909640b58486a8a9e4e639c"}, + {file = "pyobjc_framework_SearchKit-10.3-py2.py3-none-any.whl", hash = "sha256:24e883795b2649cfc51bd8b055fbc8565182e7b2396cfba4c8ff3a156c941fde"}, + {file = "pyobjc_framework_searchkit-10.3.tar.gz", hash = "sha256:5e81256dac0bff081dfe3f95c0d7f6fe5d0a4ba7e7ed2cad15edc60348a7f614"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-CoreServices = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-CoreServices = ">=10.3" [[package]] name = "pyobjc-framework-security" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Security on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Security-10.2.tar.gz", hash = "sha256:20ec8ebb41506037d54b40606590b90f66a89adceeddd9a40674b0c7ea7c8c82"}, - {file = "pyobjc_framework_Security-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5a9c1bf88db62ebe1186dbecb40c6fdf8dab2d614012b5da8e9b90ee3bd8575e"}, - {file = "pyobjc_framework_Security-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9119f8bad7bead85e5b57c8538d319ef19eb5159500a0e3677c11ddbb774a17a"}, - {file = "pyobjc_framework_Security-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:317add1dcbc6866ce2e9389ef5a2a46db82e042aca6e5fad9aa5ce17782493fe"}, - {file = "pyobjc_framework_Security-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:75f061f0d03c3099d01b7818409eb602b882f6a31b4381bbf289f10ce1cf7753"}, - {file = "pyobjc_framework_Security-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d99aeba0e3a7ee95bf5582b06885a5d6f8115ff3a2e47506562514117022f170"}, - {file = "pyobjc_framework_Security-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:186a97497209acdb8d56aa7bbd56ab8021663fff2fb83f0d0e1b4e1f57ac5bbb"}, + {file = "pyobjc_framework_Security-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e4df7ea48f93034dd784277d4456c83abd79060a9a5847c5604f664d39ea45da"}, + {file = "pyobjc_framework_Security-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9dc80b7b694ff5594742624a9fade022829a09a79c1c6b97eef97d33d49f7f4c"}, + {file = "pyobjc_framework_Security-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6d1ddb3fd3cc11aa621f414277c9daf9481894fa5fbe99e2430a3fd2773e81a2"}, + {file = "pyobjc_framework_Security-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:aa8737b6a367550e3d12e0c71c267346b5ec235b62364bc17d0a2b883d175933"}, + {file = "pyobjc_framework_Security-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2fbd7a004361a28cbf4775820589a9b79443f13720d0cf755df066dc3fbbb98b"}, + {file = "pyobjc_framework_Security-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:e3d342a0741bb13da470dda087499a67c9e2bf27ee0d3a490e797ffb88cf9443"}, + {file = "pyobjc_framework_Security-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07b34541ce0960e924be8ef4a40b35a3b85104b61684d67a3063826f657122c2"}, + {file = "pyobjc_framework_security-10.3.tar.gz", hash = "sha256:1be270a9205d9f392a658a267dec9ec602d6a98448419541f0005dc80da97013"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-securityfoundation" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SecurityFoundation on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SecurityFoundation-10.2.tar.gz", hash = "sha256:ed612afab0f70e24b29f2e2b3a31cfefb1ad17244b5c147e7bcad8dfc7e60bd1"}, - {file = "pyobjc_framework_SecurityFoundation-10.2-py2.py3-none-any.whl", hash = "sha256:296f7f9ff96a35c19e4aef7621a567c0efe584aafd20ac25a2839dd96bf46a04"}, + {file = "pyobjc_framework_SecurityFoundation-10.3-py2.py3-none-any.whl", hash = "sha256:6befffef47d857cad2f76087fee8e8648f210803ca883ab2af4aedceb58a9bef"}, + {file = "pyobjc_framework_securityfoundation-10.3.tar.gz", hash = "sha256:aaac1ccfed767de7d4469a46378fa48d29dcf55fa0209fa04b576464481e7ebc"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Security = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Security = ">=10.3" [[package]] name = "pyobjc-framework-securityinterface" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SecurityInterface on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SecurityInterface-10.2.tar.gz", hash = "sha256:43930539fed05e74f3c692f5ee7848681e7e65c44387af300447514fe8e23ab6"}, - {file = "pyobjc_framework_SecurityInterface-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:70f2cb61261e84fb366f43a9a44fb19a19188cf650d3cf3f3e6ee3a16a73e62d"}, - {file = "pyobjc_framework_SecurityInterface-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:52a18a18af6d47f7fbdfeef898a038ff3ab7537a694c591ddcf8f895b9e55cce"}, - {file = "pyobjc_framework_SecurityInterface-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b2472e3714cc17b22e5bb0173887aac77c80ccc2188ec2c40d2b906bd2490f6b"}, + {file = "pyobjc_framework_SecurityInterface-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:91403223d8ed6ebc67b6d641988119b39be5933e477ab2466a56ffefbcf9a94a"}, + {file = "pyobjc_framework_SecurityInterface-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6bb826b244d18350591631434be2ef0a788a9c18421501dd00026c182b43b457"}, + {file = "pyobjc_framework_SecurityInterface-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ab2e22755467ffaddb1ae35115fdac2a6d9a06a49cb682e04b7ec02008ae332e"}, + {file = "pyobjc_framework_securityinterface-10.3.tar.gz", hash = "sha256:e7d002e70f7474205002e13d7689ec464263e29d6021d2753424558420549089"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Security = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Security = ">=10.3" [[package]] name = "pyobjc-framework-sensitivecontentanalysis" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SensitiveContentAnalysis on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SensitiveContentAnalysis-10.2.tar.gz", hash = "sha256:ef111cb8a85bc86e47954cdb01e3ccb654aba64a3d855f17a0c786361859aef8"}, - {file = "pyobjc_framework_SensitiveContentAnalysis-10.2-py2.py3-none-any.whl", hash = "sha256:3c875856837e217c9eba68e5c2b4f5b862dee1bb64513b463a7af8c3e67e5a50"}, + {file = "pyobjc_framework_SensitiveContentAnalysis-10.3-py2.py3-none-any.whl", hash = "sha256:4ae985f6412c5cd277fb40fe16c10a4622407a07db8aa476fbf64c140ae0429a"}, + {file = "pyobjc_framework_sensitivecontentanalysis-10.3.tar.gz", hash = "sha256:1989765de0bf77d7578ef45c5d1973b364555bfa26b9fd6c41431646d31a650d"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-servicemanagement" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ServiceManagement on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ServiceManagement-10.2.tar.gz", hash = "sha256:62413cd911932cc16262710a3853061fdae341ed95e1aa0426b4ff0011d18c0c"}, - {file = "pyobjc_framework_ServiceManagement-10.2-py2.py3-none-any.whl", hash = "sha256:e5a1c1746788d0e125cc87cbe0749b2b824fb7a08bc4344c06c9ac6007859187"}, + {file = "pyobjc_framework_ServiceManagement-10.3-py2.py3-none-any.whl", hash = "sha256:923baa4178f9c0de6e615ffd5afe35715e9704829eb1d5ae35bbfde711ca0872"}, + {file = "pyobjc_framework_servicemanagement-10.3.tar.gz", hash = "sha256:e874633a4332cab1824aeed8f59eed3700448daea7c2fe9b621e14886894244e"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-sharedwithyou" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SharedWithYou on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SharedWithYou-10.2.tar.gz", hash = "sha256:bc13756ef20af488cd3022c036a11a0f7572e1b286e9eb7d31c61a8cb7655c70"}, - {file = "pyobjc_framework_SharedWithYou-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b69169db01c78bef3178b8795fb5e2a9eccfa4c26b7de008e23a5aa6f0c709f0"}, - {file = "pyobjc_framework_SharedWithYou-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e4ec724f103b0904893212d473c68c462f8fbe46a470b0c9f88cb8330969a94e"}, - {file = "pyobjc_framework_SharedWithYou-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:04b477d42a6edd25c187fc61422ce62156fd5d8670b7007ff3f1a10723b1b4b8"}, + {file = "pyobjc_framework_SharedWithYou-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a1663d0136b378c4ed6ebdc2536c5f43de576c323af900648f8d2a1cfa07b1f8"}, + {file = "pyobjc_framework_SharedWithYou-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ac3ec93544b4b93a2d40f125ce0242ba4f9d55c62396888347613f5b70e91ae5"}, + {file = "pyobjc_framework_SharedWithYou-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1422bc1df5d89e47573b2ba78b91c390b105a9631f780f14d781e6b51d75a645"}, + {file = "pyobjc_framework_sharedwithyou-10.3.tar.gz", hash = "sha256:a9742bdc4a0449c83dc7f704908da3cd1c64829a00007aad4d999749b20d5ad9"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-SharedWithYouCore = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-SharedWithYouCore = ">=10.3" [[package]] name = "pyobjc-framework-sharedwithyoucore" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SharedWithYouCore on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SharedWithYouCore-10.2.tar.gz", hash = "sha256:cc8faa9f549f6c931be33cf99f49b8cde11db52cb542e3797c3a27f98e5e9a2a"}, - {file = "pyobjc_framework_SharedWithYouCore-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:275b50a6b9205b1c0a08632c2ede98293b26df28d6c35bc34714ec9d5a7065d6"}, - {file = "pyobjc_framework_SharedWithYouCore-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:55aaac1bea38e566e70084cbe348b2af0f5cda782c8da54c6bbbd70345a50b27"}, - {file = "pyobjc_framework_SharedWithYouCore-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b118ba79e7bb2fab26369927316b90aa952795976a29e7dc49dcb47a87f7924c"}, + {file = "pyobjc_framework_SharedWithYouCore-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ba335881c9505832336c53f273d073f146240c3ca4575351a04606273dc19000"}, + {file = "pyobjc_framework_SharedWithYouCore-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0f6ce6989fb3995329516dd08570936c96c848a26430ad54ec2bd0e4b79d4e83"}, + {file = "pyobjc_framework_SharedWithYouCore-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e3ef63867c4f9305b5b9f384f0dce3bb9a4ad14d6aa8a45520ef6eb94f3b0efd"}, + {file = "pyobjc_framework_sharedwithyoucore-10.3.tar.gz", hash = "sha256:862a0b554bed5c944a31e4b14918af49b55fe6497cc8c25956200cbc7bcde811"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-shazamkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ShazamKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ShazamKit-10.2.tar.gz", hash = "sha256:f3359be7a0ffe0084d047b8813dd9e9b5339a0970baecad89cbe85513e838e74"}, - {file = "pyobjc_framework_ShazamKit-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a33d2ad28cc7731e67906eccf324c441383ba741399c88e993b5375e734509ba"}, - {file = "pyobjc_framework_ShazamKit-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13976c21722389e81d9e10ab419dfb0904f48cec639f0932aada0f039d78dac3"}, - {file = "pyobjc_framework_ShazamKit-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:380992e9da3000ebefe45b50f65ed3bf88ba87574c4a6486a29553cfbfc04c22"}, - {file = "pyobjc_framework_ShazamKit-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e8494bfcf6ceb8b59e1bf2678073e00155f6dd2afbec01eaefd2128d3a4f5c76"}, - {file = "pyobjc_framework_ShazamKit-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:71cb7db481c791a52d261b924063431b72c4c288afd14a00cf7106274596a1c3"}, - {file = "pyobjc_framework_ShazamKit-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0a537e1f86f47ddde742fd0491173c669e6cda6b9edddbe72e56a148a40111f8"}, + {file = "pyobjc_framework_ShazamKit-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9641a02efdd4c38c35c8c3e684ff66be2aeec6a786819045e4141ff365bec19f"}, + {file = "pyobjc_framework_ShazamKit-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:997eb038d951b850fea3e26151c0815756ed1ca781a8f5af39c0ae94cbbfea85"}, + {file = "pyobjc_framework_ShazamKit-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b08cf45e30625487fcb1e1e253a1e5dba17f2764549a72f1cb1a71266fd76454"}, + {file = "pyobjc_framework_ShazamKit-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:27e567d8ff3cd103accc72695881ba82ef4ef707b176d06726a3f66052e8fa51"}, + {file = "pyobjc_framework_ShazamKit-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9bc70b8d520a27e6c65f1458d28165e4a0d08dd984367ab1b35e4c1412565d32"}, + {file = "pyobjc_framework_ShazamKit-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:501233d67cd0f7d439b8eea2db740a53238d265a96ecca41bd724959406e54ac"}, + {file = "pyobjc_framework_ShazamKit-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cc0bacb7db45b8f88007c718f0c2685a11455992fa0a2bdc2349d457be3ef953"}, + {file = "pyobjc_framework_shazamkit-10.3.tar.gz", hash = "sha256:89467af0f3d353c6ebc3a53995cc01078a8bcbb6ccbb648aa95b7d480fd2c05f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-social" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Social on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Social-10.2.tar.gz", hash = "sha256:34995cd0c0f6c4adbe7bfa9049463058c7a8676d34d3d5b9de37f87416f22a0a"}, - {file = "pyobjc_framework_Social-10.2-py2.py3-none-any.whl", hash = "sha256:76ed463e3a77c58e5b527c37eb8b2dd60658dd736ba243cfa24b4704580b58c4"}, + {file = "pyobjc_framework_Social-10.3-py2.py3-none-any.whl", hash = "sha256:5a8eb2b80857912de19677506f834893c9f22351f1c745f93649d964fa4530de"}, + {file = "pyobjc_framework_social-10.3.tar.gz", hash = "sha256:aa7adeaf0849b311236e6f400a65b10aa910b4e6ff202e7b50c6ca0a46de0e9c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-soundanalysis" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SoundAnalysis on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SoundAnalysis-10.2.tar.gz", hash = "sha256:960434f16a130da4fe5cd86ceac832b7eb17831a1e739472f7636aceea65e018"}, - {file = "pyobjc_framework_SoundAnalysis-10.2-py2.py3-none-any.whl", hash = "sha256:a09b49acca76a3c161b937002e5d034cf32c33d033677a8143d446eb53ca941d"}, + {file = "pyobjc_framework_SoundAnalysis-10.3-py2.py3-none-any.whl", hash = "sha256:06ff451ac1fa977d291417a1e2409ee12d28e65a2b45671e52d30e4692c67115"}, + {file = "pyobjc_framework_soundanalysis-10.3.tar.gz", hash = "sha256:ff540b99f9d70aaea1a2dd72fdb76c397fc8b7545f1f66e160e1dff505d04efd"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-speech" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Speech on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Speech-10.2.tar.gz", hash = "sha256:4cb3445ff31a3f8d50492d420941723e07967b4fc4fc46c336403d8ca245c086"}, - {file = "pyobjc_framework_Speech-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:175195f945d89d2382c0f6052b798ef3ee41384b8bfa4954c16add126dc181f6"}, - {file = "pyobjc_framework_Speech-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c65cbda4b8d357b80d41695b1b505a759d3be8b63bca9dd7675053876878577"}, - {file = "pyobjc_framework_Speech-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b139f64cc3636f1cfdc78a4071068d34e9ea70283201fd7a821e41d5bbbcf306"}, + {file = "pyobjc_framework_Speech-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5838e6fa05aa8d490ae8b508cf0c70321864ca16c7e996c94b1e65236f3a7b9"}, + {file = "pyobjc_framework_Speech-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1c216a7475ee3d0f9614da518897cc30c6911ae71a80188a8b5fe0dadf9aa162"}, + {file = "pyobjc_framework_Speech-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3e5f7b9cde46a64e753f99baf2ed4901a325c4e52864459735b86743a1077beb"}, + {file = "pyobjc_framework_speech-10.3.tar.gz", hash = "sha256:c720a06da6e57c04757c34fae8f0f02456f8d266d03c66649688f3a7462838d7"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-spritekit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SpriteKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SpriteKit-10.2.tar.gz", hash = "sha256:31b3e639a617c456574df8f3ce18275eff613cf49e98ea8df974cda05d13a7fc"}, - {file = "pyobjc_framework_SpriteKit-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7b312677a70a7fe684af8726a39837e935fd6660f0271246885934f60d773506"}, - {file = "pyobjc_framework_SpriteKit-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a8e015451fa701c7d9b383a95315809208145790d8e68a542def9fb10d6c2ce2"}, - {file = "pyobjc_framework_SpriteKit-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:803138edacb0c5bbc40bfeb964c70521259a7fb9c0dd31a79824b36be3942f59"}, - {file = "pyobjc_framework_SpriteKit-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ae44f20076286dd0d600f9b4c8c31f144abe1f44dbd37ca96ecdba98732bfb4a"}, - {file = "pyobjc_framework_SpriteKit-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:9f5b65ac9fd0a40e28673a15c6c7785208402c02422a1e150f713b2c82681b51"}, - {file = "pyobjc_framework_SpriteKit-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a8f2e140ad818d6891f654369853f9439d0f280302bf5750c28df8a4fcc019ec"}, + {file = "pyobjc_framework_SpriteKit-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cebd65a82fbbbf992687a6c117213a105360132e6636563f44130b36e2df5176"}, + {file = "pyobjc_framework_SpriteKit-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bf3b501d579870c17dda4448bd63bf97004b2856cbcecf72493673dd5888932d"}, + {file = "pyobjc_framework_SpriteKit-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:409a66c21e966593438feec3c156264fbead7adb7133512fc3626e0db586b95b"}, + {file = "pyobjc_framework_SpriteKit-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:d40e89a90a32f7238b75cc6132df86a1280486e8c9b4b778950609926403cabf"}, + {file = "pyobjc_framework_SpriteKit-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7da06167a43e6ff6548cb68cdbfe200f73c02bd3670f453c9c9a56218f27ae4e"}, + {file = "pyobjc_framework_SpriteKit-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:3da69814e8660671dcb336cf8d2639d6187d249574c8ac833583b4c079fdd925"}, + {file = "pyobjc_framework_SpriteKit-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:34a60b707588808858e43d12bb24fa0e716d450f3787e6474514273b0d8d16bf"}, + {file = "pyobjc_framework_spritekit-10.3.tar.gz", hash = "sha256:52d5a91b13d222757c05c5c0daea629ecc3afca1df9a2b0bf6d7e5b5b1823919"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-storekit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework StoreKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-StoreKit-10.2.tar.gz", hash = "sha256:44cf0b5fe605b9e5dc6aed2ae9e09d807d04d5f2eaf78afb8c04e3f109a0d680"}, - {file = "pyobjc_framework_StoreKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f9e511ebf2d954f10999c2a46e5ecffee0235e0c35eda24c8fcfdb433768935d"}, - {file = "pyobjc_framework_StoreKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e22a701666a787d4df9f45bf1507cf41e45357b22c55ad79c608b24a506981e1"}, - {file = "pyobjc_framework_StoreKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:44c0a65bd39e64e276d8a7b991d93b59b149b3b886cadddb6a38253d48b123e5"}, + {file = "pyobjc_framework_StoreKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5ba61f886e6a7709e45640d8caee632e8b0ff43082cfaae62660061701a8186f"}, + {file = "pyobjc_framework_StoreKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e999085df79e16dd7ac2963390dadacfbdcb0c9a57ad6b27a4b24fa25ac945c8"}, + {file = "pyobjc_framework_StoreKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4e716f93d14cb4743e90d7eb759359217602119a97e54b0b4a306e018af40306"}, + {file = "pyobjc_framework_storekit-10.3.tar.gz", hash = "sha256:235996fa6270dc8844d9ca447d10833bc835ce842a9f4c4daf71f2bcefd01b9c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-symbols" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Symbols on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Symbols-10.2.tar.gz", hash = "sha256:b1874e79fdcaf65deaadda35a3c9dbd24eb92d7dc8aa4db5d7f14f2b06d8a312"}, - {file = "pyobjc_framework_Symbols-10.2-py2.py3-none-any.whl", hash = "sha256:3b5fa1e162acb04eab092e0e1dbe686e2fb61cf648850953e15314edb56fb05f"}, + {file = "pyobjc_framework_Symbols-10.3-py2.py3-none-any.whl", hash = "sha256:51ea45ea4183359f0954be9276a2a7e739791119e6e90a5f9be00c102f8ae43f"}, + {file = "pyobjc_framework_symbols-10.3.tar.gz", hash = "sha256:04187be130368080ac7eed34d452fad485067cbd1cd001354e931c5ea30b4c1f"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-syncservices" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SyncServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SyncServices-10.2.tar.gz", hash = "sha256:1c76073484924201336e6aab40f10358573bc640a92ed4066b8062c748957576"}, - {file = "pyobjc_framework_SyncServices-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf40e4194bd42bb447212037876ca3e90e0e5a7aa21e59a6987f300209a83fb7"}, - {file = "pyobjc_framework_SyncServices-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:4e438c0cf74aecb95c2a86db9c39236fee3edf0a91814255e2aff18bf24e7e82"}, - {file = "pyobjc_framework_SyncServices-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:dffc9ddf9235176c1f1575095beae97d6d2ffa9cffe9c195f815c46f69070787"}, + {file = "pyobjc_framework_SyncServices-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:15f3beaac7b1a57222812fe75654b465b99684553631ae02042f864518179a74"}, + {file = "pyobjc_framework_SyncServices-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8ac1da78e4b939bfc74378bc0a57584103d164796467054d7a09db32429a32da"}, + {file = "pyobjc_framework_SyncServices-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6715c4b12953629108f35be0029d7f590718c92060359a28915d5c501106bfb6"}, + {file = "pyobjc_framework_syncservices-10.3.tar.gz", hash = "sha256:90140a0a993d5d4fe60be1b378b72cb0d9285a80819a16226bb611aec0c4013b"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreData = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreData = ">=10.3" [[package]] name = "pyobjc-framework-systemconfiguration" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SystemConfiguration on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SystemConfiguration-10.2.tar.gz", hash = "sha256:e9ec946ca56514a68e28040c55c79ba105c9a70b56698635767250e629c37e49"}, - {file = "pyobjc_framework_SystemConfiguration-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d25ff4b8525f087fc004ece9518b38d365ef6bbc06e4c0f847d70cb72ca961df"}, - {file = "pyobjc_framework_SystemConfiguration-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2fc0a9d1c1c6a5d5b9d9289ee8e5de0d4ef8cb4c9bc03e8a33513217580a307b"}, - {file = "pyobjc_framework_SystemConfiguration-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d33ebea6881c2e4b9ddd03f8def7495dc884b7e53fe3d6e1340d9f9cc7441878"}, + {file = "pyobjc_framework_SystemConfiguration-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5aa695972ed09a8d8284e6b1a8019b8958be826a2db7c24ffb8a9b05f73c34d2"}, + {file = "pyobjc_framework_SystemConfiguration-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e474133579db7f5711f876a2f34e433a152d9f51c5df82886729f284836c6ab4"}, + {file = "pyobjc_framework_SystemConfiguration-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:66946d2d8dfd646d37ff066f53267d7bbfeb0ec82b2fef1622eacd23ade6575a"}, + {file = "pyobjc_framework_systemconfiguration-10.3.tar.gz", hash = "sha256:48f8fd81f02891b5431b77fcf11831aab46b093ea56f35a4695cbb63281bf69c"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-systemextensions" -version = "10.2" +version = "10.3" description = "Wrappers for the framework SystemExtensions on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-SystemExtensions-10.2.tar.gz", hash = "sha256:883c41cb257fb2b5baadafa4213dc0f0fffc97edb35ebaf6ed95a185a786eb85"}, - {file = "pyobjc_framework_SystemExtensions-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8a85c71121abe33a83742b84d046684e30e5400c5d2bbb4bca4322c4e9d5506b"}, - {file = "pyobjc_framework_SystemExtensions-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3374105ebc3992e8898b46ba85e860ac1f2f24985c640834bf2b9da26a8f40a7"}, - {file = "pyobjc_framework_SystemExtensions-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5b699c94a05a7253d803fb75b6ea5c67d2c59eb906deceb7f3d0a44f42b5d7a8"}, + {file = "pyobjc_framework_SystemExtensions-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:39275100899586ce856b57120bef7582e3e16b33aa8a23d0066881fa2bba37ab"}, + {file = "pyobjc_framework_SystemExtensions-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e50596f8afd14c6f00faac499b1d4904f37fcd48df94e6fbf4a73a920559e20f"}, + {file = "pyobjc_framework_SystemExtensions-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:76b6534e61a19c12ef64a9edf6dde634e29be14e657fb0e63cd28e51fcca99cb"}, + {file = "pyobjc_framework_systemextensions-10.3.tar.gz", hash = "sha256:5811fdbfb1c14f1db288455038bef0c8c61c1266e3b61da4f5cfb2bb6adf0333"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-threadnetwork" -version = "10.2" +version = "10.3" description = "Wrappers for the framework ThreadNetwork on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-ThreadNetwork-10.2.tar.gz", hash = "sha256:864ebabdb187cef16e1fba0f5439a73b1ed9a4e66b888f7954b12150c323c0f8"}, - {file = "pyobjc_framework_ThreadNetwork-10.2-py2.py3-none-any.whl", hash = "sha256:f7ad31b4a67f9ed00097a21c7bbd48ffa4ce2c22174a52ac508beedf7cb2aa9e"}, + {file = "pyobjc_framework_ThreadNetwork-10.3-py2.py3-none-any.whl", hash = "sha256:84b50c566bcde4d607b0e92fad21b64102032056281ecb83a1ad80acde74aa19"}, + {file = "pyobjc_framework_threadnetwork-10.3.tar.gz", hash = "sha256:d8d1cb19d1426cbc4a531bb047551ff819d57c7c54777d27c4de959b6dbac234"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-uniformtypeidentifiers" -version = "10.2" +version = "10.3" description = "Wrappers for the framework UniformTypeIdentifiers on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-UniformTypeIdentifiers-10.2.tar.gz", hash = "sha256:4d3e7add89766fe7abc6fd6e29387e92d7b38343b37d365607c9d287c5e758f6"}, - {file = "pyobjc_framework_UniformTypeIdentifiers-10.2-py2.py3-none-any.whl", hash = "sha256:25b72005063a88c5e67bf91d1355973f4bbf3dd7c1b3fb8eb00503020a837b33"}, + {file = "pyobjc_framework_UniformTypeIdentifiers-10.3-py2.py3-none-any.whl", hash = "sha256:2219841495944ba998c3241f7c5b1f0642b1110c46a2731cad42e8d0e203c099"}, + {file = "pyobjc_framework_uniformtypeidentifiers-10.3.tar.gz", hash = "sha256:ec16633648537d2d8017e1151fedb37c344c5f1922bc8b3097616d0b3e3437f1"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-usernotifications" -version = "10.2" +version = "10.3" description = "Wrappers for the framework UserNotifications on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-UserNotifications-10.2.tar.gz", hash = "sha256:3a1b7d77c95dff109f904451525752ece3c38f38cfa0825fd01735388c2b0264"}, - {file = "pyobjc_framework_UserNotifications-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f4ce290d1874d8b4ec36b2fae9181fa230e6ce0dced3aeb0fd0d88b7cda6a75a"}, - {file = "pyobjc_framework_UserNotifications-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8bc0c9599d7bbf35bb79eb661d537d6ea506859d2f1332ae2ee34b140bd937ef"}, - {file = "pyobjc_framework_UserNotifications-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:12d1ea6683af36813e3bdbdb065c28d71d01dfed7ea4deedeb3585e55179cbbb"}, + {file = "pyobjc_framework_UserNotifications-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c9a7e745828e3c6df44ebdaea3092ddc3c56f638130e5a0f47a2e0ae3ea405fb"}, + {file = "pyobjc_framework_UserNotifications-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e5bf6e386243eb7ad518b9ba102471713ed5b0bd05ea8a3f62478a7201754e37"}, + {file = "pyobjc_framework_UserNotifications-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e6ff9ca6de68b7635f111da623c68b533bd78fcf90ae620cfc23825bfc75ec4a"}, + {file = "pyobjc_framework_usernotifications-10.3.tar.gz", hash = "sha256:2e2172f3ca50e083ea6b20f18efb0c23c174cb6be19f91252ab770f51f5e3b06"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-usernotificationsui" -version = "10.2" +version = "10.3" description = "Wrappers for the framework UserNotificationsUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-UserNotificationsUI-10.2.tar.gz", hash = "sha256:f476d4a9f5b0746beda3d06ed6eb8a1b072372e644c707e675f4e11703528a81"}, - {file = "pyobjc_framework_UserNotificationsUI-10.2-py2.py3-none-any.whl", hash = "sha256:b0909b11655a7ae14e54ba6f80f1c6d34d46de5e8b565d0a51c22f87604ad3d3"}, + {file = "pyobjc_framework_UserNotificationsUI-10.3-py2.py3-none-any.whl", hash = "sha256:f809685da10d3eb1b0e659870df7584de79f228d8b49f00167d2a694249ead55"}, + {file = "pyobjc_framework_usernotificationsui-10.3.tar.gz", hash = "sha256:0a843e3dad58650c595097e25cf2ca234216920abb8f92dfbd96822ca3afbb88"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-UserNotifications = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-UserNotifications = ">=10.3" [[package]] name = "pyobjc-framework-videosubscriberaccount" -version = "10.2" +version = "10.3" description = "Wrappers for the framework VideoSubscriberAccount on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-VideoSubscriberAccount-10.2.tar.gz", hash = "sha256:26ea7fe843ba316eea90c488ed3ff46651b94b51b6e3bd87db2ff93f9fa8e496"}, - {file = "pyobjc_framework_VideoSubscriberAccount-10.2-py2.py3-none-any.whl", hash = "sha256:300c9f419821aab400ab9798bed9fc659984f19eb8577934e6faae0428b89096"}, + {file = "pyobjc_framework_VideoSubscriberAccount-10.3-py2.py3-none-any.whl", hash = "sha256:0519c0eaec8aabb9d89e6bf1ab968e59ae3434365a0c98e4eeb3c8837a712d76"}, + {file = "pyobjc_framework_videosubscriberaccount-10.3.tar.gz", hash = "sha256:c65a74c087b354b3d73fba2be2396985e9d51bbe5fc42c00acdb4cd3d78aa0ba"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-videotoolbox" -version = "10.2" +version = "10.3" description = "Wrappers for the framework VideoToolbox on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-VideoToolbox-10.2.tar.gz", hash = "sha256:347259a8e920dbc3dd1fada5ab0d829485cef3165166fa65f78c23ada4f9b80a"}, - {file = "pyobjc_framework_VideoToolbox-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb8147d673defdb02526b80b1584369f94b94721016950bb12425b2309b92c88"}, - {file = "pyobjc_framework_VideoToolbox-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6527180eede44301c21790baa7e1a5f5429893e3995e61640f3941c3b6fb08f9"}, - {file = "pyobjc_framework_VideoToolbox-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:de55d7629a9659439901a16d6074e9fc9b229e93a555097a1c92e0df6cfb5cdb"}, + {file = "pyobjc_framework_VideoToolbox-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e34b41b5816101414e3089b1a770e0bf8831acd62755945a625f7917a49c1bd"}, + {file = "pyobjc_framework_VideoToolbox-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cb5d91a6fc213ad853eeea410289cb5f6e87e7a8c4df2c6e0bb5e9c977b9b010"}, + {file = "pyobjc_framework_VideoToolbox-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:df7047d9f077690fa4f82f33cf82b740c418ebfdb03ac6dcf36e7786ffe6718f"}, + {file = "pyobjc_framework_videotoolbox-10.3.tar.gz", hash = "sha256:801d1140de6acaa62e249fd50e2852c307b3ad461288c348f81c623704138519"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreMedia = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreMedia = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-virtualization" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Virtualization on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Virtualization-10.2.tar.gz", hash = "sha256:49eb8d0ec3017c2194620f0698e95ccf20b8b706c73ab3b1b50902c57f0f86ff"}, - {file = "pyobjc_framework_Virtualization-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:492daa384cf3117749ff35127f81313bd1ea9bbd09385c2a882b82ca4ca0797e"}, - {file = "pyobjc_framework_Virtualization-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1bea91b57d419d91e76865f9621ba4762793e05f7a694cefe73206f3a19b4eda"}, - {file = "pyobjc_framework_Virtualization-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c1198bcd31e4711c6a0c6816c77483361217a1ed2f0ad69608f9ba5633efc144"}, + {file = "pyobjc_framework_Virtualization-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca9b15238573459bde886b3d1930a75904f447ee033032c004582b19141b751d"}, + {file = "pyobjc_framework_Virtualization-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6113d9e10f671ea43ac07fdfe91e16f41bdc06fccfd1f8b9ce014ab4e7a08335"}, + {file = "pyobjc_framework_Virtualization-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f60f3f22cb5d832429fc072368911f6989fc5e66fc164fe0e15b66102e8da7c6"}, + {file = "pyobjc_framework_virtualization-10.3.tar.gz", hash = "sha256:eb40b50a05d8fd574c1cd4265dbe5a6fd19dddd223ae37a22c27279bffc56de3"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyobjc-framework-vision" -version = "10.2" +version = "10.3" description = "Wrappers for the framework Vision on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Vision-10.2.tar.gz", hash = "sha256:722e0a6da64738b5fc3c763a102445cad5892c0af94597637e89455099da397e"}, - {file = "pyobjc_framework_Vision-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:42b7383c317c2076edcb44f7ad8ed4a6e675250a3fd20e87eef8e0e4233b1b58"}, - {file = "pyobjc_framework_Vision-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5e3adb56fca35d41a4bb113f3eadbe45e9667d8e3edf64908da3d6b130e14a8c"}, - {file = "pyobjc_framework_Vision-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e424d106052112897c8aa882d8334ac984e12509f9a473a285827ba47bfbcc9a"}, + {file = "pyobjc_framework_Vision-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d89b51e4732ae90ae5640fe68b018d4dbdfd200bc2705663c1e590d1dd8a7863"}, + {file = "pyobjc_framework_Vision-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:22cbb17f3a6b76133357ab427bcf553cb604d2720a80a9b27c0a42f6c2a7138a"}, + {file = "pyobjc_framework_Vision-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:bcb1e04a7248d57bce443ecaec0660e14d2eb635a2deff43d8c03867a3df21c3"}, + {file = "pyobjc_framework_vision-10.3.tar.gz", hash = "sha256:fe82dfbc120d04dbe8771d576f5210dcdb5b981feac7e75fcc2384ab8ffa31eb"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" -pyobjc-framework-CoreML = ">=10.2" -pyobjc-framework-Quartz = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" +pyobjc-framework-CoreML = ">=10.3" +pyobjc-framework-Quartz = ">=10.3" [[package]] name = "pyobjc-framework-webkit" -version = "10.2" +version = "10.3" description = "Wrappers for the framework WebKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-WebKit-10.2.tar.gz", hash = "sha256:3717104dbc901a1bd46d97886c5adb6eb32798ff4451c4544e04740e41706083"}, - {file = "pyobjc_framework_WebKit-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0d128a9e053b3dfaa71857eba6e6aadfbde88347382e1e58e288b5e410b71226"}, - {file = "pyobjc_framework_WebKit-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:d20344d55c3cb4aa27314e096f59db5cefa70539112d8c1658f2a2076df58612"}, - {file = "pyobjc_framework_WebKit-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f7dcf2e51964406cc2440e556c855d087c4706289c5f53464e8ffb0fba37adda"}, + {file = "pyobjc_framework_WebKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2f66212dffcf419a7b8a462fca22f76d7a2d534b4deb15a499d38e026f005985"}, + {file = "pyobjc_framework_WebKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d6d1174d63b6d9ea3247761431812ce30722fbdac93443d6563b4ea45a3323d"}, + {file = "pyobjc_framework_WebKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ca76f5c17f559c59338cd55342d6bd9d2f24f536c64095383b55802b6639d648"}, + {file = "pyobjc_framework_webkit-10.3.tar.gz", hash = "sha256:600a0033bf42114795b032c23139c0679aad236cb964961130ba3cd96da026ff"}, ] [package.dependencies] -pyobjc-core = ">=10.2" -pyobjc-framework-Cocoa = ">=10.2" +pyobjc-core = ">=10.3" +pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyopencl" @@ -6734,6 +6743,20 @@ files = [ [package.dependencies] pytest = "*" +[[package]] +name = "pytest-repeat" +version = "0.9.3" +description = "pytest plugin for repeating tests" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest_repeat-0.9.3-py3-none-any.whl", hash = "sha256:26ab2df18226af9d5ce441c858f273121e92ff55f5bb311d25755b8d7abdd8ed"}, + {file = "pytest_repeat-0.9.3.tar.gz", hash = "sha256:ffd3836dfcd67bb270bec648b330e20be37d2966448c4148c4092d1e8aba8185"}, +] + +[package.dependencies] +pytest = "*" + [[package]] name = "pytest-subtests" version = "0.12.1" @@ -7086,13 +7109,13 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -7107,16 +7130,16 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rerun-sdk" -version = "0.16.0" +version = "0.16.1" description = "The Rerun Logging SDK" optional = false python-versions = "<3.13,>=3.8" files = [ - {file = "rerun_sdk-0.16.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1cc6dc66d089e296f945dc238301889efb61dd6d338b5d00f76981cf7aed0a74"}, - {file = "rerun_sdk-0.16.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:faf231897655e46eb975695df2b0ace07db362d697e697f9a3dff52f81c0dc5d"}, - {file = "rerun_sdk-0.16.0-cp38-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:860a6394380d3e9b9e48bf34423bd56dda54d5b0158d2ae0e433698659b34198"}, - {file = "rerun_sdk-0.16.0-cp38-abi3-manylinux_2_31_x86_64.whl", hash = "sha256:5b8d1476f73a3ad1a5d3f21b61c633f3ab62aa80fa0b049f5ad10bf1227681ab"}, - {file = "rerun_sdk-0.16.0-cp38-abi3-win_amd64.whl", hash = "sha256:aff0051a263b8c3067243c0126d319845baf4fe640899f04aeef7daf151f35e4"}, + {file = "rerun_sdk-0.16.1-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:170c6976634008611753e10dfef8cdc395ce8180e634c169e7c61cef2f89a277"}, + {file = "rerun_sdk-0.16.1-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c9a76eab7eb5559276737dad655200e9350df0837158dbc5a896970ab4201454"}, + {file = "rerun_sdk-0.16.1-cp38-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:4d6436752d57e8b8038489a0e7e37f0c760b088e96db5fb81667d3a376d63fea"}, + {file = "rerun_sdk-0.16.1-cp38-abi3-manylinux_2_31_x86_64.whl", hash = "sha256:37b7b47948471873e84f224b16f417a94a91c7cbd6c72c68281eeff1ba414b8f"}, + {file = "rerun_sdk-0.16.1-cp38-abi3-win_amd64.whl", hash = "sha256:be88799c8afdf68eafa99e64e2e4f0a484e187e017a180219abbe6bb988acd4e"}, ] [package.dependencies] @@ -7146,28 +7169,28 @@ docs = ["furo (==2024.4.27)", "pyenchant (==3.2.2)", "sphinx (==7.1.2)", "sphinx [[package]] name = "ruff" -version = "0.4.5" +version = "0.4.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.4.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8f58e615dec58b1a6b291769b559e12fdffb53cc4187160a2fc83250eaf54e96"}, - {file = "ruff-0.4.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:84dd157474e16e3a82745d2afa1016c17d27cb5d52b12e3d45d418bcc6d49264"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f483ad9d50b00e7fd577f6d0305aa18494c6af139bce7319c68a17180087f4"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63fde3bf6f3ad4e990357af1d30e8ba2730860a954ea9282c95fc0846f5f64af"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e3ba4620dee27f76bbcad97067766026c918ba0f2d035c2fc25cbdd04d9c97"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:441dab55c568e38d02bbda68a926a3d0b54f5510095c9de7f95e47a39e0168aa"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1169e47e9c4136c997f08f9857ae889d614c5035d87d38fda9b44b4338909cdf"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:755ac9ac2598a941512fc36a9070a13c88d72ff874a9781493eb237ab02d75df"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4b02a65985be2b34b170025a8b92449088ce61e33e69956ce4d316c0fe7cce0"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:75a426506a183d9201e7e5664de3f6b414ad3850d7625764106f7b6d0486f0a1"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6e1b139b45e2911419044237d90b60e472f57285950e1492c757dfc88259bb06"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6f29a8221d2e3d85ff0c7b4371c0e37b39c87732c969b4d90f3dad2e721c5b1"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d6ef817124d72b54cc923f3444828ba24fa45c3164bc9e8f1813db2f3d3a8a11"}, - {file = "ruff-0.4.5-py3-none-win32.whl", hash = "sha256:aed8166c18b1a169a5d3ec28a49b43340949e400665555b51ee06f22813ef062"}, - {file = "ruff-0.4.5-py3-none-win_amd64.whl", hash = "sha256:b0b03c619d2b4350b4a27e34fd2ac64d0dabe1afbf43de57d0f9d8a05ecffa45"}, - {file = "ruff-0.4.5-py3-none-win_arm64.whl", hash = "sha256:9d15de3425f53161b3f5a5658d4522e4eee5ea002bf2ac7aa380743dd9ad5fba"}, - {file = "ruff-0.4.5.tar.gz", hash = "sha256:286eabd47e7d4d521d199cab84deca135557e6d1e0f0d01c29e757c3cb151b54"}, + {file = "ruff-0.4.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e089371c67892a73b6bb1525608e89a2aca1b77b5440acf7a71dda5dac958f9e"}, + {file = "ruff-0.4.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:10f973d521d910e5f9c72ab27e409e839089f955be8a4c8826601a6323a89753"}, + {file = "ruff-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c3d110970001dfa494bcd95478e62286c751126dfb15c3c46e7915fc49694f"}, + {file = "ruff-0.4.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa9773c6c00f4958f73b317bc0fd125295110c3776089f6ef318f4b775f0abe4"}, + {file = "ruff-0.4.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07fc80bbb61e42b3b23b10fda6a2a0f5a067f810180a3760c5ef1b456c21b9db"}, + {file = "ruff-0.4.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:fa4dafe3fe66d90e2e2b63fa1591dd6e3f090ca2128daa0be33db894e6c18648"}, + {file = "ruff-0.4.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7c0083febdec17571455903b184a10026603a1de078428ba155e7ce9358c5f6"}, + {file = "ruff-0.4.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad1b20e66a44057c326168437d680a2166c177c939346b19c0d6b08a62a37589"}, + {file = "ruff-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf5d818553add7511c38b05532d94a407f499d1a76ebb0cad0374e32bc67202"}, + {file = "ruff-0.4.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50e9651578b629baec3d1513b2534de0ac7ed7753e1382272b8d609997e27e83"}, + {file = "ruff-0.4.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8874a9df7766cb956b218a0a239e0a5d23d9e843e4da1e113ae1d27ee420877a"}, + {file = "ruff-0.4.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b9de9a6e49f7d529decd09381c0860c3f82fa0b0ea00ea78409b785d2308a567"}, + {file = "ruff-0.4.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:13a1768b0691619822ae6d446132dbdfd568b700ecd3652b20d4e8bc1e498f78"}, + {file = "ruff-0.4.7-py3-none-win32.whl", hash = "sha256:769e5a51df61e07e887b81e6f039e7ed3573316ab7dd9f635c5afaa310e4030e"}, + {file = "ruff-0.4.7-py3-none-win_amd64.whl", hash = "sha256:9e3ab684ad403a9ed1226894c32c3ab9c2e0718440f6f50c7c5829932bc9e054"}, + {file = "ruff-0.4.7-py3-none-win_arm64.whl", hash = "sha256:10f2204b9a613988e3484194c2c9e96a22079206b22b787605c255f130db5ed7"}, + {file = "ruff-0.4.7.tar.gz", hash = "sha256:2331d2b051dc77a289a653fcc6a42cce357087c5975738157cd966590b18b5e1"}, ] [[package]] @@ -7517,16 +7540,16 @@ files = [ [[package]] name = "sounddevice" -version = "0.4.6" +version = "0.4.7" description = "Play and Record Sound with Python" optional = false python-versions = ">=3.7" files = [ - {file = "sounddevice-0.4.6-py3-none-any.whl", hash = "sha256:5de768ba6fe56ad2b5aaa2eea794b76b73e427961c95acad2ee2ed7f866a4b20"}, - {file = "sounddevice-0.4.6-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:8b0b806c205dd3e3cd5a97262b2482624fd21db7d47083b887090148a08051c8"}, - {file = "sounddevice-0.4.6-py3-none-win32.whl", hash = "sha256:e3ba6e674ffa8f79a591d744a1d4ab922fe5bdfd4faf8b25069a08e051010b7b"}, - {file = "sounddevice-0.4.6-py3-none-win_amd64.whl", hash = "sha256:7830d4f8f8570f2e5552942f81d96999c5fcd9a0b682d6fc5d5c5529df23be2c"}, - {file = "sounddevice-0.4.6.tar.gz", hash = "sha256:3236b78f15f0415bdf006a620cef073d0c0522851d66f4a961ed6d8eb1482fe9"}, + {file = "sounddevice-0.4.7-py3-none-any.whl", hash = "sha256:1c3f18bfa4d9a257f5715f2ab83f2c0eb412a09f3e6a9fa73720886ca88f6bc7"}, + {file = "sounddevice-0.4.7-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d6ddfd341ad7412b14ca001f2c4dbf5fa2503bdc9eb15ad2c3105f6c260b698a"}, + {file = "sounddevice-0.4.7-py3-none-win32.whl", hash = "sha256:1ec1df094c468a210113aa22c4f390d5b4d9c7a73e41a6cb6ecfec83db59b380"}, + {file = "sounddevice-0.4.7-py3-none-win_amd64.whl", hash = "sha256:0c8b3543da1496f282b66a7bc54b755577ba638b1af06c146d4ac7f39d86b548"}, + {file = "sounddevice-0.4.7.tar.gz", hash = "sha256:69b386818d50a2d518607d4b973442e8d524760c7cd6c8b8be03d8c98fc4bce7"}, ] [package.dependencies] @@ -7726,17 +7749,17 @@ files = [ [[package]] name = "sympy" -version = "1.12" +version = "1.12.1" description = "Computer algebra system (CAS) in Python" optional = false python-versions = ">=3.8" files = [ - {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"}, - {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"}, + {file = "sympy-1.12.1-py3-none-any.whl", hash = "sha256:9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515"}, + {file = "sympy-1.12.1.tar.gz", hash = "sha256:2877b03f998cd8c08f07cd0de5b767119cd3ef40d09f41c30d722f6686b0fb88"}, ] [package.dependencies] -mpmath = ">=0.19" +mpmath = ">=1.1.0,<1.4.0" [[package]] name = "tabulate" @@ -7806,13 +7829,13 @@ telegram = ["requests"] [[package]] name = "types-requests" -version = "2.32.0.20240523" +version = "2.32.0.20240602" description = "Typing stubs for requests" optional = false python-versions = ">=3.8" files = [ - {file = "types-requests-2.32.0.20240523.tar.gz", hash = "sha256:26b8a6de32d9f561192b9942b41c0ab2d8010df5677ca8aa146289d11d505f57"}, - {file = "types_requests-2.32.0.20240523-py3-none-any.whl", hash = "sha256:f19ed0e2daa74302069bbbbf9e82902854ffa780bc790742a810a9aaa52f65ec"}, + {file = "types-requests-2.32.0.20240602.tar.gz", hash = "sha256:3f98d7bbd0dd94ebd10ff43a7fbe20c3b8528acace6d8efafef0b6a184793f06"}, + {file = "types_requests-2.32.0.20240602-py3-none-any.whl", hash = "sha256:ed3946063ea9fbc6b5fc0c44fa279188bae42d582cb63760be6cb4b9d06c3de8"}, ] [package.dependencies] @@ -7831,13 +7854,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.12.0" +version = "4.12.1" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, - {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, + {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, + {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, ] [[package]] @@ -8025,20 +8048,20 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.18.2" +version = "3.19.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.18.2-py3-none-any.whl", hash = "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e"}, - {file = "zipp-3.18.2.tar.gz", hash = "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059"}, + {file = "zipp-3.19.1-py3-none-any.whl", hash = "sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091"}, + {file = "zipp-3.19.1.tar.gz", hash = "sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "ac6ceb0682848e6c5e39110842e8d96fdc98b15037c56491a7fc1e03b7b89cbd" +content-hash = "804b6450fde7f96b7bd127d8598d24645bf048aa094c625c3c0e43a3460fcf5e" diff --git a/pyproject.toml b/pyproject.toml index 312e760b5..e8b7e3e23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -147,6 +147,7 @@ pytest-timeout = "*" pytest-randomly = "*" pytest-asyncio = "*" pytest-mock = "*" +pytest-repeat = "*" rerun-sdk = "*" ruff = "*" sphinx = "*" From c7b3ece37ef4445bcc18403b6a9e0217db4abd96 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 3 Jun 2024 17:19:27 -0700 Subject: [PATCH 125/220] revert marking some files as unexecutable (#32613) * this is not a test * these are not tests! --- selfdrive/debug/test_fw_query_on_routes.py | 1 + selfdrive/test/process_replay/test_processes.py | 1 + tools/car_porting/test_car_model.py | 1 + 3 files changed, 3 insertions(+) mode change 100644 => 100755 selfdrive/debug/test_fw_query_on_routes.py mode change 100644 => 100755 selfdrive/test/process_replay/test_processes.py mode change 100644 => 100755 tools/car_porting/test_car_model.py diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py old mode 100644 new mode 100755 index 73c913858..e338110a7 --- a/selfdrive/debug/test_fw_query_on_routes.py +++ b/selfdrive/debug/test_fw_query_on_routes.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 # type: ignore from collections import defaultdict diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py old mode 100644 new mode 100755 index ae844ac9b..533ab125f --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import argparse import concurrent.futures import os diff --git a/tools/car_porting/test_car_model.py b/tools/car_porting/test_car_model.py old mode 100644 new mode 100755 index b96f81075..cf0be1a80 --- a/tools/car_porting/test_car_model.py +++ b/tools/car_porting/test_car_model.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import argparse import sys import unittest # noqa: TID251 From 25e15846f1a16407d674f83e1a1125f579181a67 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 5 Jun 2024 01:25:46 +0800 Subject: [PATCH 126/220] ui/cameraview: fix deadlock on exit due to Qt::BlockingQueuedConnection (#32620) fix deadlock --- selfdrive/ui/qt/widgets/cameraview.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index e4f139626..914b04b65 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -104,6 +105,7 @@ CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool QObject::connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); QObject::connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived, Qt::QueuedConnection); QObject::connect(this, &CameraWidget::vipcAvailableStreamsUpdated, this, &CameraWidget::availableStreamsUpdated, Qt::QueuedConnection); + QObject::connect(QApplication::instance(), &QCoreApplication::aboutToQuit, this, &CameraWidget::stopVipcThread); } CameraWidget::~CameraWidget() { From 8a4bfcf5b4f4adc5cf9f0c91895d621421e994a2 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 4 Jun 2024 11:10:04 -0700 Subject: [PATCH 127/220] [torqued] Reduce friction for some Hyundai cars (#32578) * reduce friction coeff for ev6 and ioniq6 * Update ref --------- Co-authored-by: Bruce Wayne --- selfdrive/car/torque_data/override.toml | 2 +- selfdrive/car/torque_data/params.toml | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/torque_data/override.toml b/selfdrive/car/torque_data/override.toml index f6f4eacc1..993eb3fb3 100644 --- a/selfdrive/car/torque_data/override.toml +++ b/selfdrive/car/torque_data/override.toml @@ -61,7 +61,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "GMC_ACADIA" = [1.6, 1.6, 0.2] "LEXUS_IS_TSS2" = [2.0, 2.0, 0.1] "HYUNDAI_KONA_EV_2ND_GEN" = [2.5, 2.5, 0.1] -"HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.1] +"HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.005] "HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1] "HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1] "KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1] diff --git a/selfdrive/car/torque_data/params.toml b/selfdrive/car/torque_data/params.toml index f91bc3aba..34cfd0e06 100644 --- a/selfdrive/car/torque_data/params.toml +++ b/selfdrive/car/torque_data/params.toml @@ -40,7 +40,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "HYUNDAI_TUCSON_4TH_GEN" = [2.960174, 2.860284, 0.108745] "JEEP_GRAND_CHEROKEE_2019" = [2.30972, 1.289689569171081, 0.117048] "JEEP_GRAND_CHEROKEE" = [2.27116, 1.4057367824262523, 0.11725947414922003] -"KIA_EV6" = [3.2, 2.093457, 0.05] +"KIA_EV6" = [3.2, 2.093457, 0.005] "KIA_K5_2021" = [2.405339728085138, 1.460032270828705, 0.11650989850813716] "KIA_NIRO_EV" = [2.9215954981365337, 2.1500583840260044, 0.09236802474810267] "KIA_SORENTO" = [2.464854685101844, 1.5335274218367956, 0.12056170567599558] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 0a9a54325..70178b8ea 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -87aa5052e36d5cf83698b1eb6e50aef5c86df8ca \ No newline at end of file +e536df5586a71b22baa789dc584d7eab67f1fbbb From 2482ed085ebfd2c09394ce59900348334772d58f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 5 Jun 2024 02:20:17 +0800 Subject: [PATCH 128/220] modeld: cleanup commonmodel (#32618) cleanup --- selfdrive/modeld/models/commonmodel.cc | 18 ------------------ selfdrive/modeld/models/commonmodel.h | 9 --------- 2 files changed, 27 deletions(-) diff --git a/selfdrive/modeld/models/commonmodel.cc b/selfdrive/modeld/models/commonmodel.cc index 5e28e9b95..523ce00e4 100644 --- a/selfdrive/modeld/models/commonmodel.cc +++ b/selfdrive/modeld/models/commonmodel.cc @@ -1,13 +1,10 @@ #include "selfdrive/modeld/models/commonmodel.h" -#include #include #include #include #include "common/clutil.h" -#include "common/mat.h" -#include "common/timing.h" ModelFrame::ModelFrame(cl_device_id device_id, cl_context context) { input_frames = std::make_unique(buf_size); @@ -52,21 +49,6 @@ ModelFrame::~ModelFrame() { CL_CHECK(clReleaseCommandQueue(q)); } -void softmax(const float* input, float* output, size_t len) { - const float max_val = *std::max_element(input, input + len); - float denominator = 0; - for (int i = 0; i < len; i++) { - float const v_exp = expf(input[i] - max_val); - denominator += v_exp; - output[i] = v_exp; - } - - const float inv_denominator = 1. / denominator; - for (int i = 0; i < len; i++) { - output[i] *= inv_denominator; - } -} - float sigmoid(float input) { return 1 / (1 + expf(-input)); } diff --git a/selfdrive/modeld/models/commonmodel.h b/selfdrive/modeld/models/commonmodel.h index 1a079da05..2cf79094a 100644 --- a/selfdrive/modeld/models/commonmodel.h +++ b/selfdrive/modeld/models/commonmodel.h @@ -13,20 +13,11 @@ #endif #include "common/mat.h" -#include "cereal/messaging/messaging.h" #include "selfdrive/modeld/transforms/loadyuv.h" #include "selfdrive/modeld/transforms/transform.h" -const bool send_raw_pred = getenv("SEND_RAW_PRED") != NULL; - -void softmax(const float* input, float* output, size_t len); float sigmoid(float input); -template -constexpr const kj::ArrayPtr to_kj_array_ptr(const std::array &arr) { - return kj::ArrayPtr(arr.data(), arr.size()); -} - class ModelFrame { public: ModelFrame(cl_device_id device_id, cl_context context); From 149238845c1ed98dc5b86446c5c6d49e53b5e340 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 4 Jun 2024 12:09:06 -0700 Subject: [PATCH 129/220] Revert "`pytest`: discover `openpilot/` (#32561)" (#32622) This reverts commit 00b10f3d9ad03a6695446aab7b3a34d86229549a. --- .github/workflows/selfdrive_tests.yaml | 2 +- pyproject.toml | 34 ++++++++++++++++++-------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 9392b9b8d..0ccf1844d 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -19,7 +19,7 @@ env: DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} BUILD: selfdrive/test/docker_build.sh base - RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c + RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical diff --git a/pyproject.toml b/pyproject.toml index e8b7e3e23..99d6c0472 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,8 +9,8 @@ Homepage = "https://comma.ai" [tool.pytest.ini_options] minversion = "6.0" -addopts = "--ignore=selfdrive/test/process_replay/test_processes.py --ignore=selfdrive/test/process_replay/test_regen.py -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" -cpp_files = "test_*.cc" +addopts = "--ignore=openpilot/ --ignore=cereal/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=teleoprtc_repo/ -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" +cpp_files = "test_*" cpp_harness = "selfdrive/test/cpp_harness.py" python_files = "test_*.py" #timeout = "30" # you get this long by default @@ -19,10 +19,28 @@ markers = [ "tici: tests that are only meant to run on the C3/C3X", ] testpaths = [ - "tools/", - "common/", - "system/", - "selfdrive/", + "common", + "selfdrive/boardd", + "selfdrive/car", + "selfdrive/controls", + "selfdrive/locationd", + "selfdrive/monitoring", + "selfdrive/navd/tests", + "selfdrive/test/longitudinal_maneuvers", + "selfdrive/test/process_replay/test_fuzzy.py", + "system/updated", + "system/thermald", + "system/athena", + "system/camerad", + "system/hardware/tici", + "system/loggerd", + "system/proclogd", + "system/tests", + "system/ubloxd", + "system/webrtc", + "tools/lib/tests", + "tools/replay", + "tools/cabana" ] [tool.mypy] @@ -210,10 +228,6 @@ lint.flake8-implicit-str-concat.allow-multiline=false "unittest".msg = "Use pytest" [tool.coverage.run] -omit = [ - "config.py", - "config-3.py" -] concurrency = ["multiprocessing", "thread"] [tool.ruff.format] quote-style = "preserve" From ba9ea0a25f636d0a425b05e19b5fd1bc4cfee31a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 4 Jun 2024 16:31:16 -0700 Subject: [PATCH 130/220] Hyundai: remove Ioniq EV 2020 CAN fingerprint (#32625) * add from afc1609bb1584f28 * remove HYUNDAI_IONIQ_EV_2020 CAN fingerprint --- selfdrive/car/hyundai/fingerprints.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 5f57f7154..60a222b06 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -23,9 +23,6 @@ FINGERPRINTS = { CAR.GENESIS_G90: [{ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1162: 4, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 3, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2003: 8, 2004: 8, 2005: 8, 2008: 8, 2011: 8, 2012: 8, 2013: 8 }], - CAR.HYUNDAI_IONIQ_EV_2020: [{ - 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 524: 8, 544: 7, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1164: 8, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8, 2013: 8 - }], CAR.HYUNDAI_KONA_EV: [{ 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 549: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1307: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1378: 4, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 1157: 4, 1193: 8, 1379: 8, 1988: 8, 1996: 8 }], @@ -136,6 +133,7 @@ FW_VERSIONS = { b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7500 ', b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7000 ', b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7100 ', + b'\xf1\x00AEev SCC FHCUP 1.00 1.01 99110-G7100 ', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7310 4APEC101', From e494d989601f295ed1dfbcbfacaf891f26a0408c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 4 Jun 2024 16:35:24 -0700 Subject: [PATCH 131/220] Honda: helpful non-essential ECU comment --- selfdrive/car/honda/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 1b0da8d7d..05f826d1b 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -299,6 +299,7 @@ FW_QUERY_CONFIG = FwQueryConfig( ], # We lose these ECUs without the comma power on these cars. # Note that we still attempt to match with them when they are present + # This is or'd with (ALL_ECUS - ESSENTIAL_ECUS) from fw_versions.py non_essential_ecus={ Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC_2022, CAR.HONDA_E, CAR.HONDA_HRV_3G], Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CIVIC_2022, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID, From 23fcd687071c7825a7d518aec898fcdd536b2855 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 5 Jun 2024 08:04:50 +0800 Subject: [PATCH 132/220] LongControl: storing T_IDXS[:CONTROL_N] in a variable for reuse (#32599) Improve Control Trajectory Interpolation Efficiency --- selfdrive/controls/lib/longcontrol.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 2dd3390bb..d08ee0503 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -5,6 +5,8 @@ from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_dead from openpilot.selfdrive.controls.lib.pid import PIDController from openpilot.selfdrive.modeld.constants import ModelConstants +CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N] + LongCtrlState = car.CarControl.Actuators.LongControlState @@ -68,19 +70,19 @@ class LongControl: # Interp control trajectory speeds = long_plan.speeds if len(speeds) == CONTROL_N: - v_target_now = interp(t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds) - a_target_now = interp(t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], long_plan.accels) + v_target_now = interp(t_since_plan, CONTROL_N_T_IDX, speeds) + a_target_now = interp(t_since_plan, CONTROL_N_T_IDX, long_plan.accels) - v_target_lower = interp(self.CP.longitudinalActuatorDelayLowerBound + t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds) + v_target_lower = interp(self.CP.longitudinalActuatorDelayLowerBound + t_since_plan, CONTROL_N_T_IDX, speeds) a_target_lower = 2 * (v_target_lower - v_target_now) / self.CP.longitudinalActuatorDelayLowerBound - a_target_now - v_target_upper = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds) + v_target_upper = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan, CONTROL_N_T_IDX, speeds) a_target_upper = 2 * (v_target_upper - v_target_now) / self.CP.longitudinalActuatorDelayUpperBound - a_target_now v_target = min(v_target_lower, v_target_upper) a_target = min(a_target_lower, a_target_upper) - v_target_1sec = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan + 1.0, ModelConstants.T_IDXS[:CONTROL_N], speeds) + v_target_1sec = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan + 1.0, CONTROL_N_T_IDX, speeds) else: v_target = 0.0 v_target_now = 0.0 From a3d2d7892f180bf8f6ad1a82b894e4c829ae0bb7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 4 Jun 2024 18:22:23 -0700 Subject: [PATCH 133/220] Hyundai CAN FD: fix spotty FW query without comma power (#32627) bump --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 59d5be937..77ecf515e 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 59d5be937e40b8d93e9ebb79b33c65961a01de97 +Subproject commit 77ecf515e55750b1e2dc0fc60b04fe3fd3ec13a3 From 34e329649d7a388d4cd1f25dac9dda9d5409bf4a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 4 Jun 2024 19:16:55 -0700 Subject: [PATCH 134/220] boardd is pandad (#32628) * boardd is pandad * rename tests --- .gitignore | 3 +-- Jenkinsfile | 10 +++++----- RELEASES.md | 6 +++--- SConstruct | 2 +- common/realtime.py | 2 +- docs/c_docs.rst | 4 ++-- pyproject.toml | 2 +- selfdrive/SConscript | 2 +- selfdrive/boardd/.gitignore | 3 --- selfdrive/boardd/tests/__init__.py | 0 selfdrive/car/card.py | 4 ++-- selfdrive/car/ecu_addrs.py | 2 +- selfdrive/car/fw_query_definitions.py | 2 +- selfdrive/car/fw_versions.py | 2 +- selfdrive/car/isotp_parallel_query.py | 2 +- selfdrive/controls/controlsd.py | 2 +- selfdrive/controls/tests/test_startup.py | 4 ++-- selfdrive/debug/clear_dtc.py | 6 +++--- selfdrive/debug/cpu_usage_stat.py | 6 +++--- selfdrive/debug/get_fingerprint.py | 2 +- .../debug/hyundai_enable_radar_points.py | 6 +++--- selfdrive/debug/read_dtc_status.py | 6 +++--- selfdrive/pandad/.gitignore | 3 +++ selfdrive/{boardd => pandad}/SConscript | 6 +++--- .../{boardd/boardd.py => pandad/__init__.py} | 2 +- .../can_list_to_can_capnp.cc | 2 +- selfdrive/{boardd => pandad}/main.cc | 6 +++--- selfdrive/{boardd => pandad}/panda.cc | 2 +- selfdrive/{boardd => pandad}/panda.h | 2 +- selfdrive/{boardd => pandad}/panda_comms.cc | 2 +- selfdrive/{boardd => pandad}/panda_comms.h | 0 .../{boardd/boardd.cc => pandad/pandad.cc} | 18 +++++++++--------- .../{boardd/boardd.h => pandad/pandad.h} | 4 ++-- selfdrive/{boardd => pandad}/pandad.py | 10 +++++----- .../pandad_api_impl.pyx} | 0 selfdrive/{boardd => pandad}/spi.cc | 2 +- .../{boardd => pandad/tests}/__init__.py | 0 .../tests/bootstub.panda.bin | Bin .../tests/bootstub.panda_h7.bin | Bin .../tests/bootstub.panda_h7_spiv0.bin | Bin .../{boardd => pandad}/tests/test_pandad.py | 4 ++-- .../tests/test_pandad_loopback.py} | 12 ++++++------ .../tests/test_pandad_spi.py} | 4 ++-- .../tests/test_pandad_usbprotocol.cc} | 2 +- selfdrive/test/test_onroad.py | 6 +++--- system/hardware/tici/hardware.py | 4 ++-- system/manager/manager.py | 2 +- system/manager/process_config.py | 4 ++-- system/qcomgpsd/nmeaport.py | 2 +- tools/cabana/SConscript | 2 +- tools/cabana/streams/pandastream.h | 2 +- tools/latencylogger/README.md | 2 +- tools/latencylogger/latency_logger.py | 6 +++--- tools/replay/can_replay.py | 2 +- tools/sim/lib/simulated_car.py | 2 +- 55 files changed, 96 insertions(+), 97 deletions(-) delete mode 100644 selfdrive/boardd/.gitignore delete mode 100644 selfdrive/boardd/tests/__init__.py create mode 100644 selfdrive/pandad/.gitignore rename selfdrive/{boardd => pandad}/SConscript (61%) rename selfdrive/{boardd/boardd.py => pandad/__init__.py} (81%) rename selfdrive/{boardd => pandad}/can_list_to_can_capnp.cc (95%) rename selfdrive/{boardd => pandad}/main.cc (80%) rename selfdrive/{boardd => pandad}/panda.cc (99%) rename selfdrive/{boardd => pandad}/panda.h (98%) rename selfdrive/{boardd => pandad}/panda_comms.cc (99%) rename selfdrive/{boardd => pandad}/panda_comms.h (100%) rename selfdrive/{boardd/boardd.cc => pandad/pandad.cc} (97%) rename selfdrive/{boardd/boardd.h => pandad/pandad.h} (53%) rename selfdrive/{boardd => pandad}/pandad.py (95%) rename selfdrive/{boardd/boardd_api_impl.pyx => pandad/pandad_api_impl.pyx} (100%) rename selfdrive/{boardd => pandad}/spi.cc (99%) rename selfdrive/{boardd => pandad/tests}/__init__.py (100%) rename selfdrive/{boardd => pandad}/tests/bootstub.panda.bin (100%) rename selfdrive/{boardd => pandad}/tests/bootstub.panda_h7.bin (100%) rename selfdrive/{boardd => pandad}/tests/bootstub.panda_h7_spiv0.bin (100%) rename selfdrive/{boardd => pandad}/tests/test_pandad.py (97%) rename selfdrive/{boardd/tests/test_boardd_loopback.py => pandad/tests/test_pandad_loopback.py} (93%) rename selfdrive/{boardd/tests/test_boardd_spi.py => pandad/tests/test_pandad_spi.py} (96%) rename selfdrive/{boardd/tests/test_boardd_usbprotocol.cc => pandad/tests/test_pandad_usbprotocol.cc} (99%) diff --git a/.gitignore b/.gitignore index 693c532c5..4bc5fd3a2 100644 --- a/.gitignore +++ b/.gitignore @@ -40,8 +40,7 @@ compile_commands.json compare_runtime*.html persist -board/obj/ -selfdrive/boardd/boardd +selfdrive/pandad/pandad selfdrive/logcatd/logcatd selfdrive/mapd/default_speeds_by_region.json system/proclogd/proclogd diff --git a/Jenkinsfile b/Jenkinsfile index 0a044ff03..321237716 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -192,7 +192,7 @@ node { 'HW + Unit Tests': { deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [ ["build", "cd system/manager && ./build.py"], - ["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"], + ["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"], ["test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"], ["test pigeond", "pytest system/ubloxd/tests/test_pigeond.py"], @@ -202,7 +202,7 @@ node { 'loopback': { deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [ ["build openpilot", "cd system/manager && ./build.py"], - ["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"], + ["test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"], ]) }, 'camerad': { @@ -236,9 +236,9 @@ node { 'tizi': { deviceStage("tizi", "tizi", ["UNSAFE=1"], [ ["build openpilot", "cd system/manager && ./build.py"], - ["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"], - ["test boardd spi", "pytest selfdrive/boardd/tests/test_boardd_spi.py"], - ["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"], + ["test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"], + ["test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"], + ["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"], ["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"], ["test hw", "pytest system/hardware/tici/tests/test_hardware.py"], ["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"], diff --git a/RELEASES.md b/RELEASES.md index 971ba7867..c79f4ae88 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -634,7 +634,7 @@ Version 0.5.13 (2019-05-31) * Reduce CPU utilization by 20% and improve stability * Temporarily remove mapd functionalities to improve stability * Add openpilot record-only mode for unsupported cars - * Synchronize controlsd to boardd to reduce latency + * Synchronize controlsd to pandad to reduce latency * Remove panda support for Subaru giraffe Version 0.5.12 (2019-05-16) @@ -970,7 +970,7 @@ Version 0.2.8 (2017-02-27) Version 0.2.7 (2017-02-08) =========================== * Better performance and pictures at night - * Fix ptr alignment issue in boardd + * Fix ptr alignment issue in pandad * Fix brake error light, fix crash if too cold Version 0.2.6 (2017-01-31) @@ -1002,7 +1002,7 @@ Version 0.2.2 (2017-01-10) Version 0.2.1 (2016-12-14) =========================== * Performance improvements, removal of more numpy - * Fix boardd process priority + * Fix pandad process priority * Make counter timer reset on use of steering wheel Version 0.2 (2016-12-12) diff --git a/SConstruct b/SConstruct index 1e9f2a6b5..df34d5af9 100644 --- a/SConstruct +++ b/SConstruct @@ -226,7 +226,7 @@ env = Environment( "#cereal", "#third_party", "#opendbc/can", - "#selfdrive/boardd", + "#selfdrive/pandad", "#common", "#rednose/helpers", ], diff --git a/common/realtime.py b/common/realtime.py index 6b8587ff0..16e9a220e 100644 --- a/common/realtime.py +++ b/common/realtime.py @@ -23,7 +23,7 @@ class Priority: CTRL_LOW = 51 # plannerd & radard # CORE 3 - # - boardd = 55 + # - pandad = 55 CTRL_HIGH = 53 diff --git a/docs/c_docs.rst b/docs/c_docs.rst index 6e8808ec2..7303c89be 100644 --- a/docs/c_docs.rst +++ b/docs/c_docs.rst @@ -77,10 +77,10 @@ sensorsd .. autodoxygenindex:: :project: system_sensord_sensors -boardd +pandad ^^^^^^ .. autodoxygenindex:: - :project: selfdrive_boardd + :project: selfdrive_pandad rednose diff --git a/pyproject.toml b/pyproject.toml index 99d6c0472..5f6994829 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ markers = [ ] testpaths = [ "common", - "selfdrive/boardd", + "selfdrive/pandad", "selfdrive/car", "selfdrive/controls", "selfdrive/locationd", diff --git a/selfdrive/SConscript b/selfdrive/SConscript index 6b72177d8..52898f758 100644 --- a/selfdrive/SConscript +++ b/selfdrive/SConscript @@ -1,4 +1,4 @@ -SConscript(['boardd/SConscript']) +SConscript(['pandad/SConscript']) SConscript(['controls/lib/lateral_mpc_lib/SConscript']) SConscript(['controls/lib/longitudinal_mpc_lib/SConscript']) SConscript(['locationd/SConscript']) diff --git a/selfdrive/boardd/.gitignore b/selfdrive/boardd/.gitignore deleted file mode 100644 index e8daa2ef2..000000000 --- a/selfdrive/boardd/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -boardd -boardd_api_impl.cpp -tests/test_boardd_usbprotocol diff --git a/selfdrive/boardd/tests/__init__.py b/selfdrive/boardd/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 199c42578..330ad40e0 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -11,7 +11,7 @@ from panda import ALTERNATIVE_EXPERIENCE from openpilot.common.params import Params from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL -from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp +from openpilot.selfdrive.pandad import can_list_to_can_capnp from openpilot.selfdrive.car.car_helpers import get_car, get_one_can from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.controls.lib.events import Events @@ -153,7 +153,7 @@ class Car: # Initialize CarInterface, once controls are ready # TODO: this can make us miss at least a few cycles when doing an ECU knockout self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan']) - # signal boardd to switch to car safety mode + # signal pandad to switch to car safety mode self.params.put_bool_nonblocking("ControlsReady", True) if self.sm.all_alive(['carControl']): diff --git a/selfdrive/car/ecu_addrs.py b/selfdrive/car/ecu_addrs.py index da5e7b461..e7a9fbcf2 100755 --- a/selfdrive/car/ecu_addrs.py +++ b/selfdrive/car/ecu_addrs.py @@ -6,7 +6,7 @@ import cereal.messaging as messaging from panda.python.uds import SERVICE_TYPE from openpilot.selfdrive.car import make_can_msg from openpilot.selfdrive.car.fw_query_definitions import EcuAddrBusType -from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp +from openpilot.selfdrive.pandad import can_list_to_can_capnp from openpilot.common.swaglog import cloudlog diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index ad4dcdc8f..bb2827571 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -85,7 +85,7 @@ class Request: auxiliary: bool = False # FW responses from these queries will not be used for fingerprinting logging: bool = False - # boardd toggles OBD multiplexing on/off as needed + # pandad toggles OBD multiplexing on/off as needed obd_multiplexing: bool = True diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index fef3c52d3..4bb6413d0 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -352,7 +352,7 @@ if __name__ == "__main__": pandaStates_sock = messaging.sub_sock('pandaStates') sendcan = messaging.pub_sock('sendcan') - # Set up params for boardd + # Set up params for pandad params = Params() params.remove("FirmwareQueryDone") params.put_bool("IsOnroad", False) diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py index 8fdc747e9..447c7093c 100644 --- a/selfdrive/car/isotp_parallel_query.py +++ b/selfdrive/car/isotp_parallel_query.py @@ -4,7 +4,7 @@ from functools import partial import cereal.messaging as messaging from openpilot.common.swaglog import cloudlog -from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp +from openpilot.selfdrive.pandad import can_list_to_can_capnp from openpilot.selfdrive.car.fw_query_definitions import AddrType from panda.python.uds import CanClient, IsoTpMessage, FUNCTIONAL_ADDRS, get_rx_addr_for_tx_addr diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 1fb7f5949..c8cc76cfc 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -279,7 +279,7 @@ class Controls: else: safety_mismatch = pandaState.safetyModel not in IGNORED_SAFETY_MODES - # safety mismatch allows some time for boardd to set the safety mode and publish it back from panda + # safety mismatch allows some time for pandad to set the safety mode and publish it back from panda if (safety_mismatch and self.sm.frame*DT_CTRL > 10.) or pandaState.safetyRxChecksInvalid or self.mismatch_counter >= 200: self.events.add(EventName.controlsMismatch) diff --git a/selfdrive/controls/tests/test_startup.py b/selfdrive/controls/tests/test_startup.py index fc9f8ab12..14b0788a3 100644 --- a/selfdrive/controls/tests/test_startup.py +++ b/selfdrive/controls/tests/test_startup.py @@ -4,7 +4,7 @@ from parameterized import parameterized from cereal import log, car import cereal.messaging as messaging from openpilot.common.params import Params -from openpilot.selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp +from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp from openpilot.selfdrive.car.fingerprints import _FINGERPRINTS from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA from openpilot.selfdrive.car.mazda.values import CAR as MAZDA @@ -105,7 +105,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand): msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()] for _ in range(1000): - # card waits for boardd to echo back that it has changed the multiplexing mode + # card waits for pandad to echo back that it has changed the multiplexing mode if not params.get_bool("ObdMultiplexingChanged"): params.put_bool("ObdMultiplexingChanged", True) diff --git a/selfdrive/debug/clear_dtc.py b/selfdrive/debug/clear_dtc.py index dea21331b..a931c423a 100755 --- a/selfdrive/debug/clear_dtc.py +++ b/selfdrive/debug/clear_dtc.py @@ -12,11 +12,11 @@ parser.add_argument('--debug', action='store_true') args = parser.parse_args() try: - check_output(["pidof", "boardd"]) - print("boardd is running, please kill openpilot before running this script! (aborted)") + check_output(["pidof", "pandad"]) + print("pandad is running, please kill openpilot before running this script! (aborted)") sys.exit(1) except CalledProcessError as e: - if e.returncode != 1: # 1 == no process found (boardd not running) + if e.returncode != 1: # 1 == no process found (pandad not running) raise e panda = Panda() diff --git a/selfdrive/debug/cpu_usage_stat.py b/selfdrive/debug/cpu_usage_stat.py index baf44b908..234dfea3c 100755 --- a/selfdrive/debug/cpu_usage_stat.py +++ b/selfdrive/debug/cpu_usage_stat.py @@ -9,10 +9,10 @@ System tools like top/htop can only show current cpu usage values, so I write th Calculate minumium/maximum/accumulated_average cpu usage as long term inspections. Monitor multiple processes simuteneously. Sample usage: - root@localhost:/data/openpilot$ python selfdrive/debug/cpu_usage_stat.py boardd,ubloxd - ('Add monitored proc:', './boardd') + root@localhost:/data/openpilot$ python selfdrive/debug/cpu_usage_stat.py pandad,ubloxd + ('Add monitored proc:', './pandad') ('Add monitored proc:', 'python locationd/ubloxd.py') - boardd: 1.96%, min: 1.96%, max: 1.96%, acc: 1.96% + pandad: 1.96%, min: 1.96%, max: 1.96%, acc: 1.96% ubloxd.py: 0.39%, min: 0.39%, max: 0.39%, acc: 0.39% ''' import psutil diff --git a/selfdrive/debug/get_fingerprint.py b/selfdrive/debug/get_fingerprint.py index f7f7a1604..14f6c0e33 100755 --- a/selfdrive/debug/get_fingerprint.py +++ b/selfdrive/debug/get_fingerprint.py @@ -4,7 +4,7 @@ # Instructions: # - connect to a Panda -# - run selfdrive/boardd/boardd +# - run selfdrive/pandad/pandad # - launching this script # Note: it's very important that the car is in stock mode, in order to collect a complete fingerprint # - since some messages are published at low frequency, keep this script running for at least 30s, diff --git a/selfdrive/debug/hyundai_enable_radar_points.py b/selfdrive/debug/hyundai_enable_radar_points.py index e5cae0d47..5e7080ef6 100755 --- a/selfdrive/debug/hyundai_enable_radar_points.py +++ b/selfdrive/debug/hyundai_enable_radar_points.py @@ -79,11 +79,11 @@ if __name__ == "__main__": args = parser.parse_args() try: - check_output(["pidof", "boardd"]) - print("boardd is running, please kill openpilot before running this script! (aborted)") + check_output(["pidof", "pandad"]) + print("pandad is running, please kill openpilot before running this script! (aborted)") sys.exit(1) except CalledProcessError as e: - if e.returncode != 1: # 1 == no process found (boardd not running) + if e.returncode != 1: # 1 == no process found (pandad not running) raise e confirm = input("power on the vehicle keeping the engine off (press start button twice) then type OK to continue: ").upper().strip() diff --git a/selfdrive/debug/read_dtc_status.py b/selfdrive/debug/read_dtc_status.py index 9ad556397..2d27dd2bb 100755 --- a/selfdrive/debug/read_dtc_status.py +++ b/selfdrive/debug/read_dtc_status.py @@ -13,11 +13,11 @@ parser.add_argument('--debug', action='store_true') args = parser.parse_args() try: - check_output(["pidof", "boardd"]) - print("boardd is running, please kill openpilot before running this script! (aborted)") + check_output(["pidof", "pandad"]) + print("pandad is running, please kill openpilot before running this script! (aborted)") sys.exit(1) except CalledProcessError as e: - if e.returncode != 1: # 1 == no process found (boardd not running) + if e.returncode != 1: # 1 == no process found (pandad not running) raise e panda = Panda() diff --git a/selfdrive/pandad/.gitignore b/selfdrive/pandad/.gitignore new file mode 100644 index 000000000..f7226cdb8 --- /dev/null +++ b/selfdrive/pandad/.gitignore @@ -0,0 +1,3 @@ +pandad +pandad_api_impl.cpp +tests/test_pandad_usbprotocol diff --git a/selfdrive/boardd/SConscript b/selfdrive/pandad/SConscript similarity index 61% rename from selfdrive/boardd/SConscript rename to selfdrive/pandad/SConscript index 666763d9b..5e7073651 100644 --- a/selfdrive/boardd/SConscript +++ b/selfdrive/pandad/SConscript @@ -3,9 +3,9 @@ Import('env', 'envCython', 'common', 'cereal', 'messaging') libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj'] panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc']) -env.Program('boardd', ['main.cc', 'boardd.cc'], LIBS=[panda] + libs) +env.Program('pandad', ['main.cc', 'pandad.cc'], LIBS=[panda] + libs) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) -envCython.Program('boardd_api_impl.so', 'boardd_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) +envCython.Program('pandad_api_impl.so', 'pandad_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) if GetOption('extras'): - env.Program('tests/test_boardd_usbprotocol', ['tests/test_boardd_usbprotocol.cc'], LIBS=[panda] + libs) + env.Program('tests/test_pandad_usbprotocol', ['tests/test_pandad_usbprotocol.cc'], LIBS=[panda] + libs) diff --git a/selfdrive/boardd/boardd.py b/selfdrive/pandad/__init__.py similarity index 81% rename from selfdrive/boardd/boardd.py rename to selfdrive/pandad/__init__.py index 0cdaf5e91..8081a62dd 100644 --- a/selfdrive/boardd/boardd.py +++ b/selfdrive/pandad/__init__.py @@ -1,5 +1,5 @@ # Cython, now uses scons to build -from openpilot.selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp +from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp assert can_list_to_can_capnp def can_capnp_to_can_list(can, src_filter=None): diff --git a/selfdrive/boardd/can_list_to_can_capnp.cc b/selfdrive/pandad/can_list_to_can_capnp.cc similarity index 95% rename from selfdrive/boardd/can_list_to_can_capnp.cc rename to selfdrive/pandad/can_list_to_can_capnp.cc index 72ca72688..9fc2648da 100644 --- a/selfdrive/boardd/can_list_to_can_capnp.cc +++ b/selfdrive/pandad/can_list_to_can_capnp.cc @@ -1,5 +1,5 @@ #include "cereal/messaging/messaging.h" -#include "selfdrive/boardd/panda.h" +#include "selfdrive/pandad/panda.h" void can_list_to_can_capnp_cpp(const std::vector &can_list, std::string &out, bool sendCan, bool valid) { MessageBuilder msg; diff --git a/selfdrive/boardd/main.cc b/selfdrive/pandad/main.cc similarity index 80% rename from selfdrive/boardd/main.cc rename to selfdrive/pandad/main.cc index cb17a584b..f6f43d372 100644 --- a/selfdrive/boardd/main.cc +++ b/selfdrive/pandad/main.cc @@ -1,12 +1,12 @@ #include -#include "selfdrive/boardd/boardd.h" +#include "selfdrive/pandad/pandad.h" #include "common/swaglog.h" #include "common/util.h" #include "system/hardware/hw.h" int main(int argc, char *argv[]) { - LOGW("starting boardd"); + LOGW("starting pandad"); if (!Hardware::PC()) { int err; @@ -17,6 +17,6 @@ int main(int argc, char *argv[]) { } std::vector serials(argv + 1, argv + argc); - boardd_main_thread(serials); + pandad_main_thread(serials); return 0; } diff --git a/selfdrive/boardd/panda.cc b/selfdrive/pandad/panda.cc similarity index 99% rename from selfdrive/boardd/panda.cc rename to selfdrive/pandad/panda.cc index a2e557409..37df4072f 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/pandad/panda.cc @@ -1,4 +1,4 @@ -#include "selfdrive/boardd/panda.h" +#include "selfdrive/pandad/panda.h" #include diff --git a/selfdrive/boardd/panda.h b/selfdrive/pandad/panda.h similarity index 98% rename from selfdrive/boardd/panda.h rename to selfdrive/pandad/panda.h index 3002afeba..7e1e4706d 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/pandad/panda.h @@ -13,7 +13,7 @@ #include "cereal/gen/cpp/log.capnp.h" #include "panda/board/health.h" #include "panda/board/can_definitions.h" -#include "selfdrive/boardd/panda_comms.h" +#include "selfdrive/pandad/panda_comms.h" #define USB_TX_SOFT_LIMIT (0x100U) #define USBPACKET_MAX_SIZE (0x40) diff --git a/selfdrive/boardd/panda_comms.cc b/selfdrive/pandad/panda_comms.cc similarity index 99% rename from selfdrive/boardd/panda_comms.cc rename to selfdrive/pandad/panda_comms.cc index e2c78abea..4e8a0a27b 100644 --- a/selfdrive/boardd/panda_comms.cc +++ b/selfdrive/pandad/panda_comms.cc @@ -1,4 +1,4 @@ -#include "selfdrive/boardd/panda.h" +#include "selfdrive/pandad/panda.h" #include #include diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/pandad/panda_comms.h similarity index 100% rename from selfdrive/boardd/panda_comms.h rename to selfdrive/pandad/panda_comms.h diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/pandad/pandad.cc similarity index 97% rename from selfdrive/boardd/boardd.cc rename to selfdrive/pandad/pandad.cc index fcbf58999..095a7893b 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/pandad/pandad.cc @@ -1,4 +1,4 @@ -#include "selfdrive/boardd/boardd.h" +#include "selfdrive/pandad/pandad.h" #include #include @@ -25,7 +25,7 @@ // - The internal panda will always be the first panda // - Consecutive pandas will be sorted based on panda type, and then serial number // Connecting: -// - If a panda connection is dropped, boardd will reconnect to all pandas +// - If a panda connection is dropped, pandad will reconnect to all pandas // - If a panda is added, we will only reconnect when we are offroad // CAN buses: // - Each panda will have it's block of 4 buses. E.g.: the second panda will use @@ -163,7 +163,7 @@ Panda *connect(std::string serial="", uint32_t index=0) { } void can_send_thread(std::vector pandas, bool fake_send) { - util::set_thread_name("boardd_can_send"); + util::set_thread_name("pandad_can_send"); AlignedBuffer aligned_buf; std::unique_ptr context(Context::create()); @@ -198,12 +198,12 @@ void can_send_thread(std::vector pandas, bool fake_send) { } void can_recv_thread(std::vector pandas) { - util::set_thread_name("boardd_can_recv"); + util::set_thread_name("pandad_can_recv"); PubMaster pm({"can"}); // run at 100Hz - RateKeeper rk("boardd_can_recv", 100); + RateKeeper rk("pandad_can_recv", 100); std::vector raw_can_data; while (!do_exit && check_all_connected(pandas)) { @@ -405,7 +405,7 @@ void send_peripheral_state(PubMaster *pm, Panda *panda) { } void panda_state_thread(std::vector pandas, bool spoofing_started) { - util::set_thread_name("boardd_panda_state"); + util::set_thread_name("pandad_panda_state"); Params params; SubMaster sm({"controlsState"}); @@ -495,7 +495,7 @@ void panda_state_thread(std::vector pandas, bool spoofing_started) { void peripheral_control_thread(Panda *panda, bool no_fan_control) { - util::set_thread_name("boardd_peripheral_control"); + util::set_thread_name("pandad_peripheral_control"); SubMaster sm({"deviceState", "driverCameraState"}); @@ -546,8 +546,8 @@ void peripheral_control_thread(Panda *panda, bool no_fan_control) { } } -void boardd_main_thread(std::vector serials) { - LOGW("launching boardd"); +void pandad_main_thread(std::vector serials) { + LOGW("launching pandad"); if (serials.size() == 0) { serials = Panda::list(); diff --git a/selfdrive/boardd/boardd.h b/selfdrive/pandad/pandad.h similarity index 53% rename from selfdrive/boardd/boardd.h rename to selfdrive/pandad/pandad.h index 0646fc618..9d35949a8 100644 --- a/selfdrive/boardd/boardd.h +++ b/selfdrive/pandad/pandad.h @@ -3,7 +3,7 @@ #include #include -#include "selfdrive/boardd/panda.h" +#include "selfdrive/pandad/panda.h" bool safety_setter_thread(std::vector pandas); -void boardd_main_thread(std::vector serials); +void pandad_main_thread(std::vector serials); diff --git a/selfdrive/boardd/pandad.py b/selfdrive/pandad/pandad.py similarity index 95% rename from selfdrive/boardd/pandad.py rename to selfdrive/pandad/pandad.py index b4ac2d954..12accdbf5 100755 --- a/selfdrive/boardd/pandad.py +++ b/selfdrive/pandad/pandad.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# simple boardd wrapper that updates the panda first +# simple pandad wrapper that updates the panda first import os import usb1 import time @@ -157,10 +157,10 @@ def main() -> NoReturn: first_run = False - # run boardd with all connected serials as arguments - os.environ['MANAGER_DAEMON'] = 'boardd' - os.chdir(os.path.join(BASEDIR, "selfdrive/boardd")) - subprocess.run(["./boardd", *panda_serials], check=True) + # run pandad with all connected serials as arguments + os.environ['MANAGER_DAEMON'] = 'pandad' + os.chdir(os.path.join(BASEDIR, "selfdrive/pandad")) + subprocess.run(["./pandad", *panda_serials], check=True) if __name__ == "__main__": main() diff --git a/selfdrive/boardd/boardd_api_impl.pyx b/selfdrive/pandad/pandad_api_impl.pyx similarity index 100% rename from selfdrive/boardd/boardd_api_impl.pyx rename to selfdrive/pandad/pandad_api_impl.pyx diff --git a/selfdrive/boardd/spi.cc b/selfdrive/pandad/spi.cc similarity index 99% rename from selfdrive/boardd/spi.cc rename to selfdrive/pandad/spi.cc index 66e6a0f0a..836df5986 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/pandad/spi.cc @@ -13,7 +13,7 @@ #include "common/timing.h" #include "common/swaglog.h" #include "panda/board/comms_definitions.h" -#include "selfdrive/boardd/panda_comms.h" +#include "selfdrive/pandad/panda_comms.h" #define SPI_SYNC 0x5AU diff --git a/selfdrive/boardd/__init__.py b/selfdrive/pandad/tests/__init__.py similarity index 100% rename from selfdrive/boardd/__init__.py rename to selfdrive/pandad/tests/__init__.py diff --git a/selfdrive/boardd/tests/bootstub.panda.bin b/selfdrive/pandad/tests/bootstub.panda.bin similarity index 100% rename from selfdrive/boardd/tests/bootstub.panda.bin rename to selfdrive/pandad/tests/bootstub.panda.bin diff --git a/selfdrive/boardd/tests/bootstub.panda_h7.bin b/selfdrive/pandad/tests/bootstub.panda_h7.bin similarity index 100% rename from selfdrive/boardd/tests/bootstub.panda_h7.bin rename to selfdrive/pandad/tests/bootstub.panda_h7.bin diff --git a/selfdrive/boardd/tests/bootstub.panda_h7_spiv0.bin b/selfdrive/pandad/tests/bootstub.panda_h7_spiv0.bin similarity index 100% rename from selfdrive/boardd/tests/bootstub.panda_h7_spiv0.bin rename to selfdrive/pandad/tests/bootstub.panda_h7_spiv0.bin diff --git a/selfdrive/boardd/tests/test_pandad.py b/selfdrive/pandad/tests/test_pandad.py similarity index 97% rename from selfdrive/boardd/tests/test_pandad.py rename to selfdrive/pandad/tests/test_pandad.py index 5c74b40ce..467c7f04c 100644 --- a/selfdrive/boardd/tests/test_pandad.py +++ b/selfdrive/pandad/tests/test_pandad.py @@ -39,7 +39,7 @@ class TestPandad: managed_processes['pandad'].stop() if len(sm['pandaStates']) == 0 or sm['pandaStates'][0].pandaType == log.PandaState.PandaType.unknown: - raise Exception("boardd failed to start") + raise Exception("pandad failed to start") return dt @@ -101,7 +101,7 @@ class TestPandad: ts.append(dt) # 5s for USB (due to enumeration) - # - 0.2s pandad -> boardd + # - 0.2s pandad -> pandad # - plus some buffer assert 0.1 < (sum(ts)/len(ts)) < (0.5 if self.spi else 5.0) print("startup times", ts, sum(ts) / len(ts)) diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/pandad/tests/test_pandad_loopback.py similarity index 93% rename from selfdrive/boardd/tests/test_boardd_loopback.py rename to selfdrive/pandad/tests/test_pandad_loopback.py index 3f5cc5a74..365bb7611 100644 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/pandad/tests/test_pandad_loopback.py @@ -11,18 +11,18 @@ from cereal import car, log from openpilot.common.retry import retry from openpilot.common.params import Params from openpilot.common.timeout import Timeout -from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp +from openpilot.selfdrive.pandad import can_list_to_can_capnp from openpilot.selfdrive.car import make_can_msg from openpilot.system.hardware import TICI from openpilot.selfdrive.test.helpers import phone_only, with_processes @retry(attempts=3) -def setup_boardd(num_pandas): +def setup_pandad(num_pandas): params = Params() params.put_bool("IsOnroad", False) - with Timeout(90, "boardd didn't start"): + with Timeout(90, "pandad didn't start"): sm = messaging.SubMaster(['pandaStates']) while sm.recv_frame['pandaStates'] < 1 or len(sm['pandaStates']) == 0 or \ any(ps.pandaType == log.PandaState.PandaType.unknown for ps in sm['pandaStates']): @@ -32,7 +32,7 @@ def setup_boardd(num_pandas): assert num_pandas == found_pandas, "connected pandas ({found_pandas}) doesn't match expected panda count ({num_pandas}). \ connect another panda for multipanda tests." - # boardd safety setting relies on these params + # pandad safety setting relies on these params cp = car.CarParams.new_message() safety_config = car.CarParams.SafetyConfig.new_message() @@ -72,7 +72,7 @@ class TestBoarddLoopback: @with_processes(['pandad']) def test_loopback(self): num_pandas = 2 if TICI and "SINGLE_PANDA" not in os.environ else 1 - setup_boardd(num_pandas) + setup_pandad(num_pandas) sendcan = messaging.pub_sock('sendcan') can = messaging.sub_sock('can', conflate=False, timeout=100) sm = messaging.SubMaster(['pandaStates']) @@ -80,7 +80,7 @@ class TestBoarddLoopback: n = 200 for i in range(n): - print(f"boardd loopback {i}/{n}") + print(f"pandad loopback {i}/{n}") sent_msgs = send_random_can_messages(sendcan, random.randrange(20, 100), num_pandas) diff --git a/selfdrive/boardd/tests/test_boardd_spi.py b/selfdrive/pandad/tests/test_pandad_spi.py similarity index 96% rename from selfdrive/boardd/tests/test_boardd_spi.py rename to selfdrive/pandad/tests/test_pandad_spi.py index 3bb41155d..3447ea378 100644 --- a/selfdrive/boardd/tests/test_boardd_spi.py +++ b/selfdrive/pandad/tests/test_pandad_spi.py @@ -8,7 +8,7 @@ import cereal.messaging as messaging from cereal.services import SERVICE_LIST from openpilot.system.hardware import HARDWARE from openpilot.selfdrive.test.helpers import phone_only, with_processes -from openpilot.selfdrive.boardd.tests.test_boardd_loopback import setup_boardd, send_random_can_messages +from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages @pytest.mark.tici @@ -25,7 +25,7 @@ class TestBoarddSpi: @phone_only @with_processes(['pandad']) def test_spi_corruption(self, subtests): - setup_boardd(1) + setup_pandad(1) sendcan = messaging.pub_sock('sendcan') socks = {s: messaging.sub_sock(s, conflate=False, timeout=100) for s in ('can', 'pandaStates', 'peripheralState')} diff --git a/selfdrive/boardd/tests/test_boardd_usbprotocol.cc b/selfdrive/pandad/tests/test_pandad_usbprotocol.cc similarity index 99% rename from selfdrive/boardd/tests/test_boardd_usbprotocol.cc rename to selfdrive/pandad/tests/test_pandad_usbprotocol.cc index aa67e8cf8..11f7184ef 100644 --- a/selfdrive/boardd/tests/test_boardd_usbprotocol.cc +++ b/selfdrive/pandad/tests/test_pandad_usbprotocol.cc @@ -4,7 +4,7 @@ #include "catch2/catch.hpp" #include "cereal/messaging/messaging.h" #include "common/util.h" -#include "selfdrive/boardd/panda.h" +#include "selfdrive/pandad/panda.h" struct PandaTest : public Panda { PandaTest(uint32_t bus_offset, int can_list_size, cereal::PandaState::PandaType hw_type); diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 2e2b40d03..bcdf71f8e 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -58,7 +58,7 @@ PROCS = { "./logcatd": 0, "system.micd": 6.0, "system.timed": 0, - "selfdrive.boardd.pandad": 0, + "selfdrive.pandad.pandad": 0, "system.statsd": 0.4, "selfdrive.navd.navd": 0.4, "system.loggerd.uploader": (0.5, 15.0), @@ -67,12 +67,12 @@ PROCS = { PROCS.update({ "tici": { - "./boardd": 4.0, + "./pandad": 4.0, "./ubloxd": 0.02, "system.ubloxd.pigeond": 6.0, }, "tizi": { - "./boardd": 19.0, + "./pandad": 19.0, "system.qcomgpsd.qcomgpsd": 1.0, } }.get(HARDWARE.get_device_type(), {})) diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 45d20d976..57fbf9d63 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -379,7 +379,7 @@ class Tici(HardwareBase): # *** CPU config *** - # offline big cluster, leave core 4 online for boardd + # offline big cluster, leave core 4 online for pandad for i in range(5, 8): val = '0' if powersave_enabled else '1' sudo_write(val, f'/sys/devices/system/cpu/cpu{i}/online') @@ -390,7 +390,7 @@ class Tici(HardwareBase): # *** IRQ config *** - # boardd core + # pandad core affine_irq(4, "spi_geni") # SPI affine_irq(4, "xhci-hcd:usb3") # aux panda USB (or potentially anything else on USB) if "tici" in self.get_device_type(): diff --git a/system/manager/manager.py b/system/manager/manager.py index 93fab3ad1..6d1b8d9c2 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -145,7 +145,7 @@ def manager_thread() -> None: elif not started and started_prev: params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) - # update onroad params, which drives boardd's safety setter thread + # update onroad params, which drives pandad's safety setter thread if started != started_prev: write_onroad_params(started, params) diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 5e153ffb9..25c5f4649 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -60,7 +60,7 @@ procs = [ NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None)), PythonProcess("soundd", "selfdrive.ui.soundd", only_onroad), NativeProcess("locationd", "selfdrive/locationd", ["./locationd"], only_onroad), - NativeProcess("boardd", "selfdrive/boardd", ["./boardd"], always_run, enabled=False), + NativeProcess("pandad", "selfdrive/pandad", ["./pandad"], always_run, enabled=False), PythonProcess("calibrationd", "selfdrive.locationd.calibrationd", only_onroad), PythonProcess("torqued", "selfdrive.locationd.torqued", only_onroad), PythonProcess("controlsd", "selfdrive.controls.controlsd", only_onroad), @@ -70,7 +70,7 @@ procs = [ PythonProcess("qcomgpsd", "system.qcomgpsd.qcomgpsd", qcomgps, enabled=TICI), #PythonProcess("ugpsd", "system.ugpsd", only_onroad, enabled=TICI), PythonProcess("navd", "selfdrive.navd.navd", only_onroad), - PythonProcess("pandad", "selfdrive.boardd.pandad", always_run), + PythonProcess("pandad", "selfdrive.pandad.pandad", always_run), PythonProcess("paramsd", "selfdrive.locationd.paramsd", only_onroad), NativeProcess("ubloxd", "system/ubloxd", ["./ubloxd"], ublox, enabled=TICI), PythonProcess("pigeond", "system.ubloxd.pigeond", ublox, enabled=TICI), diff --git a/system/qcomgpsd/nmeaport.py b/system/qcomgpsd/nmeaport.py index caff7af64..8b9ab5108 100644 --- a/system/qcomgpsd/nmeaport.py +++ b/system/qcomgpsd/nmeaport.py @@ -127,7 +127,7 @@ def main() -> NoReturn: print("qcomgpsd is running, please kill openpilot before running this script! (aborted)") sys.exit(1) except CalledProcessError as e: - if e.returncode != 1: # 1 == no process found (boardd not running) + if e.returncode != 1: # 1 == no process found (pandad not running) raise e print("power up antenna ...") diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 2574e3368..5bcfdb175 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -39,4 +39,4 @@ output_json_file = 'tools/cabana/dbc/car_fingerprint_to_dbc.json' generate_dbc = cabana_env.Command('#' + output_json_file, ['dbc/generate_dbc_json.py'], "python3 tools/cabana/dbc/generate_dbc_json.py --out " + output_json_file) -cabana_env.Depends(generate_dbc, ["#common", "#selfdrive/boardd", '#opendbc', "#cereal", Glob("#opendbc/*.dbc")]) +cabana_env.Depends(generate_dbc, ["#common", "#selfdrive/pandad", '#opendbc', "#cereal", Glob("#opendbc/*.dbc")]) diff --git a/tools/cabana/streams/pandastream.h b/tools/cabana/streams/pandastream.h index c50407be1..3e7624768 100644 --- a/tools/cabana/streams/pandastream.h +++ b/tools/cabana/streams/pandastream.h @@ -7,7 +7,7 @@ #include #include "tools/cabana/streams/livestream.h" -#include "selfdrive/boardd/panda.h" +#include "selfdrive/pandad/panda.h" const uint32_t speeds[] = {10U, 20U, 50U, 100U, 125U, 250U, 500U, 1000U}; const uint32_t data_speeds[] = {10U, 20U, 50U, 100U, 125U, 250U, 500U, 1000U, 2000U, 5000U}; diff --git a/tools/latencylogger/README.md b/tools/latencylogger/README.md index a961f8361..421a6a0b4 100644 --- a/tools/latencylogger/README.md +++ b/tools/latencylogger/README.md @@ -76,7 +76,7 @@ Frame ID: 1202 Events updated 111.183541 sendcan published 112.981692 controlsState published 113.731994 - boardd + pandad sending sendcan to panda: 250027001751393037323631 81.928119 sendcan sent to panda: 250027001751393037323631 82.164834 sending sendcan to panda: 250027001751393037323631 93.569986 diff --git a/tools/latencylogger/latency_logger.py b/tools/latencylogger/latency_logger.py index 8c6af56b6..8691149e9 100755 --- a/tools/latencylogger/latency_logger.py +++ b/tools/latencylogger/latency_logger.py @@ -12,7 +12,7 @@ from openpilot.tools.lib.logreader import LogReader DEMO_ROUTE = "9f583b1d93915c31|2022-05-18--10-49-51--0" -SERVICES = ['camerad', 'modeld', 'plannerd', 'controlsd', 'boardd'] +SERVICES = ['camerad', 'modeld', 'plannerd', 'controlsd', 'pandad'] MONOTIME_KEYS = ['modelMonoTime', 'lateralPlanMonoTime'] MSGQ_TO_SERVICE = { 'roadCameraState': 'camerad', @@ -137,7 +137,7 @@ def insert_cloudlogs(lr, timestamps, start_times, end_times): timestamps[int(jmsg['msg']['timestamp']['frame_id'])][service].append((event, time)) continue - if service == "boardd": + if service == "pandad": timestamps[latest_controls_frameid][service].append((event, time)) end_times[latest_controls_frameid][service] = time else: @@ -153,7 +153,7 @@ def insert_cloudlogs(lr, timestamps, start_times, end_times): failed_inserts += 1 if latest_controls_frameid == 0: - print("Warning: failed to bind boardd logs to a frame ID. Add a timestamp cloudlog in controlsd.") + print("Warning: failed to bind pandad logs to a frame ID. Add a timestamp cloudlog in controlsd.") elif failed_inserts > len(timestamps): print(f"Warning: failed to bind {failed_inserts} cloudlog timestamps to a frame ID") diff --git a/tools/replay/can_replay.py b/tools/replay/can_replay.py index c7da8caf7..3ab33a1df 100755 --- a/tools/replay/can_replay.py +++ b/tools/replay/can_replay.py @@ -8,7 +8,7 @@ import threading os.environ['FILEREADER_CACHE'] = '1' from openpilot.common.realtime import config_realtime_process, Ratekeeper, DT_CTRL -from openpilot.selfdrive.boardd.boardd import can_capnp_to_can_list +from openpilot.selfdrive.pandad import can_capnp_to_can_list from openpilot.tools.lib.logreader import LogReader from panda import PandaJungle diff --git a/tools/sim/lib/simulated_car.py b/tools/sim/lib/simulated_car.py index 8c15195dc..6d324e478 100644 --- a/tools/sim/lib/simulated_car.py +++ b/tools/sim/lib/simulated_car.py @@ -3,7 +3,7 @@ import cereal.messaging as messaging from opendbc.can.packer import CANPacker from opendbc.can.parser import CANParser from openpilot.common.params import Params -from openpilot.selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp +from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp from openpilot.tools.sim.lib.common import SimulatorState from panda.python import Panda From 877b810ac9e89c62f1cb7632235d4c8f87a4e716 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 4 Jun 2024 21:26:16 -0700 Subject: [PATCH 135/220] pandad: reset CAN comms on checksum failure (#32629) --- panda | 2 +- selfdrive/pandad/panda.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panda b/panda index 77ecf515e..faa180266 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 77ecf515e55750b1e2dc0fc60b04fe3fd3ec13a3 +Subproject commit faa18026692f7714ee537261fe649dafe4882579 diff --git a/selfdrive/pandad/panda.cc b/selfdrive/pandad/panda.cc index 37df4072f..f0645584a 100644 --- a/selfdrive/pandad/panda.cc +++ b/selfdrive/pandad/panda.cc @@ -246,9 +246,9 @@ bool Panda::unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector Date: Tue, 4 Jun 2024 21:29:05 -0700 Subject: [PATCH 136/220] Honda: remove programmedFuelInjection ECU (#32626) * set up for quick test * remove pgfi * Revert "set up for quick test" This reverts commit aa6af2ff838b2cd203a6feaacaa5b4f3b71272ed. * still query JIC --- selfdrive/car/honda/fingerprints.py | 251 ---------------------------- selfdrive/car/honda/values.py | 1 + 2 files changed, 1 insertion(+), 251 deletions(-) diff --git a/selfdrive/car/honda/fingerprints.py b/selfdrive/car/honda/fingerprints.py index 439568888..8a5b79b41 100644 --- a/selfdrive/car/honda/fingerprints.py +++ b/selfdrive/car/honda/fingerprints.py @@ -11,43 +11,6 @@ Ecu = car.CarParams.Ecu FW_VERSIONS = { CAR.HONDA_ACCORD: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-6A0-8720\x00\x00', - b'37805-6A0-9520\x00\x00', - b'37805-6A0-9620\x00\x00', - b'37805-6A0-9720\x00\x00', - b'37805-6A0-A540\x00\x00', - b'37805-6A0-A550\x00\x00', - b'37805-6A0-A640\x00\x00', - b'37805-6A0-A650\x00\x00', - b'37805-6A0-A740\x00\x00', - b'37805-6A0-A750\x00\x00', - b'37805-6A0-A840\x00\x00', - b'37805-6A0-A850\x00\x00', - b'37805-6A0-A930\x00\x00', - b'37805-6A0-AF30\x00\x00', - b'37805-6A0-AG30\x00\x00', - b'37805-6A0-AJ10\x00\x00', - b'37805-6A0-C540\x00\x00', - b'37805-6A0-CG20\x00\x00', - b'37805-6A1-H650\x00\x00', - b'37805-6B2-A550\x00\x00', - b'37805-6B2-A560\x00\x00', - b'37805-6B2-A650\x00\x00', - b'37805-6B2-A660\x00\x00', - b'37805-6B2-A720\x00\x00', - b'37805-6B2-A810\x00\x00', - b'37805-6B2-A820\x00\x00', - b'37805-6B2-A920\x00\x00', - b'37805-6B2-A960\x00\x00', - b'37805-6B2-AA10\x00\x00', - b'37805-6B2-C520\x00\x00', - b'37805-6B2-C540\x00\x00', - b'37805-6B2-C560\x00\x00', - b'37805-6B2-M520\x00\x00', - b'37805-6B2-Y810\x00\x00', - b'37805-6M4-B730\x00\x00', - ], (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TVC-A910\x00\x00', b'54008-TWA-A910\x00\x00', @@ -161,38 +124,6 @@ FW_VERSIONS = { ], }, CAR.HONDA_CIVIC: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-5AA-A640\x00\x00', - b'37805-5AA-A650\x00\x00', - b'37805-5AA-A670\x00\x00', - b'37805-5AA-A680\x00\x00', - b'37805-5AA-A810\x00\x00', - b'37805-5AA-C640\x00\x00', - b'37805-5AA-C680\x00\x00', - b'37805-5AA-C820\x00\x00', - b'37805-5AA-L650\x00\x00', - b'37805-5AA-L660\x00\x00', - b'37805-5AA-L680\x00\x00', - b'37805-5AA-L690\x00\x00', - b'37805-5AA-L810\x00\x00', - b'37805-5AG-Q710\x00\x00', - b'37805-5AJ-A610\x00\x00', - b'37805-5AJ-A620\x00\x00', - b'37805-5AJ-L610\x00\x00', - b'37805-5BA-A310\x00\x00', - b'37805-5BA-A510\x00\x00', - b'37805-5BA-A740\x00\x00', - b'37805-5BA-A760\x00\x00', - b'37805-5BA-A930\x00\x00', - b'37805-5BA-A960\x00\x00', - b'37805-5BA-C640\x00\x00', - b'37805-5BA-C860\x00\x00', - b'37805-5BA-L410\x00\x00', - b'37805-5BA-L760\x00\x00', - b'37805-5BA-L930\x00\x00', - b'37805-5BA-L940\x00\x00', - b'37805-5BA-L960\x00\x00', - ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5CG-A040\x00\x00', b'28101-5CG-A050\x00\x00', @@ -242,61 +173,6 @@ FW_VERSIONS = { ], }, CAR.HONDA_CIVIC_BOSCH: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-5AA-A940\x00\x00', - b'37805-5AA-A950\x00\x00', - b'37805-5AA-C950\x00\x00', - b'37805-5AA-L940\x00\x00', - b'37805-5AA-L950\x00\x00', - b'37805-5AG-Z910\x00\x00', - b'37805-5AJ-A750\x00\x00', - b'37805-5AJ-L750\x00\x00', - b'37805-5AK-T530\x00\x00', - b'37805-5AN-A750\x00\x00', - b'37805-5AN-A830\x00\x00', - b'37805-5AN-A840\x00\x00', - b'37805-5AN-A930\x00\x00', - b'37805-5AN-A940\x00\x00', - b'37805-5AN-A950\x00\x00', - b'37805-5AN-AG20\x00\x00', - b'37805-5AN-AH20\x00\x00', - b'37805-5AN-AJ30\x00\x00', - b'37805-5AN-AK10\x00\x00', - b'37805-5AN-AK20\x00\x00', - b'37805-5AN-AR10\x00\x00', - b'37805-5AN-AR20\x00\x00', - b'37805-5AN-C650\x00\x00', - b'37805-5AN-CH20\x00\x00', - b'37805-5AN-E630\x00\x00', - b'37805-5AN-E720\x00\x00', - b'37805-5AN-E820\x00\x00', - b'37805-5AN-J820\x00\x00', - b'37805-5AN-L840\x00\x00', - b'37805-5AN-L930\x00\x00', - b'37805-5AN-L940\x00\x00', - b'37805-5AN-LF20\x00\x00', - b'37805-5AN-LH20\x00\x00', - b'37805-5AN-LJ20\x00\x00', - b'37805-5AN-LR20\x00\x00', - b'37805-5AN-LS20\x00\x00', - b'37805-5AW-G720\x00\x00', - b'37805-5AZ-E850\x00\x00', - b'37805-5AZ-G540\x00\x00', - b'37805-5AZ-G740\x00\x00', - b'37805-5AZ-G840\x00\x00', - b'37805-5BB-A530\x00\x00', - b'37805-5BB-A540\x00\x00', - b'37805-5BB-A620\x00\x00', - b'37805-5BB-A630\x00\x00', - b'37805-5BB-A640\x00\x00', - b'37805-5BB-C540\x00\x00', - b'37805-5BB-C630\x00\x00', - b'37805-5BB-C640\x00\x00', - b'37805-5BB-L540\x00\x00', - b'37805-5BB-L630\x00\x00', - b'37805-5BB-L640\x00\x00', - b'37805-5BF-J130\x00\x00', - ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5CG-A920\x00\x00', b'28101-5CG-AB10\x00\x00', @@ -400,10 +276,6 @@ FW_VERSIONS = { ], }, CAR.HONDA_CIVIC_BOSCH_DIESEL: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-59N-G630\x00\x00', - b'37805-59N-G830\x00\x00', - ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-59Y-G220\x00\x00', b'28101-59Y-G620\x00\x00', @@ -449,41 +321,6 @@ FW_VERSIONS = { ], }, CAR.HONDA_CRV_5G: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-5PA-3060\x00\x00', - b'37805-5PA-3080\x00\x00', - b'37805-5PA-3180\x00\x00', - b'37805-5PA-4050\x00\x00', - b'37805-5PA-4150\x00\x00', - b'37805-5PA-6520\x00\x00', - b'37805-5PA-6530\x00\x00', - b'37805-5PA-6630\x00\x00', - b'37805-5PA-6640\x00\x00', - b'37805-5PA-7630\x00\x00', - b'37805-5PA-9530\x00\x00', - b'37805-5PA-9630\x00\x00', - b'37805-5PA-9640\x00\x00', - b'37805-5PA-9730\x00\x00', - b'37805-5PA-9830\x00\x00', - b'37805-5PA-9840\x00\x00', - b'37805-5PA-A650\x00\x00', - b'37805-5PA-A670\x00\x00', - b'37805-5PA-A680\x00\x00', - b'37805-5PA-A850\x00\x00', - b'37805-5PA-A870\x00\x00', - b'37805-5PA-A880\x00\x00', - b'37805-5PA-A890\x00\x00', - b'37805-5PA-AB10\x00\x00', - b'37805-5PA-AD10\x00\x00', - b'37805-5PA-AF20\x00\x00', - b'37805-5PA-AF30\x00\x00', - b'37805-5PA-AH20\x00\x00', - b'37805-5PA-BF10\x00\x00', - b'37805-5PA-C680\x00\x00', - b'37805-5PD-Q630\x00\x00', - b'37805-5PF-F730\x00\x00', - b'37805-5PF-M630\x00\x00', - ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5RG-A020\x00\x00', b'28101-5RG-A030\x00\x00', @@ -559,10 +396,6 @@ FW_VERSIONS = { ], }, CAR.HONDA_CRV_EU: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-R5Z-G740\x00\x00', - b'37805-R5Z-G780\x00\x00', - ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-T1V-G920\x00\x00', ], @@ -663,24 +496,6 @@ FW_VERSIONS = { b'38897-THR-A010\x00\x00', b'38897-THR-A020\x00\x00', ], - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-5MR-3050\x00\x00', - b'37805-5MR-3150\x00\x00', - b'37805-5MR-3250\x00\x00', - b'37805-5MR-4070\x00\x00', - b'37805-5MR-4080\x00\x00', - b'37805-5MR-4170\x00\x00', - b'37805-5MR-4180\x00\x00', - b'37805-5MR-A240\x00\x00', - b'37805-5MR-A250\x00\x00', - b'37805-5MR-A310\x00\x00', - b'37805-5MR-A740\x00\x00', - b'37805-5MR-A750\x00\x00', - b'37805-5MR-A840\x00\x00', - b'37805-5MR-C620\x00\x00', - b'37805-5MR-D530\x00\x00', - b'37805-5MR-K730\x00\x00', - ], (Ecu.eps, 0x18da30f1, None): [ b'39990-THR-A020\x00\x00', b'39990-THR-A030\x00\x00', @@ -765,39 +580,6 @@ FW_VERSIONS = { b'28101-5EZ-A700\x00\x00', b'28103-5EY-A110\x00\x00', ], - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-RLV-4060\x00\x00', - b'37805-RLV-4070\x00\x00', - b'37805-RLV-5140\x00\x00', - b'37805-RLV-5230\x00\x00', - b'37805-RLV-5250\x00\x00', - b'37805-RLV-A630\x00\x00', - b'37805-RLV-A830\x00\x00', - b'37805-RLV-A840\x00\x00', - b'37805-RLV-B210\x00\x00', - b'37805-RLV-B220\x00\x00', - b'37805-RLV-B420\x00\x00', - b'37805-RLV-B430\x00\x00', - b'37805-RLV-B620\x00\x00', - b'37805-RLV-B710\x00\x00', - b'37805-RLV-B720\x00\x00', - b'37805-RLV-C430\x00\x00', - b'37805-RLV-C510\x00\x00', - b'37805-RLV-C520\x00\x00', - b'37805-RLV-C530\x00\x00', - b'37805-RLV-C910\x00\x00', - b'37805-RLV-F120\x00\x00', - b'37805-RLV-L080\x00\x00', - b'37805-RLV-L090\x00\x00', - b'37805-RLV-L150\x00\x00', - b'37805-RLV-L160\x00\x00', - b'37805-RLV-L180\x00\x00', - b'37805-RLV-L350\x00\x00', - b'37805-RLV-L410\x00\x00', - b'37805-RLV-L430\x00\x00', - b'37805-RLV-L830\x00\x00', - b'37805-RLV-L850\x00\x00', - ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TG7-A030\x00\x00', b'38897-TG7-A040\x00\x00', @@ -875,26 +657,6 @@ FW_VERSIONS = { ], }, CAR.ACURA_RDX_3G: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-5YF-A130\x00\x00', - b'37805-5YF-A230\x00\x00', - b'37805-5YF-A320\x00\x00', - b'37805-5YF-A330\x00\x00', - b'37805-5YF-A420\x00\x00', - b'37805-5YF-A430\x00\x00', - b'37805-5YF-A750\x00\x00', - b'37805-5YF-A760\x00\x00', - b'37805-5YF-A770\x00\x00', - b'37805-5YF-A850\x00\x00', - b'37805-5YF-A860\x00\x00', - b'37805-5YF-A870\x00\x00', - b'37805-5YF-AD20\x00\x00', - b'37805-5YF-C210\x00\x00', - b'37805-5YF-C220\x00\x00', - b'37805-5YF-C410\x00\x00', - b'37805-5YF-C420\x00\x00', - b'37805-5YF-C430\x00\x00', - ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TJB-A030\x00\x00', b'57114-TJB-A040\x00\x00', @@ -1049,10 +811,6 @@ FW_VERSIONS = { b'28101-6EH-A010\x00\x00', b'28101-6JC-M310\x00\x00', ], - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-6CT-A710\x00\x00', - b'37805-6HZ-M630\x00\x00', - ], (Ecu.electricBrakeBooster, 0x18da2bf1, None): [ b'46114-3W0-A020\x00\x00', ], @@ -1133,14 +891,5 @@ FW_VERSIONS = { b'28101-65H-A120\x00\x00', b'28101-65J-N010\x00\x00', ], - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-64A-A540\x00\x00', - b'37805-64A-A620\x00\x00', - b'37805-64D-P510\x00\x00', - b'37805-64L-A540\x00\x00', - b'37805-64S-A540\x00\x00', - b'37805-64S-A720\x00\x00', - b'37805-64S-AA10\x00\x00', - ], }, } diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 05f826d1b..c3005c667 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -307,6 +307,7 @@ FW_QUERY_CONFIG = FwQueryConfig( }, extra_ecus=[ (Ecu.combinationMeter, 0x18da60f1, None), + (Ecu.programmedFuelInjection, 0x18da10f1, None), # The only other ECU on PT bus accessible by camera on radarless Civic # This is likely a manufacturer-specific sub-address implementation: the camera responds to this and 0x18dab0f1 # Unclear what the part number refers to: 8S103 is 'Camera Set Mono', while 36160 is 'Camera Monocular - Honda' From bbc21b9f524a3790bb269ccbf4ff7e784992a82e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 4 Jun 2024 22:09:54 -0700 Subject: [PATCH 137/220] [bot] Fingerprints: add missing FW versions from new users (#32605) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 2 ++ selfdrive/car/hyundai/fingerprints.py | 3 +++ selfdrive/car/toyota/fingerprints.py | 1 + 3 files changed, 6 insertions(+) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 178905458..01faa49bf 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -557,6 +557,7 @@ FW_VERSIONS = { b'68467936AC ', b'68500630AD', b'68500630AE', + b'68500631AE', b'68502719AC ', b'68502722AC ', b'68502733AC ', @@ -603,6 +604,7 @@ FW_VERSIONS = { b'68484467AC', b'68484471AC', b'68502994AD', + b'68502996AD', b'68520867AE', b'68520867AF', b'68520870AC', diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 60a222b06..d115283dd 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -750,6 +750,7 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00DEhe SCC F-CUP 1.00 1.00 99110-G5600 ', + b'\xf1\x00DEhe SCC FHCUP 1.00 1.00 99110-G5600 ', ], }, CAR.KIA_NIRO_HEV_2021: { @@ -878,6 +879,7 @@ FW_VERSIONS = { b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AA000 200819', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AB000 220426', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111', + b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.07 99210-AA000 220426', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.08 99210-AA000 220728', ], (Ecu.abs, 0x7d1, None): [ @@ -1002,6 +1004,7 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00CE MFC AT CAN LHD 1.00 1.04 99211-KL000 221213', b'\xf1\x00CE MFC AT EUR LHD 1.00 1.03 99211-KL000 221011', + b'\xf1\x00CE MFC AT EUR LHD 1.00 1.04 99211-KL000 221213', b'\xf1\x00CE MFC AT USA LHD 1.00 1.04 99211-KL000 221213', ], }, diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index 631953571..0866a4d43 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -214,6 +214,7 @@ FW_VERSIONS = { b'8646F0601400 ', b'8646F0603400 ', b'8646F0603500 ', + b'8646F0604000 ', b'8646F0604100 ', b'8646F0605000 ', b'8646F0606000 ', From 1d61f320a8dafc067efdf3dcc68653c8fc5dee60 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 5 Jun 2024 23:49:58 +0800 Subject: [PATCH 138/220] cabana: stop stream thread before exiting main event loop (#32634) stop stream thread before exiting main event loop --- tools/cabana/cabana.cc | 5 ++--- tools/cabana/streams/abstractstream.cc | 2 ++ tools/cabana/streams/replaystream.cc | 4 ++++ tools/cabana/streams/replaystream.h | 1 + tools/replay/replay.cc | 1 + 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index bb29a7e3a..4a3b4126d 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -91,7 +91,6 @@ int main(int argc, char *argv[]) { w.openStream(); } w.show(); - int ret = app.exec(); - delete can; - return ret; + + return app.exec(); } diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 540634b9b..2e6ca9662 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -3,6 +3,7 @@ #include #include +#include #include "common/timing.h" #include "tools/cabana/settings.h" @@ -19,6 +20,7 @@ AbstractStream::AbstractStream(QObject *parent) : QObject(parent) { assert(parent != nullptr); event_buffer_ = std::make_unique(EVENT_NEXT_BUFFER_SIZE); + QObject::connect(QApplication::instance(), &QCoreApplication::aboutToQuit, this, &AbstractStream::stop); QObject::connect(this, &AbstractStream::privateUpdateLastMsgsSignal, this, &AbstractStream::updateLastMessages, Qt::QueuedConnection); QObject::connect(this, &AbstractStream::seekedTo, this, &AbstractStream::updateLastMsgsTo); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &AbstractStream::updateMasks); diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 3c3e431ce..b1768fcdc 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -64,6 +64,10 @@ void ReplayStream::start() { replay->start(); } +void ReplayStream::stop() { + replay.reset(nullptr); +} + bool ReplayStream::eventFilter(const Event *event) { static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index e3278d9a3..049ccddaf 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -16,6 +16,7 @@ class ReplayStream : public AbstractStream { public: ReplayStream(QObject *parent); void start() override; + void stop() override; bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); bool eventFilter(const Event *event); void seekTo(double ts) override; diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 6a159aa8e..f477e327e 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -56,6 +56,7 @@ Replay::~Replay() { stream_thread_->quit(); stream_thread_->wait(); delete stream_thread_; + stream_thread_ = nullptr; } timeline_future.waitForFinished(); rInfo("shutdown: done"); From 59a30972427584505ac2cd7838beab2ef31481ce Mon Sep 17 00:00:00 2001 From: Yassine Date: Wed, 5 Jun 2024 11:42:22 -0700 Subject: [PATCH 139/220] 0.9.7 model release notes --- RELEASES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index c79f4ae88..7688646cc 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,9 @@ Version 0.9.7 (2024-06-11) ======================== * New driving model + * Inputs the past curvature for a smoother and more accurate lateral control + * Simplified neural network architecture in the model's last layers + * Minor fixes: desire augmentation, weight decay * Adjust driving personality with the follow distance button * Added toggle to enable driver monitoring even when openpilot is not engaged * Support for hybrid variants of supported Ford models From 449d70333c4ae8db2d369ac5180f3f6983feddeb Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 5 Jun 2024 13:22:19 -0700 Subject: [PATCH 140/220] Update RELEASES.md --- RELEASES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 7688646cc..31fdd1561 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,9 +1,9 @@ Version 0.9.7 (2024-06-11) ======================== * New driving model - * Inputs the past curvature for a smoother and more accurate lateral control + * Inputs the past curvature for smoother and more accurate lateral control * Simplified neural network architecture in the model's last layers - * Minor fixes: desire augmentation, weight decay + * Minor fixes to desire augmentation and weight decay * Adjust driving personality with the follow distance button * Added toggle to enable driver monitoring even when openpilot is not engaged * Support for hybrid variants of supported Ford models From 95263340493ed516c9a2f84ce770276560007b89 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 5 Jun 2024 14:00:55 -0700 Subject: [PATCH 141/220] jenkins: fix unsafe checkout when changing submodules (#32635) do it twice --- selfdrive/test/setup_device_ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh index 5c85312f1..84dae2582 100755 --- a/selfdrive/test/setup_device_ci.sh +++ b/selfdrive/test/setup_device_ci.sh @@ -70,6 +70,7 @@ safe_checkout() { git checkout $GIT_COMMIT git clean -xdff git submodule sync + git submodule foreach --recursive "git reset --hard && git clean -xdff" git submodule update --init --recursive git submodule foreach --recursive "git reset --hard && git clean -xdff" @@ -95,6 +96,7 @@ unsafe_checkout() { git reset --hard $GIT_COMMIT git clean -df git submodule sync + git submodule foreach --recursive "git reset --hard && git clean -df" git submodule update --init --recursive git submodule foreach --recursive "git reset --hard && git clean -df" From 7381872a544f48daa3b1f26cf88a61714083801b Mon Sep 17 00:00:00 2001 From: Riley Williams Date: Wed, 5 Jun 2024 17:34:02 -0400 Subject: [PATCH 142/220] 2024 IONIQ 6 (#32302) * Tweak carspecs for 2023 (and now also 24) ioniq 6 to reflect public info instead of cloning ioniq 5 specs * Regenerated car docs * revert specs *for now* --------- Co-authored-by: Riley Williams Co-authored-by: Riley Williams Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 26b7fe203..7861bb654 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -93,7 +93,7 @@ A supported vehicle is one that just works when you install a comma device. All |Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Ioniq 6 (with HDA II) 2023[5](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Ioniq 6 (with HDA II) 2023-24[5](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Ioniq Electric 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 9b01a2e12..f27bdb45b 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -314,7 +314,7 @@ class CAR(Platforms): flags=HyundaiFlags.EV, ) HYUNDAI_IONIQ_6 = HyundaiCanFDPlatformConfig( - [HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))], + [HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))], HYUNDAI_IONIQ_5.specs, flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE, ) From 7b092858172220efd6805d3586355c0f393b2d86 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 5 Jun 2024 14:50:25 -0700 Subject: [PATCH 143/220] pandad: move to core 3 (#32402) * move to core 3 * core is fully offlined now * move to init --------- Co-authored-by: Comma Device --- selfdrive/pandad/main.cc | 2 +- system/hardware/tici/hardware.py | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/selfdrive/pandad/main.cc b/selfdrive/pandad/main.cc index f6f43d372..b63d884a4 100644 --- a/selfdrive/pandad/main.cc +++ b/selfdrive/pandad/main.cc @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) { int err; err = util::set_realtime_priority(54); assert(err == 0); - err = util::set_core_affinity({4}); + err = util::set_core_affinity({3}); assert(err == 0); } diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 57fbf9d63..b6b41c472 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -380,22 +380,18 @@ class Tici(HardwareBase): # *** CPU config *** # offline big cluster, leave core 4 online for pandad - for i in range(5, 8): + for i in range(4, 8): val = '0' if powersave_enabled else '1' sudo_write(val, f'/sys/devices/system/cpu/cpu{i}/online') for n in ('0', '4'): + if powersave_enabled and n == '4': + continue gov = 'ondemand' if powersave_enabled else 'performance' sudo_write(gov, f'/sys/devices/system/cpu/cpufreq/policy{n}/scaling_governor') # *** IRQ config *** - # pandad core - affine_irq(4, "spi_geni") # SPI - affine_irq(4, "xhci-hcd:usb3") # aux panda USB (or potentially anything else on USB) - if "tici" in self.get_device_type(): - affine_irq(4, "xhci-hcd:usb1") # internal panda USB (also modem) - # GPU affine_irq(5, "kgsl-3d0") @@ -453,6 +449,18 @@ class Tici(HardwareBase): sudo_write("N", "/sys/kernel/debug/msm_vidc/clock_scaling") sudo_write("Y", "/sys/kernel/debug/msm_vidc/disable_thermal_mitigation") + # pandad core + affine_irq(3, "spi_geni") # SPI + if "tici" in self.get_device_type(): + affine_irq(3, "xhci-hcd:usb3") # aux panda USB (or potentially anything else on USB) + affine_irq(3, "xhci-hcd:usb1") # internal panda USB (also modem) + try: + pid = subprocess.check_output(["pgrep", "-f", "spi0"], encoding='utf8').strip() + subprocess.call(["sudo", "chrt", "-f", "-p", "1", pid]) + subprocess.call(["sudo", "taskset", "-pc", "3", pid]) + except subprocess.CalledProcessException as e: + print(str(e)) + def configure_modem(self): sim_id = self.get_sim_info().get('sim_id', '') From a46f1c6eba712e2814619d37427a3aaaee50fc3a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 5 Jun 2024 15:23:25 -0700 Subject: [PATCH 144/220] pandad: add jungle spam mode to test (#32636) Co-authored-by: Comma Device --- selfdrive/pandad/tests/test_pandad_spi.py | 27 ++++++++++++++++------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/selfdrive/pandad/tests/test_pandad_spi.py b/selfdrive/pandad/tests/test_pandad_spi.py index 3447ea378..ed81c1ea2 100644 --- a/selfdrive/pandad/tests/test_pandad_spi.py +++ b/selfdrive/pandad/tests/test_pandad_spi.py @@ -10,6 +10,7 @@ from openpilot.system.hardware import HARDWARE from openpilot.selfdrive.test.helpers import phone_only, with_processes from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages +JUNGLE_SPAM = "JUNGLE_SPAM" in os.environ @pytest.mark.tici class TestBoarddSpi: @@ -18,9 +19,9 @@ class TestBoarddSpi: if HARDWARE.get_device_type() == 'tici': pytest.skip("only for spi pandas") os.environ['STARTED'] = '1' - os.environ['BOARDD_LOOPBACK'] = '1' - #os.environ['SPI_ERR_PROB'] = '-1' os.environ['SPI_ERR_PROB'] = '0.001' + if not JUNGLE_SPAM: + os.environ['BOARDD_LOOPBACK'] = '1' @phone_only @with_processes(['pandad']) @@ -39,12 +40,13 @@ class TestBoarddSpi: st = time.monotonic() ts = {s: list() for s in socks.keys()} - for _ in range(20): + for _ in range(int(os.getenv("TEST_TIME", "20"))): # send some CAN messages - sent = send_random_can_messages(sendcan, random.randrange(2, 20)) - for k, v in sent.items(): - sent_msgs[k].extend(list(v)) - total_sent_count += len(v) + if not JUNGLE_SPAM: + sent = send_random_can_messages(sendcan, random.randrange(2, 20)) + for k, v in sent.items(): + sent_msgs[k].extend(list(v)) + total_sent_count += len(v) for service, sock in socks.items(): for m in messaging.drain_sock(sock): @@ -54,6 +56,15 @@ class TestBoarddSpi: assert m.valid or (service == "can") if service == "can": for msg in m.can: + if JUNGLE_SPAM: + # PandaJungle.set_generated_can(True) + i = msg.address - 0x200 + assert msg.address >= 0x200 + assert msg.src == (i%3) + assert msg.dat == b"\xff"*(i%8) + total_recv_count += 1 + continue + if msg.src > 4: continue key = (msg.address, msg.dat) @@ -91,5 +102,5 @@ class TestBoarddSpi: assert len(dts) >= ((et-0.5)*SERVICE_LIST[service].frequency*0.8) with subtests.test(msg="CAN traffic"): - print(f"Sent {total_sent_count} CAN messages, got {total_recv_count} back. {total_recv_count/total_sent_count:.2%} received") + print(f"Sent {total_sent_count} CAN messages, got {total_recv_count} back. {total_recv_count/(total_sent_count+1e-4):.2%} received") assert total_recv_count > 20 From 51fdf2330453fe863597db0eb8daf87c2ec4ff8d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 5 Jun 2024 15:58:00 -0700 Subject: [PATCH 145/220] thermald is hardwared (#32637) * thermald is deviced * hardwared * rename --- common/realtime.py | 2 +- pyproject.toml | 3 +-- selfdrive/test/test_onroad.py | 2 +- system/camerad/snapshot/snapshot.py | 2 +- .../{thermald => hardware}/fan_controller.py | 4 ++-- .../thermald.py => hardware/hardwared.py} | 24 +++++++++---------- .../power_monitoring.py | 0 .../{thermald => hardware/tests}/__init__.py | 0 .../tests/test_fan_controller.py | 2 +- .../tests/test_power_monitoring.py | 6 ++--- system/hardware/tici/hardware.py | 2 +- system/manager/process_config.py | 2 +- system/thermald/tests/__init__.py | 0 13 files changed, 24 insertions(+), 25 deletions(-) rename system/{thermald => hardware}/fan_controller.py (94%) rename system/{thermald/thermald.py => hardware/hardwared.py} (96%) rename system/{thermald => hardware}/power_monitoring.py (100%) rename system/{thermald => hardware/tests}/__init__.py (100%) rename system/{thermald => hardware}/tests/test_fan_controller.py (96%) rename system/{thermald => hardware}/tests/test_power_monitoring.py (97%) delete mode 100644 system/thermald/tests/__init__.py diff --git a/common/realtime.py b/common/realtime.py index 16e9a220e..dd97ea3d7 100644 --- a/common/realtime.py +++ b/common/realtime.py @@ -12,7 +12,7 @@ from openpilot.system.hardware import PC # time step for each process DT_CTRL = 0.01 # controlsd DT_MDL = 0.05 # model -DT_TRML = 0.5 # thermald and manager +DT_HW = 0.5 # hardwared and manager DT_DMON = 0.05 # driver monitoring diff --git a/pyproject.toml b/pyproject.toml index 5f6994829..8642eff4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,10 +29,9 @@ testpaths = [ "selfdrive/test/longitudinal_maneuvers", "selfdrive/test/process_replay/test_fuzzy.py", "system/updated", - "system/thermald", "system/athena", "system/camerad", - "system/hardware/tici", + "system/hardware", "system/loggerd", "system/proclogd", "system/tests", diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index bcdf71f8e..75585e2f1 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -47,7 +47,7 @@ PROCS = { "selfdrive.controls.radard": 7.0, "selfdrive.modeld.modeld": 13.0, "selfdrive.modeld.dmonitoringmodeld": 8.0, - "system.thermald.thermald": 3.87, + "system.hardware.hardwared": 3.87, "selfdrive.locationd.calibrationd": 2.0, "selfdrive.locationd.torqued": 5.0, "selfdrive.ui.soundd": 3.5, diff --git a/system/camerad/snapshot/snapshot.py b/system/camerad/snapshot/snapshot.py index d9377eebe..381240212 100755 --- a/system/camerad/snapshot/snapshot.py +++ b/system/camerad/snapshot/snapshot.py @@ -83,7 +83,7 @@ def snapshot(): front_camera_allowed = params.get_bool("RecordFront") params.put_bool("IsTakingSnapshot", True) set_offroad_alert("Offroad_IsTakingSnapshot", True) - time.sleep(2.0) # Give thermald time to read the param, or if just started give camerad time to start + time.sleep(2.0) # Give hardwared time to read the param, or if just started give camerad time to start # Check if camerad is already started try: diff --git a/system/thermald/fan_controller.py b/system/hardware/fan_controller.py similarity index 94% rename from system/thermald/fan_controller.py rename to system/hardware/fan_controller.py index 19c3292ce..f32133f6b 100755 --- a/system/thermald/fan_controller.py +++ b/system/hardware/fan_controller.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from abc import ABC, abstractmethod -from openpilot.common.realtime import DT_TRML +from openpilot.common.realtime import DT_HW from openpilot.common.numpy_fast import interp from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.controls.lib.pid import PIDController @@ -18,7 +18,7 @@ class TiciFanController(BaseFanController): cloudlog.info("Setting up TICI fan handler") self.last_ignition = False - self.controller = PIDController(k_p=0, k_i=4e-3, k_f=1, rate=(1 / DT_TRML)) + self.controller = PIDController(k_p=0, k_i=4e-3, k_f=1, rate=(1 / DT_HW)) def update(self, cur_temp: float, ignition: bool) -> int: self.controller.neg_limit = -(100 if ignition else 30) diff --git a/system/thermald/thermald.py b/system/hardware/hardwared.py similarity index 96% rename from system/thermald/thermald.py rename to system/hardware/hardwared.py index 90f6494a2..e3a4c8171 100755 --- a/system/thermald/thermald.py +++ b/system/hardware/hardwared.py @@ -15,14 +15,14 @@ from cereal.services import SERVICE_LIST from openpilot.common.dict_helpers import strip_deprecated_keys from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.params import Params -from openpilot.common.realtime import DT_TRML +from openpilot.common.realtime import DT_HW from openpilot.selfdrive.controls.lib.alertmanager import set_offroad_alert from openpilot.system.hardware import HARDWARE, TICI, AGNOS from openpilot.system.loggerd.config import get_available_percent from openpilot.system.statsd import statlog from openpilot.common.swaglog import cloudlog -from openpilot.system.thermald.power_monitoring import PowerMonitoring -from openpilot.system.thermald.fan_controller import TiciFanController +from openpilot.system.hardware.power_monitoring import PowerMonitoring +from openpilot.system.hardware.fan_controller import TiciFanController from openpilot.system.version import terms_version, training_version ThermalStatus = log.DeviceState.ThermalStatus @@ -106,7 +106,7 @@ def hw_state_thread(end_event, hw_queue): while not end_event.is_set(): # these are expensive calls. update every 10s - if (count % int(10. / DT_TRML)) == 0: + if (count % int(10. / DT_HW)) == 0: try: network_type = HARDWARE.get_network_type() modem_temps = HARDWARE.get_modem_temperatures() @@ -159,10 +159,10 @@ def hw_state_thread(end_event, hw_queue): cloudlog.exception("Error getting hardware state") count += 1 - time.sleep(DT_TRML) + time.sleep(DT_HW) -def thermald_thread(end_event, hw_queue) -> None: +def hardware_thread(end_event, hw_queue) -> None: pm = messaging.PubMaster(['deviceState']) sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates"], poll="pandaStates") @@ -190,8 +190,8 @@ def thermald_thread(end_event, hw_queue) -> None: modem_temps=[], ) - all_temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML, initialized=False) - offroad_temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML, initialized=False) + all_temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_HW, initialized=False) + offroad_temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_HW, initialized=False) should_start_prev = False in_car = False engaged_prev = False @@ -232,7 +232,7 @@ def thermald_thread(end_event, hw_queue) -> None: # Run at 2Hz, plus rising edge of ignition ign_edge = started_ts is None and onroad_conditions["ignition"] - if (sm.frame % round(SERVICE_LIST['pandaStates'].frequency * DT_TRML) != 0) and not ign_edge: + if (sm.frame % round(SERVICE_LIST['pandaStates'].frequency * DT_HW) != 0) and not ign_edge: continue msg = read_thermal(thermal_config) @@ -349,7 +349,7 @@ def thermald_thread(end_event, hw_queue) -> None: try: with open('/dev/kmsg', 'w') as kmsg: - kmsg.write(f"<3>[thermald] engaged: {engaged}\n") + kmsg.write(f"<3>[hardware] engaged: {engaged}\n") except Exception: pass @@ -423,7 +423,7 @@ def thermald_thread(end_event, hw_queue) -> None: # report to server once every 10 minutes rising_edge_started = should_start and not should_start_prev - if rising_edge_started or (count % int(600. / DT_TRML)) == 0: + if rising_edge_started or (count % int(600. / DT_HW)) == 0: dat = { 'count': count, 'pandaStates': [strip_deprecated_keys(p.to_dict()) for p in pandaStates], @@ -452,7 +452,7 @@ def main(): threads = [ threading.Thread(target=hw_state_thread, args=(end_event, hw_queue)), - threading.Thread(target=thermald_thread, args=(end_event, hw_queue)), + threading.Thread(target=hardware_thread, args=(end_event, hw_queue)), ] for t in threads: diff --git a/system/thermald/power_monitoring.py b/system/hardware/power_monitoring.py similarity index 100% rename from system/thermald/power_monitoring.py rename to system/hardware/power_monitoring.py diff --git a/system/thermald/__init__.py b/system/hardware/tests/__init__.py similarity index 100% rename from system/thermald/__init__.py rename to system/hardware/tests/__init__.py diff --git a/system/thermald/tests/test_fan_controller.py b/system/hardware/tests/test_fan_controller.py similarity index 96% rename from system/thermald/tests/test_fan_controller.py rename to system/hardware/tests/test_fan_controller.py index ffbf180ac..002c1edfd 100644 --- a/system/thermald/tests/test_fan_controller.py +++ b/system/hardware/tests/test_fan_controller.py @@ -1,6 +1,6 @@ import pytest -from openpilot.system.thermald.fan_controller import TiciFanController +from openpilot.system.hardware.fan_controller import TiciFanController ALL_CONTROLLERS = [TiciFanController] diff --git a/system/thermald/tests/test_power_monitoring.py b/system/hardware/tests/test_power_monitoring.py similarity index 97% rename from system/thermald/tests/test_power_monitoring.py rename to system/hardware/tests/test_power_monitoring.py index 95166094b..1dff6c6c5 100644 --- a/system/thermald/tests/test_power_monitoring.py +++ b/system/hardware/tests/test_power_monitoring.py @@ -1,7 +1,7 @@ import pytest from openpilot.common.params import Params -from openpilot.system.thermald.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \ +from openpilot.system.hardware.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \ CAR_CHARGING_RATE_W, VBATT_PAUSE_CHARGING, DELAY_SHUTDOWN_TIME_S # Create fake time @@ -17,9 +17,9 @@ VOLTAGE_BELOW_PAUSE_CHARGING = (VBATT_PAUSE_CHARGING - 1) * 1e3 def pm_patch(mocker, name, value, constant=False): if constant: - mocker.patch(f"openpilot.system.thermald.power_monitoring.{name}", value) + mocker.patch(f"openpilot.system.hardware.power_monitoring.{name}", value) else: - mocker.patch(f"openpilot.system.thermald.power_monitoring.{name}", return_value=value) + mocker.patch(f"openpilot.system.hardware.power_monitoring.{name}", return_value=value) @pytest.fixture(autouse=True) diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index b6b41c472..a5dee88b5 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -412,7 +412,7 @@ class Tici(HardwareBase): if self.amplifier is not None: self.amplifier.initialize_configuration(self.get_device_type()) - # Allow thermald to write engagement status to kmsg + # Allow hardwared to write engagement status to kmsg os.system("sudo chmod a+w /dev/kmsg") # Ensure fan gpio is enabled so fan runs until shutdown, also turned on at boot by the ABL diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 25c5f4649..ced31077c 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -76,7 +76,7 @@ procs = [ PythonProcess("pigeond", "system.ubloxd.pigeond", ublox, enabled=TICI), PythonProcess("plannerd", "selfdrive.controls.plannerd", only_onroad), PythonProcess("radard", "selfdrive.controls.radard", only_onroad), - PythonProcess("thermald", "system.thermald.thermald", always_run), + PythonProcess("hardwared", "system.hardware.hardwared", always_run), PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC), PythonProcess("updated", "system.updated.updated", only_offroad, enabled=not PC), PythonProcess("uploader", "system.loggerd.uploader", always_run), diff --git a/system/thermald/tests/__init__.py b/system/thermald/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 From e828a7bdcf7744102a321b68076ad7842ec31af4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 5 Jun 2024 17:27:57 -0700 Subject: [PATCH 146/220] pandad: add more context to spi logs (#32639) * pandad: add more context to spi logs * cleanup --------- Co-authored-by: Comma Device --- selfdrive/pandad/panda_comms.h | 10 ++++++++++ selfdrive/pandad/spi.cc | 35 +++++++++++++++++----------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/selfdrive/pandad/panda_comms.h b/selfdrive/pandad/panda_comms.h index 6b64768c1..9c452faf6 100644 --- a/selfdrive/pandad/panda_comms.h +++ b/selfdrive/pandad/panda_comms.h @@ -56,6 +56,13 @@ private: }; #ifndef __APPLE__ +struct __attribute__((packed)) spi_header { + uint8_t sync; + uint8_t endpoint; + uint16_t tx_len; + uint16_t max_rx_len; +}; + class PandaSpiHandle : public PandaCommsHandle { public: PandaSpiHandle(std::string serial); @@ -79,5 +86,8 @@ private: int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout); int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout); int lltransfer(spi_ioc_transfer &t); + + spi_header header; + uint32_t xfer_count = 0; }; #endif diff --git a/selfdrive/pandad/spi.cc b/selfdrive/pandad/spi.cc index 836df5986..e2bef203e 100644 --- a/selfdrive/pandad/spi.cc +++ b/selfdrive/pandad/spi.cc @@ -28,13 +28,6 @@ enum SpiError { ACK_TIMEOUT = -3, }; -struct __attribute__((packed)) spi_header { - uint8_t sync; - uint8_t endpoint; - uint16_t tx_len; - uint16_t max_rx_len; -}; - const unsigned int SPI_ACK_TIMEOUT = 500; // milliseconds const std::string SPI_DEVICE = "/dev/spidev0.0"; @@ -55,6 +48,11 @@ private: std::recursive_mutex &m; }; +#define SPILOG(fn, fmt, ...) do { \ + fn(fmt, ## __VA_ARGS__); \ + fn(" %d / 0x%x / %d / %d", \ + xfer_count, header.endpoint, header.tx_len, header.max_rx_len); \ + } while(0) PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { int ret; @@ -178,7 +176,7 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t } if (d < 0) { - LOGE("SPI: bulk transfer failed with %d", d); + SPILOG(LOGE, "SPI: bulk transfer failed with %d", d); comms_healthy = false; return d; } @@ -247,7 +245,7 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1 } while (ret < 0 && connected && !timed_out); if (ret < 0) { - LOGE("transfer failed, after %d tries, %.2fms", timeout_count, millis_since_boot() - start_time); + SPILOG(LOGE, "transfer failed, after %d tries, %.2fms", timeout_count, millis_since_boot() - start_time); } return ret; @@ -270,20 +268,20 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout, while (true) { int ret = lltransfer(transfer); if (ret < 0) { - LOGE("SPI: failed to send ACK request"); + SPILOG(LOGE, "SPI: failed to send ACK request"); return ret; } if (rx_buf[0] == ack) { break; } else if (rx_buf[0] == SPI_NACK) { - LOGD("SPI: got NACK"); + SPILOG(LOGD, "SPI: got NACK"); return SpiError::NACK; } // handle timeout if (millis_since_boot() - start_millis > timeout) { - LOGD("SPI: timed out waiting for ACK"); + SPILOG(LOGW, "SPI: timed out waiting for ACK"); return SpiError::ACK_TIMEOUT; } } @@ -334,7 +332,8 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx assert(tx_len < SPI_BUF_SIZE); assert(max_rx_len < SPI_BUF_SIZE); - spi_header header = { + xfer_count++; + header = { .sync = SPI_SYNC, .endpoint = endpoint, .tx_len = tx_len, @@ -352,7 +351,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx transfer.len = sizeof(header) + 1; ret = lltransfer(transfer); if (ret < 0) { - LOGE("SPI: failed to send header"); + SPILOG(LOGE, "SPI: failed to send header"); return ret; } @@ -370,7 +369,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx transfer.len = tx_len + 1; ret = lltransfer(transfer); if (ret < 0) { - LOGE("SPI: failed to send data"); + SPILOG(LOGE, "SPI: failed to send data"); return ret; } @@ -383,7 +382,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx // Read data rx_data_len = *(uint16_t *)(rx_buf+1); if (rx_data_len >= SPI_BUF_SIZE) { - LOGE("SPI: RX data len larger than buf size %d", rx_data_len); + SPILOG(LOGE, "SPI: RX data len larger than buf size %d", rx_data_len); return -1; } @@ -391,11 +390,11 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx transfer.rx_buf = (uint64_t)(rx_buf + 2 + 1); ret = lltransfer(transfer); if (ret < 0) { - LOGE("SPI: failed to read rx data"); + SPILOG(LOGE, "SPI: failed to read rx data"); return ret; } if (!check_checksum(rx_buf, rx_data_len + 4)) { - LOGE("SPI: bad checksum"); + SPILOG(LOGE, "SPI: bad checksum"); return -1; } From 260e18f0aedc3bdbf65b357948e6b5067a296439 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 5 Jun 2024 17:32:47 -0700 Subject: [PATCH 147/220] fix linter --- selfdrive/pandad/spi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/pandad/spi.cc b/selfdrive/pandad/spi.cc index e2bef203e..f4882addf 100644 --- a/selfdrive/pandad/spi.cc +++ b/selfdrive/pandad/spi.cc @@ -52,7 +52,7 @@ private: fn(fmt, ## __VA_ARGS__); \ fn(" %d / 0x%x / %d / %d", \ xfer_count, header.endpoint, header.tx_len, header.max_rx_len); \ - } while(0) + } while (0) PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { int ret; From 7cfd91bb69ce1a8ccc9c1f25907d33d14e8181d4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 5 Jun 2024 18:03:23 -0700 Subject: [PATCH 148/220] Restore lateral limits report (#32640) * stash * staaaaash * clean up * more clean up * fix fix * fix * stash clean up * more * this is just simpler to understand * explicitly check --- selfdrive/car/tests/test_lateral_limits.py | 33 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) mode change 100644 => 100755 selfdrive/car/tests/test_lateral_limits.py diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py old mode 100644 new mode 100755 index 39cdb9a74..1d58c52ad --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -1,7 +1,9 @@ +#!/usr/bin/env python3 from collections import defaultdict import importlib from parameterized import parameterized_class import pytest +import sys from openpilot.common.realtime import DT_CTRL from openpilot.selfdrive.car.car_helpers import interfaces @@ -19,8 +21,6 @@ MAX_LAT_JERK_UP_TOLERANCE = 0.5 # m/s^3 # jerk is measured over half a second JERK_MEAS_T = 0.5 -car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict) - @parameterized_class('car_model', [(c,) for c in sorted(CAR_MODELS)]) class TestLateralLimits: @@ -63,9 +63,36 @@ class TestLateralLimits: def test_jerk_limits(self): up_jerk, down_jerk = self.calculate_0_5s_jerk(self.control_params, self.torque_params) - car_model_jerks[self.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk} assert up_jerk <= MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE assert down_jerk <= MAX_LAT_JERK_DOWN def test_max_lateral_accel(self): assert self.torque_params["MAX_LAT_ACCEL_MEASURED"] <= MAX_LAT_ACCEL + + +class LatAccelReport: + car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict) + + def pytest_sessionfinish(self): + print(f"\n\n---- Lateral limit report ({len(CAR_MODELS)} cars) ----\n") + + max_car_model_len = max([len(car_model) for car_model in self.car_model_jerks]) + for car_model, _jerks in sorted(self.car_model_jerks.items(), key=lambda i: i[1]['up_jerk'], reverse=True): + violation = _jerks["up_jerk"] > MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE or \ + _jerks["down_jerk"] > MAX_LAT_JERK_DOWN + violation_str = " - VIOLATION" if violation else "" + + print(f"{car_model:{max_car_model_len}} - up jerk: {round(_jerks['up_jerk'], 2):5} " + + f"m/s^3, down jerk: {round(_jerks['down_jerk'], 2):5} m/s^3{violation_str}") + + @pytest.fixture(scope="class", autouse=True) + def class_setup(self, request): + yield + cls = request.cls + if hasattr(cls, "control_params"): + up_jerk, down_jerk = TestLateralLimits.calculate_0_5s_jerk(cls.control_params, cls.torque_params) + self.car_model_jerks[cls.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk} + + +if __name__ == '__main__': + sys.exit(pytest.main([__file__, '-n0', '--no-summary'], plugins=[LatAccelReport()])) # noqa: TID251 From 91fd918fcbed4f5aa828d0ec59169c42d50cdcd0 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 6 Jun 2024 09:04:03 +0800 Subject: [PATCH 149/220] car/interfaces.py: optimize `parse_gear_shifter()` with predefined dictionary (#32592) Optimize gear shifter parsing for improved performance --- selfdrive/car/interfaces.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index a9ff1eedd..b29b5a55d 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -33,6 +33,18 @@ TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/params.tom TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.toml') TORQUE_SUBSTITUTE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/substitute.toml') +GEAR_SHIFTER_MAP: dict[str, car.CarState.GearShifter] = { + 'P': GearShifter.park, 'PARK': GearShifter.park, + 'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse, + 'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral, + 'E': GearShifter.eco, 'ECO': GearShifter.eco, + 'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic, + 'D': GearShifter.drive, 'DRIVE': GearShifter.drive, + 'S': GearShifter.sport, 'SPORT': GearShifter.sport, + 'L': GearShifter.low, 'LOW': GearShifter.low, + 'B': GearShifter.brake, 'BRAKE': GearShifter.brake, +} + class LatControlInputs(NamedTuple): lateral_acceleration: float @@ -424,19 +436,7 @@ class CarStateBase(ABC): def parse_gear_shifter(gear: str | None) -> car.CarState.GearShifter: if gear is None: return GearShifter.unknown - - d: dict[str, car.CarState.GearShifter] = { - 'P': GearShifter.park, 'PARK': GearShifter.park, - 'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse, - 'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral, - 'E': GearShifter.eco, 'ECO': GearShifter.eco, - 'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic, - 'D': GearShifter.drive, 'DRIVE': GearShifter.drive, - 'S': GearShifter.sport, 'SPORT': GearShifter.sport, - 'L': GearShifter.low, 'LOW': GearShifter.low, - 'B': GearShifter.brake, 'BRAKE': GearShifter.brake, - } - return d.get(gear.upper(), GearShifter.unknown) + return GEAR_SHIFTER_MAP.get(gear.upper(), GearShifter.unknown) @staticmethod def get_can_parser(CP): From a418c9e40a273dc83efefb46a2ef5a034d9c92d3 Mon Sep 17 00:00:00 2001 From: Solomon Jones <31631573+eszjay@users.noreply.github.com> Date: Wed, 5 Jun 2024 23:18:29 -0500 Subject: [PATCH 150/220] Fingerprint for 2017 Subaru Forester (#32584) Fingerprint for 2017 Forester --- selfdrive/car/subaru/fingerprints.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/subaru/fingerprints.py b/selfdrive/car/subaru/fingerprints.py index e3bd9d909..10c713501 100644 --- a/selfdrive/car/subaru/fingerprints.py +++ b/selfdrive/car/subaru/fingerprints.py @@ -311,6 +311,7 @@ FW_VERSIONS = { b'\x00\x00d\xd3\x1f@ \t', ], (Ecu.engine, 0x7e0, None): [ + b'\xa7"@0\x07', b'\xa7"@p\x07', b'\xa7)\xa0q\x07', b'\xba"@@\x07', @@ -319,6 +320,7 @@ FW_VERSIONS = { (Ecu.transmission, 0x7e1, None): [ b'\x1a\xf6F`\x00', b'\xda\xf2`\x80\x00', + b'\xda\xf2`p\x00', b'\xda\xfd\xe0\x80\x00', b'\xdc\xf2@`\x00', b'\xdc\xf2``\x00', From 045b9f20b717e7c5d68f84df4715bb596530b046 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 6 Jun 2024 12:21:16 +0800 Subject: [PATCH 151/220] improve get_torque_params (#32586) * Loading torque data only once and reusing it across function calls. * apply review * still check only one entry * fix that --------- Co-authored-by: Shane Smiskol --- selfdrive/car/interfaces.py | 36 ++++++++++++---------- selfdrive/car/tests/test_lateral_limits.py | 2 +- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index b29b5a55d..a3572238b 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -57,29 +57,33 @@ TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.L @cache -def get_torque_params(candidate): +def get_torque_params(): with open(TORQUE_SUBSTITUTE_PATH, 'rb') as f: sub = tomllib.load(f) - if candidate in sub: - candidate = sub[candidate] - with open(TORQUE_PARAMS_PATH, 'rb') as f: params = tomllib.load(f) with open(TORQUE_OVERRIDE_PATH, 'rb') as f: override = tomllib.load(f) - # Ensure no overlap - if sum([candidate in x for x in [sub, params, override]]) > 1: - raise RuntimeError(f'{candidate} is defined twice in torque config') + torque_params = {} + for candidate in (sub.keys() | params.keys() | override.keys()) - {'legend'}: + if sum([candidate in x for x in [sub, params, override]]) > 1: + raise RuntimeError(f'{candidate} is defined twice in torque config') - if candidate in override: - out = override[candidate] - elif candidate in params: - out = params[candidate] - else: - raise NotImplementedError(f"Did not find torque params for {candidate}") - return {key: out[i] for i, key in enumerate(params['legend'])} + sub_candidate = sub.get(candidate, candidate) + if sub_candidate in override: + out = override[sub_candidate] + elif sub_candidate in params: + out = params[sub_candidate] + else: + raise NotImplementedError(f"Did not find torque params for {sub_candidate}") + + torque_params[sub_candidate] = {key: out[i] for i, key in enumerate(params['legend'])} + if candidate in sub: + torque_params[candidate] = torque_params[sub_candidate] + + return torque_params # generic car and radar interfaces @@ -180,7 +184,7 @@ class CarInterfaceBase(ABC): ret.carFingerprint = candidate # Car docs fields - ret.maxLateralAccel = get_torque_params(candidate)['MAX_LAT_ACCEL_MEASURED'] + ret.maxLateralAccel = get_torque_params()[candidate]['MAX_LAT_ACCEL_MEASURED'] ret.autoResumeSng = True # describes whether car can resume from a stop automatically # standard ALC params @@ -213,7 +217,7 @@ class CarInterfaceBase(ABC): @staticmethod def configure_torque_tune(candidate, tune, steering_angle_deadzone_deg=0.0, use_steering_angle=True): - params = get_torque_params(candidate) + params = get_torque_params()[candidate] tune.init('torque') tune.torque.useSteeringAngle = use_steering_angle diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py index 1d58c52ad..e61d197f4 100755 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -43,7 +43,7 @@ class TestLateralLimits: CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams cls.control_params = CarControllerParams(CP) - cls.torque_params = get_torque_params(cls.car_model) + cls.torque_params = get_torque_params()[cls.car_model] @staticmethod def calculate_0_5s_jerk(control_params, torque_params): From ae375091dbc86aaca7a1bf2d9e7e3e9281a33495 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 5 Jun 2024 23:44:19 -0700 Subject: [PATCH 152/220] Genesis G70 2020: use common specs (#32641) use non-2020 specs --- selfdrive/car/hyundai/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index f27bdb45b..c489ea004 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -515,7 +515,7 @@ class CAR(Platforms): # TODO: From 3.3T Sport Advanced 2022 & Prestige 2023 Trim, 2.0T is unknown HyundaiCarDocs("Genesis G70 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])), ], - CarSpecs(mass=3673 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=12.9), + GENESIS_G70.specs, flags=HyundaiFlags.MANDO_RADAR, ) GENESIS_GV70_1ST_GEN = HyundaiCanFDPlatformConfig( From 3a43f5d7844611cd5c770748b7d235974c3eb97d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 6 Jun 2024 14:48:20 +0800 Subject: [PATCH 153/220] fuzzy_generation.py: improve performance (#32591) * improve performance * remove DEPRECATED * formatting * catch kjException --------- Co-authored-by: Shane Smiskol --- selfdrive/test/fuzzy_generation.py | 88 ++++++++++++++---------------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/selfdrive/test/fuzzy_generation.py b/selfdrive/test/fuzzy_generation.py index 26c35c0c1..0dc2e44ee 100644 --- a/selfdrive/test/fuzzy_generation.py +++ b/selfdrive/test/fuzzy_generation.py @@ -2,6 +2,7 @@ import capnp import hypothesis.strategies as st from typing import Any from collections.abc import Callable +from functools import cache from cereal import log @@ -11,67 +12,62 @@ DrawType = Callable[[st.SearchStrategy], Any] class FuzzyGenerator: def __init__(self, draw: DrawType, real_floats: bool): self.draw = draw - self.real_floats = real_floats + self.native_type_map = FuzzyGenerator._get_native_type_map(real_floats) def generate_native_type(self, field: str) -> st.SearchStrategy[bool | int | float | str | bytes]: - def floats(**kwargs) -> st.SearchStrategy[float]: - allow_nan = not self.real_floats - allow_infinity = not self.real_floats - return st.floats(**kwargs, allow_nan=allow_nan, allow_infinity=allow_infinity) - - if field == 'bool': - return st.booleans() - elif field == 'int8': - return st.integers(min_value=-2**7, max_value=2**7-1) - elif field == 'int16': - return st.integers(min_value=-2**15, max_value=2**15-1) - elif field == 'int32': - return st.integers(min_value=-2**31, max_value=2**31-1) - elif field == 'int64': - return st.integers(min_value=-2**63, max_value=2**63-1) - elif field == 'uint8': - return st.integers(min_value=0, max_value=2**8-1) - elif field == 'uint16': - return st.integers(min_value=0, max_value=2**16-1) - elif field == 'uint32': - return st.integers(min_value=0, max_value=2**32-1) - elif field == 'uint64': - return st.integers(min_value=0, max_value=2**64-1) - elif field == 'float32': - return floats(width=32) - elif field == 'float64': - return floats(width=64) - elif field == 'text': - return st.text(max_size=1000) - elif field == 'data': - return st.binary(max_size=1000) - elif field == 'anyPointer': - return st.text() + value_func = self.native_type_map.get(field) + if value_func: + return value_func else: - raise NotImplementedError(f'Invalid type : {field}') + raise NotImplementedError(f'Invalid type: {field}') def generate_field(self, field: capnp.lib.capnp._StructSchemaField) -> st.SearchStrategy: def rec(field_type: capnp.lib.capnp._DynamicStructReader) -> st.SearchStrategy: - if field_type.which() == 'struct': + type_which = field_type.which() + if type_which == 'struct': return self.generate_struct(field.schema.elementType if base_type == 'list' else field.schema) - elif field_type.which() == 'list': + elif type_which == 'list': return st.lists(rec(field_type.list.elementType)) - elif field_type.which() == 'enum': + elif type_which == 'enum': schema = field.schema.elementType if base_type == 'list' else field.schema return st.sampled_from(list(schema.enumerants.keys())) else: - return self.generate_native_type(field_type.which()) + return self.generate_native_type(type_which) - if 'slot' in field.proto.to_dict(): - base_type = field.proto.slot.type.which() - return rec(field.proto.slot.type) - else: + try: + if hasattr(field.proto, 'slot'): + slot_type = field.proto.slot.type + base_type = slot_type.which() + return rec(slot_type) + else: + return self.generate_struct(field.schema) + except capnp.lib.capnp.KjException: return self.generate_struct(field.schema) def generate_struct(self, schema: capnp.lib.capnp._StructSchema, event: str = None) -> st.SearchStrategy[dict[str, Any]]: - full_fill: list[str] = list(schema.non_union_fields) - single_fill: list[str] = [event] if event else [self.draw(st.sampled_from(schema.union_fields))] if schema.union_fields else [] - return st.fixed_dictionaries({field: self.generate_field(schema.fields[field]) for field in full_fill + single_fill}) + single_fill: tuple[str, ...] = (event,) if event else (self.draw(st.sampled_from(schema.union_fields)),) if schema.union_fields else () + fields_to_generate = schema.non_union_fields + single_fill + return st.fixed_dictionaries({field: self.generate_field(schema.fields[field]) for field in fields_to_generate if not field.endswith('DEPRECATED')}) + + @staticmethod + @cache + def _get_native_type_map(real_floats: bool) -> dict[str, st.SearchStrategy]: + return { + 'bool': st.booleans(), + 'int8': st.integers(min_value=-2**7, max_value=2**7-1), + 'int16': st.integers(min_value=-2**15, max_value=2**15-1), + 'int32': st.integers(min_value=-2**31, max_value=2**31-1), + 'int64': st.integers(min_value=-2**63, max_value=2**63-1), + 'uint8': st.integers(min_value=0, max_value=2**8-1), + 'uint16': st.integers(min_value=0, max_value=2**16-1), + 'uint32': st.integers(min_value=0, max_value=2**32-1), + 'uint64': st.integers(min_value=0, max_value=2**64-1), + 'float32': st.floats(width=32, allow_nan=not real_floats, allow_infinity=not real_floats), + 'float64': st.floats(width=64, allow_nan=not real_floats, allow_infinity=not real_floats), + 'text': st.text(max_size=1000), + 'data': st.binary(max_size=1000), + 'anyPointer': st.text(), # Note: No need to define a separate function for anyPointer + } @classmethod def get_random_msg(cls, draw: DrawType, struct: capnp.lib.capnp._StructModule, real_floats: bool = False) -> dict[str, Any]: From 983063c3e6ce344b8569814fcdc2eafc2830c4e9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 6 Jun 2024 15:13:57 +0800 Subject: [PATCH 154/220] events.py: rename event counters (#32596) * improve prev event counters * just rename --------- Co-authored-by: Shane Smiskol --- selfdrive/controls/lib/events.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index e697eb010..b01818d70 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -51,7 +51,7 @@ class Events: def __init__(self): self.events: list[int] = [] self.static_events: list[int] = [] - self.events_prev = dict.fromkeys(EVENTS.keys(), 0) + self.event_counters = dict.fromkeys(EVENTS.keys(), 0) @property def names(self) -> list[int]: @@ -66,7 +66,7 @@ class Events: bisect.insort(self.events, event_name) def clear(self) -> None: - self.events_prev = {k: (v + 1 if k in self.events else 0) for k, v in self.events_prev.items()} + self.event_counters = {k: (v + 1 if k in self.events else 0) for k, v in self.event_counters.items()} self.events = self.static_events.copy() def contains(self, event_type: str) -> bool: @@ -85,7 +85,7 @@ class Events: if not isinstance(alert, Alert): alert = alert(*callback_args) - if DT_CTRL * (self.events_prev[e] + 1) >= alert.creation_delay: + if DT_CTRL * (self.event_counters[e] + 1) >= alert.creation_delay: alert.alert_type = f"{EVENT_NAME[e]}/{et}" alert.event_type = et ret.append(alert) From e8857a6713db6b8b3b8cd67aca1b8c046a4dccd9 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Thu, 6 Jun 2024 01:14:28 -0700 Subject: [PATCH 155/220] [Lag] Increase Optima Lag (#32583) increase lag in optima to 0.2 --- selfdrive/car/hyundai/interface.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 00452a9ae..22c54bce6 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -75,6 +75,9 @@ class CarInterface(CarInterfaceBase): ret.steerLimitTimer = 0.4 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + if candidate == CAR.KIA_OPTIMA_G4_FL: + ret.steerActuatorDelay = 0.2 + # *** longitudinal control *** if candidate in CANFD_CAR: ret.longitudinalTuning.kpV = [0.1] From 4c549778c0b0bd4430f2ec18023c40d3a6252a1a Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:59:57 -0400 Subject: [PATCH 156/220] CI/tools_test: remove redundant `git lfs pull` (#32642) remove redundant --- .github/workflows/tools_tests.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index b3cfd56d1..10c5b7091 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -47,7 +47,6 @@ jobs: - uses: actions/checkout@v4 with: submodules: true - - run: git lfs pull - uses: ./.github/workflows/setup-with-retry - name: Build openpilot run: | From e71ec4e8d7e39a56235f590227e7cb361cd8b79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 6 Jun 2024 14:31:56 -0700 Subject: [PATCH 157/220] Split cereal into cereal/msgq (#32631) * squash * fix doc * compile device * compile device * Update ref * add msgq to precommit exclusions * No service ports * fix compile * address comments * More comments * Delete logger * Update opendbc * Linting * bump msgq --- .gitignore | 2 + .gitmodules | 4 +- .pre-commit-config.yaml | 12 +- Dockerfile.openpilot | 1 + SConstruct | 3 + cereal | 1 - cereal/.pre-commit-config.yaml | 47 + cereal/Dockerfile | 54 + cereal/LICENSE | 7 + cereal/README.md | 60 + cereal/SConscript | 31 + cereal/__init__.py | 9 + cereal/car.capnp | 706 +++++ cereal/codecov.yml | 8 + cereal/custom.capnp | 39 + cereal/generate_javascript.sh | 26 + cereal/include/c++.capnp | 26 + cereal/legacy.capnp | 574 ++++ cereal/log.capnp | 2369 +++++++++++++++++ cereal/maptile.capnp | 49 + cereal/messaging/.gitignore | 10 + cereal/messaging/__init__.py | 306 +++ cereal/messaging/bridge.cc | 92 + cereal/messaging/demo.cc | 50 + cereal/messaging/demo.py | 29 + cereal/messaging/messaging.h | 112 + cereal/messaging/msgq.md | 54 + cereal/messaging/msgq_tests.cc | 394 +++ cereal/messaging/socketmaster.cc | 211 ++ cereal/messaging/stress.py | 14 + cereal/messaging/test_runner.cc | 2 + cereal/messaging/tests/__init__.py | 0 cereal/messaging/tests/test_fake.py | 193 ++ cereal/messaging/tests/test_messaging.py | 247 ++ cereal/messaging/tests/test_poller.py | 142 + cereal/messaging/tests/test_pub_sub_master.py | 163 ++ cereal/messaging/tests/test_services.py | 25 + cereal/services.py | 118 + docs/c_docs.rst | 4 +- msgq | 1 + opendbc | 2 +- selfdrive/controls/controlsd.py | 2 +- selfdrive/locationd/SConscript | 4 +- selfdrive/modeld/dmonitoringmodeld.py | 2 +- selfdrive/modeld/modeld.py | 2 +- selfdrive/modeld/models/commonmodel.pxd | 2 +- selfdrive/modeld/models/commonmodel_pyx.pxd | 4 +- selfdrive/modeld/models/commonmodel_pyx.pyx | 4 +- selfdrive/modeld/runners/snpemodel.pxd | 2 +- selfdrive/modeld/runners/thneedmodel.pxd | 2 +- selfdrive/modeld/tests/test_modeld.py | 2 +- selfdrive/navd/SConscript | 4 +- selfdrive/navd/map_renderer.h | 2 +- selfdrive/navd/tests/test_map_renderer.py | 2 +- selfdrive/pandad/SConscript | 4 +- .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/vision_meta.py | 2 +- selfdrive/ui/SConscript | 4 +- selfdrive/ui/qt/widgets/cameraview.h | 2 +- selfdrive/ui/tests/test_ui/run.py | 2 +- system/camerad/SConscript | 4 +- system/camerad/cameras/camera_common.h | 2 +- system/camerad/snapshot/snapshot.py | 2 +- system/hardware/base.h | 2 +- system/logcatd/SConscript | 4 +- system/loggerd/SConscript | 4 +- system/loggerd/encoder/encoder.h | 2 +- system/loggerd/loggerd.cc | 2 +- system/loggerd/loggerd.h | 2 +- system/loggerd/tests/test_loggerd.py | 2 +- system/proclogd/SConscript | 4 +- system/sensord/SConscript | 4 +- system/ubloxd/SConscript | 4 +- tools/cabana/SConscript | 4 +- tools/camerastream/compressed_vipc.py | 2 +- tools/replay/SConscript | 4 +- tools/replay/camera.h | 2 +- tools/replay/framereader.h | 2 +- tools/replay/ui.py | 2 +- tools/sim/Dockerfile.sim | 1 + tools/sim/lib/camerad.py | 2 +- tools/webcam/camerad.py | 2 +- 82 files changed, 6240 insertions(+), 66 deletions(-) delete mode 160000 cereal create mode 100644 cereal/.pre-commit-config.yaml create mode 100644 cereal/Dockerfile create mode 100644 cereal/LICENSE create mode 100644 cereal/README.md create mode 100644 cereal/SConscript create mode 100644 cereal/__init__.py create mode 100644 cereal/car.capnp create mode 100644 cereal/codecov.yml create mode 100644 cereal/custom.capnp create mode 100755 cereal/generate_javascript.sh create mode 100644 cereal/include/c++.capnp create mode 100644 cereal/legacy.capnp create mode 100644 cereal/log.capnp create mode 100644 cereal/maptile.capnp create mode 100644 cereal/messaging/.gitignore create mode 100644 cereal/messaging/__init__.py create mode 100644 cereal/messaging/bridge.cc create mode 100644 cereal/messaging/demo.cc create mode 100644 cereal/messaging/demo.py create mode 100644 cereal/messaging/messaging.h create mode 100644 cereal/messaging/msgq.md create mode 100644 cereal/messaging/msgq_tests.cc create mode 100644 cereal/messaging/socketmaster.cc create mode 100644 cereal/messaging/stress.py create mode 100644 cereal/messaging/test_runner.cc create mode 100644 cereal/messaging/tests/__init__.py create mode 100644 cereal/messaging/tests/test_fake.py create mode 100755 cereal/messaging/tests/test_messaging.py create mode 100644 cereal/messaging/tests/test_poller.py create mode 100755 cereal/messaging/tests/test_pub_sub_master.py create mode 100755 cereal/messaging/tests/test_services.py create mode 100755 cereal/services.py create mode 160000 msgq diff --git a/.gitignore b/.gitignore index 4bc5fd3a2..370335e6a 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,8 @@ compare_runtime*.html persist selfdrive/pandad/pandad +cereal/services.h +cereal/gen selfdrive/logcatd/logcatd selfdrive/mapd/default_speeds_by_region.json system/proclogd/proclogd diff --git a/.gitmodules b/.gitmodules index 73f832b1d..ee65939b6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,8 +4,8 @@ [submodule "opendbc"] path = opendbc url = ../../commaai/opendbc.git -[submodule "cereal"] - path = cereal +[submodule "msgq"] + path = msgq url = ../../commaai/cereal.git [submodule "rednose_repo"] path = rednose_repo diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 68d303cd6..75ddcfb61 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: rev: v2.2.6 hooks: - id: codespell - exclude: '^(third_party/)|(body/)|(cereal/)|(panda/)|(opendbc/)|(rednose/)|(rednose_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)' + exclude: '^(third_party/)|(body/)|(msgq/)|(panda/)|(opendbc/)|(rednose/)|(rednose_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)' args: # if you've got a short variable name that's getting flagged, add it here - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints @@ -36,7 +36,7 @@ repos: rev: v0.4.4 hooks: - id: ruff - exclude: '^(third_party/)|(cereal/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' + exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' - repo: local hooks: - id: mypy @@ -47,7 +47,7 @@ repos: args: - --local-partial-types - --explicit-package-bases - exclude: '^(third_party/)|(body/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' + exclude: '^(third_party/)|(body/)|(msgq/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' - repo: local hooks: - id: cppcheck @@ -55,7 +55,7 @@ repos: entry: cppcheck language: system types: [c++] - exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)' + exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)' args: - --error-exitcode=1 - --language=c++ @@ -66,7 +66,7 @@ repos: rev: 1.6.1 hooks: - id: cpplint - exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)' + exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)' args: - --quiet - --counting=total @@ -78,7 +78,7 @@ repos: rev: v0.16.2 hooks: - id: cython-lint - exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)' + exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)' args: - --max-line-length=240 - --ignore=E111, E302, E305 diff --git a/Dockerfile.openpilot b/Dockerfile.openpilot index 1e15722bb..9aa1aa8b7 100644 --- a/Dockerfile.openpilot +++ b/Dockerfile.openpilot @@ -20,6 +20,7 @@ COPY ./release ${OPENPILOT_PATH}/release COPY ./common ${OPENPILOT_PATH}/common COPY ./opendbc ${OPENPILOT_PATH}/opendbc COPY ./cereal ${OPENPILOT_PATH}/cereal +COPY ./msgq ${OPENPILOT_PATH}/msgq COPY ./panda ${OPENPILOT_PATH}/panda COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive COPY ./system ${OPENPILOT_PATH}/system diff --git a/SConstruct b/SConstruct index df34d5af9..ba49d926a 100644 --- a/SConstruct +++ b/SConstruct @@ -209,6 +209,7 @@ env = Environment( "#third_party/qrcode", "#third_party", "#cereal", + "#msgq", "#opendbc/can", "#third_party/maplibre-native-qt/include", f"#third_party/maplibre-native-qt/{arch}/include" @@ -224,6 +225,7 @@ env = Environment( CXXFLAGS=["-std=c++1z"] + cxxflags, LIBPATH=libpath + [ "#cereal", + "#msgq", "#third_party", "#opendbc/can", "#selfdrive/pandad", @@ -357,6 +359,7 @@ gpucommon = [_gpucommon] Export('common', 'gpucommon') # Build cereal and messaging +SConscript(['msgq/SConscript']) SConscript(['cereal/SConscript']) # Build other submodules diff --git a/cereal b/cereal deleted file mode 160000 index d0ceac712..000000000 --- a/cereal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0ceac712f531c125923cbdc4ec7bedbdc5a7baf diff --git a/cereal/.pre-commit-config.yaml b/cereal/.pre-commit-config.yaml new file mode 100644 index 000000000..03360e0f9 --- /dev/null +++ b/cereal/.pre-commit-config.yaml @@ -0,0 +1,47 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-ast + - id: check-yaml + - id: check-executables-have-shebangs + - id: check-shebang-scripts-are-executable +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.9.0 + hooks: + - id: mypy +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.5 + hooks: + - id: ruff +- repo: local + hooks: + - id: cppcheck + name: cppcheck + entry: cppcheck + language: system + types: [c++] + exclude: '^(messaging/msgq_tests.cc|messaging/test_runner.cc)' + args: + - --error-exitcode=1 + - --inline-suppr + - --language=c++ + - --force + - --quiet + - -j4 +- repo: https://github.com/cpplint/cpplint + rev: 1.6.1 + hooks: + - id: cpplint + args: + - --quiet + - --counting=detailed + - --linelength=240 + - --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces +- repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + args: + - -L ned + - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US diff --git a/cereal/Dockerfile b/cereal/Dockerfile new file mode 100644 index 000000000..d2e3ab591 --- /dev/null +++ b/cereal/Dockerfile @@ -0,0 +1,54 @@ +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + autoconf \ + build-essential \ + ca-certificates \ + capnproto \ + clang \ + cppcheck \ + curl \ + git \ + libbz2-dev \ + libcapnp-dev \ + libclang-rt-dev \ + libffi-dev \ + liblzma-dev \ + libncurses5-dev \ + libncursesw5-dev \ + libreadline-dev \ + libsqlite3-dev \ + libssl-dev \ + libtool \ + libzmq3-dev \ + llvm \ + make \ + cmake \ + ocl-icd-opencl-dev \ + opencl-headers \ + python3-dev \ + python3-pip \ + tk-dev \ + wget \ + xz-utils \ + zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* + +RUN pip3 install --break-system-packages --no-cache-dir pyyaml Cython scons pycapnp pre-commit ruff parameterized coverage numpy + +WORKDIR /project/ +RUN cd /tmp/ && \ + git clone -b v2.x --depth 1 https://github.com/catchorg/Catch2.git && \ + cd Catch2 && \ + mv single_include/catch2/ /project/ && \ + cd .. \ + rm -rf Catch2 + +WORKDIR /project/cereal + +ENV PYTHONPATH=/project + +COPY . . +RUN rm -rf .git && \ + scons -c && scons -j$(nproc) diff --git a/cereal/LICENSE b/cereal/LICENSE new file mode 100644 index 000000000..f1fd199c6 --- /dev/null +++ b/cereal/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2020, Comma.ai, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cereal/README.md b/cereal/README.md new file mode 100644 index 000000000..e3326aab0 --- /dev/null +++ b/cereal/README.md @@ -0,0 +1,60 @@ +# What is cereal? [![cereal tests](https://github.com/commaai/cereal/workflows/tests/badge.svg?event=push)](https://github.com/commaai/cereal/actions) [![codecov](https://codecov.io/gh/commaai/cereal/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/cereal) + +cereal is both a messaging spec for robotics systems as well as generic high performance IPC pub sub messaging with a single publisher and multiple subscribers. + +Imagine this use case: +* A sensor process reads gyro measurements directly from an IMU and publishes a `sensorEvents` packet +* A calibration process subscribes to the `sensorEvents` packet to use the IMU +* A localization process subscribes to the `sensorEvents` packet to use the IMU also + + +## Messaging Spec + +You'll find the message types in [log.capnp](log.capnp). It uses [Cap'n proto](https://capnproto.org/capnp-tool.html) and defines one struct called `Event`. + +All `Events` have a `logMonoTime` and a `valid`. Then a big union defines the packet type. + +### Best Practices + +- **All fields must describe quantities in SI units**, unless otherwise specified in the field name. +- In the context of the message they are in, field names should be completely unambiguous. +- All values should be easy to plot and be human-readable with minimal parsing. + +### Maintaining backwards-compatibility + +When making changes to the messaging spec you want to maintain backwards-compatibility, such that old logs can +be parsed with a new version of cereal. Adding structs and adding members to structs is generally safe, most other +things are not. Read more details [here](https://capnproto.org/language.html). + +### Custom forks + +Forks of [openpilot](https://github.com/commaai/openpilot) might want to add things to the messaging +spec, however this could conflict with future changes made in mainline cereal/openpilot. Rebasing against mainline openpilot +then means breaking backwards-compatibility with all old logs of your fork. So we added reserved events in +[custom.capnp](custom.capnp) that we will leave empty in mainline cereal/openpilot. **If you only modify those, you can ensure your +fork will remain backwards-compatible with all versions of mainline cereal/openpilot and your fork.** + +## Pub Sub Backends + +cereal supports two backends, one based on [zmq](https://zeromq.org/) and another called [msgq](messaging/msgq.cc), a custom pub sub based on shared memory that doesn't require the bytes to pass through the kernel. + +Example +--- +```python +import cereal.messaging as messaging + +# in subscriber +sm = messaging.SubMaster(['sensorEvents']) +while 1: + sm.update() + print(sm['sensorEvents']) + +``` + +```python +# in publisher +pm = messaging.PubMaster(['sensorEvents']) +dat = messaging.new_message('sensorEvents', size=1) +dat.sensorEvents[0] = {"gyro": {"v": [0.1, -0.1, 0.1]}} +pm.send('sensorEvents', dat) +``` diff --git a/cereal/SConscript b/cereal/SConscript new file mode 100644 index 000000000..5a71abbb8 --- /dev/null +++ b/cereal/SConscript @@ -0,0 +1,31 @@ +Import('env', 'envCython', 'arch', 'common', 'messaging') + +import shutil + +cereal_dir = Dir('.') +gen_dir = Dir('gen') +other_dir = Dir('#msgq/messaging') + +# Build cereal +schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp'] +env.Command(["gen/c/include/c++.capnp.h"], [], "mkdir -p " + gen_dir.path + "/c/include && touch $TARGETS") +env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files], + schema_files, + f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/") + +# TODO: remove non shared cereal and messaging +cereal_objects = env.SharedObject([f'gen/cpp/{s}.c++' for s in schema_files]) + +cereal = env.Library('cereal', cereal_objects) +env.SharedLibrary('cereal_shared', cereal_objects) + +# Build messaging + +services_h = env.Command(['services.h'], ['services.py'], 'python3 ' + cereal_dir.path + '/services.py > $TARGET') +env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[messaging, 'zmq', common]) + + +socketmaster = env.SharedObject(['messaging/socketmaster.cc']) +socketmaster = env.Library('socketmaster', socketmaster) + +Export('cereal', 'socketmaster') diff --git a/cereal/__init__.py b/cereal/__init__.py new file mode 100644 index 000000000..89c5cf38e --- /dev/null +++ b/cereal/__init__.py @@ -0,0 +1,9 @@ +import os +import capnp + +CEREAL_PATH = os.path.dirname(os.path.abspath(__file__)) +capnp.remove_import_hook() + +log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp")) +car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp")) +custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp")) diff --git a/cereal/car.capnp b/cereal/car.capnp new file mode 100644 index 000000000..d7ec1b248 --- /dev/null +++ b/cereal/car.capnp @@ -0,0 +1,706 @@ +using Cxx = import "./include/c++.capnp"; +$Cxx.namespace("cereal"); + +@0x8e2af1e708af8b8d; + +# ******* events causing controls state machine transition ******* + +struct CarEvent @0x9b1657f34caf3ad3 { + name @0 :EventName; + + # event types + enable @1 :Bool; + noEntry @2 :Bool; + warning @3 :Bool; # alerts presented only when enabled or soft disabling + userDisable @4 :Bool; + softDisable @5 :Bool; + immediateDisable @6 :Bool; + preEnable @7 :Bool; + permanent @8 :Bool; # alerts presented regardless of openpilot state + overrideLateral @10 :Bool; + overrideLongitudinal @9 :Bool; + + enum EventName @0xbaa8c5d505f727de { + canError @0; + steerUnavailable @1; + wrongGear @4; + doorOpen @5; + seatbeltNotLatched @6; + espDisabled @7; + wrongCarMode @8; + steerTempUnavailable @9; + reverseGear @10; + buttonCancel @11; + buttonEnable @12; + pedalPressed @13; # exits active state + preEnableStandstill @73; # added during pre-enable state with brake + gasPressedOverride @108; # added when user is pressing gas with no disengage on gas + steerOverride @114; + cruiseDisabled @14; + speedTooLow @17; + outOfSpace @18; + overheat @19; + calibrationIncomplete @20; + calibrationInvalid @21; + calibrationRecalibrating @117; + controlsMismatch @22; + pcmEnable @23; + pcmDisable @24; + radarFault @26; + brakeHold @28; + parkBrake @29; + manualRestart @30; + lowSpeedLockout @31; + joystickDebug @34; + steerTempUnavailableSilent @35; + resumeRequired @36; + preDriverDistracted @37; + promptDriverDistracted @38; + driverDistracted @39; + preDriverUnresponsive @43; + promptDriverUnresponsive @44; + driverUnresponsive @45; + belowSteerSpeed @46; + lowBattery @48; + accFaulted @51; + sensorDataInvalid @52; + commIssue @53; + commIssueAvgFreq @109; + tooDistracted @54; + posenetInvalid @55; + soundsUnavailable @56; + preLaneChangeLeft @57; + preLaneChangeRight @58; + laneChange @59; + lowMemory @63; + stockAeb @64; + ldw @65; + carUnrecognized @66; + invalidLkasSetting @69; + speedTooHigh @70; + laneChangeBlocked @71; + relayMalfunction @72; + stockFcw @74; + startup @75; + startupNoCar @76; + startupNoControl @77; + startupMaster @78; + startupNoFw @104; + fcw @79; + steerSaturated @80; + belowEngageSpeed @84; + noGps @85; + wrongCruiseMode @87; + modeldLagging @89; + deviceFalling @90; + fanMalfunction @91; + cameraMalfunction @92; + cameraFrameRate @110; + processNotRunning @95; + dashcamMode @96; + controlsInitializing @98; + usbError @99; + roadCameraError @100; + driverCameraError @101; + wideRoadCameraError @102; + highCpuUsage @105; + cruiseMismatch @106; + lkasDisabled @107; + canBusMissing @111; + controlsdLagging @112; + resumeBlocked @113; + steerTimeLimit @115; + vehicleSensorsInvalid @116; + locationdTemporaryError @103; + locationdPermanentError @118; + paramsdTemporaryError @50; + paramsdPermanentError @119; + actuatorsApiUnavailable @120; + + radarCanErrorDEPRECATED @15; + communityFeatureDisallowedDEPRECATED @62; + radarCommIssueDEPRECATED @67; + driverMonitorLowAccDEPRECATED @68; + gasUnavailableDEPRECATED @3; + dataNeededDEPRECATED @16; + modelCommIssueDEPRECATED @27; + ipasOverrideDEPRECATED @33; + geofenceDEPRECATED @40; + driverMonitorOnDEPRECATED @41; + driverMonitorOffDEPRECATED @42; + calibrationProgressDEPRECATED @47; + invalidGiraffeHondaDEPRECATED @49; + invalidGiraffeToyotaDEPRECATED @60; + internetConnectivityNeededDEPRECATED @61; + whitePandaUnsupportedDEPRECATED @81; + commIssueWarningDEPRECATED @83; + focusRecoverActiveDEPRECATED @86; + neosUpdateRequiredDEPRECATED @88; + modelLagWarningDEPRECATED @93; + startupOneplusDEPRECATED @82; + startupFuzzyFingerprintDEPRECATED @97; + noTargetDEPRECATED @25; + brakeUnavailableDEPRECATED @2; + plannerErrorDEPRECATED @32; + gpsMalfunctionDEPRECATED @94; + } +} + +# ******* main car state @ 100hz ******* +# all speeds in m/s + +struct CarState { + events @13 :List(CarEvent); + + # CAN health + canValid @26 :Bool; # invalid counter/checksums + canTimeout @40 :Bool; # CAN bus dropped out + canErrorCounter @48 :UInt32; + canRcvTimeout @49 :Bool; + + # car speed + vEgo @1 :Float32; # best estimate of speed + aEgo @16 :Float32; # best estimate of acceleration + vEgoRaw @17 :Float32; # unfiltered speed from CAN sensors + vEgoCluster @44 :Float32; # best estimate of speed shown on car's instrument cluster, used for UI + + yawRate @22 :Float32; # best estimate of yaw rate + standstill @18 :Bool; + wheelSpeeds @2 :WheelSpeeds; + + # gas pedal, 0.0-1.0 + gas @3 :Float32; # this is user pedal only + gasPressed @4 :Bool; # this is user pedal only + + engineRpm @46 :Float32; + + # brake pedal, 0.0-1.0 + brake @5 :Float32; # this is user pedal only + brakePressed @6 :Bool; # this is user pedal only + regenBraking @45 :Bool; # this is user pedal only + parkingBrake @39 :Bool; + brakeHoldActive @38 :Bool; + + # steering wheel + steeringAngleDeg @7 :Float32; + steeringAngleOffsetDeg @37 :Float32; # Offset betweens sensors in case there multiple + steeringRateDeg @15 :Float32; + steeringTorque @8 :Float32; # TODO: standardize units + steeringTorqueEps @27 :Float32; # TODO: standardize units + steeringPressed @9 :Bool; # if the user is using the steering wheel + steerFaultTemporary @35 :Bool; # temporary EPS fault + steerFaultPermanent @36 :Bool; # permanent EPS fault + stockAeb @30 :Bool; + stockFcw @31 :Bool; + espDisabled @32 :Bool; + accFaulted @42 :Bool; + carFaultedNonCritical @47 :Bool; # some ECU is faulted, but car remains controllable + + # cruise state + cruiseState @10 :CruiseState; + + # gear + gearShifter @14 :GearShifter; + + # button presses + buttonEvents @11 :List(ButtonEvent); + leftBlinker @20 :Bool; + rightBlinker @21 :Bool; + genericToggle @23 :Bool; + + # lock info + doorOpen @24 :Bool; + seatbeltUnlatched @25 :Bool; + + # clutch (manual transmission only) + clutchPressed @28 :Bool; + + # blindspot sensors + leftBlindspot @33 :Bool; # Is there something blocking the left lane change + rightBlindspot @34 :Bool; # Is there something blocking the right lane change + + fuelGauge @41 :Float32; # battery or fuel tank level from 0.0 to 1.0 + charging @43 :Bool; + + # process meta + cumLagMs @50 :Float32; + + struct WheelSpeeds { + # optional wheel speeds + fl @0 :Float32; + fr @1 :Float32; + rl @2 :Float32; + rr @3 :Float32; + } + + struct CruiseState { + enabled @0 :Bool; + speed @1 :Float32; + speedCluster @6 :Float32; # Set speed as shown on instrument cluster + available @2 :Bool; + speedOffset @3 :Float32; + standstill @4 :Bool; + nonAdaptive @5 :Bool; + } + + enum GearShifter { + unknown @0; + park @1; + drive @2; + neutral @3; + reverse @4; + sport @5; + low @6; + brake @7; + eco @8; + manumatic @9; + } + + # send on change + struct ButtonEvent { + pressed @0 :Bool; + type @1 :Type; + + enum Type { + unknown @0; + leftBlinker @1; + rightBlinker @2; + accelCruise @3; + decelCruise @4; + cancel @5; + altButton1 @6; + altButton2 @7; + altButton3 @8; + setCruise @9; + resumeCruise @10; + gapAdjustCruise @11; + } + } + + # deprecated + errorsDEPRECATED @0 :List(CarEvent.EventName); + brakeLightsDEPRECATED @19 :Bool; + steeringRateLimitedDEPRECATED @29 :Bool; + canMonoTimesDEPRECATED @12: List(UInt64); +} + +# ******* radar state @ 20hz ******* + +struct RadarData @0x888ad6581cf0aacb { + errors @0 :List(Error); + points @1 :List(RadarPoint); + + enum Error { + canError @0; + fault @1; + wrongConfig @2; + } + + # similar to LiveTracks + # is one timestamp valid for all? I think so + struct RadarPoint { + trackId @0 :UInt64; # no trackId reuse + + # these 3 are the minimum required + dRel @1 :Float32; # m from the front bumper of the car + yRel @2 :Float32; # m + vRel @3 :Float32; # m/s + + # these are optional and valid if they are not NaN + aRel @4 :Float32; # m/s^2 + yvRel @5 :Float32; # m/s + + # some radars flag measurements VS estimates + measured @6 :Bool; + } + + # deprecated + canMonoTimesDEPRECATED @2 :List(UInt64); +} + +# ******* car controls @ 100hz ******* + +struct CarControl { + # must be true for any actuator commands to work + enabled @0 :Bool; + latActive @11: Bool; + longActive @12: Bool; + + # Actuator commands as computed by controlsd + actuators @6 :Actuators; + + # moved to CarOutput + actuatorsOutputDEPRECATED @10 :Actuators; + + leftBlinker @15: Bool; + rightBlinker @16: Bool; + + orientationNED @13 :List(Float32); + angularVelocity @14 :List(Float32); + + cruiseControl @4 :CruiseControl; + hudControl @5 :HUDControl; + + struct Actuators { + # range from 0.0 - 1.0 + gas @0: Float32; + brake @1: Float32; + # range from -1.0 - 1.0 + steer @2: Float32; + # value sent over can to the car + steerOutputCan @8: Float32; + steeringAngleDeg @3: Float32; + + curvature @7: Float32; + + speed @6: Float32; # m/s + accel @4: Float32; # m/s^2 + longControlState @5: LongControlState; + + enum LongControlState @0xe40f3a917d908282{ + off @0; + pid @1; + stopping @2; + starting @3; + } + } + + struct CruiseControl { + cancel @0: Bool; + resume @1: Bool; + override @4: Bool; + speedOverrideDEPRECATED @2: Float32; + accelOverrideDEPRECATED @3: Float32; + } + + struct HUDControl { + speedVisible @0: Bool; + setSpeed @1: Float32; + lanesVisible @2: Bool; + leadVisible @3: Bool; + visualAlert @4: VisualAlert; + audibleAlert @5: AudibleAlert; + rightLaneVisible @6: Bool; + leftLaneVisible @7: Bool; + rightLaneDepart @8: Bool; + leftLaneDepart @9: Bool; + leadDistanceBars @10: Int8; # 1-3: 1 is closest, 3 is farthest. some ports may utilize 2-4 bars instead + + enum VisualAlert { + # these are the choices from the Honda + # map as good as you can for your car + none @0; + fcw @1; + steerRequired @2; + brakePressed @3; + wrongGear @4; + seatbeltUnbuckled @5; + speedTooHigh @6; + ldw @7; + } + + enum AudibleAlert { + none @0; + + engage @1; + disengage @2; + refuse @3; + + warningSoft @4; + warningImmediate @5; + + prompt @6; + promptRepeat @7; + promptDistracted @8; + } + } + + gasDEPRECATED @1 :Float32; + brakeDEPRECATED @2 :Float32; + steeringTorqueDEPRECATED @3 :Float32; + activeDEPRECATED @7 :Bool; + rollDEPRECATED @8 :Float32; + pitchDEPRECATED @9 :Float32; +} + +struct CarOutput { + # Any car specific rate limits or quirks applied by + # the CarController are reflected in actuatorsOutput + # and matches what is sent to the car + actuatorsOutput @0 :CarControl.Actuators; +} + +# ****** car param ****** + +struct CarParams { + carName @0 :Text; + carFingerprint @1 :Text; + fuzzyFingerprint @55 :Bool; + + notCar @66 :Bool; # flag for non-car robotics platforms + + pcmCruise @3 :Bool; # is openpilot's state tied to the PCM's cruise state? + enableDsu @5 :Bool; # driving support unit + enableBsm @56 :Bool; # blind spot monitoring + flags @64 :UInt32; # flags for car specific quirks + experimentalLongitudinalAvailable @71 :Bool; + + minEnableSpeed @7 :Float32; + minSteerSpeed @8 :Float32; + safetyConfigs @62 :List(SafetyConfig); + alternativeExperience @65 :Int16; # panda flag for features like no disengage on gas + + # Car docs fields + maxLateralAccel @68 :Float32; + autoResumeSng @69 :Bool; # describes whether car can resume from a stop automatically + + # things about the car in the manual + mass @17 :Float32; # [kg] curb weight: all fluids no cargo + wheelbase @18 :Float32; # [m] distance from rear axle to front axle + centerToFront @19 :Float32; # [m] distance from center of mass to front axle + steerRatio @20 :Float32; # [] ratio of steering wheel angle to front wheel angle + steerRatioRear @21 :Float32; # [] ratio of steering wheel angle to rear wheel angle (usually 0) + + # things we can derive + rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia + tireStiffnessFactor @72 :Float32; # scaling factor used in calculating tireStiffness[Front,Rear] + tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff + tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff + + longitudinalTuning @25 :LongitudinalPIDTuning; + lateralParams @48 :LateralParams; + lateralTuning :union { + pid @26 :LateralPIDTuning; + indiDEPRECATED @27 :LateralINDITuning; + lqrDEPRECATED @40 :LateralLQRTuning; + torque @67 :LateralTorqueTuning; + } + + steerLimitAlert @28 :Bool; + steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued + + vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state + vEgoStarting @59 :Float32; # Speed at which the car goes into starting state + stoppingControl @31 :Bool; # Does the car allow full control even at lows speeds when stopping + steerControlType @34 :SteerControlType; + radarUnavailable @35 :Bool; # True when radar objects aren't visible on CAN or aren't parsed out + stopAccel @60 :Float32; # Required acceleration to keep vehicle stationary + stoppingDecelRate @52 :Float32; # m/s^2/s while trying to stop + startAccel @32 :Float32; # Required acceleration to get car moving + startingState @70 :Bool; # Does this car make use of special starting state + + steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds + longitudinalActuatorDelayLowerBound @61 :Float32; # Gas/Brake actuator delay in seconds, lower bound + longitudinalActuatorDelayUpperBound @58 :Float32; # Gas/Brake actuator delay in seconds, upper bound + openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control? + carVin @38 :Text; # VIN number queried during fingerprinting + dashcamOnly @41: Bool; + passive @73: Bool; # is openpilot in control? + transmissionType @43 :TransmissionType; + carFw @44 :List(CarFw); + + radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard + fingerprintSource @49: FingerprintSource; + networkLocation @50 :NetworkLocation; # Where Panda/C2 is integrated into the car's CAN network + + wheelSpeedFactor @63 :Float32; # Multiplier on wheels speeds to computer actual speeds + + struct SafetyConfig { + safetyModel @0 :SafetyModel; + safetyParam @3 :UInt16; + safetyParamDEPRECATED @1 :Int16; + safetyParam2DEPRECATED @2 :UInt32; + } + + struct LateralParams { + torqueBP @0 :List(Int32); + torqueV @1 :List(Int32); + } + + struct LateralPIDTuning { + kpBP @0 :List(Float32); + kpV @1 :List(Float32); + kiBP @2 :List(Float32); + kiV @3 :List(Float32); + kf @4 :Float32; + } + + struct LateralTorqueTuning { + useSteeringAngle @0 :Bool; + kp @1 :Float32; + ki @2 :Float32; + friction @3 :Float32; + kf @4 :Float32; + steeringAngleDeadzoneDeg @5 :Float32; + latAccelFactor @6 :Float32; + latAccelOffset @7 :Float32; + } + + struct LongitudinalPIDTuning { + kpBP @0 :List(Float32); + kpV @1 :List(Float32); + kiBP @2 :List(Float32); + kiV @3 :List(Float32); + kf @6 :Float32; + deadzoneBP @4 :List(Float32); + deadzoneV @5 :List(Float32); + } + + struct LateralINDITuning { + outerLoopGainBP @4 :List(Float32); + outerLoopGainV @5 :List(Float32); + innerLoopGainBP @6 :List(Float32); + innerLoopGainV @7 :List(Float32); + timeConstantBP @8 :List(Float32); + timeConstantV @9 :List(Float32); + actuatorEffectivenessBP @10 :List(Float32); + actuatorEffectivenessV @11 :List(Float32); + + outerLoopGainDEPRECATED @0 :Float32; + innerLoopGainDEPRECATED @1 :Float32; + timeConstantDEPRECATED @2 :Float32; + actuatorEffectivenessDEPRECATED @3 :Float32; + } + + struct LateralLQRTuning { + scale @0 :Float32; + ki @1 :Float32; + dcGain @2 :Float32; + + # State space system + a @3 :List(Float32); + b @4 :List(Float32); + c @5 :List(Float32); + + k @6 :List(Float32); # LQR gain + l @7 :List(Float32); # Kalman gain + } + + enum SafetyModel { + silent @0; + hondaNidec @1; + toyota @2; + elm327 @3; + gm @4; + hondaBoschGiraffe @5; + ford @6; + cadillac @7; + hyundai @8; + chrysler @9; + tesla @10; + subaru @11; + gmPassive @12; + mazda @13; + nissan @14; + volkswagen @15; + toyotaIpas @16; + allOutput @17; + gmAscm @18; + noOutput @19; # like silent but without silent CAN TXs + hondaBosch @20; + volkswagenPq @21; + subaruPreglobal @22; # pre-Global platform + hyundaiLegacy @23; + hyundaiCommunity @24; + volkswagenMlb @25; + hongqi @26; + body @27; + hyundaiCanfd @28; + volkswagenMqbEvo @29; + chryslerCusw @30; + psa @31; + } + + enum SteerControlType { + torque @0; + angle @1; + + curvatureDEPRECATED @2; + } + + enum TransmissionType { + unknown @0; + automatic @1; # Traditional auto, including DSG + manual @2; # True "stick shift" only + direct @3; # Electric vehicle or other direct drive + cvt @4; + } + + struct CarFw { + ecu @0 :Ecu; + fwVersion @1 :Data; + address @2 :UInt32; + subAddress @3 :UInt8; + responseAddress @4 :UInt32; + request @5 :List(Data); + brand @6 :Text; + bus @7 :UInt8; + logging @8 :Bool; + obdMultiplexing @9 :Bool; + } + + enum Ecu { + eps @0; + abs @1; + fwdRadar @2; + fwdCamera @3; + engine @4; + unknown @5; + transmission @8; # Transmission Control Module + hybrid @18; # hybrid control unit, e.g. Chrysler's HCP, Honda's IMA Control Unit, Toyota's hybrid control computer + srs @9; # airbag + gateway @10; # can gateway + hud @11; # heads up display + combinationMeter @12; # instrument cluster + electricBrakeBooster @15; + shiftByWire @16; + adas @19; + cornerRadar @21; + hvac @20; + parkingAdas @7; # parking assist system ECU, e.g. Toyota's IPAS, Hyundai's RSPA, etc. + epb @22; # electronic parking brake + telematics @23; + body @24; # body control module + + # Toyota only + dsu @6; + + # Honda only + vsa @13; # Vehicle Stability Assist + programmedFuelInjection @14; + + debug @17; + } + + enum FingerprintSource { + can @0; + fw @1; + fixed @2; + } + + enum NetworkLocation { + fwdCamera @0; # Standard/default integration at LKAS camera + gateway @1; # Integration at vehicle's CAN gateway + } + + enableGasInterceptorDEPRECATED @2 :Bool; + enableCameraDEPRECATED @4 :Bool; + enableApgsDEPRECATED @6 :Bool; + steerRateCostDEPRECATED @33 :Float32; + isPandaBlackDEPRECATED @39 :Bool; + hasStockCameraDEPRECATED @57 :Bool; + safetyParamDEPRECATED @10 :Int16; + safetyModelDEPRECATED @9 :SafetyModel; + safetyModelPassiveDEPRECATED @42 :SafetyModel = silent; + minSpeedCanDEPRECATED @51 :Float32; + communityFeatureDEPRECATED @46: Bool; + startingAccelRateDEPRECATED @53 :Float32; + steerMaxBPDEPRECATED @11 :List(Float32); + steerMaxVDEPRECATED @12 :List(Float32); + gasMaxBPDEPRECATED @13 :List(Float32); + gasMaxVDEPRECATED @14 :List(Float32); + brakeMaxBPDEPRECATED @15 :List(Float32); + brakeMaxVDEPRECATED @16 :List(Float32); + directAccelControlDEPRECATED @30 :Bool; + maxSteeringAngleDegDEPRECATED @54 :Float32; +} diff --git a/cereal/codecov.yml b/cereal/codecov.yml new file mode 100644 index 000000000..83427c3ee --- /dev/null +++ b/cereal/codecov.yml @@ -0,0 +1,8 @@ +comment: false +coverage: + status: + project: + default: + informational: true + patch: off + diff --git a/cereal/custom.capnp b/cereal/custom.capnp new file mode 100644 index 000000000..369222add --- /dev/null +++ b/cereal/custom.capnp @@ -0,0 +1,39 @@ +using Cxx = import "./include/c++.capnp"; +$Cxx.namespace("cereal"); + +@0xb526ba661d550a59; + +# custom.capnp: a home for empty structs reserved for custom forks +# These structs are guaranteed to remain reserved and empty in mainline +# cereal, so use these if you want custom events in your fork. + +# you can rename the struct, but don't change the identifier +struct CustomReserved0 @0x81c2f05a394cf4af { +} + +struct CustomReserved1 @0xaedffd8f31e7b55d { +} + +struct CustomReserved2 @0xf35cc4560bbf6ec2 { +} + +struct CustomReserved3 @0xda96579883444c35 { +} + +struct CustomReserved4 @0x80ae746ee2596b11 { +} + +struct CustomReserved5 @0xa5cd762cd951a455 { +} + +struct CustomReserved6 @0xf98d843bfd7004a3 { +} + +struct CustomReserved7 @0xb86e6369214c01c8 { +} + +struct CustomReserved8 @0xf416ec09499d9d19 { +} + +struct CustomReserved9 @0xa1680744031fdb2d { +} diff --git a/cereal/generate_javascript.sh b/cereal/generate_javascript.sh new file mode 100755 index 000000000..d6525a64d --- /dev/null +++ b/cereal/generate_javascript.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +rm -r gen/ts +rm -r gen/js + +mkdir gen/ts +mkdir gen/js + +echo "Installing needed npm modules" +npm i capnpc-ts capnp-ts + +capnpc -o node_modules/.bin/capnpc-ts:gen/ts log.capnp car.capnp +capnpc -o node_modules/.bin/capnpc-ts:gen/ts car.capnp + +cat log.capnp | egrep '\([a-zA-Z]*\.[^\s]+\.[^s]+\)' | sed 's/^.*([a-zA-Z]*\.\([a-zA-Z.]*\)).*/\1/' | while read line +do + TOKEN=`echo $line | sed 's/\./_/g'` + ROOT=`echo $line | sed 's/\..*$//g'` + cat gen/ts/log.capnp.ts | grep '^import.*'${TOKEN} + if [[ "$?" == "1" ]] + then + sed -i 's/^\(import {.*\)'${ROOT}'\(,*\) \(.*\)$/\1'${ROOT}', '${TOKEN}'\2 \3/' ./gen/ts/log.capnp.ts + fi +done + +tsc ./gen/ts/* --lib es2015 --outDir ./gen/js diff --git a/cereal/include/c++.capnp b/cereal/include/c++.capnp new file mode 100644 index 000000000..2bda54717 --- /dev/null +++ b/cereal/include/c++.capnp @@ -0,0 +1,26 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xbdf87d7bb8304e81; +$namespace("capnp::annotations"); + +annotation namespace(file): Text; +annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text; diff --git a/cereal/legacy.capnp b/cereal/legacy.capnp new file mode 100644 index 000000000..a8fa5e4a1 --- /dev/null +++ b/cereal/legacy.capnp @@ -0,0 +1,574 @@ +using Cxx = import "./include/c++.capnp"; +$Cxx.namespace("cereal"); + +@0x80ef1ec4889c2a63; + +# legacy.capnp: a home for deprecated structs + +struct LogRotate @0x9811e1f38f62f2d1 { + segmentNum @0 :Int32; + path @1 :Text; +} + +struct LiveUI @0xc08240f996aefced { + rearViewCam @0 :Bool; + alertText1 @1 :Text; + alertText2 @2 :Text; + awarenessStatus @3 :Float32; +} + +struct UiLayoutState @0x88dcce08ad29dda0 { + activeApp @0 :App; + sidebarCollapsed @1 :Bool; + mapEnabled @2 :Bool; + mockEngaged @3 :Bool; + + enum App @0x9917470acf94d285 { + home @0; + music @1; + nav @2; + settings @3; + none @4; + } +} + +struct OrbslamCorrection @0x8afd33dc9b35e1aa { + correctionMonoTime @0 :UInt64; + prePositionECEF @1 :List(Float64); + postPositionECEF @2 :List(Float64); + prePoseQuatECEF @3 :List(Float32); + postPoseQuatECEF @4 :List(Float32); + numInliers @5 :UInt32; +} + +struct EthernetPacket @0xa99a9d5b33cf5859 { + pkt @0 :Data; + ts @1 :Float32; +} + +struct CellInfo @0xcff7566681c277ce { + timestamp @0 :UInt64; + repr @1 :Text; # android toString() for now +} + +struct WifiScan @0xd4df5a192382ba0b { + bssid @0 :Text; + ssid @1 :Text; + capabilities @2 :Text; + frequency @3 :Int32; + level @4 :Int32; + timestamp @5 :Int64; + + centerFreq0 @6 :Int32; + centerFreq1 @7 :Int32; + channelWidth @8 :ChannelWidth; + operatorFriendlyName @9 :Text; + venueName @10 :Text; + is80211mcResponder @11 :Bool; + passpoint @12 :Bool; + + distanceCm @13 :Int32; + distanceSdCm @14 :Int32; + + enum ChannelWidth @0xcb6a279f015f6b51 { + w20Mhz @0; + w40Mhz @1; + w80Mhz @2; + w160Mhz @3; + w80Plus80Mhz @4; + } +} + +struct LiveEventData @0x94b7baa90c5c321e { + name @0 :Text; + value @1 :Int32; +} + +struct ModelData @0xb8aad62cffef28a9 { + frameId @0 :UInt32; + frameAge @12 :UInt32; + frameDropPerc @13 :Float32; + timestampEof @9 :UInt64; + modelExecutionTime @14 :Float32; + gpuExecutionTime @16 :Float32; + rawPred @15 :Data; + + path @1 :PathData; + leftLane @2 :PathData; + rightLane @3 :PathData; + lead @4 :LeadData; + freePath @6 :List(Float32); + + settings @5 :ModelSettings; + leadFuture @7 :LeadData; + speed @8 :List(Float32); + meta @10 :MetaData; + longitudinal @11 :LongitudinalData; + + struct PathData @0x8817eeea389e9f08 { + points @0 :List(Float32); + prob @1 :Float32; + std @2 :Float32; + stds @3 :List(Float32); + poly @4 :List(Float32); + validLen @5 :Float32; + } + + struct LeadData @0xd1c9bef96d26fa91 { + dist @0 :Float32; + prob @1 :Float32; + std @2 :Float32; + relVel @3 :Float32; + relVelStd @4 :Float32; + relY @5 :Float32; + relYStd @6 :Float32; + relA @7 :Float32; + relAStd @8 :Float32; + } + + struct ModelSettings @0xa26e3710efd3e914 { + bigBoxX @0 :UInt16; + bigBoxY @1 :UInt16; + bigBoxWidth @2 :UInt16; + bigBoxHeight @3 :UInt16; + boxProjection @4 :List(Float32); + yuvCorrection @5 :List(Float32); + inputTransform @6 :List(Float32); + } + + struct MetaData @0x9744f25fb60f2bf8 { + engagedProb @0 :Float32; + desirePrediction @1 :List(Float32); + brakeDisengageProb @2 :Float32; + gasDisengageProb @3 :Float32; + steerOverrideProb @4 :Float32; + desireState @5 :List(Float32); + } + + struct LongitudinalData @0xf98f999c6a071122 { + distances @2 :List(Float32); + speeds @0 :List(Float32); + accelerations @1 :List(Float32); + } +} + +struct ECEFPoint @0xc25bbbd524983447 { + x @0 :Float64; + y @1 :Float64; + z @2 :Float64; +} + +struct ECEFPointDEPRECATED @0xe10e21168db0c7f7 { + x @0 :Float32; + y @1 :Float32; + z @2 :Float32; +} + +struct GPSPlannerPoints @0xab54c59699f8f9f3 { + curPosDEPRECATED @0 :ECEFPointDEPRECATED; + pointsDEPRECATED @1 :List(ECEFPointDEPRECATED); + curPos @6 :ECEFPoint; + points @7 :List(ECEFPoint); + valid @2 :Bool; + trackName @3 :Text; + speedLimit @4 :Float32; + accelTarget @5 :Float32; +} + +struct GPSPlannerPlan @0xf5ad1d90cdc1dd6b { + valid @0 :Bool; + poly @1 :List(Float32); + trackName @2 :Text; + speed @3 :Float32; + acceleration @4 :Float32; + pointsDEPRECATED @5 :List(ECEFPointDEPRECATED); + points @6 :List(ECEFPoint); + xLookahead @7 :Float32; +} + +struct UiNavigationEvent @0x90c8426c3eaddd3b { + type @0: Type; + status @1: Status; + distanceTo @2: Float32; + endRoadPointDEPRECATED @3: ECEFPointDEPRECATED; + endRoadPoint @4: ECEFPoint; + + enum Type @0xe8db07dcf8fcea05 { + none @0; + laneChangeLeft @1; + laneChangeRight @2; + mergeLeft @3; + mergeRight @4; + turnLeft @5; + turnRight @6; + } + + enum Status @0xb9aa88c75ef99a1f { + none @0; + passive @1; + approaching @2; + active @3; + } +} + +struct LiveLocationData @0xb99b2bc7a57e8128 { + status @0 :UInt8; + + # 3D fix + lat @1 :Float64; + lon @2 :Float64; + alt @3 :Float32; # m + + # speed + speed @4 :Float32; # m/s + + # NED velocity components + vNED @5 :List(Float32); + + # roll, pitch, heading (x,y,z) + roll @6 :Float32; # WRT to center of earth? + pitch @7 :Float32; # WRT to center of earth? + heading @8 :Float32; # WRT to north? + + # what are these? + wanderAngle @9 :Float32; + trackAngle @10 :Float32; + + # car frame -- https://upload.wikimedia.org/wikipedia/commons/f/f5/RPY_angles_of_cars.png + + # gyro, in car frame, deg/s + gyro @11 :List(Float32); + + # accel, in car frame, m/s^2 + accel @12 :List(Float32); + + accuracy @13 :Accuracy; + + source @14 :SensorSource; + # if we are fixing a location in the past + fixMonoTime @15 :UInt64; + + gpsWeek @16 :Int32; + timeOfWeek @17 :Float64; + + positionECEF @18 :List(Float64); + poseQuatECEF @19 :List(Float32); + pitchCalibration @20 :Float32; + yawCalibration @21 :Float32; + imuFrame @22 :List(Float32); + + struct Accuracy @0x943dc4625473b03f { + pNEDError @0 :List(Float32); + vNEDError @1 :List(Float32); + rollError @2 :Float32; + pitchError @3 :Float32; + headingError @4 :Float32; + ellipsoidSemiMajorError @5 :Float32; + ellipsoidSemiMinorError @6 :Float32; + ellipsoidOrientationError @7 :Float32; + } + + enum SensorSource @0xc871d3cc252af657 { + applanix @0; + kalman @1; + orbslam @2; + timing @3; + dummy @4; + } +} + +struct OrbOdometry @0xd7700859ed1f5b76 { + # timing first + startMonoTime @0 :UInt64; + endMonoTime @1 :UInt64; + + # fundamental matrix and error + f @2: List(Float64); + err @3: Float64; + + # number of inlier points + inliers @4: Int32; + + # for debug only + # indexed by endMonoTime features + # value is startMonoTime feature match + # -1 if no match + matches @5: List(Int16); +} + +struct OrbFeatures @0xcd60164a8a0159ef { + timestampEof @0 :UInt64; + # transposed arrays of normalized image coordinates + # len(xs) == len(ys) == len(descriptors) * 32 + xs @1 :List(Float32); + ys @2 :List(Float32); + descriptors @3 :Data; + octaves @4 :List(Int8); + + # match index to last OrbFeatures + # -1 if no match + timestampLastEof @5 :UInt64; + matches @6: List(Int16); +} + +struct OrbFeaturesSummary @0xd500d30c5803fa4f { + timestampEof @0 :UInt64; + timestampLastEof @1 :UInt64; + + featureCount @2 :UInt16; + matchCount @3 :UInt16; + computeNs @4 :UInt64; +} + +struct OrbKeyFrame @0xc8233c0345e27e24 { + # this is a globally unique id for the KeyFrame + id @0: UInt64; + + # this is the location of the KeyFrame + pos @1: ECEFPoint; + + # these are the features in the world + # len(dpos) == len(descriptors) * 32 + dpos @2 :List(ECEFPoint); + descriptors @3 :Data; +} + +struct KalmanOdometry @0x92e21bb7ea38793a { + trans @0 :List(Float32); # m/s in device frame + rot @1 :List(Float32); # rad/s in device frame + transStd @2 :List(Float32); # std m/s in device frame + rotStd @3 :List(Float32); # std rad/s in device frame +} + +struct OrbObservation @0x9b326d4e436afec7 { + observationMonoTime @0 :UInt64; + normalizedCoordinates @1 :List(Float32); + locationECEF @2 :List(Float64); + matchDistance @3: UInt32; +} + +struct CalibrationFeatures @0x8fdfadb254ea867a { + frameId @0 :UInt32; + + p0 @1 :List(Float32); + p1 @2 :List(Float32); + status @3 :List(Int8); +} + +struct NavStatus @0xbd8822120928120c { + isNavigating @0 :Bool; + currentAddress @1 :Address; + + struct Address @0xce7cd672cacc7814 { + title @0 :Text; + lat @1 :Float64; + lng @2 :Float64; + house @3 :Text; + address @4 :Text; + street @5 :Text; + city @6 :Text; + state @7 :Text; + country @8 :Text; + } +} + +struct NavUpdate @0xdb98be6565516acb { + isNavigating @0 :Bool; + curSegment @1 :Int32; + segments @2 :List(Segment); + + struct LatLng @0x9eaef9187cadbb9b { + lat @0 :Float64; + lng @1 :Float64; + } + + struct Segment @0xa5b39b4fc4d7da3f { + from @0 :LatLng; + to @1 :LatLng; + updateTime @2 :Int32; + distance @3 :Int32; + crossTime @4 :Int32; + exitNo @5 :Int32; + instruction @6 :Instruction; + + parts @7 :List(LatLng); + + enum Instruction @0xc5417a637451246f { + turnLeft @0; + turnRight @1; + keepLeft @2; + keepRight @3; + straight @4; + roundaboutExitNumber @5; + roundaboutExit @6; + roundaboutTurnLeft @7; + unkn8 @8; + roundaboutStraight @9; + unkn10 @10; + roundaboutTurnRight @11; + unkn12 @12; + roundaboutUturn @13; + unkn14 @14; + arrive @15; + exitLeft @16; + exitRight @17; + unkn18 @18; + uturn @19; + # ... + } + } +} + +struct TrafficEvent @0xacfa74a094e62626 { + type @0 :Type; + distance @1 :Float32; + action @2 :Action; + resuming @3 :Bool; + + enum Type @0xd85d75253435bf4b { + stopSign @0; + lightRed @1; + lightYellow @2; + lightGreen @3; + stopLight @4; + } + + enum Action @0xa6f6ce72165ccb49 { + none @0; + yield @1; + stop @2; + resumeReady @3; + } + +} + + +struct AndroidGnss @0xdfdf30d03fc485bd { + union { + measurements @0 :Measurements; + navigationMessage @1 :NavigationMessage; + } + + struct Measurements @0xa20710d4f428d6cd { + clock @0 :Clock; + measurements @1 :List(Measurement); + + struct Clock @0xa0e27b453a38f450 { + timeNanos @0 :Int64; + hardwareClockDiscontinuityCount @1 :Int32; + + hasTimeUncertaintyNanos @2 :Bool; + timeUncertaintyNanos @3 :Float64; + + hasLeapSecond @4 :Bool; + leapSecond @5 :Int32; + + hasFullBiasNanos @6 :Bool; + fullBiasNanos @7 :Int64; + + hasBiasNanos @8 :Bool; + biasNanos @9 :Float64; + + hasBiasUncertaintyNanos @10 :Bool; + biasUncertaintyNanos @11 :Float64; + + hasDriftNanosPerSecond @12 :Bool; + driftNanosPerSecond @13 :Float64; + + hasDriftUncertaintyNanosPerSecond @14 :Bool; + driftUncertaintyNanosPerSecond @15 :Float64; + } + + struct Measurement @0xd949bf717d77614d { + svId @0 :Int32; + constellation @1 :Constellation; + + timeOffsetNanos @2 :Float64; + state @3 :Int32; + receivedSvTimeNanos @4 :Int64; + receivedSvTimeUncertaintyNanos @5 :Int64; + cn0DbHz @6 :Float64; + pseudorangeRateMetersPerSecond @7 :Float64; + pseudorangeRateUncertaintyMetersPerSecond @8 :Float64; + accumulatedDeltaRangeState @9 :Int32; + accumulatedDeltaRangeMeters @10 :Float64; + accumulatedDeltaRangeUncertaintyMeters @11 :Float64; + + hasCarrierFrequencyHz @12 :Bool; + carrierFrequencyHz @13 :Float32; + hasCarrierCycles @14 :Bool; + carrierCycles @15 :Int64; + hasCarrierPhase @16 :Bool; + carrierPhase @17 :Float64; + hasCarrierPhaseUncertainty @18 :Bool; + carrierPhaseUncertainty @19 :Float64; + hasSnrInDb @20 :Bool; + snrInDb @21 :Float64; + + multipathIndicator @22 :MultipathIndicator; + + enum Constellation @0x9ef1f3ff0deb5ffb { + unknown @0; + gps @1; + sbas @2; + glonass @3; + qzss @4; + beidou @5; + galileo @6; + } + + enum State @0xcbb9490adce12d72 { + unknown @0; + codeLock @1; + bitSync @2; + subframeSync @3; + towDecoded @4; + msecAmbiguous @5; + symbolSync @6; + gloStringSync @7; + gloTodDecoded @8; + bdsD2BitSync @9; + bdsD2SubframeSync @10; + galE1bcCodeLock @11; + galE1c2ndCodeLock @12; + galE1bPageSync @13; + sbasSync @14; + } + + enum MultipathIndicator @0xc04e7b6231d4caa8 { + unknown @0; + detected @1; + notDetected @2; + } + } + } + + struct NavigationMessage @0xe2517b083095fd4e { + type @0 :Int32; + svId @1 :Int32; + messageId @2 :Int32; + submessageId @3 :Int32; + data @4 :Data; + status @5 :Status; + + enum Status @0xec1ff7996b35366f { + unknown @0; + parityPassed @1; + parityRebuilt @2; + } + } +} + +struct LidarPts @0xe3d6685d4e9d8f7a { + r @0 :List(UInt16); # uint16 m*500.0 + theta @1 :List(UInt16); # uint16 deg*100.0 + reflect @2 :List(UInt8); # uint8 0-255 + + # For storing out of file. + idx @3 :UInt64; + + # For storing in file + pkt @4 :Data; +} + + diff --git a/cereal/log.capnp b/cereal/log.capnp new file mode 100644 index 000000000..36ca692dc --- /dev/null +++ b/cereal/log.capnp @@ -0,0 +1,2369 @@ +using Cxx = import "./include/c++.capnp"; +$Cxx.namespace("cereal"); + +using Car = import "car.capnp"; +using Legacy = import "legacy.capnp"; +using Custom = import "custom.capnp"; + +@0xf3b1f17e25a4285b; + +const logVersion :Int32 = 1; + +struct Map(Key, Value) { + entries @0 :List(Entry); + struct Entry { + key @0 :Key; + value @1 :Value; + } +} + +enum LongitudinalPersonality { + aggressive @0; + standard @1; + relaxed @2; +} + +struct InitData { + kernelArgs @0 :List(Text); + kernelVersion @15 :Text; + osVersion @18 :Text; + + dongleId @2 :Text; + bootlogId @22 :Text; + + deviceType @3 :DeviceType; + version @4 :Text; + gitCommit @10 :Text; + gitCommitDate @21 :Text; + gitBranch @11 :Text; + gitRemote @13 :Text; + + androidProperties @16 :Map(Text, Text); + + pandaInfo @8 :PandaInfo; + + dirty @9 :Bool; + passive @12 :Bool; + params @17 :Map(Text, Data); + + commands @19 :Map(Text, Data); + + wallTimeNanos @20 :UInt64; + + enum DeviceType { + unknown @0; + neo @1; + chffrAndroid @2; + chffrIos @3; + tici @4; + pc @5; + tizi @6; + mici @7; + } + + struct PandaInfo { + hasPanda @0 :Bool; + dongleId @1 :Text; + stVersion @2 :Text; + espVersion @3 :Text; + } + + # ***** deprecated stuff ***** + gctxDEPRECATED @1 :Text; + androidBuildInfo @5 :AndroidBuildInfo; + androidSensorsDEPRECATED @6 :List(AndroidSensor); + chffrAndroidExtraDEPRECATED @7 :ChffrAndroidExtra; + iosBuildInfoDEPRECATED @14 :IosBuildInfo; + + struct AndroidBuildInfo { + board @0 :Text; + bootloader @1 :Text; + brand @2 :Text; + device @3 :Text; + display @4 :Text; + fingerprint @5 :Text; + hardware @6 :Text; + host @7 :Text; + id @8 :Text; + manufacturer @9 :Text; + model @10 :Text; + product @11 :Text; + radioVersion @12 :Text; + serial @13 :Text; + supportedAbis @14 :List(Text); + tags @15 :Text; + time @16 :Int64; + type @17 :Text; + user @18 :Text; + + versionCodename @19 :Text; + versionRelease @20 :Text; + versionSdk @21 :Int32; + versionSecurityPatch @22 :Text; + } + + struct AndroidSensor { + id @0 :Int32; + name @1 :Text; + vendor @2 :Text; + version @3 :Int32; + handle @4 :Int32; + type @5 :Int32; + maxRange @6 :Float32; + resolution @7 :Float32; + power @8 :Float32; + minDelay @9 :Int32; + fifoReservedEventCount @10 :UInt32; + fifoMaxEventCount @11 :UInt32; + stringType @12 :Text; + maxDelay @13 :Int32; + } + + struct ChffrAndroidExtra { + allCameraCharacteristics @0 :Map(Text, Text); + } + + struct IosBuildInfo { + appVersion @0 :Text; + appBuild @1 :UInt32; + osVersion @2 :Text; + deviceModel @3 :Text; + } +} + +struct FrameData { + frameId @0 :UInt32; + frameIdSensor @25 :UInt32; + requestId @28 :UInt32; + encodeId @1 :UInt32; + + frameType @7 :FrameType; + + # Timestamps + timestampEof @2 :UInt64; + timestampSof @8 :UInt64; + processingTime @23 :Float32; + + # Exposure + integLines @4 :Int32; + highConversionGain @20 :Bool; + gain @15 :Float32; # This includes highConversionGain if enabled + measuredGreyFraction @21 :Float32; + targetGreyFraction @22 :Float32; + exposureValPercent @27 :Float32; + + transform @10 :List(Float32); + + image @6 :Data; + + temperaturesC @24 :List(Float32); + + enum FrameType { + unknown @0; + neo @1; + chffrAndroid @2; + front @3; + } + + sensor @26 :ImageSensor; + enum ImageSensor { + unknown @0; + ar0231 @1; + ox03c10 @2; + os04c10 @3; + } + + frameLengthDEPRECATED @3 :Int32; + globalGainDEPRECATED @5 :Int32; + androidCaptureResultDEPRECATED @9 :AndroidCaptureResult; + lensPosDEPRECATED @11 :Int32; + lensSagDEPRECATED @12 :Float32; + lensErrDEPRECATED @13 :Float32; + lensTruePosDEPRECATED @14 :Float32; + focusValDEPRECATED @16 :List(Int16); + focusConfDEPRECATED @17 :List(UInt8); + sharpnessScoreDEPRECATED @18 :List(UInt16); + recoverStateDEPRECATED @19 :Int32; + struct AndroidCaptureResult { + sensitivity @0 :Int32; + frameDuration @1 :Int64; + exposureTime @2 :Int64; + rollingShutterSkew @3 :UInt64; + colorCorrectionTransform @4 :List(Int32); + colorCorrectionGains @5 :List(Float32); + displayRotation @6 :Int8; + } +} + +struct Thumbnail { + frameId @0 :UInt32; + timestampEof @1 :UInt64; + thumbnail @2 :Data; + encoding @3 :Encoding; + + enum Encoding { + unknown @0; + jpeg @1; + keyframe @2; + } +} + +struct GPSNMEAData { + timestamp @0 :Int64; + localWallTime @1 :UInt64; + nmea @2 :Text; +} + +# android sensor_event_t +struct SensorEventData { + version @0 :Int32; + sensor @1 :Int32; + type @2 :Int32; + timestamp @3 :Int64; + uncalibratedDEPRECATED @10 :Bool; + + union { + acceleration @4 :SensorVec; + magnetic @5 :SensorVec; + orientation @6 :SensorVec; + gyro @7 :SensorVec; + pressure @9 :SensorVec; + magneticUncalibrated @11 :SensorVec; + gyroUncalibrated @12 :SensorVec; + proximity @13: Float32; + light @14: Float32; + temperature @15: Float32; + } + source @8 :SensorSource; + + struct SensorVec { + v @0 :List(Float32); + status @1 :Int8; + } + + enum SensorSource { + android @0; + iOS @1; + fiber @2; + velodyne @3; # Velodyne IMU + bno055 @4; # Bosch accelerometer + lsm6ds3 @5; # includes LSM6DS3 and LSM6DS3TR, TR = tape reel + bmp280 @6; # barometer + mmc3416x @7; # magnetometer + bmx055 @8; + rpr0521 @9; + lsm6ds3trc @10; + mmc5603nj @11; + } +} + +# android struct GpsLocation +struct GpsLocationData { + # Contains module-specific flags. + flags @0 :UInt16; + + # Represents latitude in degrees. + latitude @1 :Float64; + + # Represents longitude in degrees. + longitude @2 :Float64; + + # Represents altitude in meters above the WGS 84 reference ellipsoid. + altitude @3 :Float64; + + # Represents speed in meters per second. + speed @4 :Float32; + + # Represents heading in degrees. + bearingDeg @5 :Float32; + + # Represents expected horizontal accuracy in meters. + horizontalAccuracy @6 :Float32; + + unixTimestampMillis @7 :Int64; + + source @8 :SensorSource; + + # Represents NED velocity in m/s. + vNED @9 :List(Float32); + + # Represents expected vertical accuracy in meters. (presumably 1 sigma?) + verticalAccuracy @10 :Float32; + + # Represents bearing accuracy in degrees. (presumably 1 sigma?) + bearingAccuracyDeg @11 :Float32; + + # Represents velocity accuracy in m/s. (presumably 1 sigma?) + speedAccuracy @12 :Float32; + + hasFix @13 :Bool; + + enum SensorSource { + android @0; + iOS @1; + car @2; + velodyne @3; # Velodyne IMU + fusion @4; + external @5; + ublox @6; + trimble @7; + qcomdiag @8; + unicore @9; + } +} + +enum Desire { + none @0; + turnLeft @1; + turnRight @2; + laneChangeLeft @3; + laneChangeRight @4; + keepLeft @5; + keepRight @6; +} + +enum LaneChangeState { + off @0; + preLaneChange @1; + laneChangeStarting @2; + laneChangeFinishing @3; +} + +enum LaneChangeDirection { + none @0; + left @1; + right @2; +} + +struct CanData { + address @0 :UInt32; + busTime @1 :UInt16; + dat @2 :Data; + src @3 :UInt8; +} + +struct DeviceState @0xa4d8b5af2aa492eb { + deviceType @45 :InitData.DeviceType; + + networkType @22 :NetworkType; + networkInfo @31 :NetworkInfo; + networkStrength @24 :NetworkStrength; + networkStats @43 :NetworkStats; + networkMetered @41 :Bool; + lastAthenaPingTime @32 :UInt64; + + started @11 :Bool; + startedMonoTime @13 :UInt64; + + # system utilization + freeSpacePercent @7 :Float32; + memoryUsagePercent @19 :Int8; + gpuUsagePercent @33 :Int8; + cpuUsagePercent @34 :List(Int8); # per-core cpu usage + + # power + offroadPowerUsageUwh @23 :UInt32; + carBatteryCapacityUwh @25 :UInt32; + powerDrawW @40 :Float32; + somPowerDrawW @42 :Float32; + + # device thermals + cpuTempC @26 :List(Float32); + gpuTempC @27 :List(Float32); + memoryTempC @28 :Float32; + nvmeTempC @35 :List(Float32); + modemTempC @36 :List(Float32); + pmicTempC @39 :List(Float32); + maxTempC @44 :Float32; # max of other temps, used to control fan + thermalZones @38 :List(ThermalZone); + thermalStatus @14 :ThermalStatus; + + fanSpeedPercentDesired @10 :UInt16; + screenBrightnessPercent @37 :Int8; + + struct ThermalZone { + name @0 :Text; + temp @1 :Float32; + } + + enum ThermalStatus { + green @0; + yellow @1; + red @2; + danger @3; + } + + enum NetworkType { + none @0; + wifi @1; + cell2G @2; + cell3G @3; + cell4G @4; + cell5G @5; + ethernet @6; + } + + enum NetworkStrength { + unknown @0; + poor @1; + moderate @2; + good @3; + great @4; + } + + struct NetworkInfo { + technology @0 :Text; + operator @1 :Text; + band @2 :Text; + channel @3 :UInt16; + extra @4 :Text; + state @5 :Text; + } + + struct NetworkStats { + wwanTx @0 :Int64; + wwanRx @1 :Int64; + } + + # deprecated + cpu0DEPRECATED @0 :UInt16; + cpu1DEPRECATED @1 :UInt16; + cpu2DEPRECATED @2 :UInt16; + cpu3DEPRECATED @3 :UInt16; + memDEPRECATED @4 :UInt16; + gpuDEPRECATED @5 :UInt16; + batDEPRECATED @6 :UInt32; + pa0DEPRECATED @21 :UInt16; + cpuUsagePercentDEPRECATED @20 :Int8; + batteryStatusDEPRECATED @9 :Text; + batteryVoltageDEPRECATED @16 :Int32; + batteryTempCDEPRECATED @29 :Float32; + batteryPercentDEPRECATED @8 :Int16; + batteryCurrentDEPRECATED @15 :Int32; + chargingErrorDEPRECATED @17 :Bool; + chargingDisabledDEPRECATED @18 :Bool; + usbOnlineDEPRECATED @12 :Bool; + ambientTempCDEPRECATED @30 :Float32; +} + +struct PandaState @0xa7649e2575e4591e { + ignitionLine @2 :Bool; + rxBufferOverflow @7 :UInt32; + txBufferOverflow @8 :UInt32; + pandaType @10 :PandaType; + ignitionCan @13 :Bool; + faultStatus @15 :FaultStatus; + powerSaveEnabled @16 :Bool; + uptime @17 :UInt32; + faults @18 :List(FaultType); + heartbeatLost @22 :Bool; + interruptLoad @25 :Float32; + fanPower @28 :UInt8; + fanStallCount @34 :UInt8; + + spiChecksumErrorCount @33 :UInt16; + + harnessStatus @21 :HarnessStatus; + sbu1Voltage @35 :Float32; + sbu2Voltage @36 :Float32; + + # can health + canState0 @29 :PandaCanState; + canState1 @30 :PandaCanState; + canState2 @31 :PandaCanState; + + # safety stuff + controlsAllowed @3 :Bool; + safetyRxInvalid @19 :UInt32; + safetyTxBlocked @24 :UInt32; + safetyModel @14 :Car.CarParams.SafetyModel; + safetyParam @27 :UInt16; + alternativeExperience @23 :Int16; + safetyRxChecksInvalid @32 :Bool; + + voltage @0 :UInt32; + current @1 :UInt32; + + enum FaultStatus { + none @0; + faultTemp @1; + faultPerm @2; + } + + enum FaultType { + relayMalfunction @0; + unusedInterruptHandled @1; + interruptRateCan1 @2; + interruptRateCan2 @3; + interruptRateCan3 @4; + interruptRateTach @5; + interruptRateGmlanDEPRECATED @6; + interruptRateInterrupts @7; + interruptRateSpiDma @8; + interruptRateSpiCs @9; + interruptRateUart1 @10; + interruptRateUart2 @11; + interruptRateUart3 @12; + interruptRateUart5 @13; + interruptRateUartDma @14; + interruptRateUsb @15; + interruptRateTim1 @16; + interruptRateTim3 @17; + registerDivergent @18; + interruptRateKlineInit @19; + interruptRateClockSource @20; + interruptRateTick @21; + interruptRateExti @22; + interruptRateSpi @23; + interruptRateUart7 @24; + sirenMalfunction @25; + heartbeatLoopWatchdog @26; + # Update max fault type in boardd when adding faults + } + + enum PandaType @0x8a58adf93e5b3751 { + unknown @0; + whitePanda @1; + greyPanda @2; + blackPanda @3; + pedal @4; + uno @5; + dos @6; + redPanda @7; + redPandaV2 @8; + tres @9; + cuatro @10; + } + + enum HarnessStatus { + notConnected @0; + normal @1; + flipped @2; + } + + struct PandaCanState { + busOff @0 :Bool; + busOffCnt @1 :UInt32; + errorWarning @2 :Bool; + errorPassive @3 :Bool; + lastError @4 :LecErrorCode; + lastStoredError @5 :LecErrorCode; + lastDataError @6 :LecErrorCode; + lastDataStoredError @7 :LecErrorCode; + receiveErrorCnt @8 :UInt8; + transmitErrorCnt @9 :UInt8; + totalErrorCnt @10 :UInt32; + totalTxLostCnt @11 :UInt32; + totalRxLostCnt @12 :UInt32; + totalTxCnt @13 :UInt32; + totalRxCnt @14 :UInt32; + totalFwdCnt @15 :UInt32; + canSpeed @16 :UInt16; + canDataSpeed @17 :UInt16; + canfdEnabled @18 :Bool; + brsEnabled @19 :Bool; + canfdNonIso @20 :Bool; + irq0CallRate @21 :UInt32; + irq1CallRate @22 :UInt32; + irq2CallRate @23 :UInt32; + canCoreResetCnt @24 :UInt32; + + enum LecErrorCode { + noError @0; + stuffError @1; + formError @2; + ackError @3; + bit1Error @4; + bit0Error @5; + crcError @6; + noChange @7; + } + } + + gasInterceptorDetectedDEPRECATED @4 :Bool; + startedSignalDetectedDEPRECATED @5 :Bool; + hasGpsDEPRECATED @6 :Bool; + gmlanSendErrsDEPRECATED @9 :UInt32; + fanSpeedRpmDEPRECATED @11 :UInt16; + usbPowerModeDEPRECATED @12 :PeripheralState.UsbPowerModeDEPRECATED; + safetyParamDEPRECATED @20 :Int16; + safetyParam2DEPRECATED @26 :UInt32; +} + +struct PeripheralState { + pandaType @0 :PandaState.PandaType; + voltage @1 :UInt32; + current @2 :UInt32; + fanSpeedRpm @3 :UInt16; + + usbPowerModeDEPRECATED @4 :UsbPowerModeDEPRECATED; + enum UsbPowerModeDEPRECATED @0xa8883583b32c9877 { + none @0; + client @1; + cdp @2; + dcp @3; + } +} + +struct RadarState @0x9a185389d6fdd05f { + mdMonoTime @6 :UInt64; + carStateMonoTime @11 :UInt64; + radarErrors @12 :List(Car.RadarData.Error); + + leadOne @3 :LeadData; + leadTwo @4 :LeadData; + cumLagMs @5 :Float32; + + struct LeadData { + dRel @0 :Float32; + yRel @1 :Float32; + vRel @2 :Float32; + aRel @3 :Float32; + vLead @4 :Float32; + dPath @6 :Float32; + vLat @7 :Float32; + vLeadK @8 :Float32; + aLeadK @9 :Float32; + fcw @10 :Bool; + status @11 :Bool; + aLeadTau @12 :Float32; + modelProb @13 :Float32; + radar @14 :Bool; + radarTrackId @15 :Int32 = -1; + + aLeadDEPRECATED @5 :Float32; + } + + # deprecated + ftMonoTimeDEPRECATED @7 :UInt64; + warpMatrixDEPRECATED @0 :List(Float32); + angleOffsetDEPRECATED @1 :Float32; + calStatusDEPRECATED @2 :Int8; + calCycleDEPRECATED @8 :Int32; + calPercDEPRECATED @9 :Int8; + canMonoTimesDEPRECATED @10 :List(UInt64); +} + +struct LiveCalibrationData { + calStatus @11 :Status; + calCycle @2 :Int32; + calPerc @3 :Int8; + validBlocks @9 :Int32; + + # view_frame_from_road_frame + # ui's is inversed needs new + extrinsicMatrix @4 :List(Float32); + # the direction of travel vector in device frame + rpyCalib @7 :List(Float32); + rpyCalibSpread @8 :List(Float32); + wideFromDeviceEuler @10 :List(Float32); + height @12 :List(Float32); + + warpMatrixDEPRECATED @0 :List(Float32); + calStatusDEPRECATED @1 :Int8; + warpMatrix2DEPRECATED @5 :List(Float32); + warpMatrixBigDEPRECATED @6 :List(Float32); + + enum Status { + uncalibrated @0; + calibrated @1; + invalid @2; + recalibrating @3; + } +} + +struct LiveTracks { + trackId @0 :Int32; + dRel @1 :Float32; + yRel @2 :Float32; + vRel @3 :Float32; + aRel @4 :Float32; + timeStamp @5 :Float32; + status @6 :Float32; + currentTime @7 :Float32; + stationary @8 :Bool; + oncoming @9 :Bool; +} + +struct ControlsState @0x97ff69c53601abf1 { + startMonoTime @48 :UInt64; + longitudinalPlanMonoTime @28 :UInt64; + lateralPlanMonoTime @50 :UInt64; + + state @31 :OpenpilotState; + enabled @19 :Bool; + active @36 :Bool; + + experimentalMode @64 :Bool; + personality @66 :LongitudinalPersonality; + + longControlState @30 :Car.CarControl.Actuators.LongControlState; + vPid @2 :Float32; + vTargetLead @3 :Float32; + vCruise @22 :Float32; # actual set speed + vCruiseCluster @63 :Float32; # set speed to display in the UI + upAccelCmd @4 :Float32; + uiAccelCmd @5 :Float32; + ufAccelCmd @33 :Float32; + aTarget @35 :Float32; + curvature @37 :Float32; # path curvature from vehicle model + desiredCurvature @61 :Float32; # lag adjusted curvatures used by lateral controllers + forceDecel @51 :Bool; + + # UI alerts + alertText1 @24 :Text; + alertText2 @25 :Text; + alertStatus @38 :AlertStatus; + alertSize @39 :AlertSize; + alertBlinkingRate @42 :Float32; + alertType @44 :Text; + alertSound @56 :Car.CarControl.HUDControl.AudibleAlert; + engageable @41 :Bool; # can OP be engaged? + + cumLagMs @15 :Float32; + + lateralControlState :union { + indiState @52 :LateralINDIState; + pidState @53 :LateralPIDState; + angleState @58 :LateralAngleState; + debugState @59 :LateralDebugState; + torqueState @60 :LateralTorqueState; + + curvatureStateDEPRECATED @65 :LateralCurvatureState; + lqrStateDEPRECATED @55 :LateralLQRState; + } + + enum OpenpilotState @0xdbe58b96d2d1ac61 { + disabled @0; + preEnabled @1; + enabled @2; + softDisabling @3; + overriding @4; # superset of overriding with steering or accelerator + } + + enum AlertStatus { + normal @0; # low priority alert for user's convenience + userPrompt @1; # mid priority alert that might require user intervention + critical @2; # high priority alert that needs immediate user intervention + } + + enum AlertSize { + none @0; # don't display the alert + small @1; # small box + mid @2; # mid screen + full @3; # full screen + } + + struct LateralINDIState { + active @0 :Bool; + steeringAngleDeg @1 :Float32; + steeringRateDeg @2 :Float32; + steeringAccelDeg @3 :Float32; + rateSetPoint @4 :Float32; + accelSetPoint @5 :Float32; + accelError @6 :Float32; + delayedOutput @7 :Float32; + delta @8 :Float32; + output @9 :Float32; + saturated @10 :Bool; + steeringAngleDesiredDeg @11 :Float32; + steeringRateDesiredDeg @12 :Float32; + } + + struct LateralPIDState { + active @0 :Bool; + steeringAngleDeg @1 :Float32; + steeringRateDeg @2 :Float32; + angleError @3 :Float32; + p @4 :Float32; + i @5 :Float32; + f @6 :Float32; + output @7 :Float32; + saturated @8 :Bool; + steeringAngleDesiredDeg @9 :Float32; + } + + struct LateralTorqueState { + active @0 :Bool; + error @1 :Float32; + errorRate @8 :Float32; + p @2 :Float32; + i @3 :Float32; + d @4 :Float32; + f @5 :Float32; + output @6 :Float32; + saturated @7 :Bool; + actualLateralAccel @9 :Float32; + desiredLateralAccel @10 :Float32; + } + + struct LateralLQRState { + active @0 :Bool; + steeringAngleDeg @1 :Float32; + i @2 :Float32; + output @3 :Float32; + lqrOutput @4 :Float32; + saturated @5 :Bool; + steeringAngleDesiredDeg @6 :Float32; + } + + struct LateralAngleState { + active @0 :Bool; + steeringAngleDeg @1 :Float32; + output @2 :Float32; + saturated @3 :Bool; + steeringAngleDesiredDeg @4 :Float32; + } + + struct LateralCurvatureState { + active @0 :Bool; + actualCurvature @1 :Float32; + desiredCurvature @2 :Float32; + error @3 :Float32; + p @4 :Float32; + i @5 :Float32; + f @6 :Float32; + output @7 :Float32; + saturated @8 :Bool; + } + + struct LateralDebugState { + active @0 :Bool; + steeringAngleDeg @1 :Float32; + output @2 :Float32; + saturated @3 :Bool; + } + + # deprecated + vEgoDEPRECATED @0 :Float32; + vEgoRawDEPRECATED @32 :Float32; + aEgoDEPRECATED @1 :Float32; + canMonoTimeDEPRECATED @16 :UInt64; + radarStateMonoTimeDEPRECATED @17 :UInt64; + mdMonoTimeDEPRECATED @18 :UInt64; + yActualDEPRECATED @6 :Float32; + yDesDEPRECATED @7 :Float32; + upSteerDEPRECATED @8 :Float32; + uiSteerDEPRECATED @9 :Float32; + ufSteerDEPRECATED @34 :Float32; + aTargetMinDEPRECATED @10 :Float32; + aTargetMaxDEPRECATED @11 :Float32; + rearViewCamDEPRECATED @23 :Bool; + driverMonitoringOnDEPRECATED @43 :Bool; + hudLeadDEPRECATED @14 :Int32; + alertSoundDEPRECATED @45 :Text; + angleModelBiasDEPRECATED @27 :Float32; + gpsPlannerActiveDEPRECATED @40 :Bool; + decelForTurnDEPRECATED @47 :Bool; + decelForModelDEPRECATED @54 :Bool; + awarenessStatusDEPRECATED @26 :Float32; + angleSteersDEPRECATED @13 :Float32; + vCurvatureDEPRECATED @46 :Float32; + mapValidDEPRECATED @49 :Bool; + jerkFactorDEPRECATED @12 :Float32; + steerOverrideDEPRECATED @20 :Bool; + steeringAngleDesiredDegDEPRECATED @29 :Float32; + canMonoTimesDEPRECATED @21 :List(UInt64); + desiredCurvatureRateDEPRECATED @62 :Float32; + canErrorCounterDEPRECATED @57 :UInt32; +} + +# All SI units and in device frame +struct XYZTData @0xc3cbae1fd505ae80 { + x @0 :List(Float32); + y @1 :List(Float32); + z @2 :List(Float32); + t @3 :List(Float32); + xStd @4 :List(Float32); + yStd @5 :List(Float32); + zStd @6 :List(Float32); +} + +struct ModelDataV2 { + frameId @0 :UInt32; + frameIdExtra @20 :UInt32; + frameAge @1 :UInt32; + frameDropPerc @2 :Float32; + timestampEof @3 :UInt64; + modelExecutionTime @15 :Float32; + gpuExecutionTime @17 :Float32; + rawPredictions @16 :Data; + + # predicted future position, orientation, etc.. + position @4 :XYZTData; + orientation @5 :XYZTData; + velocity @6 :XYZTData; + orientationRate @7 :XYZTData; + acceleration @19 :XYZTData; + + # prediction lanelines and road edges + laneLines @8 :List(XYZTData); + laneLineProbs @9 :List(Float32); + laneLineStds @13 :List(Float32); + roadEdges @10 :List(XYZTData); + roadEdgeStds @14 :List(Float32); + + # predicted lead cars + leads @11 :List(LeadDataV2); + leadsV3 @18 :List(LeadDataV3); + + meta @12 :MetaData; + confidence @23: ConfidenceClass; + + # Model perceived motion + temporalPose @21 :Pose; + + navEnabledDEPRECATED @22 :Bool; + locationMonoTimeDEPRECATED @24 :UInt64; + + # e2e lateral planner + lateralPlannerSolutionDEPRECATED @25: LateralPlannerSolution; + action @26: Action; + + struct LeadDataV2 { + prob @0 :Float32; # probability that car is your lead at time t + t @1 :Float32; + + # x and y are relative position in device frame + # v is norm relative speed + # a is norm relative acceleration + xyva @2 :List(Float32); + xyvaStd @3 :List(Float32); + } + + struct LeadDataV3 { + prob @0 :Float32; # probability that car is your lead at time t + probTime @1 :Float32; + t @2 :List(Float32); + + # x and y are relative position in device frame + # v absolute norm speed + # a is derivative of v + x @3 :List(Float32); + xStd @4 :List(Float32); + y @5 :List(Float32); + yStd @6 :List(Float32); + v @7 :List(Float32); + vStd @8 :List(Float32); + a @9 :List(Float32); + aStd @10 :List(Float32); + } + + + struct MetaData { + engagedProb @0 :Float32; + desirePrediction @1 :List(Float32); + desireState @5 :List(Float32); + disengagePredictions @6 :DisengagePredictions; + hardBrakePredicted @7 :Bool; + laneChangeState @8 :LaneChangeState; + laneChangeDirection @9 :LaneChangeDirection; + + + # deprecated + brakeDisengageProbDEPRECATED @2 :Float32; + gasDisengageProbDEPRECATED @3 :Float32; + steerOverrideProbDEPRECATED @4 :Float32; + } + + enum ConfidenceClass { + red @0; + yellow @1; + green @2; + } + + struct DisengagePredictions { + t @0 :List(Float32); + brakeDisengageProbs @1 :List(Float32); + gasDisengageProbs @2 :List(Float32); + steerOverrideProbs @3 :List(Float32); + brake3MetersPerSecondSquaredProbs @4 :List(Float32); + brake4MetersPerSecondSquaredProbs @5 :List(Float32); + brake5MetersPerSecondSquaredProbs @6 :List(Float32); + } + + struct Pose { + trans @0 :List(Float32); # m/s in device frame + rot @1 :List(Float32); # rad/s in device frame + transStd @2 :List(Float32); # std m/s in device frame + rotStd @3 :List(Float32); # std rad/s in device frame + } + + struct LateralPlannerSolution { + x @0 :List(Float32); + y @1 :List(Float32); + yaw @2 :List(Float32); + yawRate @3 :List(Float32); + xStd @4 :List(Float32); + yStd @5 :List(Float32); + yawStd @6 :List(Float32); + yawRateStd @7 :List(Float32); + } + + struct Action { + desiredCurvature @0 :Float32; + } +} + +struct EncodeIndex { + # picture from camera + frameId @0 :UInt32; + type @1 :Type; + # index of encoder from start of route + encodeId @2 :UInt32; + # minute long segment this frame is in + segmentNum @3 :Int32; + # index into camera file in segment in presentation order + segmentId @4 :UInt32; + # index into camera file in segment in encode order + segmentIdEncode @5 :UInt32; + timestampSof @6 :UInt64; + timestampEof @7 :UInt64; + + # encoder metadata + flags @8 :UInt32; + len @9 :UInt32; + + enum Type { + bigBoxLossless @0; + fullHEVC @1; + qcameraH264 @6; + livestreamH264 @7; + + # deprecated + bigBoxHEVCDEPRECATED @2; + chffrAndroidH264DEPRECATED @3; + fullLosslessClipDEPRECATED @4; + frontDEPRECATED @5; + + } +} + +struct AndroidLogEntry { + id @0 :UInt8; + ts @1 :UInt64; + priority @2 :UInt8; + pid @3 :Int32; + tid @4 :Int32; + tag @5 :Text; + message @6 :Text; +} + +struct LongitudinalPlan @0xe00b5b3eba12876c { + modelMonoTime @9 :UInt64; + hasLead @7 :Bool; + fcw @8 :Bool; + longitudinalPlanSource @15 :LongitudinalPlanSource; + processingDelay @29 :Float32; + + # desired speed/accel/jerk over next 2.5s + accels @32 :List(Float32); + speeds @33 :List(Float32); + jerks @34 :List(Float32); + + solverExecutionTime @35 :Float32; + + enum LongitudinalPlanSource { + cruise @0; + lead0 @1; + lead1 @2; + lead2 @3; + e2e @4; + } + + # deprecated + vCruiseDEPRECATED @16 :Float32; + aCruiseDEPRECATED @17 :Float32; + vTargetDEPRECATED @3 :Float32; + vTargetFutureDEPRECATED @14 :Float32; + aTargetDEPRECATED @18 :Float32; + vStartDEPRECATED @26 :Float32; + aStartDEPRECATED @27 :Float32; + vMaxDEPRECATED @20 :Float32; + radarStateMonoTimeDEPRECATED @10 :UInt64; + jerkFactorDEPRECATED @6 :Float32; + hasLeftLaneDEPRECATED @23 :Bool; + hasRightLaneDEPRECATED @24 :Bool; + aTargetMinDEPRECATED @4 :Float32; + aTargetMaxDEPRECATED @5 :Float32; + lateralValidDEPRECATED @0 :Bool; + longitudinalValidDEPRECATED @2 :Bool; + dPolyDEPRECATED @1 :List(Float32); + laneWidthDEPRECATED @11 :Float32; + vCurvatureDEPRECATED @21 :Float32; + decelForTurnDEPRECATED @22 :Bool; + mapValidDEPRECATED @25 :Bool; + radarValidDEPRECATED @28 :Bool; + radarCanErrorDEPRECATED @30 :Bool; + commIssueDEPRECATED @31 :Bool; + eventsDEPRECATED @13 :List(Car.CarEvent); + gpsTrajectoryDEPRECATED @12 :GpsTrajectory; + gpsPlannerActiveDEPRECATED @19 :Bool; + personalityDEPRECATED @36 :LongitudinalPersonality; + + struct GpsTrajectory { + x @0 :List(Float32); + y @1 :List(Float32); + } +} +struct UiPlan { + frameId @2 :UInt32; + position @0 :XYZTData; + accel @1 :List(Float32); +} + +struct LateralPlan @0xe1e9318e2ae8b51e { + modelMonoTime @31 :UInt64; + laneWidthDEPRECATED @0 :Float32; + lProbDEPRECATED @5 :Float32; + rProbDEPRECATED @7 :Float32; + dPathPoints @20 :List(Float32); + dProbDEPRECATED @21 :Float32; + + mpcSolutionValid @9 :Bool; + desire @17 :Desire; + laneChangeState @18 :LaneChangeState; + laneChangeDirection @19 :LaneChangeDirection; + useLaneLines @29 :Bool; + + # desired curvatures over next 2.5s in rad/m + psis @26 :List(Float32); + curvatures @27 :List(Float32); + curvatureRates @28 :List(Float32); + + solverExecutionTime @30 :Float32; + solverCost @32 :Float32; + solverState @33 :SolverState; + + struct SolverState { + x @0 :List(List(Float32)); + u @1 :List(Float32); + } + + # deprecated + curvatureDEPRECATED @22 :Float32; + curvatureRateDEPRECATED @23 :Float32; + rawCurvatureDEPRECATED @24 :Float32; + rawCurvatureRateDEPRECATED @25 :Float32; + cProbDEPRECATED @3 :Float32; + dPolyDEPRECATED @1 :List(Float32); + cPolyDEPRECATED @2 :List(Float32); + lPolyDEPRECATED @4 :List(Float32); + rPolyDEPRECATED @6 :List(Float32); + modelValidDEPRECATED @12 :Bool; + commIssueDEPRECATED @15 :Bool; + posenetValidDEPRECATED @16 :Bool; + sensorValidDEPRECATED @14 :Bool; + paramsValidDEPRECATED @10 :Bool; + steeringAngleDegDEPRECATED @8 :Float32; # deg + steeringRateDegDEPRECATED @13 :Float32; # deg/s + angleOffsetDegDEPRECATED @11 :Float32; +} + +struct LiveLocationKalman { + + # More info on reference frames: + # https://github.com/commaai/openpilot/tree/master/common/transformations + + positionECEF @0 : Measurement; + positionGeodetic @1 : Measurement; + velocityECEF @2 : Measurement; + velocityNED @3 : Measurement; + velocityDevice @4 : Measurement; + accelerationDevice @5: Measurement; + + + # These angles are all eulers and roll, pitch, yaw + # orientationECEF transforms to rot matrix: ecef_from_device + orientationECEF @6 : Measurement; + calibratedOrientationECEF @20 : Measurement; + orientationNED @7 : Measurement; + angularVelocityDevice @8 : Measurement; + + # orientationNEDCalibrated transforms to rot matrix: NED_from_calibrated + calibratedOrientationNED @9 : Measurement; + + # Calibrated frame is simply device frame + # aligned with the vehicle + velocityCalibrated @10 : Measurement; + accelerationCalibrated @11 : Measurement; + angularVelocityCalibrated @12 : Measurement; + + gpsWeek @13 :Int32; + gpsTimeOfWeek @14 :Float64; + status @15 :Status; + unixTimestampMillis @16 :Int64; + inputsOK @17 :Bool = true; + posenetOK @18 :Bool = true; + gpsOK @19 :Bool = true; + sensorsOK @21 :Bool = true; + deviceStable @22 :Bool = true; + timeSinceReset @23 :Float64; + excessiveResets @24 :Bool; + timeToFirstFix @25 :Float32; + + filterState @26 : Measurement; + + enum Status { + uninitialized @0; + uncalibrated @1; + valid @2; + } + + struct Measurement { + value @0 : List(Float64); + std @1 : List(Float64); + valid @2 : Bool; + } +} + +struct ProcLog { + cpuTimes @0 :List(CPUTimes); + mem @1 :Mem; + procs @2 :List(Process); + + struct Process { + pid @0 :Int32; + name @1 :Text; + state @2 :UInt8; + ppid @3 :Int32; + + cpuUser @4 :Float32; + cpuSystem @5 :Float32; + cpuChildrenUser @6 :Float32; + cpuChildrenSystem @7 :Float32; + priority @8 :Int64; + nice @9 :Int32; + numThreads @10 :Int32; + startTime @11 :Float64; + + memVms @12 :UInt64; + memRss @13 :UInt64; + + processor @14 :Int32; + + cmdline @15 :List(Text); + exe @16 :Text; + } + + struct CPUTimes { + cpuNum @0 :Int64; + user @1 :Float32; + nice @2 :Float32; + system @3 :Float32; + idle @4 :Float32; + iowait @5 :Float32; + irq @6 :Float32; + softirq @7 :Float32; + } + + struct Mem { + total @0 :UInt64; + free @1 :UInt64; + available @2 :UInt64; + buffers @3 :UInt64; + cached @4 :UInt64; + active @5 :UInt64; + inactive @6 :UInt64; + shared @7 :UInt64; + } +} + +struct GnssMeasurements { + measTime @0 :UInt64; + gpsWeek @1 :Int16; + gpsTimeOfWeek @2 :Float64; + + correctedMeasurements @3 :List(CorrectedMeasurement); + ephemerisStatuses @9 :List(EphemerisStatus); + + kalmanPositionECEF @4 :LiveLocationKalman.Measurement; + kalmanVelocityECEF @5 :LiveLocationKalman.Measurement; + positionECEF @6 :LiveLocationKalman.Measurement; + velocityECEF @7 :LiveLocationKalman.Measurement; + timeToFirstFix @8 :Float32; + # Todo sync this with timing pulse of ublox + + struct EphemerisStatus { + constellationId @0 :ConstellationId; + svId @1 :UInt8; + type @2 :EphemerisType; + source @3 :EphemerisSource; + gpsWeek @4 : UInt16; + tow @5 :Float64; + } + + struct CorrectedMeasurement { + constellationId @0 :ConstellationId; + svId @1 :UInt8; + # Is 0 when not Glonass constellation. + glonassFrequency @2 :Int8; + pseudorange @3 :Float64; + pseudorangeStd @4 :Float64; + pseudorangeRate @5 :Float64; + pseudorangeRateStd @6 :Float64; + # Satellite position and velocity [x,y,z] + satPos @7 :List(Float64); + satVel @8 :List(Float64); + ephemerisSourceDEPRECATED @9 :EphemerisSourceDEPRECATED; + } + + struct EphemerisSourceDEPRECATED { + type @0 :EphemerisType; + # first epoch in file: + gpsWeek @1 :Int16; # -1 if Nav + gpsTimeOfWeek @2 :Int32; # -1 if Nav. Integer for seconds is good enough for logs. + } + + enum ConstellationId { + # Satellite Constellation using the Ublox gnssid as index + gps @0; + sbas @1; + galileo @2; + beidou @3; + imes @4; + qznss @5; + glonass @6; + } + + enum EphemerisType { + nav @0; + # Different ultra-rapid files: + nasaUltraRapid @1; + glonassIacUltraRapid @2; + qcom @3; + } + + enum EphemerisSource { + gnssChip @0; + internet @1; + cache @2; + unknown @3; + } +} + +struct UbloxGnss { + union { + measurementReport @0 :MeasurementReport; + ephemeris @1 :Ephemeris; + ionoData @2 :IonoData; + hwStatus @3 :HwStatus; + hwStatus2 @4 :HwStatus2; + glonassEphemeris @5 :GlonassEphemeris; + satReport @6 :SatReport; + } + + struct SatReport { + #received time of week in gps time in seconds and gps week + iTow @0 :UInt32; + svs @1 :List(SatInfo); + + struct SatInfo { + svId @0 :UInt8; + gnssId @1 :UInt8; + flagsBitfield @2 :UInt32; + } + } + + struct MeasurementReport { + #received time of week in gps time in seconds and gps week + rcvTow @0 :Float64; + gpsWeek @1 :UInt16; + # leap seconds in seconds + leapSeconds @2 :UInt16; + # receiver status + receiverStatus @3 :ReceiverStatus; + # num of measurements to follow + numMeas @4 :UInt8; + measurements @5 :List(Measurement); + + struct ReceiverStatus { + # leap seconds have been determined + leapSecValid @0 :Bool; + # Clock reset applied + clkReset @1 :Bool; + } + + struct Measurement { + svId @0 :UInt8; + trackingStatus @1 :TrackingStatus; + # pseudorange in meters + pseudorange @2 :Float64; + # carrier phase measurement in cycles + carrierCycles @3 :Float64; + # doppler measurement in Hz + doppler @4 :Float32; + # GNSS id, 0 is gps + gnssId @5 :UInt8; + glonassFrequencyIndex @6 :UInt8; + # carrier phase locktime counter in ms + locktime @7 :UInt16; + # Carrier-to-noise density ratio (signal strength) in dBHz + cno @8 :UInt8; + # pseudorange standard deviation in meters + pseudorangeStdev @9 :Float32; + # carrier phase standard deviation in cycles + carrierPhaseStdev @10 :Float32; + # doppler standard deviation in Hz + dopplerStdev @11 :Float32; + sigId @12 :UInt8; + + struct TrackingStatus { + # pseudorange valid + pseudorangeValid @0 :Bool; + # carrier phase valid + carrierPhaseValid @1 :Bool; + # half cycle valid + halfCycleValid @2 :Bool; + # half cycle subtracted from phase + halfCycleSubtracted @3 :Bool; + } + } + } + + struct Ephemeris { + # This is according to the rinex (2?) format + svId @0 :UInt16; + year @1 :UInt16; + month @2 :UInt16; + day @3 :UInt16; + hour @4 :UInt16; + minute @5 :UInt16; + second @6 :Float32; + af0 @7 :Float64; + af1 @8 :Float64; + af2 @9 :Float64; + + iode @10 :Float64; + crs @11 :Float64; + deltaN @12 :Float64; + m0 @13 :Float64; + + cuc @14 :Float64; + ecc @15 :Float64; + cus @16 :Float64; + a @17 :Float64; # note that this is not the root!! + + toe @18 :Float64; + cic @19 :Float64; + omega0 @20 :Float64; + cis @21 :Float64; + + i0 @22 :Float64; + crc @23 :Float64; + omega @24 :Float64; + omegaDot @25 :Float64; + + iDot @26 :Float64; + codesL2 @27 :Float64; + gpsWeekDEPRECATED @28 :Float64; + l2 @29 :Float64; + + svAcc @30 :Float64; + svHealth @31 :Float64; + tgd @32 :Float64; + iodc @33 :Float64; + + transmissionTime @34 :Float64; + fitInterval @35 :Float64; + + toc @36 :Float64; + + ionoCoeffsValid @37 :Bool; + ionoAlpha @38 :List(Float64); + ionoBeta @39 :List(Float64); + + towCount @40 :UInt32; + toeWeek @41 :UInt16; + tocWeek @42 :UInt16; + } + + struct IonoData { + svHealth @0 :UInt32; + tow @1 :Float64; + gpsWeek @2 :Float64; + + ionoAlpha @3 :List(Float64); + ionoBeta @4 :List(Float64); + + healthValid @5 :Bool; + ionoCoeffsValid @6 :Bool; + } + + struct HwStatus { + noisePerMS @0 :UInt16; + agcCnt @1 :UInt16; + aStatus @2 :AntennaSupervisorState; + aPower @3 :AntennaPowerStatus; + jamInd @4 :UInt8; + flags @5 :UInt8; + + enum AntennaSupervisorState { + init @0; + dontknow @1; + ok @2; + short @3; + open @4; + } + + enum AntennaPowerStatus { + off @0; + on @1; + dontknow @2; + } + } + + struct HwStatus2 { + ofsI @0 :Int8; + magI @1 :UInt8; + ofsQ @2 :Int8; + magQ @3 :UInt8; + cfgSource @4 :ConfigSource; + lowLevCfg @5 :UInt32; + postStatus @6 :UInt32; + + enum ConfigSource { + undefined @0; + rom @1; + otp @2; + configpins @3; + flash @4; + } + } + + struct GlonassEphemeris { + svId @0 :UInt16; + year @1 :UInt16; + dayInYear @2 :UInt16; + hour @3 :UInt16; + minute @4 :UInt16; + second @5 :Float32; + + x @6 :Float64; + xVel @7 :Float64; + xAccel @8 :Float64; + y @9 :Float64; + yVel @10 :Float64; + yAccel @11 :Float64; + z @12 :Float64; + zVel @13 :Float64; + zAccel @14 :Float64; + + svType @15 :UInt8; + svURA @16 :Float32; + age @17 :UInt8; + + svHealth @18 :UInt8; + tkDEPRECATED @19 :UInt16; + tb @20 :UInt16; + + tauN @21 :Float64; + deltaTauN @22 :Float64; + gammaN @23 :Float64; + + p1 @24 :UInt8; + p2 @25 :UInt8; + p3 @26 :UInt8; + p4 @27 :UInt8; + + freqNumDEPRECATED @28 :UInt32; + + n4 @29 :UInt8; + nt @30 :UInt16; + freqNum @31 :Int16; + tkSeconds @32 :UInt32; + } +} + +struct QcomGnss @0xde94674b07ae51c1 { + logTs @0 :UInt64; + union { + measurementReport @1 :MeasurementReport; + clockReport @2 :ClockReport; + drMeasurementReport @3 :DrMeasurementReport; + drSvPoly @4 :DrSvPolyReport; + rawLog @5 :Data; + } + + enum MeasurementSource @0xd71a12b6faada7ee { + gps @0; + glonass @1; + beidou @2; + unknown3 @3; + unknown4 @4; + unknown5 @5; + sbas @6; + } + + enum SVObservationState @0xe81e829a0d6c83e9 { + idle @0; + search @1; + searchVerify @2; + bitEdge @3; + trackVerify @4; + track @5; + restart @6; + dpo @7; + glo10msBe @8; + glo10msAt @9; + } + + struct MeasurementStatus @0xe501010e1bcae83b { + subMillisecondIsValid @0 :Bool; + subBitTimeIsKnown @1 :Bool; + satelliteTimeIsKnown @2 :Bool; + bitEdgeConfirmedFromSignal @3 :Bool; + measuredVelocity @4 :Bool; + fineOrCoarseVelocity @5 :Bool; + lockPointValid @6 :Bool; + lockPointPositive @7 :Bool; + lastUpdateFromDifference @8 :Bool; + lastUpdateFromVelocityDifference @9 :Bool; + strongIndicationOfCrossCorelation @10 :Bool; + tentativeMeasurement @11 :Bool; + measurementNotUsable @12 :Bool; + sirCheckIsNeeded @13 :Bool; + probationMode @14 :Bool; + + glonassMeanderBitEdgeValid @15 :Bool; + glonassTimeMarkValid @16 :Bool; + + gpsRoundRobinRxDiversity @17 :Bool; + gpsRxDiversity @18 :Bool; + gpsLowBandwidthRxDiversityCombined @19 :Bool; + gpsHighBandwidthNu4 @20 :Bool; + gpsHighBandwidthNu8 @21 :Bool; + gpsHighBandwidthUniform @22 :Bool; + multipathIndicator @23 :Bool; + + imdJammingIndicator @24 :Bool; + lteB13TxJammingIndicator @25 :Bool; + freshMeasurementIndicator @26 :Bool; + + multipathEstimateIsValid @27 :Bool; + directionIsValid @28 :Bool; + } + + struct MeasurementReport @0xf580d7d86b7b8692 { + source @0 :MeasurementSource; + + fCount @1 :UInt32; + + gpsWeek @2 :UInt16; + glonassCycleNumber @3 :UInt8; + glonassNumberOfDays @4 :UInt16; + + milliseconds @5 :UInt32; + timeBias @6 :Float32; + clockTimeUncertainty @7 :Float32; + clockFrequencyBias @8 :Float32; + clockFrequencyUncertainty @9 :Float32; + + sv @10 :List(SV); + + struct SV @0xf10c595ae7bb2c27 { + svId @0 :UInt8; + observationState @2 :SVObservationState; + observations @3 :UInt8; + goodObservations @4 :UInt8; + gpsParityErrorCount @5 :UInt16; + glonassFrequencyIndex @1 :Int8; + glonassHemmingErrorCount @6 :UInt8; + filterStages @7 :UInt8; + carrierNoise @8 :UInt16; + latency @9 :Int16; + predetectInterval @10 :UInt8; + postdetections @11 :UInt16; + + unfilteredMeasurementIntegral @12 :UInt32; + unfilteredMeasurementFraction @13 :Float32; + unfilteredTimeUncertainty @14 :Float32; + unfilteredSpeed @15 :Float32; + unfilteredSpeedUncertainty @16 :Float32; + measurementStatus @17 :MeasurementStatus; + multipathEstimate @18 :UInt32; + azimuth @19 :Float32; + elevation @20 :Float32; + carrierPhaseCyclesIntegral @21 :Int32; + carrierPhaseCyclesFraction @22 :UInt16; + fineSpeed @23 :Float32; + fineSpeedUncertainty @24 :Float32; + cycleSlipCount @25 :UInt8; + } + + } + + struct ClockReport @0xca965e4add8f4f0b { + hasFCount @0 :Bool; + fCount @1 :UInt32; + + hasGpsWeek @2 :Bool; + gpsWeek @3 :UInt16; + hasGpsMilliseconds @4 :Bool; + gpsMilliseconds @5 :UInt32; + gpsTimeBias @6 :Float32; + gpsClockTimeUncertainty @7 :Float32; + gpsClockSource @8 :UInt8; + + hasGlonassYear @9 :Bool; + glonassYear @10 :UInt8; + hasGlonassDay @11 :Bool; + glonassDay @12 :UInt16; + hasGlonassMilliseconds @13 :Bool; + glonassMilliseconds @14 :UInt32; + glonassTimeBias @15 :Float32; + glonassClockTimeUncertainty @16 :Float32; + glonassClockSource @17 :UInt8; + + bdsWeek @18 :UInt16; + bdsMilliseconds @19 :UInt32; + bdsTimeBias @20 :Float32; + bdsClockTimeUncertainty @21 :Float32; + bdsClockSource @22 :UInt8; + + galWeek @23 :UInt16; + galMilliseconds @24 :UInt32; + galTimeBias @25 :Float32; + galClockTimeUncertainty @26 :Float32; + galClockSource @27 :UInt8; + + clockFrequencyBias @28 :Float32; + clockFrequencyUncertainty @29 :Float32; + frequencySource @30 :UInt8; + gpsLeapSeconds @31 :UInt8; + gpsLeapSecondsUncertainty @32 :UInt8; + gpsLeapSecondsSource @33 :UInt8; + + gpsToGlonassTimeBiasMilliseconds @34 :Float32; + gpsToGlonassTimeBiasMillisecondsUncertainty @35 :Float32; + gpsToBdsTimeBiasMilliseconds @36 :Float32; + gpsToBdsTimeBiasMillisecondsUncertainty @37 :Float32; + bdsToGloTimeBiasMilliseconds @38 :Float32; + bdsToGloTimeBiasMillisecondsUncertainty @39 :Float32; + gpsToGalTimeBiasMilliseconds @40 :Float32; + gpsToGalTimeBiasMillisecondsUncertainty @41 :Float32; + galToGloTimeBiasMilliseconds @42 :Float32; + galToGloTimeBiasMillisecondsUncertainty @43 :Float32; + galToBdsTimeBiasMilliseconds @44 :Float32; + galToBdsTimeBiasMillisecondsUncertainty @45 :Float32; + + hasRtcTime @46 :Bool; + systemRtcTime @47 :UInt32; + fCountOffset @48 :UInt32; + lpmRtcCount @49 :UInt32; + clockResets @50 :UInt32; + } + + struct DrMeasurementReport @0x8053c39445c6c75c { + + reason @0 :UInt8; + seqNum @1 :UInt8; + seqMax @2 :UInt8; + rfLoss @3 :UInt16; + + systemRtcValid @4 :Bool; + fCount @5 :UInt32; + clockResets @6 :UInt32; + systemRtcTime @7 :UInt64; + + gpsLeapSeconds @8 :UInt8; + gpsLeapSecondsUncertainty @9 :UInt8; + gpsToGlonassTimeBiasMilliseconds @10 :Float32; + gpsToGlonassTimeBiasMillisecondsUncertainty @11 :Float32; + + gpsWeek @12 :UInt16; + gpsMilliseconds @13 :UInt32; + gpsTimeBiasMs @14 :UInt32; + gpsClockTimeUncertaintyMs @15 :UInt32; + gpsClockSource @16 :UInt8; + + glonassClockSource @17 :UInt8; + glonassYear @18 :UInt8; + glonassDay @19 :UInt16; + glonassMilliseconds @20 :UInt32; + glonassTimeBias @21 :Float32; + glonassClockTimeUncertainty @22 :Float32; + + clockFrequencyBias @23 :Float32; + clockFrequencyUncertainty @24 :Float32; + frequencySource @25 :UInt8; + + source @26 :MeasurementSource; + + sv @27 :List(SV); + + struct SV @0xf08b81df8cbf459c { + svId @0 :UInt8; + glonassFrequencyIndex @1 :Int8; + observationState @2 :SVObservationState; + observations @3 :UInt8; + goodObservations @4 :UInt8; + filterStages @5 :UInt8; + predetectInterval @6 :UInt8; + cycleSlipCount @7 :UInt8; + postdetections @8 :UInt16; + + measurementStatus @9 :MeasurementStatus; + + carrierNoise @10 :UInt16; + rfLoss @11 :UInt16; + latency @12 :Int16; + + filteredMeasurementFraction @13 :Float32; + filteredMeasurementIntegral @14 :UInt32; + filteredTimeUncertainty @15 :Float32; + filteredSpeed @16 :Float32; + filteredSpeedUncertainty @17 :Float32; + + unfilteredMeasurementFraction @18 :Float32; + unfilteredMeasurementIntegral @19 :UInt32; + unfilteredTimeUncertainty @20 :Float32; + unfilteredSpeed @21 :Float32; + unfilteredSpeedUncertainty @22 :Float32; + + multipathEstimate @23 :UInt32; + azimuth @24 :Float32; + elevation @25 :Float32; + dopplerAcceleration @26 :Float32; + fineSpeed @27 :Float32; + fineSpeedUncertainty @28 :Float32; + + carrierPhase @29 :Float64; + fCount @30 :UInt32; + + parityErrorCount @31 :UInt16; + goodParity @32 :Bool; + } + } + + struct DrSvPolyReport @0xb1fb80811a673270 { + svId @0 :UInt16; + frequencyIndex @1 :Int8; + + hasPosition @2 :Bool; + hasIono @3 :Bool; + hasTropo @4 :Bool; + hasElevation @5 :Bool; + polyFromXtra @6 :Bool; + hasSbasIono @7 :Bool; + + iode @8 :UInt16; + t0 @9 :Float64; + xyz0 @10 :List(Float64); + xyzN @11 :List(Float64); + other @12 :List(Float32); + + positionUncertainty @13 :Float32; + ionoDelay @14 :Float32; + ionoDot @15 :Float32; + sbasIonoDelay @16 :Float32; + sbasIonoDot @17 :Float32; + tropoDelay @18 :Float32; + elevation @19 :Float32; + elevationDot @20 :Float32; + elevationUncertainty @21 :Float32; + velocityCoeff @22 :List(Float64); + + gpsWeek @23 :UInt16; + gpsTow @24 :Float64; + } +} + +struct Clocks { + wallTimeNanos @3 :UInt64; # unix epoch time + + bootTimeNanosDEPRECATED @0 :UInt64; + monotonicNanosDEPRECATED @1 :UInt64; + monotonicRawNanosDEPRECATD @2 :UInt64; + modemUptimeMillisDEPRECATED @4 :UInt64; +} + +struct LiveMpcData { + x @0 :List(Float32); + y @1 :List(Float32); + psi @2 :List(Float32); + curvature @3 :List(Float32); + qpIterations @4 :UInt32; + calculationTime @5 :UInt64; + cost @6 :Float64; +} + +struct LiveLongitudinalMpcData { + xEgo @0 :List(Float32); + vEgo @1 :List(Float32); + aEgo @2 :List(Float32); + xLead @3 :List(Float32); + vLead @4 :List(Float32); + aLead @5 :List(Float32); + aLeadTau @6 :Float32; # lead accel time constant + qpIterations @7 :UInt32; + mpcId @8 :UInt32; + calculationTime @9 :UInt64; + cost @10 :Float64; +} + +struct Joystick { + # convenient for debug and live tuning + axes @0: List(Float32); + buttons @1: List(Bool); +} + +struct DriverStateV2 { + frameId @0 :UInt32; + modelExecutionTime @1 :Float32; + dspExecutionTime @2 :Float32; + rawPredictions @3 :Data; + + poorVisionProb @4 :Float32; + wheelOnRightProb @5 :Float32; + + leftDriverData @6 :DriverData; + rightDriverData @7 :DriverData; + + struct DriverData { + faceOrientation @0 :List(Float32); + faceOrientationStd @1 :List(Float32); + facePosition @2 :List(Float32); + facePositionStd @3 :List(Float32); + faceProb @4 :Float32; + leftEyeProb @5 :Float32; + rightEyeProb @6 :Float32; + leftBlinkProb @7 :Float32; + rightBlinkProb @8 :Float32; + sunglassesProb @9 :Float32; + occludedProb @10 :Float32; + readyProb @11 :List(Float32); + notReadyProb @12 :List(Float32); + } +} + +struct DriverStateDEPRECATED @0xb83c6cc593ed0a00 { + frameId @0 :UInt32; + modelExecutionTime @14 :Float32; + dspExecutionTime @16 :Float32; + rawPredictions @15 :Data; + + faceOrientation @3 :List(Float32); + facePosition @4 :List(Float32); + faceProb @5 :Float32; + leftEyeProb @6 :Float32; + rightEyeProb @7 :Float32; + leftBlinkProb @8 :Float32; + rightBlinkProb @9 :Float32; + faceOrientationStd @11 :List(Float32); + facePositionStd @12 :List(Float32); + sunglassesProb @13 :Float32; + poorVision @17 :Float32; + partialFace @18 :Float32; + distractedPose @19 :Float32; + distractedEyes @20 :Float32; + eyesOnRoad @21 :Float32; + phoneUse @22 :Float32; + occludedProb @23 :Float32; + + readyProb @24 :List(Float32); + notReadyProb @25 :List(Float32); + + irPwrDEPRECATED @10 :Float32; + descriptorDEPRECATED @1 :List(Float32); + stdDEPRECATED @2 :Float32; +} + +struct DriverMonitoringState @0xb83cda094a1da284 { + events @0 :List(Car.CarEvent); + faceDetected @1 :Bool; + isDistracted @2 :Bool; + distractedType @17 :UInt32; + awarenessStatus @3 :Float32; + posePitchOffset @6 :Float32; + posePitchValidCount @7 :UInt32; + poseYawOffset @8 :Float32; + poseYawValidCount @9 :UInt32; + stepChange @10 :Float32; + awarenessActive @11 :Float32; + awarenessPassive @12 :Float32; + isLowStd @13 :Bool; + hiStdCount @14 :UInt32; + isActiveMode @16 :Bool; + isRHD @4 :Bool; + + isPreviewDEPRECATED @15 :Bool; + rhdCheckedDEPRECATED @5 :Bool; +} + +struct Boot { + wallTimeNanos @0 :UInt64; + pstore @4 :Map(Text, Data); + commands @5 :Map(Text, Data); + launchLog @3 :Text; + + lastKmsgDEPRECATED @1 :Data; + lastPmsgDEPRECATED @2 :Data; +} + +struct LiveParametersData { + valid @0 :Bool; + gyroBias @1 :Float32; + angleOffsetDeg @2 :Float32; + angleOffsetAverageDeg @3 :Float32; + stiffnessFactor @4 :Float32; + steerRatio @5 :Float32; + sensorValid @6 :Bool; + posenetSpeed @8 :Float32; + posenetValid @9 :Bool; + angleOffsetFastStd @10 :Float32; + angleOffsetAverageStd @11 :Float32; + stiffnessFactorStd @12 :Float32; + steerRatioStd @13 :Float32; + roll @14 :Float32; + filterState @15 :LiveLocationKalman.Measurement; + + yawRateDEPRECATED @7 :Float32; +} + +struct LiveTorqueParametersData { + liveValid @0 :Bool; + latAccelFactorRaw @1 :Float32; + latAccelOffsetRaw @2 :Float32; + frictionCoefficientRaw @3 :Float32; + latAccelFactorFiltered @4 :Float32; + latAccelOffsetFiltered @5 :Float32; + frictionCoefficientFiltered @6 :Float32; + totalBucketPoints @7 :Float32; + decay @8 :Float32; + maxResets @9 :Float32; + points @10 :List(List(Float32)); + version @11 :Int32; + useParams @12 :Bool; +} + +struct LiveMapDataDEPRECATED { + speedLimitValid @0 :Bool; + speedLimit @1 :Float32; + speedAdvisoryValid @12 :Bool; + speedAdvisory @13 :Float32; + speedLimitAheadValid @14 :Bool; + speedLimitAhead @15 :Float32; + speedLimitAheadDistance @16 :Float32; + curvatureValid @2 :Bool; + curvature @3 :Float32; + wayId @4 :UInt64; + roadX @5 :List(Float32); + roadY @6 :List(Float32); + lastGps @7: GpsLocationData; + roadCurvatureX @8 :List(Float32); + roadCurvature @9 :List(Float32); + distToTurn @10 :Float32; + mapValid @11 :Bool; +} + +struct CameraOdometry { + frameId @4 :UInt32; + timestampEof @5 :UInt64; + trans @0 :List(Float32); # m/s in device frame + rot @1 :List(Float32); # rad/s in device frame + transStd @2 :List(Float32); # std m/s in device frame + rotStd @3 :List(Float32); # std rad/s in device frame + wideFromDeviceEuler @6 :List(Float32); + wideFromDeviceEulerStd @7 :List(Float32); + roadTransformTrans @8 :List(Float32); + roadTransformTransStd @9 :List(Float32); +} + +struct Sentinel { + enum SentinelType { + endOfSegment @0; + endOfRoute @1; + startOfSegment @2; + startOfRoute @3; + } + type @0 :SentinelType; + signal @1 :Int32; +} + +struct UIDebug { + drawTimeMillis @0 :Float32; +} + +struct ManagerState { + processes @0 :List(ProcessState); + + struct ProcessState { + name @0 :Text; + pid @1 :Int32; + running @2 :Bool; + shouldBeRunning @4 :Bool; + exitCode @3 :Int32; + } +} + +struct UploaderState { + immediateQueueSize @0 :UInt32; + immediateQueueCount @1 :UInt32; + rawQueueSize @2 :UInt32; + rawQueueCount @3 :UInt32; + + # stats for last successfully uploaded file + lastTime @4 :Float32; # s + lastSpeed @5 :Float32; # MB/s + lastFilename @6 :Text; +} + +struct NavInstruction { + maneuverPrimaryText @0 :Text; + maneuverSecondaryText @1 :Text; + maneuverDistance @2 :Float32; # m + maneuverType @3 :Text; # TODO: Make Enum + maneuverModifier @4 :Text; # TODO: Make Enum + + distanceRemaining @5 :Float32; # m + timeRemaining @6 :Float32; # s + timeRemainingTypical @7 :Float32; # s + + lanes @8 :List(Lane); + showFull @9 :Bool; + + speedLimit @10 :Float32; # m/s + speedLimitSign @11 :SpeedLimitSign; + + allManeuvers @12 :List(Maneuver); + + struct Lane { + directions @0 :List(Direction); + active @1 :Bool; + activeDirection @2 :Direction; + } + + enum Direction { + none @0; + left @1; + right @2; + straight @3; + slightLeft @4; + slightRight @5; + } + + enum SpeedLimitSign { + mutcd @0; # US Style + vienna @1; # EU Style + } + + struct Maneuver { + distance @0 :Float32; + type @1 :Text; + modifier @2 :Text; + } +} + +struct NavRoute { + coordinates @0 :List(Coordinate); + + struct Coordinate { + latitude @0 :Float32; + longitude @1 :Float32; + } +} + +struct MapRenderState { + locationMonoTime @0 :UInt64; + renderTime @1 :Float32; + frameId @2: UInt32; +} + +struct NavModelData { + frameId @0 :UInt32; + locationMonoTime @6 :UInt64; + modelExecutionTime @1 :Float32; + dspExecutionTime @2 :Float32; + features @3 :List(Float32); + # predicted future position + position @4 :XYData; + desirePrediction @5 :List(Float32); + + # All SI units and in device frame + struct XYData { + x @0 :List(Float32); + y @1 :List(Float32); + xStd @2 :List(Float32); + yStd @3 :List(Float32); + } +} + +struct EncodeData { + idx @0 :EncodeIndex; + data @1 :Data; + header @2 :Data; + unixTimestampNanos @3 :UInt64; + width @4 :UInt32; + height @5 :UInt32; +} + +struct UserFlag { +} + +struct Microphone { + soundPressure @0 :Float32; + + # uncalibrated, A-weighted + soundPressureWeighted @3 :Float32; + soundPressureWeightedDb @1 :Float32; + filteredSoundPressureWeightedDb @2 :Float32; +} + +struct Event { + logMonoTime @0 :UInt64; # nanoseconds + valid @67 :Bool = true; + + union { + # *********** log metadata *********** + initData @1 :InitData; + sentinel @73 :Sentinel; + + # *********** bootlog *********** + boot @60 :Boot; + + # ********** openpilot daemon msgs ********** + gpsNMEA @3 :GPSNMEAData; + can @5 :List(CanData); + controlsState @7 :ControlsState; + gyroscope @99 :SensorEventData; + gyroscope2 @100 :SensorEventData; + accelerometer @98 :SensorEventData; + accelerometer2 @101 :SensorEventData; + magnetometer @95 :SensorEventData; + lightSensor @96 :SensorEventData; + temperatureSensor @97 :SensorEventData; + temperatureSensor2 @123 :SensorEventData; + pandaStates @81 :List(PandaState); + peripheralState @80 :PeripheralState; + radarState @13 :RadarState; + liveTracks @16 :List(LiveTracks); + sendcan @17 :List(CanData); + liveCalibration @19 :LiveCalibrationData; + carState @22 :Car.CarState; + carControl @23 :Car.CarControl; + carOutput @127 :Car.CarOutput; + longitudinalPlan @24 :LongitudinalPlan; + uiPlan @106 :UiPlan; + ubloxGnss @34 :UbloxGnss; + ubloxRaw @39 :Data; + qcomGnss @31 :QcomGnss; + gpsLocationExternal @48 :GpsLocationData; + gpsLocation @21 :GpsLocationData; + gnssMeasurements @91 :GnssMeasurements; + liveParameters @61 :LiveParametersData; + liveTorqueParameters @94 :LiveTorqueParametersData; + cameraOdometry @63 :CameraOdometry; + thumbnail @66: Thumbnail; + onroadEvents @68: List(Car.CarEvent); + carParams @69: Car.CarParams; + driverMonitoringState @71: DriverMonitoringState; + liveLocationKalman @72 :LiveLocationKalman; + modelV2 @75 :ModelDataV2; + driverStateV2 @92 :DriverStateV2; + + # camera stuff, each camera state has a matching encode idx + roadCameraState @2 :FrameData; + driverCameraState @70: FrameData; + wideRoadCameraState @74: FrameData; + roadEncodeIdx @15 :EncodeIndex; + driverEncodeIdx @76 :EncodeIndex; + wideRoadEncodeIdx @77 :EncodeIndex; + qRoadEncodeIdx @90 :EncodeIndex; + + livestreamRoadEncodeIdx @117 :EncodeIndex; + livestreamWideRoadEncodeIdx @118 :EncodeIndex; + livestreamDriverEncodeIdx @119 :EncodeIndex; + + # microphone data + microphone @103 :Microphone; + + # systems stuff + androidLog @20 :AndroidLogEntry; + managerState @78 :ManagerState; + uploaderState @79 :UploaderState; + procLog @33 :ProcLog; + clocks @35 :Clocks; + deviceState @6 :DeviceState; + logMessage @18 :Text; + errorLogMessage @85 :Text; + + # navigation + navInstruction @82 :NavInstruction; + navRoute @83 :NavRoute; + navThumbnail @84: Thumbnail; + mapRenderState @105: MapRenderState; + + # UI services + userFlag @93 :UserFlag; + uiDebug @102 :UIDebug; + + # *********** debug *********** + testJoystick @52 :Joystick; + roadEncodeData @86 :EncodeData; + driverEncodeData @87 :EncodeData; + wideRoadEncodeData @88 :EncodeData; + qRoadEncodeData @89 :EncodeData; + + livestreamRoadEncodeData @120 :EncodeData; + livestreamWideRoadEncodeData @121 :EncodeData; + livestreamDriverEncodeData @122 :EncodeData; + + customReservedRawData0 @124 :Data; + customReservedRawData1 @125 :Data; + customReservedRawData2 @126 :Data; + + # *********** Custom: reserved for forks *********** + customReserved0 @107 :Custom.CustomReserved0; + customReserved1 @108 :Custom.CustomReserved1; + customReserved2 @109 :Custom.CustomReserved2; + customReserved3 @110 :Custom.CustomReserved3; + customReserved4 @111 :Custom.CustomReserved4; + customReserved5 @112 :Custom.CustomReserved5; + customReserved6 @113 :Custom.CustomReserved6; + customReserved7 @114 :Custom.CustomReserved7; + customReserved8 @115 :Custom.CustomReserved8; + customReserved9 @116 :Custom.CustomReserved9; + + # *********** legacy + deprecated *********** + model @9 :Legacy.ModelData; # TODO: rename modelV2 and mark this as deprecated + liveMpcDEPRECATED @36 :LiveMpcData; + liveLongitudinalMpcDEPRECATED @37 :LiveLongitudinalMpcData; + liveLocationKalmanDEPRECATED @51 :Legacy.LiveLocationData; + orbslamCorrectionDEPRECATED @45 :Legacy.OrbslamCorrection; + liveUIDEPRECATED @14 :Legacy.LiveUI; + sensorEventDEPRECATED @4 :SensorEventData; + liveEventDEPRECATED @8 :List(Legacy.LiveEventData); + liveLocationDEPRECATED @25 :Legacy.LiveLocationData; + ethernetDataDEPRECATED @26 :List(Legacy.EthernetPacket); + cellInfoDEPRECATED @28 :List(Legacy.CellInfo); + wifiScanDEPRECATED @29 :List(Legacy.WifiScan); + uiNavigationEventDEPRECATED @50 :Legacy.UiNavigationEvent; + liveMapDataDEPRECATED @62 :LiveMapDataDEPRECATED; + gpsPlannerPointsDEPRECATED @40 :Legacy.GPSPlannerPoints; + gpsPlannerPlanDEPRECATED @41 :Legacy.GPSPlannerPlan; + applanixRawDEPRECATED @42 :Data; + androidGnssDEPRECATED @30 :Legacy.AndroidGnss; + lidarPtsDEPRECATED @32 :Legacy.LidarPts; + navStatusDEPRECATED @38 :Legacy.NavStatus; + trafficEventsDEPRECATED @43 :List(Legacy.TrafficEvent); + liveLocationTimingDEPRECATED @44 :Legacy.LiveLocationData; + liveLocationCorrectedDEPRECATED @46 :Legacy.LiveLocationData; + navUpdateDEPRECATED @27 :Legacy.NavUpdate; + orbObservationDEPRECATED @47 :List(Legacy.OrbObservation); + locationDEPRECATED @49 :Legacy.LiveLocationData; + orbOdometryDEPRECATED @53 :Legacy.OrbOdometry; + orbFeaturesDEPRECATED @54 :Legacy.OrbFeatures; + applanixLocationDEPRECATED @55 :Legacy.LiveLocationData; + orbKeyFrameDEPRECATED @56 :Legacy.OrbKeyFrame; + orbFeaturesSummaryDEPRECATED @58 :Legacy.OrbFeaturesSummary; + featuresDEPRECATED @10 :Legacy.CalibrationFeatures; + kalmanOdometryDEPRECATED @65 :Legacy.KalmanOdometry; + uiLayoutStateDEPRECATED @57 :Legacy.UiLayoutState; + pandaStateDEPRECATED @12 :PandaState; + driverStateDEPRECATED @59 :DriverStateDEPRECATED; + sensorEventsDEPRECATED @11 :List(SensorEventData); + lateralPlanDEPRECATED @64 :LateralPlan; + navModelDEPRECATED @104 :NavModelData; + } +} diff --git a/cereal/maptile.capnp b/cereal/maptile.capnp new file mode 100644 index 000000000..c8a23a182 --- /dev/null +++ b/cereal/maptile.capnp @@ -0,0 +1,49 @@ +using Cxx = import "./include/c++.capnp"; +$Cxx.namespace("cereal"); + +@0xa086df597ef5d7a0; + +# Geometry +struct Point { + x @0: Float64; + y @1: Float64; + z @2: Float64; +} + +struct PolyLine { + points @0: List(Point); +} + +# Map features +struct Lane { + id @0 :Text; + + leftBoundary @1 :LaneBoundary; + rightBoundary @2 :LaneBoundary; + + leftAdjacentId @3 :Text; + rightAdjacentId @4 :Text; + + inboundIds @5 :List(Text); + outboundIds @6 :List(Text); + + struct LaneBoundary { + polyLine @0 :PolyLine; + startHeading @1 :Float32; # WRT north + } +} + +# Map tiles +struct TileSummary { + version @0 :Text; + updatedAt @1 :UInt64; # Millis since epoch + + level @2 :UInt8; + x @3 :UInt16; + y @4 :UInt16; +} + +struct MapTile { + summary @0 :TileSummary; + lanes @1 :List(Lane); +} diff --git a/cereal/messaging/.gitignore b/cereal/messaging/.gitignore new file mode 100644 index 000000000..dbbe8e22a --- /dev/null +++ b/cereal/messaging/.gitignore @@ -0,0 +1,10 @@ +demo +bridge +test_runner +*.o +*.os +*.d +*.a +*.so +messaging_pyx.cpp +build/ diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py new file mode 100644 index 000000000..d8115d181 --- /dev/null +++ b/cereal/messaging/__init__.py @@ -0,0 +1,306 @@ +# must be built with scons +from msgq.messaging.messaging_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \ + set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event +from msgq.messaging.messaging_pyx import MultiplePublishersError, MessagingError + +import os +import capnp +import time + +from typing import Optional, List, Union, Dict, Deque +from collections import deque + +from cereal import log +from cereal.services import SERVICE_LIST + +assert MultiplePublishersError +assert MessagingError +assert toggle_fake_events +assert set_fake_prefix +assert get_fake_prefix +assert delete_fake_prefix +assert wait_for_one_event + +NO_TRAVERSAL_LIMIT = 2**64-1 + +context = Context() + + +def fake_event_handle(endpoint: str, identifier: Optional[str] = None, override: bool = True, enable: bool = False) -> SocketEventHandle: + identifier = identifier or get_fake_prefix() + handle = SocketEventHandle(endpoint, identifier, override) + if override: + handle.enabled = enable + + return handle + + +def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader: + with log.Event.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg: + return msg + + +def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder: + args = { + 'valid': False, + 'logMonoTime': int(time.monotonic() * 1e9), + **kwargs + } + dat = log.Event.new_message(**args) + if service is not None: + if size is None: + dat.init(service) + else: + dat.init(service, size) + return dat + + +def pub_sock(endpoint: str) -> PubSocket: + sock = PubSocket() + sock.connect(context, endpoint) + return sock + + +def sub_sock(endpoint: str, poller: Optional[Poller] = None, addr: str = "127.0.0.1", + conflate: bool = False, timeout: Optional[int] = None) -> SubSocket: + sock = SubSocket() + sock.connect(context, endpoint, addr.encode('utf8'), conflate) + + if timeout is not None: + sock.setTimeout(timeout) + + if poller is not None: + poller.registerSocket(sock) + return sock + + +def drain_sock_raw(sock: SubSocket, wait_for_one: bool = False) -> List[bytes]: + """Receive all message currently available on the queue""" + ret: List[bytes] = [] + while 1: + if wait_for_one and len(ret) == 0: + dat = sock.receive() + else: + dat = sock.receive(non_blocking=True) + + if dat is None: + break + + ret.append(dat) + + return ret + + +def drain_sock(sock: SubSocket, wait_for_one: bool = False) -> List[capnp.lib.capnp._DynamicStructReader]: + """Receive all message currently available on the queue""" + msgs = drain_sock_raw(sock, wait_for_one=wait_for_one) + return [log_from_bytes(m) for m in msgs] + + +# TODO: print when we drop packets? +def recv_sock(sock: SubSocket, wait: bool = False) -> Optional[capnp.lib.capnp._DynamicStructReader]: + """Same as drain sock, but only returns latest message. Consider using conflate instead.""" + dat = None + + while 1: + if wait and dat is None: + recv = sock.receive() + else: + recv = sock.receive(non_blocking=True) + + if recv is None: # Timeout hit + break + + dat = recv + + if dat is not None: + dat = log_from_bytes(dat) + + return dat + + +def recv_one(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]: + dat = sock.receive() + if dat is not None: + dat = log_from_bytes(dat) + return dat + + +def recv_one_or_none(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]: + dat = sock.receive(non_blocking=True) + if dat is not None: + dat = log_from_bytes(dat) + return dat + + +def recv_one_retry(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader: + """Keep receiving until we get a message""" + while True: + dat = sock.receive() + if dat is not None: + return log_from_bytes(dat) + + +class SubMaster: + def __init__(self, services: List[str], poll: Optional[str] = None, + ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None, + ignore_valid: Optional[List[str]] = None, addr: str = "127.0.0.1", frequency: Optional[float] = None): + self.frame = -1 + self.seen = {s: False for s in services} + self.updated = {s: False for s in services} + self.recv_time = {s: 0. for s in services} + self.recv_frame = {s: 0 for s in services} + self.alive = {s: False for s in services} + self.freq_ok = {s: False for s in services} + self.recv_dts: Dict[str, Deque[float]] = {} + self.sock = {} + self.data = {} + self.valid = {} + self.logMonoTime = {} + + self.max_freq = {} + self.min_freq = {} + + self.poller = Poller() + polled_services = set([poll, ] if poll is not None else services) + self.non_polled_services = set(services) - polled_services + + self.ignore_average_freq = [] if ignore_avg_freq is None else ignore_avg_freq + self.ignore_alive = [] if ignore_alive is None else ignore_alive + self.ignore_valid = [] if ignore_valid is None else ignore_valid + + self.simulation = bool(int(os.getenv("SIMULATION", "0"))) + + # if freq and poll aren't specified, assume the max to be conservative + assert frequency is None or poll is None, "Do not specify 'frequency' - frequency of the polled service will be used." + self.update_freq = frequency or max([SERVICE_LIST[s].frequency for s in polled_services]) + + for s in services: + p = self.poller if s not in self.non_polled_services else None + self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True) + + try: + data = new_message(s) + except capnp.lib.capnp.KjException: + data = new_message(s, 0) # lists + + self.data[s] = getattr(data.as_reader(), s) + self.logMonoTime[s] = 0 + self.valid[s] = True # FIXME: this should default to False + + freq = max(min([SERVICE_LIST[s].frequency, self.update_freq]), 1.) + if s == poll: + max_freq = freq + min_freq = freq + else: + max_freq = min(freq, self.update_freq) + if SERVICE_LIST[s].frequency >= 2*self.update_freq: + min_freq = self.update_freq + elif self.update_freq >= 2*SERVICE_LIST[s].frequency: + min_freq = freq + else: + min_freq = min(freq, freq / 2.) + self.max_freq[s] = max_freq*1.2 + self.min_freq[s] = min_freq*0.8 + self.recv_dts[s] = deque(maxlen=int(10*freq)) + + def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader: + return self.data[s] + + def _check_avg_freq(self, s: str) -> bool: + return SERVICE_LIST[s].frequency > 0.99 and (s not in self.ignore_average_freq) and (s not in self.ignore_alive) + + def update(self, timeout: int = 100) -> None: + msgs = [] + for sock in self.poller.poll(timeout): + msgs.append(recv_one_or_none(sock)) + + # non-blocking receive for non-polled sockets + for s in self.non_polled_services: + msgs.append(recv_one_or_none(self.sock[s])) + self.update_msgs(time.monotonic(), msgs) + + def update_msgs(self, cur_time: float, msgs: List[capnp.lib.capnp._DynamicStructReader]) -> None: + self.frame += 1 + self.updated = dict.fromkeys(self.updated, False) + for msg in msgs: + if msg is None: + continue + + s = msg.which() + self.seen[s] = True + self.updated[s] = True + + if self.recv_time[s] > 1e-5: + self.recv_dts[s].append(cur_time - self.recv_time[s]) + self.recv_time[s] = cur_time + self.recv_frame[s] = self.frame + self.data[s] = getattr(msg, s) + self.logMonoTime[s] = msg.logMonoTime + self.valid[s] = msg.valid + + for s in self.data: + if SERVICE_LIST[s].frequency > 1e-5 and not self.simulation: + # alive if delay is within 10x the expected frequency + self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) + + # check average frequency; slow to fall, quick to recover + dts = self.recv_dts[s] + assert dts.maxlen is not None + recent_dts = list(dts)[-int(dts.maxlen / 10):] + try: + avg_freq = 1 / (sum(dts) / len(dts)) + avg_freq_recent = 1 / (sum(recent_dts) / len(recent_dts)) + except ZeroDivisionError: + avg_freq = 0 + avg_freq_recent = 0 + + avg_freq_ok = self.min_freq[s] <= avg_freq <= self.max_freq[s] + recent_freq_ok = self.min_freq[s] <= avg_freq_recent <= self.max_freq[s] + self.freq_ok[s] = avg_freq_ok or recent_freq_ok + else: + self.freq_ok[s] = True + if self.simulation: + self.alive[s] = self.seen[s] # alive is defined as seen when simulation flag set + else: + self.alive[s] = True + + def all_alive(self, service_list: Optional[List[str]] = None) -> bool: + if service_list is None: + service_list = list(self.sock.keys()) + return all(self.alive[s] for s in service_list if s not in self.ignore_alive) + + def all_freq_ok(self, service_list: Optional[List[str]] = None) -> bool: + if service_list is None: + service_list = list(self.sock.keys()) + return all(self.freq_ok[s] for s in service_list if self._check_avg_freq(s)) + + def all_valid(self, service_list: Optional[List[str]] = None) -> bool: + if service_list is None: + service_list = list(self.sock.keys()) + return all(self.valid[s] for s in service_list if s not in self.ignore_valid) + + def all_checks(self, service_list: Optional[List[str]] = None) -> bool: + return self.all_alive(service_list) and self.all_freq_ok(service_list) and self.all_valid(service_list) + + +class PubMaster: + def __init__(self, services: List[str]): + self.sock = {} + for s in services: + self.sock[s] = pub_sock(s) + + def send(self, s: str, dat: Union[bytes, capnp.lib.capnp._DynamicStructBuilder]) -> None: + if not isinstance(dat, bytes): + dat = dat.to_bytes() + self.sock[s].send(dat) + + def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool: + for _ in range(int(timeout*(1./dt))): + if self.sock[s].all_readers_updated(): + return True + time.sleep(dt) + return False + + def all_readers_updated(self, s: str) -> bool: + return self.sock[s].all_readers_updated() # type: ignore diff --git a/cereal/messaging/bridge.cc b/cereal/messaging/bridge.cc new file mode 100644 index 000000000..b16548314 --- /dev/null +++ b/cereal/messaging/bridge.cc @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include + +typedef void (*sighandler_t)(int sig); + +#include "cereal/services.h" +#include "msgq/messaging/impl_msgq.h" +#include "msgq/messaging/impl_zmq.h" + +std::atomic do_exit = false; +static void set_do_exit(int sig) { + do_exit = true; +} + +void sigpipe_handler(int sig) { + assert(sig == SIGPIPE); + std::cout << "SIGPIPE received" << std::endl; +} + +static std::vector get_services(std::string whitelist_str, bool zmq_to_msgq) { + std::vector service_list; + for (const auto& it : services) { + std::string name = it.second.name; + bool in_whitelist = whitelist_str.find(name) != std::string::npos; + if (name == "plusFrame" || name == "uiLayoutState" || (zmq_to_msgq && !in_whitelist)) { + continue; + } + service_list.push_back(name); + } + return service_list; +} + +int main(int argc, char** argv) { + signal(SIGPIPE, (sighandler_t)sigpipe_handler); + signal(SIGINT, (sighandler_t)set_do_exit); + signal(SIGTERM, (sighandler_t)set_do_exit); + + bool zmq_to_msgq = argc > 2; + std::string ip = zmq_to_msgq ? argv[1] : "127.0.0.1"; + std::string whitelist_str = zmq_to_msgq ? std::string(argv[2]) : ""; + + Poller *poller; + Context *pub_context; + Context *sub_context; + if (zmq_to_msgq) { // republishes zmq debugging messages as msgq + poller = new ZMQPoller(); + pub_context = new MSGQContext(); + sub_context = new ZMQContext(); + } else { + poller = new MSGQPoller(); + pub_context = new ZMQContext(); + sub_context = new MSGQContext(); + } + + std::map sub2pub; + for (auto endpoint : get_services(whitelist_str, zmq_to_msgq)) { + PubSocket * pub_sock; + SubSocket * sub_sock; + if (zmq_to_msgq) { + pub_sock = new MSGQPubSocket(); + sub_sock = new ZMQSubSocket(); + } else { + pub_sock = new ZMQPubSocket(); + sub_sock = new MSGQSubSocket(); + } + pub_sock->connect(pub_context, endpoint); + sub_sock->connect(sub_context, endpoint, ip, false); + + poller->registerSocket(sub_sock); + sub2pub[sub_sock] = pub_sock; + } + + while (!do_exit) { + for (auto sub_sock : poller->poll(100)) { + Message * msg = sub_sock->receive(); + if (msg == NULL) continue; + int ret; + do { + ret = sub2pub[sub_sock]->sendMessage(msg); + } while (ret == -1 && errno == EINTR && !do_exit); + assert(ret >= 0 || do_exit); + delete msg; + + if (do_exit) break; + } + } + return 0; +} diff --git a/cereal/messaging/demo.cc b/cereal/messaging/demo.cc new file mode 100644 index 000000000..5b4d24468 --- /dev/null +++ b/cereal/messaging/demo.cc @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +#include "cereal/messaging/messaging.h" +#include "cereal/messaging/impl_zmq.h" + +#define MSGS 1e5 + +int main() { + Context * c = Context::create(); + SubSocket * sub_sock = SubSocket::create(c, "controlsState"); + PubSocket * pub_sock = PubSocket::create(c, "controlsState"); + + char data[8]; + + Poller * poller = Poller::create({sub_sock}); + + auto start = std::chrono::steady_clock::now(); + + for (uint64_t i = 0; i < MSGS; i++){ + *(uint64_t*)data = i; + pub_sock->send(data, 8); + + auto r = poller->poll(100); + + for (auto p : r){ + Message * m = p->receive(); + uint64_t ii = *(uint64_t*)m->getData(); + assert(i == ii); + delete m; + } + } + + + auto end = std::chrono::steady_clock::now(); + double elapsed = std::chrono::duration_cast(end - start).count() / 1e9; + double throughput = ((double) MSGS / (double) elapsed); + std::cout << throughput << " msg/s" << std::endl; + + delete poller; + delete sub_sock; + delete pub_sock; + delete c; + + + return 0; +} diff --git a/cereal/messaging/demo.py b/cereal/messaging/demo.py new file mode 100644 index 000000000..e4850e32b --- /dev/null +++ b/cereal/messaging/demo.py @@ -0,0 +1,29 @@ +import time + +from messaging_pyx import Context, Poller, SubSocket, PubSocket + +MSGS = 1e5 + +if __name__ == "__main__": + c = Context() + sub_sock = SubSocket() + pub_sock = PubSocket() + + sub_sock.connect(c, "controlsState") + pub_sock.connect(c, "controlsState") + + poller = Poller() + poller.registerSocket(sub_sock) + + t = time.time() + for i in range(int(MSGS)): + bts = i.to_bytes(4, 'little') + pub_sock.send(bts) + + for s in poller.poll(100): + dat = s.receive() + ii = int.from_bytes(dat, 'little') + assert(i == ii) + + dt = time.time() - t + print("%.1f msg/s" % (MSGS / dt)) diff --git a/cereal/messaging/messaging.h b/cereal/messaging/messaging.h new file mode 100644 index 000000000..b0f8b5535 --- /dev/null +++ b/cereal/messaging/messaging.h @@ -0,0 +1,112 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include "cereal/gen/cpp/log.capnp.h" +#include "msgq/messaging/messaging.h" + +#ifdef __APPLE__ +#define CLOCK_BOOTTIME CLOCK_MONOTONIC +#endif + +#define MSG_MULTIPLE_PUBLISHERS 100 + + +class SubMaster { +public: + SubMaster(const std::vector &service_list, const std::vector &poll = {}, + const char *address = nullptr, const std::vector &ignore_alive = {}); + void update(int timeout = 1000); + void update_msgs(uint64_t current_time, const std::vector> &messages); + inline bool allAlive(const std::vector &service_list = {}) { return all_(service_list, false, true); } + inline bool allValid(const std::vector &service_list = {}) { return all_(service_list, true, false); } + inline bool allAliveAndValid(const std::vector &service_list = {}) { return all_(service_list, true, true); } + void drain(); + ~SubMaster(); + + uint64_t frame = 0; + bool updated(const char *name) const; + bool alive(const char *name) const; + bool valid(const char *name) const; + uint64_t rcv_frame(const char *name) const; + uint64_t rcv_time(const char *name) const; + cereal::Event::Reader &operator[](const char *name) const; + +private: + bool all_(const std::vector &service_list, bool valid, bool alive); + Poller *poller_ = nullptr; + struct SubMessage; + std::map messages_; + std::map services_; +}; + +class MessageBuilder : public capnp::MallocMessageBuilder { +public: + MessageBuilder() = default; + + cereal::Event::Builder initEvent(bool valid = true) { + cereal::Event::Builder event = initRoot(); + struct timespec t; + clock_gettime(CLOCK_BOOTTIME, &t); + uint64_t current_time = t.tv_sec * 1000000000ULL + t.tv_nsec; + event.setLogMonoTime(current_time); + event.setValid(valid); + return event; + } + + kj::ArrayPtr toBytes() { + heapArray_ = capnp::messageToFlatArray(*this); + return heapArray_.asBytes(); + } + + size_t getSerializedSize() { + return capnp::computeSerializedSizeInWords(*this) * sizeof(capnp::word); + } + + int serializeToBuffer(unsigned char *buffer, size_t buffer_size) { + size_t serialized_size = getSerializedSize(); + if (serialized_size > buffer_size) { return -1; } + kj::ArrayOutputStream out(kj::ArrayPtr(buffer, buffer_size)); + capnp::writeMessage(out, *this); + return serialized_size; + } + +private: + kj::Array heapArray_; +}; + +class PubMaster { +public: + PubMaster(const std::vector &service_list); + inline int send(const char *name, capnp::byte *data, size_t size) { return sockets_.at(name)->send((char *)data, size); } + int send(const char *name, MessageBuilder &msg); + ~PubMaster(); + +private: + std::map sockets_; +}; + +class AlignedBuffer { +public: + kj::ArrayPtr align(const char *data, const size_t size) { + words_size = size / sizeof(capnp::word) + 1; + if (aligned_buf.size() < words_size) { + aligned_buf = kj::heapArray(words_size < 512 ? 512 : words_size); + } + memcpy(aligned_buf.begin(), data, size); + return aligned_buf.slice(0, words_size); + } + inline kj::ArrayPtr align(Message *m) { + return align(m->getData(), m->getSize()); + } +private: + kj::Array aligned_buf; + size_t words_size; +}; diff --git a/cereal/messaging/msgq.md b/cereal/messaging/msgq.md new file mode 100644 index 000000000..34fe35682 --- /dev/null +++ b/cereal/messaging/msgq.md @@ -0,0 +1,54 @@ +# MSGQ: A lock free single producer multi consumer message queue + +## What is MSGQ? +MSGQ is a system to pass messages from a single producer to multiple consumers. All the consumers need to be able to receive all the messages. It is designed to be a high performance replacement for ZMQ-like SUB/PUB patterns. It uses a ring buffer in shared memory to efficiently read and write data. Each read requires a copy. Writing can be done without a copy, as long as the size of the data is known in advance. + +## Storage +The storage for the queue consists of an area of metadata, and the actual buffer. The metadata contains: + +1. A counter to the number of readers that are active +2. A pointer to the head of the queue for writing. From now on referred to as *write pointer* +3. A cycle counter for the writer. This counter is incremented when the writer wraps around +4. N pointers, pointing to the current read position for all the readers. From now on referred to as *read pointer* +5. N counters, counting the number of cycles for all the readers +6. N booleans, indicating validity for all the readers. From now on referred to as *validity flag* + +The counter and the pointer are both 32 bit values, packed into 64 bit so they can be read and written atomically. + +The data buffer is a ring buffer. All messages are prefixed by an 8 byte size field, followed by the data. A size of -1 indicates a wrap-around, and means the next message is stored at the beginning of the buffer. + + +## Writing +Writing involves the following steps: + +1. Check if the area that is to be written overlaps with any of the read pointers, mark those readers as invalid by clearing the validity flag. +2. Write the message +3. Increase the write pointer by the size of the message + +In case there is not enough space at the end of the buffer, a special empty message with a prefix of -1 is written. The cycle counter is incremented by one. In this case step 1 will check there are no read pointers pointing to the remainder of the buffer. Then another write cycle will start with the actual message. + +There always needs to be 8 bytes of empty space at the end of the buffer. By doing this there is always space to write the -1. + +## Reset reader +When the reader is lagging too much behind the read pointer becomes invalid and no longer points to the beginning of a valid message. To reset a reader to the current write pointer, the following steps are performed: + +1. Set valid flag +2. Set read cycle counter to that of the writer +3. Set read pointer to write pointer + +## Reading +Reading involves the following steps: + +1. Read the size field at the current read pointer +2. Read the validity flag +3. Copy the data out of the buffer +4. Increase the read pointer by the size of the message +5. Check the validity flag again + +Before starting the copy, the valid flag is checked. This is to prevent a race condition where the size prefix was invalid, and the read could read outside of the buffer. Make sure that step 1 and 2 are not reordered by your compiler or CPU. + +If a writer overwrites the data while it's being copied out, the data will be invalid. Therefore the validity flag is also checked after reading it. The order of step 4 and 5 does not matter. + +If at steps 2 or 5 the validity flag is not set, the reader is reset. Any data that was already read is discarded. After the reader is reset, the reading starts from the beginning. + +If a message with size -1 is encountered, step 3 and 4 are replaced by increasing the cycle counter and setting the read pointer to the beginning of the buffer. After that another read is performed. diff --git a/cereal/messaging/msgq_tests.cc b/cereal/messaging/msgq_tests.cc new file mode 100644 index 000000000..d33facbc0 --- /dev/null +++ b/cereal/messaging/msgq_tests.cc @@ -0,0 +1,394 @@ +#include "catch2/catch.hpp" +#include "cereal/messaging/msgq.h" + +TEST_CASE("ALIGN"){ + REQUIRE(ALIGN(0) == 0); + REQUIRE(ALIGN(1) == 8); + REQUIRE(ALIGN(7) == 8); + REQUIRE(ALIGN(8) == 8); + REQUIRE(ALIGN(99999) == 100000); +} + +TEST_CASE("msgq_msg_init_size"){ + const size_t msg_size = 30; + msgq_msg_t msg; + + msgq_msg_init_size(&msg, msg_size); + REQUIRE(msg.size == msg_size); + + msgq_msg_close(&msg); +} + +TEST_CASE("msgq_msg_init_data"){ + const size_t msg_size = 30; + char * data = new char[msg_size]; + + for (size_t i = 0; i < msg_size; i++){ + data[i] = i; + } + + msgq_msg_t msg; + msgq_msg_init_data(&msg, data, msg_size); + + REQUIRE(msg.size == msg_size); + REQUIRE(memcmp(msg.data, data, msg_size) == 0); + + delete[] data; + msgq_msg_close(&msg); +} + + +TEST_CASE("msgq_init_subscriber"){ + remove("/dev/shm/test_queue"); + msgq_queue_t q; + msgq_new_queue(&q, "test_queue", 1024); + REQUIRE(*q.num_readers == 0); + + q.reader_id = 1; + *q.read_valids[0] = false; + *q.read_pointers[0] = ((uint64_t)1 << 32); + + *q.write_pointer = 255; + + msgq_init_subscriber(&q); + REQUIRE(q.read_conflate == false); + REQUIRE(*q.read_valids[0] == true); + REQUIRE((*q.read_pointers[0] >> 32) == 0); + REQUIRE((*q.read_pointers[0] & 0xFFFFFFFF) == 255); +} + +TEST_CASE("msgq_msg_send first message"){ + remove("/dev/shm/test_queue"); + msgq_queue_t q; + msgq_new_queue(&q, "test_queue", 1024); + msgq_init_publisher(&q); + + REQUIRE(*q.write_pointer == 0); + + size_t msg_size = 128; + + SECTION("Aligned message size"){ + } + SECTION("Unaligned message size"){ + msg_size--; + } + + char * data = new char[msg_size]; + + for (size_t i = 0; i < msg_size; i++){ + data[i] = i; + } + + msgq_msg_t msg; + msgq_msg_init_data(&msg, data, msg_size); + + + msgq_msg_send(&msg, &q); + REQUIRE(*(int64_t*)q.data == msg_size); // Check size tag + REQUIRE(*q.write_pointer == 128 + sizeof(int64_t)); + REQUIRE(memcmp(q.data + sizeof(int64_t), data, msg_size) == 0); + + delete[] data; + msgq_msg_close(&msg); +} + +TEST_CASE("msgq_msg_send test wraparound"){ + remove("/dev/shm/test_queue"); + msgq_queue_t q; + msgq_new_queue(&q, "test_queue", 1024); + msgq_init_publisher(&q); + + REQUIRE((*q.write_pointer & 0xFFFFFFFF) == 0); + REQUIRE((*q.write_pointer >> 32) == 0); + + const size_t msg_size = 120; + msgq_msg_t msg; + msgq_msg_init_size(&msg, msg_size); + + for (int i = 0; i < 8; i++) { + msgq_msg_send(&msg, &q); + } + // Check 8th message was written at the beginning + REQUIRE((*q.write_pointer & 0xFFFFFFFF) == msg_size + sizeof(int64_t)); + + // Check cycle count + REQUIRE((*q.write_pointer >> 32) == 1); + + // Check wraparound tag + char * tag_location = q.data; + tag_location += 7 * (msg_size + sizeof(int64_t)); + REQUIRE(*(int64_t*)tag_location == -1); + + msgq_msg_close(&msg); +} + +TEST_CASE("msgq_msg_recv test wraparound"){ + remove("/dev/shm/test_queue"); + msgq_queue_t q_pub, q_sub; + msgq_new_queue(&q_pub, "test_queue", 1024); + msgq_new_queue(&q_sub, "test_queue", 1024); + + msgq_init_publisher(&q_pub); + msgq_init_subscriber(&q_sub); + + REQUIRE((*q_pub.write_pointer >> 32) == 0); + REQUIRE((*q_sub.read_pointers[0] >> 32) == 0); + + const size_t msg_size = 120; + msgq_msg_t msg1; + msgq_msg_init_size(&msg1, msg_size); + + + SECTION("Check cycle counter after reset") { + for (int i = 0; i < 8; i++) { + msgq_msg_send(&msg1, &q_pub); + } + + msgq_msg_t msg2; + msgq_msg_recv(&msg2, &q_sub); + REQUIRE(msg2.size == 0); // Reader had to reset + msgq_msg_close(&msg2); + } + SECTION("Check cycle counter while keeping up with writer") { + for (int i = 0; i < 8; i++) { + msgq_msg_send(&msg1, &q_pub); + + msgq_msg_t msg2; + msgq_msg_recv(&msg2, &q_sub); + REQUIRE(msg2.size > 0); + msgq_msg_close(&msg2); + } + } + + REQUIRE((*q_sub.read_pointers[0] >> 32) == 1); + msgq_msg_close(&msg1); +} + +TEST_CASE("msgq_msg_send test invalidation"){ + remove("/dev/shm/test_queue"); + msgq_queue_t q_pub, q_sub; + msgq_new_queue(&q_pub, "test_queue", 1024); + msgq_new_queue(&q_sub, "test_queue", 1024); + + msgq_init_publisher(&q_pub); + msgq_init_subscriber(&q_sub); + *q_sub.write_pointer = (uint64_t)1 << 32; + + REQUIRE(*q_sub.read_valids[0] == true); + + SECTION("read pointer in tag"){ + *q_sub.read_pointers[0] = 0; + } + SECTION("read pointer in data section"){ + *q_sub.read_pointers[0] = 64; + } + SECTION("read pointer in wraparound section"){ + *q_pub.write_pointer = ((uint64_t)1 << 32) | 1000; // Writer is one cycle ahead + *q_sub.read_pointers[0] = 1020; + } + + msgq_msg_t msg; + msgq_msg_init_size(&msg, 128); + msgq_msg_send(&msg, &q_pub); + + REQUIRE(*q_sub.read_valids[0] == false); + + msgq_msg_close(&msg); +} + +TEST_CASE("msgq_init_subscriber init 2 subscribers"){ + remove("/dev/shm/test_queue"); + msgq_queue_t q1, q2; + msgq_new_queue(&q1, "test_queue", 1024); + msgq_new_queue(&q2, "test_queue", 1024); + + *q1.num_readers = 0; + + REQUIRE(*q1.num_readers == 0); + REQUIRE(*q2.num_readers == 0); + + msgq_init_subscriber(&q1); + REQUIRE(*q1.num_readers == 1); + REQUIRE(*q2.num_readers == 1); + REQUIRE(q1.reader_id == 0); + + msgq_init_subscriber(&q2); + REQUIRE(*q1.num_readers == 2); + REQUIRE(*q2.num_readers == 2); + REQUIRE(q2.reader_id == 1); +} + + +TEST_CASE("Write 1 msg, read 1 msg", "[integration]"){ + remove("/dev/shm/test_queue"); + const size_t msg_size = 128; + msgq_queue_t writer, reader; + + msgq_new_queue(&writer, "test_queue", 1024); + msgq_new_queue(&reader, "test_queue", 1024); + + msgq_init_publisher(&writer); + msgq_init_subscriber(&reader); + + // Build 128 byte message + msgq_msg_t outgoing_msg; + msgq_msg_init_size(&outgoing_msg, msg_size); + + for (size_t i = 0; i < msg_size; i++){ + outgoing_msg.data[i] = i; + } + + REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); + + msgq_msg_t incoming_msg1; + REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size); + REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0); + + // Verify that there are no more messages + msgq_msg_t incoming_msg2; + REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == 0); + + msgq_msg_close(&outgoing_msg); + msgq_msg_close(&incoming_msg1); + msgq_msg_close(&incoming_msg2); +} + +TEST_CASE("Write 2 msg, read 2 msg - conflate = false", "[integration]"){ + remove("/dev/shm/test_queue"); + const size_t msg_size = 128; + msgq_queue_t writer, reader; + + msgq_new_queue(&writer, "test_queue", 1024); + msgq_new_queue(&reader, "test_queue", 1024); + + msgq_init_publisher(&writer); + msgq_init_subscriber(&reader); + + // Build 128 byte message + msgq_msg_t outgoing_msg; + msgq_msg_init_size(&outgoing_msg, msg_size); + + for (size_t i = 0; i < msg_size; i++){ + outgoing_msg.data[i] = i; + } + + REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); + REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); + + msgq_msg_t incoming_msg1; + REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size); + REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0); + + msgq_msg_t incoming_msg2; + REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == msg_size); + REQUIRE(memcmp(incoming_msg2.data, outgoing_msg.data, msg_size) == 0); + + msgq_msg_close(&outgoing_msg); + msgq_msg_close(&incoming_msg1); + msgq_msg_close(&incoming_msg2); +} + +TEST_CASE("Write 2 msg, read 2 msg - conflate = true", "[integration]"){ + remove("/dev/shm/test_queue"); + const size_t msg_size = 128; + msgq_queue_t writer, reader; + + msgq_new_queue(&writer, "test_queue", 1024); + msgq_new_queue(&reader, "test_queue", 1024); + + msgq_init_publisher(&writer); + msgq_init_subscriber(&reader); + reader.read_conflate = true; + + // Build 128 byte message + msgq_msg_t outgoing_msg; + msgq_msg_init_size(&outgoing_msg, msg_size); + + for (size_t i = 0; i < msg_size; i++){ + outgoing_msg.data[i] = i; + } + + REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); + REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); + + msgq_msg_t incoming_msg1; + REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size); + REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0); + + // Verify that there are no more messages + msgq_msg_t incoming_msg2; + REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == 0); + + msgq_msg_close(&outgoing_msg); + msgq_msg_close(&incoming_msg1); + msgq_msg_close(&incoming_msg2); +} + +TEST_CASE("1 publisher, 1 slow subscriber", "[integration]"){ + remove("/dev/shm/test_queue"); + msgq_queue_t writer, reader; + + msgq_new_queue(&writer, "test_queue", 1024); + msgq_new_queue(&reader, "test_queue", 1024); + + msgq_init_publisher(&writer); + msgq_init_subscriber(&reader); + + int n_received = 0; + int n_skipped = 0; + + for (uint64_t i = 0; i < 1e5; i++) { + msgq_msg_t outgoing_msg; + msgq_msg_init_data(&outgoing_msg, (char*)&i, sizeof(uint64_t)); + msgq_msg_send(&outgoing_msg, &writer); + msgq_msg_close(&outgoing_msg); + + if (i % 10 == 0){ + msgq_msg_t msg1; + msgq_msg_recv(&msg1, &reader); + + if (msg1.size == 0){ + n_skipped++; + } else { + n_received++; + } + msgq_msg_close(&msg1); + } + } + + // TODO: verify these numbers by hand + REQUIRE(n_received == 8572); + REQUIRE(n_skipped == 1428); +} + +TEST_CASE("1 publisher, 2 subscribers", "[integration]"){ + remove("/dev/shm/test_queue"); + msgq_queue_t writer, reader1, reader2; + + msgq_new_queue(&writer, "test_queue", 1024); + msgq_new_queue(&reader1, "test_queue", 1024); + msgq_new_queue(&reader2, "test_queue", 1024); + + msgq_init_publisher(&writer); + msgq_init_subscriber(&reader1); + msgq_init_subscriber(&reader2); + + for (uint64_t i = 0; i < 1024 * 3; i++) { + msgq_msg_t outgoing_msg; + msgq_msg_init_data(&outgoing_msg, (char*)&i, sizeof(uint64_t)); + msgq_msg_send(&outgoing_msg, &writer); + + msgq_msg_t msg1, msg2; + msgq_msg_recv(&msg1, &reader1); + msgq_msg_recv(&msg2, &reader2); + + REQUIRE(msg1.size == sizeof(uint64_t)); + REQUIRE(msg2.size == sizeof(uint64_t)); + REQUIRE(*(uint64_t*)msg1.data == i); + REQUIRE(*(uint64_t*)msg2.data == i); + + msgq_msg_close(&outgoing_msg); + msgq_msg_close(&msg1); + msgq_msg_close(&msg2); + } +} diff --git a/cereal/messaging/socketmaster.cc b/cereal/messaging/socketmaster.cc new file mode 100644 index 000000000..cd697b1f5 --- /dev/null +++ b/cereal/messaging/socketmaster.cc @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include + +#include "cereal/services.h" +#include "cereal/messaging/messaging.h" + + +const bool SIMULATION = (getenv("SIMULATION") != nullptr) && (std::string(getenv("SIMULATION")) == "1"); + +static inline uint64_t nanos_since_boot() { + struct timespec t; + clock_gettime(CLOCK_BOOTTIME, &t); + return t.tv_sec * 1000000000ULL + t.tv_nsec; +} + +static inline bool inList(const std::vector &list, const char *value) { + for (auto &v : list) { + if (strcmp(value, v) == 0) return true; + } + return false; +} + +class MessageContext { +public: + MessageContext() : ctx_(nullptr) {} + ~MessageContext() { delete ctx_; } + inline Context *context() { + std::call_once(init_flag, [=]() { ctx_ = Context::create(); }); + return ctx_; + } +private: + Context *ctx_; + std::once_flag init_flag; +}; + +MessageContext message_context; + +struct SubMaster::SubMessage { + std::string name; + SubSocket *socket = nullptr; + int freq = 0; + bool updated = false, alive = false, valid = true, ignore_alive; + uint64_t rcv_time = 0, rcv_frame = 0; + void *allocated_msg_reader = nullptr; + bool is_polled = false; + capnp::FlatArrayMessageReader *msg_reader = nullptr; + AlignedBuffer aligned_buf; + cereal::Event::Reader event; +}; + +SubMaster::SubMaster(const std::vector &service_list, const std::vector &poll, + const char *address, const std::vector &ignore_alive) { + poller_ = Poller::create(); + for (auto name : service_list) { + assert(services.count(std::string(name)) > 0); + + service serv = services.at(std::string(name)); + SubSocket *socket = SubSocket::create(message_context.context(), name, address ? address : "127.0.0.1", true); + assert(socket != 0); + bool is_polled = inList(poll, name) || poll.empty(); + if (is_polled) poller_->registerSocket(socket); + SubMessage *m = new SubMessage{ + .name = name, + .socket = socket, + .freq = serv.frequency, + .ignore_alive = inList(ignore_alive, name), + .allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)), + .is_polled = is_polled}; + m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader({}); + messages_[socket] = m; + services_[name] = m; + } +} + +void SubMaster::update(int timeout) { + for (auto &kv : messages_) kv.second->updated = false; + + auto sockets = poller_->poll(timeout); + + // add non-polled sockets for non-blocking receive + for (auto &kv : messages_) { + SubMessage *m = kv.second; + SubSocket *s = kv.first; + if (!m->is_polled) sockets.push_back(s); + } + + uint64_t current_time = nanos_since_boot(); + + std::vector> messages; + + for (auto s : sockets) { + Message *msg = s->receive(true); + if (msg == nullptr) continue; + + SubMessage *m = messages_.at(s); + + m->msg_reader->~FlatArrayMessageReader(); + capnp::ReaderOptions options; + options.traversalLimitInWords = kj::maxValue; // Don't limit + m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader(m->aligned_buf.align(msg), options); + delete msg; + messages.push_back({m->name, m->msg_reader->getRoot()}); + } + + update_msgs(current_time, messages); +} + +void SubMaster::update_msgs(uint64_t current_time, const std::vector> &messages){ + if (++frame == UINT64_MAX) frame = 1; + + for (auto &kv : messages) { + auto m_find = services_.find(kv.first); + if (m_find == services_.end()){ + continue; + } + SubMessage *m = m_find->second; + m->event = kv.second; + m->updated = true; + m->rcv_time = current_time; + m->rcv_frame = frame; + m->valid = m->event.getValid(); + if (SIMULATION) m->alive = true; + } + + if (!SIMULATION) { + for (auto &kv : messages_) { + SubMessage *m = kv.second; + m->alive = (m->freq <= (1e-5) || ((current_time - m->rcv_time) * (1e-9)) < (10.0 / m->freq)); + } + } +} + +bool SubMaster::all_(const std::vector &service_list, bool valid, bool alive) { + int found = 0; + for (auto &kv : messages_) { + SubMessage *m = kv.second; + if (service_list.size() == 0 || inList(service_list, m->name.c_str())) { + found += (!valid || m->valid) && (!alive || (m->alive || m->ignore_alive)); + } + } + return service_list.size() == 0 ? found == messages_.size() : found == service_list.size(); +} + +void SubMaster::drain() { + while (true) { + auto polls = poller_->poll(0); + if (polls.size() == 0) + break; + + for (auto sock : polls) { + Message *msg = sock->receive(true); + delete msg; + } + } +} + +bool SubMaster::updated(const char *name) const { + return services_.at(name)->updated; +} + +bool SubMaster::alive(const char *name) const { + return services_.at(name)->alive; +} + +bool SubMaster::valid(const char *name) const { + return services_.at(name)->valid; +} + +uint64_t SubMaster::rcv_frame(const char *name) const { + return services_.at(name)->rcv_frame; +} + +uint64_t SubMaster::rcv_time(const char *name) const { + return services_.at(name)->rcv_time; +} + +cereal::Event::Reader &SubMaster::operator[](const char *name) const { + return services_.at(name)->event; +} + +SubMaster::~SubMaster() { + delete poller_; + for (auto &kv : messages_) { + SubMessage *m = kv.second; + m->msg_reader->~FlatArrayMessageReader(); + free(m->allocated_msg_reader); + delete m->socket; + delete m; + } +} + +PubMaster::PubMaster(const std::vector &service_list) { + for (auto name : service_list) { + assert(services.count(name) > 0); + PubSocket *socket = PubSocket::create(message_context.context(), name); + assert(socket); + sockets_[name] = socket; + } +} + +int PubMaster::send(const char *name, MessageBuilder &msg) { + auto bytes = msg.toBytes(); + return send(name, bytes.begin(), bytes.size()); +} + +PubMaster::~PubMaster() { + for (auto s : sockets_) delete s.second; +} diff --git a/cereal/messaging/stress.py b/cereal/messaging/stress.py new file mode 100644 index 000000000..1a27e520e --- /dev/null +++ b/cereal/messaging/stress.py @@ -0,0 +1,14 @@ +from messaging_pyx import Context, SubSocket, PubSocket + +if __name__ == "__main__": + c = Context() + pub_sock = PubSocket() + pub_sock.connect(c, "controlsState") + + for i in range(int(1e10)): + print(i) + sub_sock = SubSocket() + sub_sock.connect(c, "controlsState") + + pub_sock.send(b'a') + print(sub_sock.receive()) diff --git a/cereal/messaging/test_runner.cc b/cereal/messaging/test_runner.cc new file mode 100644 index 000000000..62bf7476a --- /dev/null +++ b/cereal/messaging/test_runner.cc @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include "catch2/catch.hpp" diff --git a/cereal/messaging/tests/__init__.py b/cereal/messaging/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cereal/messaging/tests/test_fake.py b/cereal/messaging/tests/test_fake.py new file mode 100644 index 000000000..1d3521745 --- /dev/null +++ b/cereal/messaging/tests/test_fake.py @@ -0,0 +1,193 @@ +import os +import unittest +import multiprocessing +import platform +from parameterized import parameterized_class +from typing import Optional + +import cereal.messaging as messaging + +WAIT_TIMEOUT = 5 + + +@unittest.skipIf(platform.system() == "Darwin", "Events not supported on macOS") +class TestEvents(unittest.TestCase): + + def test_mutation(self): + handle = messaging.fake_event_handle("carState") + event = handle.recv_called_event + + self.assertFalse(event.peek()) + event.set() + self.assertTrue(event.peek()) + event.clear() + self.assertFalse(event.peek()) + + del event + + def test_wait(self): + handle = messaging.fake_event_handle("carState") + event = handle.recv_called_event + + event.set() + try: + event.wait(WAIT_TIMEOUT) + self.assertTrue(event.peek()) + except RuntimeError: + self.fail("event.wait() timed out") + + def test_wait_multiprocess(self): + handle = messaging.fake_event_handle("carState") + event = handle.recv_called_event + + def set_event_run(): + event.set() + + try: + p = multiprocessing.Process(target=set_event_run) + p.start() + event.wait(WAIT_TIMEOUT) + self.assertTrue(event.peek()) + except RuntimeError: + self.fail("event.wait() timed out") + + p.kill() + + def test_wait_zero_timeout(self): + handle = messaging.fake_event_handle("carState") + event = handle.recv_called_event + + try: + event.wait(0) + self.fail("event.wait() did not time out") + except RuntimeError: + self.assertFalse(event.peek()) + + +@unittest.skipIf(platform.system() == "Darwin", "FakeSockets not supported on macOS") +@unittest.skipIf("ZMQ" in os.environ, "FakeSockets not supported on ZMQ") +@parameterized_class([{"prefix": None}, {"prefix": "test"}]) +class TestFakeSockets(unittest.TestCase): + prefix: Optional[str] = None + + def setUp(self): + messaging.toggle_fake_events(True) + if self.prefix is not None: + messaging.set_fake_prefix(self.prefix) + else: + messaging.delete_fake_prefix() + + def tearDown(self): + messaging.toggle_fake_events(False) + messaging.delete_fake_prefix() + + def test_event_handle_init(self): + handle = messaging.fake_event_handle("controlsState", override=True) + + self.assertFalse(handle.enabled) + self.assertGreaterEqual(handle.recv_called_event.fd, 0) + self.assertGreaterEqual(handle.recv_ready_event.fd, 0) + + def test_non_managed_socket_state(self): + # non managed socket should have zero state + _ = messaging.pub_sock("ubloxGnss") + + handle = messaging.fake_event_handle("ubloxGnss", override=False) + + self.assertFalse(handle.enabled) + self.assertEqual(handle.recv_called_event.fd, 0) + self.assertEqual(handle.recv_ready_event.fd, 0) + + def test_managed_socket_state(self): + # managed socket should not change anything about the state + handle = messaging.fake_event_handle("ubloxGnss") + handle.enabled = True + + expected_enabled = handle.enabled + expected_recv_called_fd = handle.recv_called_event.fd + expected_recv_ready_fd = handle.recv_ready_event.fd + + _ = messaging.pub_sock("ubloxGnss") + + self.assertEqual(handle.enabled, expected_enabled) + self.assertEqual(handle.recv_called_event.fd, expected_recv_called_fd) + self.assertEqual(handle.recv_ready_event.fd, expected_recv_ready_fd) + + def test_sockets_enable_disable(self): + carState_handle = messaging.fake_event_handle("ubloxGnss", enable=True) + recv_called = carState_handle.recv_called_event + recv_ready = carState_handle.recv_ready_event + + pub_sock = messaging.pub_sock("ubloxGnss") + sub_sock = messaging.sub_sock("ubloxGnss") + + try: + carState_handle.enabled = True + recv_ready.set() + pub_sock.send(b"test") + _ = sub_sock.receive() + self.assertTrue(recv_called.peek()) + recv_called.clear() + + carState_handle.enabled = False + recv_ready.set() + pub_sock.send(b"test") + _ = sub_sock.receive() + self.assertFalse(recv_called.peek()) + except RuntimeError: + self.fail("event.wait() timed out") + + def test_synced_pub_sub(self): + def daemon_repub_process_run(): + pub_sock = messaging.pub_sock("ubloxGnss") + sub_sock = messaging.sub_sock("carState") + + frame = -1 + while True: + frame += 1 + msg = sub_sock.receive(non_blocking=True) + if msg is None: + print("none received") + continue + + bts = frame.to_bytes(8, 'little') + pub_sock.send(bts) + + carState_handle = messaging.fake_event_handle("carState", enable=True) + recv_called = carState_handle.recv_called_event + recv_ready = carState_handle.recv_ready_event + + p = multiprocessing.Process(target=daemon_repub_process_run) + p.start() + + pub_sock = messaging.pub_sock("carState") + sub_sock = messaging.sub_sock("ubloxGnss") + + try: + for i in range(10): + recv_called.wait(WAIT_TIMEOUT) + recv_called.clear() + + if i == 0: + sub_sock.receive(non_blocking=True) + + bts = i.to_bytes(8, 'little') + pub_sock.send(bts) + + recv_ready.set() + recv_called.wait(WAIT_TIMEOUT) + + msg = sub_sock.receive(non_blocking=True) + self.assertIsNotNone(msg) + self.assertEqual(len(msg), 8) + + frame = int.from_bytes(msg, 'little') + self.assertEqual(frame, i) + except RuntimeError: + self.fail("event.wait() timed out") + finally: + p.kill() + + +if __name__ == "__main__": + unittest.main() diff --git a/cereal/messaging/tests/test_messaging.py b/cereal/messaging/tests/test_messaging.py new file mode 100755 index 000000000..381cec03f --- /dev/null +++ b/cereal/messaging/tests/test_messaging.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python3 +import os +import capnp +import multiprocessing +import numbers +import random +import threading +import time +import unittest +from parameterized import parameterized + +from cereal import log, car +import cereal.messaging as messaging +from cereal.services import SERVICE_LIST + +events = [evt for evt in log.Event.schema.union_fields if evt in SERVICE_LIST.keys()] + +def random_sock(): + return random.choice(events) + +def random_socks(num_socks=10): + return list({random_sock() for _ in range(num_socks)}) + +def random_bytes(length=1000): + return bytes([random.randrange(0xFF) for _ in range(length)]) + +def zmq_sleep(t=1): + if "ZMQ" in os.environ: + time.sleep(t) + +def zmq_expected_failure(func): + if "ZMQ" in os.environ: + return unittest.expectedFailure(func) + else: + return func + +# TODO: this should take any capnp struct and returrn a msg with random populated data +def random_carstate(): + fields = ["vEgo", "aEgo", "gas", "steeringAngleDeg"] + msg = messaging.new_message("carState") + cs = msg.carState + for f in fields: + setattr(cs, f, random.random() * 10) + return msg + +# TODO: this should compare any capnp structs +def assert_carstate(cs1, cs2): + for f in car.CarState.schema.non_union_fields: + # TODO: check all types + val1, val2 = getattr(cs1, f), getattr(cs2, f) + if isinstance(val1, numbers.Number): + assert val1 == val2, f"{f}: sent '{val1}' vs recvd '{val2}'" + +def delayed_send(delay, sock, dat): + def send_func(): + sock.send(dat) + threading.Timer(delay, send_func).start() + +class TestPubSubSockets(unittest.TestCase): + + def setUp(self): + # ZMQ pub socket takes too long to die + # sleep to prevent multiple publishers error between tests + zmq_sleep() + + def test_pub_sub(self): + sock = random_sock() + pub_sock = messaging.pub_sock(sock) + sub_sock = messaging.sub_sock(sock, conflate=False, timeout=None) + zmq_sleep(3) + + for _ in range(1000): + msg = random_bytes() + pub_sock.send(msg) + recvd = sub_sock.receive() + self.assertEqual(msg, recvd) + + def test_conflate(self): + sock = random_sock() + pub_sock = messaging.pub_sock(sock) + for conflate in [True, False]: + for _ in range(10): + num_msgs = random.randint(3, 10) + sub_sock = messaging.sub_sock(sock, conflate=conflate, timeout=None) + zmq_sleep() + + sent_msgs = [] + for __ in range(num_msgs): + msg = random_bytes() + pub_sock.send(msg) + sent_msgs.append(msg) + time.sleep(0.1) + recvd_msgs = messaging.drain_sock_raw(sub_sock) + if conflate: + self.assertEqual(len(recvd_msgs), 1) + else: + # TODO: compare actual data + self.assertEqual(len(recvd_msgs), len(sent_msgs)) + + def test_receive_timeout(self): + sock = random_sock() + for _ in range(10): + timeout = random.randrange(200) + sub_sock = messaging.sub_sock(sock, timeout=timeout) + zmq_sleep() + + start_time = time.monotonic() + recvd = sub_sock.receive() + self.assertLess(time.monotonic() - start_time, 0.2) + assert recvd is None + +class TestMessaging(unittest.TestCase): + + def setUp(self): + # TODO: ZMQ tests are too slow; all sleeps will need to be + # replaced with logic to block on the necessary condition + if "ZMQ" in os.environ: + raise unittest.SkipTest + + # ZMQ pub socket takes too long to die + # sleep to prevent multiple publishers error between tests + zmq_sleep() + + @parameterized.expand(events) + def test_new_message(self, evt): + try: + msg = messaging.new_message(evt) + except capnp.lib.capnp.KjException: + msg = messaging.new_message(evt, random.randrange(200)) + self.assertLess(time.monotonic() - msg.logMonoTime, 0.1) + self.assertFalse(msg.valid) + self.assertEqual(evt, msg.which()) + + @parameterized.expand(events) + def test_pub_sock(self, evt): + messaging.pub_sock(evt) + + @parameterized.expand(events) + def test_sub_sock(self, evt): + messaging.sub_sock(evt) + + @parameterized.expand([ + (messaging.drain_sock, capnp._DynamicStructReader), + (messaging.drain_sock_raw, bytes), + ]) + def test_drain_sock(self, func, expected_type): + sock = "carState" + pub_sock = messaging.pub_sock(sock) + sub_sock = messaging.sub_sock(sock, timeout=1000) + zmq_sleep() + + # no wait and no msgs in queue + msgs = func(sub_sock) + self.assertIsInstance(msgs, list) + self.assertEqual(len(msgs), 0) + + # no wait but msgs are queued up + num_msgs = random.randrange(3, 10) + for _ in range(num_msgs): + pub_sock.send(messaging.new_message(sock).to_bytes()) + time.sleep(0.1) + msgs = func(sub_sock) + self.assertIsInstance(msgs, list) + self.assertTrue(all(isinstance(msg, expected_type) for msg in msgs)) + self.assertEqual(len(msgs), num_msgs) + + def test_recv_sock(self): + sock = "carState" + pub_sock = messaging.pub_sock(sock) + sub_sock = messaging.sub_sock(sock, timeout=100) + zmq_sleep() + + # no wait and no msg in queue, socket should timeout + recvd = messaging.recv_sock(sub_sock) + self.assertTrue(recvd is None) + + # no wait and one msg in queue + msg = random_carstate() + pub_sock.send(msg.to_bytes()) + time.sleep(0.01) + recvd = messaging.recv_sock(sub_sock) + self.assertIsInstance(recvd, capnp._DynamicStructReader) + # https://github.com/python/mypy/issues/13038 + assert_carstate(msg.carState, recvd.carState) + + def test_recv_one(self): + sock = "carState" + pub_sock = messaging.pub_sock(sock) + sub_sock = messaging.sub_sock(sock, timeout=1000) + zmq_sleep() + + # no msg in queue, socket should timeout + recvd = messaging.recv_one(sub_sock) + self.assertTrue(recvd is None) + + # one msg in queue + msg = random_carstate() + pub_sock.send(msg.to_bytes()) + recvd = messaging.recv_one(sub_sock) + self.assertIsInstance(recvd, capnp._DynamicStructReader) + assert_carstate(msg.carState, recvd.carState) + + @zmq_expected_failure + def test_recv_one_or_none(self): + sock = "carState" + pub_sock = messaging.pub_sock(sock) + sub_sock = messaging.sub_sock(sock) + zmq_sleep() + + # no msg in queue, socket shouldn't block + recvd = messaging.recv_one_or_none(sub_sock) + self.assertTrue(recvd is None) + + # one msg in queue + msg = random_carstate() + pub_sock.send(msg.to_bytes()) + recvd = messaging.recv_one_or_none(sub_sock) + self.assertIsInstance(recvd, capnp._DynamicStructReader) + assert_carstate(msg.carState, recvd.carState) + + def test_recv_one_retry(self): + sock = "carState" + sock_timeout = 0.1 + pub_sock = messaging.pub_sock(sock) + sub_sock = messaging.sub_sock(sock, timeout=round(sock_timeout*1000)) + zmq_sleep() + + # this test doesn't work with ZMQ since multiprocessing interrupts it + if "ZMQ" not in os.environ: + # wait 15 socket timeouts and make sure it's still retrying + p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,)) + p.start() + time.sleep(sock_timeout*15) + self.assertTrue(p.is_alive()) + p.terminate() + + # wait 15 socket timeouts before sending + msg = random_carstate() + delayed_send(sock_timeout*15, pub_sock, msg.to_bytes()) + start_time = time.monotonic() + recvd = messaging.recv_one_retry(sub_sock) + self.assertGreaterEqual(time.monotonic() - start_time, sock_timeout*15) + self.assertIsInstance(recvd, capnp._DynamicStructReader) + assert_carstate(msg.carState, recvd.carState) + +if __name__ == "__main__": + unittest.main() diff --git a/cereal/messaging/tests/test_poller.py b/cereal/messaging/tests/test_poller.py new file mode 100644 index 000000000..bcff5e40c --- /dev/null +++ b/cereal/messaging/tests/test_poller.py @@ -0,0 +1,142 @@ +import unittest +import time +import cereal.messaging as messaging + +import concurrent.futures + + +def poller(): + context = messaging.Context() + + p = messaging.Poller() + + sub = messaging.SubSocket() + sub.connect(context, 'controlsState') + p.registerSocket(sub) + + socks = p.poll(10000) + r = [s.receive(non_blocking=True) for s in socks] + + return r + + +class TestPoller(unittest.TestCase): + def test_poll_once(self): + context = messaging.Context() + + pub = messaging.PubSocket() + pub.connect(context, 'controlsState') + + with concurrent.futures.ThreadPoolExecutor() as e: + poll = e.submit(poller) + + time.sleep(0.1) # Slow joiner syndrome + + # Send message + pub.send(b"a") + + # Wait for poll result + result = poll.result() + + del pub + context.term() + + self.assertEqual(result, [b"a"]) + + def test_poll_and_create_many_subscribers(self): + context = messaging.Context() + + pub = messaging.PubSocket() + pub.connect(context, 'controlsState') + + with concurrent.futures.ThreadPoolExecutor() as e: + poll = e.submit(poller) + + time.sleep(0.1) # Slow joiner syndrome + c = messaging.Context() + for _ in range(10): + messaging.SubSocket().connect(c, 'controlsState') + + time.sleep(0.1) + + # Send message + pub.send(b"a") + + # Wait for poll result + result = poll.result() + + del pub + context.term() + + self.assertEqual(result, [b"a"]) + + def test_multiple_publishers_exception(self): + context = messaging.Context() + + with self.assertRaises(messaging.MultiplePublishersError): + pub1 = messaging.PubSocket() + pub1.connect(context, 'controlsState') + + pub2 = messaging.PubSocket() + pub2.connect(context, 'controlsState') + + pub1.send(b"a") + + del pub1 + del pub2 + context.term() + + def test_multiple_messages(self): + context = messaging.Context() + + pub = messaging.PubSocket() + pub.connect(context, 'controlsState') + + sub = messaging.SubSocket() + sub.connect(context, 'controlsState') + + time.sleep(0.1) # Slow joiner + + for i in range(1, 100): + pub.send(b'a'*i) + + msg_seen = False + i = 1 + while True: + r = sub.receive(non_blocking=True) + + if r is not None: + self.assertEqual(b'a'*i, r) + + msg_seen = True + i += 1 + + if r is None and msg_seen: # ZMQ sometimes receives nothing on the first receive + break + + del pub + del sub + context.term() + + def test_conflate(self): + context = messaging.Context() + + pub = messaging.PubSocket() + pub.connect(context, 'controlsState') + + sub = messaging.SubSocket() + sub.connect(context, 'controlsState', conflate=True) + + time.sleep(0.1) # Slow joiner + pub.send(b'a') + pub.send(b'b') + + self.assertEqual(b'b', sub.receive()) + + del pub + del sub + context.term() + + +if __name__ == "__main__": + unittest.main() diff --git a/cereal/messaging/tests/test_pub_sub_master.py b/cereal/messaging/tests/test_pub_sub_master.py new file mode 100755 index 000000000..81a1cf2d5 --- /dev/null +++ b/cereal/messaging/tests/test_pub_sub_master.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +import random +import time +from typing import Sized, cast +import unittest + +import cereal.messaging as messaging +from cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \ + random_bytes, random_carstate, assert_carstate, \ + zmq_sleep + + +class TestSubMaster(unittest.TestCase): + + def setUp(self): + # ZMQ pub socket takes too long to die + # sleep to prevent multiple publishers error between tests + zmq_sleep(3) + + def test_init(self): + sm = messaging.SubMaster(events) + for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive, + sm.sock, sm.data, sm.logMonoTime, sm.valid]: + self.assertEqual(len(cast(Sized, p)), len(events)) + + def test_init_state(self): + socks = random_socks() + sm = messaging.SubMaster(socks) + self.assertEqual(sm.frame, -1) + self.assertFalse(any(sm.updated.values())) + self.assertFalse(any(sm.alive.values())) + self.assertTrue(all(t == 0. for t in sm.recv_time.values())) + self.assertTrue(all(f == 0 for f in sm.recv_frame.values())) + self.assertTrue(all(t == 0 for t in sm.logMonoTime.values())) + + for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive, + sm.sock, sm.data, sm.logMonoTime, sm.valid]: + self.assertEqual(len(cast(Sized, p)), len(socks)) + + def test_getitem(self): + sock = "carState" + pub_sock = messaging.pub_sock(sock) + sm = messaging.SubMaster([sock,]) + zmq_sleep() + + msg = random_carstate() + pub_sock.send(msg.to_bytes()) + sm.update(1000) + assert_carstate(msg.carState, sm[sock]) + + # TODO: break this test up to individually test SubMaster.update and SubMaster.update_msgs + def test_update(self): + sock = "carState" + pub_sock = messaging.pub_sock(sock) + sm = messaging.SubMaster([sock,]) + zmq_sleep() + + for i in range(10): + msg = messaging.new_message(sock) + pub_sock.send(msg.to_bytes()) + sm.update(1000) + self.assertEqual(sm.frame, i) + self.assertTrue(all(sm.updated.values())) + + def test_update_timeout(self): + sock = random_sock() + sm = messaging.SubMaster([sock,]) + for _ in range(5): + timeout = random.randrange(1000, 5000) + start_time = time.monotonic() + sm.update(timeout) + t = time.monotonic() - start_time + self.assertGreaterEqual(t, timeout/1000.) + self.assertLess(t, 5) + self.assertFalse(any(sm.updated.values())) + + def test_avg_frequency_checks(self): + for poll in (True, False): + sm = messaging.SubMaster(["modelV2", "carParams", "carState", "cameraOdometry", "liveCalibration"], + poll=("modelV2" if poll else None), + frequency=(20. if not poll else None)) + + checks = { + "carState": (20, 20), + "modelV2": (20, 20 if poll else 10), + "cameraOdometry": (20, 10), + "liveCalibration": (4, 4), + "carParams": (None, None), + } + + for service, (max_freq, min_freq) in checks.items(): + if max_freq is not None: + assert sm._check_avg_freq(service) + assert sm.max_freq[service] == max_freq*1.2 + assert sm.min_freq[service] == min_freq*0.8 + else: + assert not sm._check_avg_freq(service) + + def test_alive(self): + pass + + def test_ignore_alive(self): + pass + + def test_valid(self): + pass + + # SubMaster should always conflate + def test_conflate(self): + sock = "carState" + pub_sock = messaging.pub_sock(sock) + sm = messaging.SubMaster([sock,]) + + n = 10 + for i in range(n+1): + msg = messaging.new_message(sock) + msg.carState.vEgo = i + pub_sock.send(msg.to_bytes()) + time.sleep(0.01) + sm.update(1000) + self.assertEqual(sm[sock].vEgo, n) + + +class TestPubMaster(unittest.TestCase): + + def setUp(self): + # ZMQ pub socket takes too long to die + # sleep to prevent multiple publishers error between tests + zmq_sleep(3) + + def test_init(self): + messaging.PubMaster(events) + + def test_send(self): + socks = random_socks() + pm = messaging.PubMaster(socks) + sub_socks = {s: messaging.sub_sock(s, conflate=True, timeout=1000) for s in socks} + zmq_sleep() + + # PubMaster accepts either a capnp msg builder or bytes + for capnp in [True, False]: + for i in range(100): + sock = socks[i % len(socks)] + + if capnp: + try: + msg = messaging.new_message(sock) + except Exception: + msg = messaging.new_message(sock, random.randrange(50)) + else: + msg = random_bytes() + + pm.send(sock, msg) + recvd = sub_socks[sock].receive() + + if capnp: + msg.clear_write_flag() + msg = msg.to_bytes() + self.assertEqual(msg, recvd, i) + + +if __name__ == "__main__": + unittest.main() diff --git a/cereal/messaging/tests/test_services.py b/cereal/messaging/tests/test_services.py new file mode 100755 index 000000000..0fac379e4 --- /dev/null +++ b/cereal/messaging/tests/test_services.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +import os +import tempfile +from typing import Dict +import unittest +from parameterized import parameterized + +import cereal.services as services +from cereal.services import SERVICE_LIST + + +class TestServices(unittest.TestCase): + + @parameterized.expand(SERVICE_LIST.keys()) + def test_services(self, s): + service = SERVICE_LIST[s] + self.assertTrue(service.frequency <= 104) + + def test_generated_header(self): + with tempfile.NamedTemporaryFile(suffix=".h") as f: + ret = os.system(f"python3 {services.__file__} > {f.name} && clang++ {f.name}") + self.assertEqual(ret, 0, "generated services header is not valid C") + +if __name__ == "__main__": + unittest.main() diff --git a/cereal/services.py b/cereal/services.py new file mode 100755 index 000000000..2ab28f6d5 --- /dev/null +++ b/cereal/services.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +from typing import Optional + + +class Service: + def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] = None): + self.should_log = should_log + self.frequency = frequency + self.decimation = decimation + + +_services: dict[str, tuple] = { + # service: (should_log, frequency, qlog decimation (optional)) + # note: the "EncodeIdx" packets will still be in the log + "gyroscope": (True, 104., 104), + "gyroscope2": (True, 100., 100), + "accelerometer": (True, 104., 104), + "accelerometer2": (True, 100., 100), + "magnetometer": (True, 25., 25), + "lightSensor": (True, 100., 100), + "temperatureSensor": (True, 2., 200), + "temperatureSensor2": (True, 2., 200), + "gpsNMEA": (True, 9.), + "deviceState": (True, 2., 1), + "can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment + "controlsState": (True, 100., 10), + "pandaStates": (True, 10., 1), + "peripheralState": (True, 2., 1), + "radarState": (True, 20., 5), + "roadEncodeIdx": (False, 20., 1), + "liveTracks": (True, 20.), + "sendcan": (True, 100., 139), + "logMessage": (True, 0.), + "errorLogMessage": (True, 0., 1), + "liveCalibration": (True, 4., 4), + "liveTorqueParameters": (True, 4., 1), + "androidLog": (True, 0.), + "carState": (True, 100., 10), + "carControl": (True, 100., 10), + "carOutput": (True, 100., 10), + "longitudinalPlan": (True, 20., 5), + "procLog": (True, 0.5, 15), + "gpsLocationExternal": (True, 10., 10), + "gpsLocation": (True, 1., 1), + "ubloxGnss": (True, 10.), + "qcomGnss": (True, 2.), + "gnssMeasurements": (True, 10., 10), + "clocks": (True, 0.1, 1), + "ubloxRaw": (True, 20.), + "liveLocationKalman": (True, 20., 5), + "liveParameters": (True, 20., 5), + "cameraOdometry": (True, 20., 5), + "thumbnail": (True, 0.2, 1), + "onroadEvents": (True, 1., 1), + "carParams": (True, 0.02, 1), + "roadCameraState": (True, 20., 20), + "driverCameraState": (True, 20., 20), + "driverEncodeIdx": (False, 20., 1), + "driverStateV2": (True, 20., 10), + "driverMonitoringState": (True, 20., 10), + "wideRoadEncodeIdx": (False, 20., 1), + "wideRoadCameraState": (True, 20., 20), + "modelV2": (True, 20., 40), + "managerState": (True, 2., 1), + "uploaderState": (True, 0., 1), + "navInstruction": (True, 1., 10), + "navRoute": (True, 0.), + "navThumbnail": (True, 0.), + "uiPlan": (True, 20., 40.), + "qRoadEncodeIdx": (False, 20.), + "userFlag": (True, 0., 1), + "microphone": (True, 10., 10), + + # debug + "uiDebug": (True, 0., 1), + "testJoystick": (True, 0.), + "roadEncodeData": (False, 20.), + "driverEncodeData": (False, 20.), + "wideRoadEncodeData": (False, 20.), + "qRoadEncodeData": (False, 20.), + "livestreamWideRoadEncodeIdx": (False, 20.), + "livestreamRoadEncodeIdx": (False, 20.), + "livestreamDriverEncodeIdx": (False, 20.), + "livestreamWideRoadEncodeData": (False, 20.), + "livestreamRoadEncodeData": (False, 20.), + "livestreamDriverEncodeData": (False, 20.), + "customReservedRawData0": (True, 0.), + "customReservedRawData1": (True, 0.), + "customReservedRawData2": (True, 0.), +} +SERVICE_LIST = {name: Service(*vals) for + idx, (name, vals) in enumerate(_services.items())} + + +def build_header(): + h = "" + h += "/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT services.py */\n" + h += "#ifndef __SERVICES_H\n" + h += "#define __SERVICES_H\n" + + h += "#include \n" + h += "#include \n" + + h += "struct service { std::string name; bool should_log; int frequency; int decimation; };\n" + h += "static std::map services = {\n" + for k, v in SERVICE_LIST.items(): + should_log = "true" if v.should_log else "false" + decimation = -1 if v.decimation is None else v.decimation + h += ' { "%s", {"%s", %s, %d, %d}},\n' % \ + (k, k, should_log, v.frequency, decimation) + h += "};\n" + + h += "#endif\n" + return h + + +if __name__ == "__main__": + print(build_header()) diff --git a/docs/c_docs.rst b/docs/c_docs.rst index 7303c89be..1027bac1b 100644 --- a/docs/c_docs.rst +++ b/docs/c_docs.rst @@ -14,12 +14,12 @@ cereal messaging ^^^^^^^^^ .. autodoxygenindex:: - :project: cereal_messaging + :project: msgq_messaging visionipc ^^^^^^^^^ .. autodoxygenindex:: - :project: cereal_visionipc + :project: msgq_visionipc selfdrive diff --git a/msgq b/msgq new file mode 160000 index 000000000..6d2cc6e22 --- /dev/null +++ b/msgq @@ -0,0 +1 @@ +Subproject commit 6d2cc6e22229a9c855d8474e5643b26fbf2b5976 diff --git a/opendbc b/opendbc index 9a92d7a23..f58bc3392 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 9a92d7a232e3abe54c501e01c960462dd04588ea +Subproject commit f58bc3392cfffd25b311e093aa72f0ef3a89f6e8 diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index c8cc76cfc..bc79c1fb4 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -8,7 +8,7 @@ from typing import SupportsFloat import cereal.messaging as messaging from cereal import car, log -from cereal.visionipc import VisionIpcClient, VisionStreamType +from msgq.visionipc import VisionIpcClient, VisionStreamType from openpilot.common.conversions import Conversions as CV diff --git a/selfdrive/locationd/SConscript b/selfdrive/locationd/SConscript index 07555a608..d3cfeb2c3 100644 --- a/selfdrive/locationd/SConscript +++ b/selfdrive/locationd/SConscript @@ -1,6 +1,6 @@ -Import('env', 'arch', 'common', 'cereal', 'messaging', 'rednose', 'transformations') +Import('env', 'arch', 'common', 'cereal', 'messaging', 'rednose', 'transformations', 'socketmaster') -loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'pthread', 'dl'] +loc_libs = [cereal, socketmaster, messaging, 'zmq', common, 'capnp', 'kj', 'pthread', 'dl'] # build ekf models rednose_gen_dir = 'models/generated' diff --git a/selfdrive/modeld/dmonitoringmodeld.py b/selfdrive/modeld/dmonitoringmodeld.py index ef403b44f..a388bf089 100755 --- a/selfdrive/modeld/dmonitoringmodeld.py +++ b/selfdrive/modeld/dmonitoringmodeld.py @@ -9,7 +9,7 @@ from pathlib import Path from cereal import messaging from cereal.messaging import PubMaster, SubMaster -from cereal.visionipc import VisionIpcClient, VisionStreamType, VisionBuf +from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.common.swaglog import cloudlog from openpilot.common.params import Params from openpilot.common.realtime import set_realtime_priority diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 526fd4d21..3ac80aad9 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -8,7 +8,7 @@ from cereal import car, log from pathlib import Path from setproctitle import setproctitle from cereal.messaging import PubMaster, SubMaster -from cereal.visionipc import VisionIpcClient, VisionStreamType, VisionBuf +from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.common.swaglog import cloudlog from openpilot.common.params import Params from openpilot.common.filter_simple import FirstOrderFilter diff --git a/selfdrive/modeld/models/commonmodel.pxd b/selfdrive/modeld/models/commonmodel.pxd index 57b79aeaf..7c3eb0b3d 100644 --- a/selfdrive/modeld/models/commonmodel.pxd +++ b/selfdrive/modeld/models/commonmodel.pxd @@ -1,6 +1,6 @@ # distutils: language = c++ -from cereal.visionipc.visionipc cimport cl_device_id, cl_context, cl_mem +from msgq.visionipc.visionipc cimport cl_device_id, cl_context, cl_mem cdef extern from "common/mat.h": cdef struct mat3: diff --git a/selfdrive/modeld/models/commonmodel_pyx.pxd b/selfdrive/modeld/models/commonmodel_pyx.pxd index 97e391458..0bb798625 100644 --- a/selfdrive/modeld/models/commonmodel_pyx.pxd +++ b/selfdrive/modeld/models/commonmodel_pyx.pxd @@ -1,7 +1,7 @@ # distutils: language = c++ -from cereal.visionipc.visionipc cimport cl_mem -from cereal.visionipc.visionipc_pyx cimport CLContext as BaseCLContext +from msgq.visionipc.visionipc cimport cl_mem +from msgq.visionipc.visionipc_pyx cimport CLContext as BaseCLContext cdef class CLContext(BaseCLContext): pass diff --git a/selfdrive/modeld/models/commonmodel_pyx.pyx b/selfdrive/modeld/models/commonmodel_pyx.pyx index bc59b7a23..e292bb0d2 100644 --- a/selfdrive/modeld/models/commonmodel_pyx.pyx +++ b/selfdrive/modeld/models/commonmodel_pyx.pyx @@ -5,8 +5,8 @@ import numpy as np cimport numpy as cnp from libc.string cimport memcpy -from cereal.visionipc.visionipc cimport cl_mem -from cereal.visionipc.visionipc_pyx cimport VisionBuf, CLContext as BaseCLContext +from msgq.visionipc.visionipc cimport cl_mem +from msgq.visionipc.visionipc_pyx cimport VisionBuf, CLContext as BaseCLContext from .commonmodel cimport CL_DEVICE_TYPE_DEFAULT, cl_get_device_id, cl_create_context from .commonmodel cimport mat3, sigmoid as cppSigmoid, ModelFrame as cppModelFrame diff --git a/selfdrive/modeld/runners/snpemodel.pxd b/selfdrive/modeld/runners/snpemodel.pxd index 1f928da33..a911b4358 100644 --- a/selfdrive/modeld/runners/snpemodel.pxd +++ b/selfdrive/modeld/runners/snpemodel.pxd @@ -2,7 +2,7 @@ from libcpp.string cimport string -from cereal.visionipc.visionipc cimport cl_context +from msgq.visionipc.visionipc cimport cl_context cdef extern from "selfdrive/modeld/runners/snpemodel.h": cdef cppclass SNPEModel: diff --git a/selfdrive/modeld/runners/thneedmodel.pxd b/selfdrive/modeld/runners/thneedmodel.pxd index 90af97286..79e24dbdd 100644 --- a/selfdrive/modeld/runners/thneedmodel.pxd +++ b/selfdrive/modeld/runners/thneedmodel.pxd @@ -2,7 +2,7 @@ from libcpp.string cimport string -from cereal.visionipc.visionipc cimport cl_context +from msgq.visionipc.visionipc cimport cl_context cdef extern from "selfdrive/modeld/runners/thneedmodel.h": cdef cppclass ThneedModel: diff --git a/selfdrive/modeld/tests/test_modeld.py b/selfdrive/modeld/tests/test_modeld.py index 413057931..1e19a591b 100644 --- a/selfdrive/modeld/tests/test_modeld.py +++ b/selfdrive/modeld/tests/test_modeld.py @@ -2,7 +2,7 @@ import numpy as np import random import cereal.messaging as messaging -from cereal.visionipc import VisionIpcServer, VisionStreamType +from msgq.visionipc import VisionIpcServer, VisionStreamType from openpilot.common.transformations.camera import DEVICE_CAMERAS from openpilot.common.realtime import DT_MDL from openpilot.selfdrive.car.car_helpers import write_car_param diff --git a/selfdrive/navd/SConscript b/selfdrive/navd/SConscript index 5a049f18b..7f5d948b7 100644 --- a/selfdrive/navd/SConscript +++ b/selfdrive/navd/SConscript @@ -1,7 +1,7 @@ -Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'transformations') +Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'transformations', 'socketmaster') map_env = qt_env.Clone() -libs = ['qt_widgets', 'qt_util', 'QMapLibre', common, messaging, cereal, visionipc, transformations, +libs = ['qt_widgets', 'qt_util', 'QMapLibre', common, socketmaster, messaging, cereal, visionipc, transformations, 'zmq', 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread', 'json11'] + map_env["LIBS"] if arch == 'larch64': libs.append(':libEGL_mesa.so.0') diff --git a/selfdrive/navd/map_renderer.h b/selfdrive/navd/map_renderer.h index 7a3d2c316..956c1d54b 100644 --- a/selfdrive/navd/map_renderer.h +++ b/selfdrive/navd/map_renderer.h @@ -12,7 +12,7 @@ #include #include -#include "cereal/visionipc/visionipc_server.h" +#include "msgq/visionipc/visionipc_server.h" #include "cereal/messaging/messaging.h" diff --git a/selfdrive/navd/tests/test_map_renderer.py b/selfdrive/navd/tests/test_map_renderer.py index 6d66528ae..04363883b 100644 --- a/selfdrive/navd/tests/test_map_renderer.py +++ b/selfdrive/navd/tests/test_map_renderer.py @@ -8,7 +8,7 @@ import http.server import cereal.messaging as messaging from typing import Any -from cereal.visionipc import VisionIpcClient, VisionStreamType +from msgq.visionipc import VisionIpcClient, VisionStreamType from openpilot.common.mock.generators import LLK_DECIMATION, LOCATION1, LOCATION2, generate_liveLocationKalman from openpilot.selfdrive.test.helpers import with_processes diff --git a/selfdrive/pandad/SConscript b/selfdrive/pandad/SConscript index 5e7073651..48187c432 100644 --- a/selfdrive/pandad/SConscript +++ b/selfdrive/pandad/SConscript @@ -1,6 +1,6 @@ -Import('env', 'envCython', 'common', 'cereal', 'messaging') +Import('env', 'envCython', 'common', 'cereal', 'messaging', 'socketmaster') -libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj'] +libs = ['usb-1.0', common, cereal, messaging, socketmaster, 'pthread', 'zmq', 'capnp', 'kj'] panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc']) env.Program('pandad', ['main.cc', 'pandad.cc'], LIBS=[panda] + libs) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index b325e6e69..739efcb98 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -16,7 +16,7 @@ import capnp import cereal.messaging as messaging from cereal import car from cereal.services import SERVICE_LIST -from cereal.visionipc import VisionIpcServer, get_endpoint_name as vipc_get_endpoint_name +from msgq.visionipc import VisionIpcServer, get_endpoint_name as vipc_get_endpoint_name from openpilot.common.params import Params from openpilot.common.prefix import OpenpilotPrefix from openpilot.common.timeout import Timeout diff --git a/selfdrive/test/process_replay/vision_meta.py b/selfdrive/test/process_replay/vision_meta.py index 9bfe214c1..12deb5872 100644 --- a/selfdrive/test/process_replay/vision_meta.py +++ b/selfdrive/test/process_replay/vision_meta.py @@ -1,5 +1,5 @@ from collections import namedtuple -from cereal.visionipc import VisionStreamType +from msgq.visionipc import VisionStreamType from openpilot.common.realtime import DT_MDL, DT_DMON from openpilot.common.transformations.camera import DEVICE_CAMERAS diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 13b6998de..5bd33f35f 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,9 +1,9 @@ import os import json Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', - 'cereal', 'transformations') + 'cereal', 'transformations', 'socketmaster') -base_libs = [common, messaging, cereal, visionipc, transformations, 'zmq', +base_libs = [common, socketmaster, messaging, cereal, visionipc, transformations, 'zmq', 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] if arch == 'larch64': diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index c97038cf4..85ec49873 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -22,7 +22,7 @@ #include #endif -#include "cereal/visionipc/visionipc_client.h" +#include "msgq/visionipc/visionipc_client.h" #include "system/camerad/cameras/camera_common.h" #include "selfdrive/ui/ui.h" diff --git a/selfdrive/ui/tests/test_ui/run.py b/selfdrive/ui/tests/test_ui/run.py index 871333563..1d33c103a 100644 --- a/selfdrive/ui/tests/test_ui/run.py +++ b/selfdrive/ui/tests/test_ui/run.py @@ -10,7 +10,7 @@ import pywinctl import time from cereal import messaging, car, log -from cereal.visionipc import VisionIpcServer, VisionStreamType +from msgq.visionipc import VisionIpcServer, VisionStreamType from cereal.messaging import SubMaster, PubMaster from openpilot.common.mock import mock_messages diff --git a/system/camerad/SConscript b/system/camerad/SConscript index 8f19e7ee1..67530c57e 100644 --- a/system/camerad/SConscript +++ b/system/camerad/SConscript @@ -1,6 +1,6 @@ -Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc') +Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc', 'socketmaster') -libs = ['m', 'pthread', common, 'jpeg', 'OpenCL', 'yuv', cereal, messaging, 'zmq', 'capnp', 'kj', visionipc, gpucommon, 'atomic'] +libs = ['m', 'pthread', common, 'jpeg', 'OpenCL', 'yuv', cereal, socketmaster, messaging, 'zmq', 'capnp', 'kj', visionipc, gpucommon, 'atomic'] camera_obj = env.Object(['cameras/camera_qcom2.cc', 'cameras/camera_common.cc', 'cameras/camera_util.cc', 'sensors/ar0231.cc', 'sensors/ox03c10.cc', 'sensors/os04c10.cc']) diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index 587968fcc..555362ab8 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -5,7 +5,7 @@ #include #include "cereal/messaging/messaging.h" -#include "cereal/visionipc/visionipc_server.h" +#include "msgq/visionipc/visionipc_server.h" #include "common/queue.h" #include "common/util.h" diff --git a/system/camerad/snapshot/snapshot.py b/system/camerad/snapshot/snapshot.py index 381240212..4ba38c1df 100755 --- a/system/camerad/snapshot/snapshot.py +++ b/system/camerad/snapshot/snapshot.py @@ -6,7 +6,7 @@ import numpy as np from PIL import Image import cereal.messaging as messaging -from cereal.visionipc import VisionIpcClient, VisionStreamType +from msgq.visionipc import VisionIpcClient, VisionStreamType from openpilot.common.params import Params from openpilot.common.realtime import DT_MDL from openpilot.system.hardware import PC diff --git a/system/hardware/base.h b/system/hardware/base.h index dc2282a93..ca24633a1 100644 --- a/system/hardware/base.h +++ b/system/hardware/base.h @@ -5,7 +5,7 @@ #include #include -#include "cereal/messaging/messaging.h" +#include "cereal/gen/cpp/log.capnp.h" // no-op base hw class class HardwareNone { diff --git a/system/logcatd/SConscript b/system/logcatd/SConscript index 6bd7c6ff3..cd34e3956 100644 --- a/system/logcatd/SConscript +++ b/system/logcatd/SConscript @@ -1,3 +1,3 @@ -Import('env', 'cereal', 'messaging', 'common') +Import('env', 'cereal', 'messaging', 'common', 'socketmaster') -env.Program('logcatd', 'logcatd_systemd.cc', LIBS=[cereal, messaging, common, 'zmq', 'capnp', 'kj', 'systemd', 'json11']) +env.Program('logcatd', 'logcatd_systemd.cc', LIBS=[cereal, socketmaster, messaging, common, 'zmq', 'capnp', 'kj', 'systemd', 'json11']) diff --git a/system/loggerd/SConscript b/system/loggerd/SConscript index d4f52fb5f..bcf941655 100644 --- a/system/loggerd/SConscript +++ b/system/loggerd/SConscript @@ -1,6 +1,6 @@ -Import('env', 'arch', 'cereal', 'messaging', 'common', 'visionipc') +Import('env', 'arch', 'cereal', 'messaging', 'common', 'visionipc', 'socketmaster') -libs = [common, cereal, messaging, visionipc, +libs = [common, cereal, socketmaster, messaging, visionipc, 'zmq', 'capnp', 'kj', 'z', 'avformat', 'avcodec', 'swscale', 'avutil', 'yuv', 'OpenCL', 'pthread'] diff --git a/system/loggerd/encoder/encoder.h b/system/loggerd/encoder/encoder.h index 75183611b..72848609e 100644 --- a/system/loggerd/encoder/encoder.h +++ b/system/loggerd/encoder/encoder.h @@ -7,7 +7,7 @@ #include #include "cereal/messaging/messaging.h" -#include "cereal/visionipc/visionipc.h" +#include "msgq/visionipc/visionipc.h" #include "common/queue.h" #include "system/camerad/cameras/camera_common.h" #include "system/loggerd/loggerd.h" diff --git a/system/loggerd/loggerd.cc b/system/loggerd/loggerd.cc index 3c0ffc166..a324479fb 100644 --- a/system/loggerd/loggerd.cc +++ b/system/loggerd/loggerd.cc @@ -215,7 +215,7 @@ void loggerd_thread() { const bool encoder = util::ends_with(it.name, "EncodeData"); const bool livestream_encoder = util::starts_with(it.name, "livestream"); if (!it.should_log && (!encoder || livestream_encoder)) continue; - LOGD("logging %s (on port %d)", it.name.c_str(), it.port); + LOGD("logging %s", it.name.c_str()); SubSocket * sock = SubSocket::create(ctx.get(), it.name); assert(sock != NULL); diff --git a/system/loggerd/loggerd.h b/system/loggerd/loggerd.h index 5eef16183..7c80ba51a 100644 --- a/system/loggerd/loggerd.h +++ b/system/loggerd/loggerd.h @@ -4,7 +4,7 @@ #include "cereal/messaging/messaging.h" #include "cereal/services.h" -#include "cereal/visionipc/visionipc_client.h" +#include "msgq/visionipc/visionipc_client.h" #include "system/camerad/cameras/camera_common.h" #include "system/hardware/hw.h" #include "common/params.h" diff --git a/system/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py index 882ce99ed..6a24540ac 100644 --- a/system/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -22,7 +22,7 @@ from openpilot.system.manager.process_config import managed_processes from openpilot.system.version import get_version from openpilot.tools.lib.helpers import RE from openpilot.tools.lib.logreader import LogReader -from cereal.visionipc import VisionIpcServer, VisionStreamType +from msgq.visionipc import VisionIpcServer, VisionStreamType from openpilot.common.transformations.camera import DEVICE_CAMERAS SentinelType = log.Sentinel.SentinelType diff --git a/system/proclogd/SConscript b/system/proclogd/SConscript index 1f4b76701..05cdb73c6 100644 --- a/system/proclogd/SConscript +++ b/system/proclogd/SConscript @@ -1,5 +1,5 @@ -Import('env', 'cereal', 'messaging', 'common') -libs = [cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj', 'common', 'zmq', 'json11'] +Import('env', 'cereal', 'messaging', 'common', 'socketmaster') +libs = [cereal, socketmaster, messaging, 'pthread', 'zmq', 'capnp', 'kj', 'common', 'zmq', 'json11'] env.Program('proclogd', ['main.cc', 'proclog.cc'], LIBS=libs) if GetOption('extras'): diff --git a/system/sensord/SConscript b/system/sensord/SConscript index 7974eb07a..1808a3154 100644 --- a/system/sensord/SConscript +++ b/system/sensord/SConscript @@ -1,4 +1,4 @@ -Import('env', 'arch', 'common', 'cereal', 'messaging') +Import('env', 'arch', 'common', 'cereal', 'messaging', 'socketmaster') sensors = [ 'sensors/i2c_sensor.cc', @@ -11,7 +11,7 @@ sensors = [ 'sensors/lsm6ds3_temp.cc', 'sensors/mmc5603nj_magn.cc', ] -libs = [common, cereal, messaging, 'capnp', 'zmq', 'kj', 'pthread'] +libs = [common, socketmaster, cereal, messaging, 'capnp', 'zmq', 'kj', 'pthread'] if arch == "larch64": libs.append('i2c') env.Program('sensord', ['sensors_qcom2.cc'] + sensors, LIBS=libs) diff --git a/system/ubloxd/SConscript b/system/ubloxd/SConscript index 67d9856da..d6bea5723 100644 --- a/system/ubloxd/SConscript +++ b/system/ubloxd/SConscript @@ -1,6 +1,6 @@ -Import('env', 'common', 'cereal', 'messaging') +Import('env', 'common', 'cereal', 'messaging', 'socketmaster') -loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'kaitai', 'pthread'] +loc_libs = [cereal, messaging, socketmaster, 'zmq', common, 'capnp', 'kj', 'kaitai', 'pthread'] if GetOption('kaitai'): generated = Dir('generated').srcnode().abspath diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 5bcfdb175..4ce4c27a0 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -1,7 +1,7 @@ -Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', 'cereal', 'widgets') +Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', 'cereal', 'widgets', 'socketmaster') base_frameworks = qt_env['FRAMEWORKS'] -base_libs = [common, messaging, cereal, visionipc, 'qt_util', 'zmq', 'capnp', 'kj', 'm', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] +base_libs = [common, messaging, cereal, visionipc, socketmaster, 'qt_util', 'zmq', 'capnp', 'kj', 'm', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] if arch == "Darwin": base_frameworks.append('OpenCL') diff --git a/tools/camerastream/compressed_vipc.py b/tools/camerastream/compressed_vipc.py index df9de096f..ea427816e 100755 --- a/tools/camerastream/compressed_vipc.py +++ b/tools/camerastream/compressed_vipc.py @@ -8,7 +8,7 @@ import multiprocessing import time import cereal.messaging as messaging -from cereal.visionipc import VisionIpcServer, VisionStreamType +from msgq.visionipc import VisionIpcServer, VisionStreamType V4L2_BUF_FLAG_KEYFRAME = 8 diff --git a/tools/replay/SConscript b/tools/replay/SConscript index 5d88f560b..813f7808f 100644 --- a/tools/replay/SConscript +++ b/tools/replay/SConscript @@ -1,7 +1,7 @@ -Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal') +Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'socketmaster') base_frameworks = qt_env['FRAMEWORKS'] -base_libs = [common, messaging, cereal, visionipc, 'zmq', +base_libs = [common, socketmaster, messaging, cereal, visionipc, 'zmq', 'capnp', 'kj', 'm', 'ssl', 'crypto', 'pthread', 'qt_util'] + qt_env["LIBS"] if arch == "Darwin": diff --git a/tools/replay/camera.h b/tools/replay/camera.h index 77a6293ec..21c3d98dc 100644 --- a/tools/replay/camera.h +++ b/tools/replay/camera.h @@ -5,7 +5,7 @@ #include #include -#include "cereal/visionipc/visionipc_server.h" +#include "msgq/visionipc/visionipc_server.h" #include "common/queue.h" #include "tools/replay/framereader.h" #include "tools/replay/logreader.h" diff --git a/tools/replay/framereader.h b/tools/replay/framereader.h index b9abefb7c..7a4d024aa 100644 --- a/tools/replay/framereader.h +++ b/tools/replay/framereader.h @@ -3,7 +3,7 @@ #include #include -#include "cereal/visionipc/visionbuf.h" +#include "msgq/visionipc/visionbuf.h" #include "system/camerad/cameras/camera_common.h" #include "tools/replay/filereader.h" diff --git a/tools/replay/ui.py b/tools/replay/ui.py index 31e4fff74..a790f14ff 100755 --- a/tools/replay/ui.py +++ b/tools/replay/ui.py @@ -18,7 +18,7 @@ from openpilot.tools.replay.lib.ui_helpers import (UP, maybe_update_radar_points, plot_lead, plot_model, pygame_modules_have_loaded) -from cereal.visionipc import VisionIpcClient, VisionStreamType +from msgq.visionipc import VisionIpcClient, VisionStreamType os.environ['BASEDIR'] = BASEDIR diff --git a/tools/sim/Dockerfile.sim b/tools/sim/Dockerfile.sim index cb573b33f..bd83c119b 100644 --- a/tools/sim/Dockerfile.sim +++ b/tools/sim/Dockerfile.sim @@ -26,6 +26,7 @@ COPY ./rednose_repo/site_scons ${OPENPILOT_PATH}/rednose_repo/site_scons COPY ./common ${OPENPILOT_PATH}/common COPY ./opendbc ${OPENPILOT_PATH}/opendbc COPY ./cereal ${OPENPILOT_PATH}/cereal +COPY ./msgq ${OPENPILOT_PATH}/msgq COPY ./panda ${OPENPILOT_PATH}/panda COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive COPY ./system ${OPENPILOT_PATH}/system diff --git a/tools/sim/lib/camerad.py b/tools/sim/lib/camerad.py index 95769dd44..b58cbeaaf 100644 --- a/tools/sim/lib/camerad.py +++ b/tools/sim/lib/camerad.py @@ -3,7 +3,7 @@ import os import pyopencl as cl import pyopencl.array as cl_array -from cereal.visionipc import VisionIpcServer, VisionStreamType +from msgq.visionipc import VisionIpcServer, VisionStreamType from cereal import messaging from openpilot.common.basedir import BASEDIR diff --git a/tools/webcam/camerad.py b/tools/webcam/camerad.py index ce33473f9..d0b879a08 100755 --- a/tools/webcam/camerad.py +++ b/tools/webcam/camerad.py @@ -3,7 +3,7 @@ import threading import os from collections import namedtuple -from cereal.visionipc import VisionIpcServer, VisionStreamType +from msgq.visionipc import VisionIpcServer, VisionStreamType from cereal import messaging from openpilot.tools.webcam.camera import Camera From 83209e0860f61aa383fbe1cc569ace996edcd13d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 6 Jun 2024 15:03:19 -0700 Subject: [PATCH 158/220] Msgq cleanups (#32643) * Dead cereal stuff * Dead code * also dead * More cleanup --- cereal/.pre-commit-config.yaml | 47 ---- cereal/Dockerfile | 54 ----- cereal/LICENSE | 7 - cereal/codecov.yml | 8 - cereal/messaging/demo.cc | 50 ---- cereal/messaging/demo.py | 29 --- cereal/messaging/msgq.md | 54 ----- cereal/messaging/msgq_tests.cc | 394 -------------------------------- cereal/messaging/test_runner.cc | 2 - msgq | 2 +- 10 files changed, 1 insertion(+), 646 deletions(-) delete mode 100644 cereal/.pre-commit-config.yaml delete mode 100644 cereal/Dockerfile delete mode 100644 cereal/LICENSE delete mode 100644 cereal/codecov.yml delete mode 100644 cereal/messaging/demo.cc delete mode 100644 cereal/messaging/demo.py delete mode 100644 cereal/messaging/msgq.md delete mode 100644 cereal/messaging/msgq_tests.cc delete mode 100644 cereal/messaging/test_runner.cc diff --git a/cereal/.pre-commit-config.yaml b/cereal/.pre-commit-config.yaml deleted file mode 100644 index 03360e0f9..000000000 --- a/cereal/.pre-commit-config.yaml +++ /dev/null @@ -1,47 +0,0 @@ -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 - hooks: - - id: check-ast - - id: check-yaml - - id: check-executables-have-shebangs - - id: check-shebang-scripts-are-executable -- repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.9.0 - hooks: - - id: mypy -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.5 - hooks: - - id: ruff -- repo: local - hooks: - - id: cppcheck - name: cppcheck - entry: cppcheck - language: system - types: [c++] - exclude: '^(messaging/msgq_tests.cc|messaging/test_runner.cc)' - args: - - --error-exitcode=1 - - --inline-suppr - - --language=c++ - - --force - - --quiet - - -j4 -- repo: https://github.com/cpplint/cpplint - rev: 1.6.1 - hooks: - - id: cpplint - args: - - --quiet - - --counting=detailed - - --linelength=240 - - --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces -- repo: https://github.com/codespell-project/codespell - rev: v2.2.6 - hooks: - - id: codespell - args: - - -L ned - - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US diff --git a/cereal/Dockerfile b/cereal/Dockerfile deleted file mode 100644 index d2e3ab591..000000000 --- a/cereal/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM ubuntu:24.04 - -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends \ - autoconf \ - build-essential \ - ca-certificates \ - capnproto \ - clang \ - cppcheck \ - curl \ - git \ - libbz2-dev \ - libcapnp-dev \ - libclang-rt-dev \ - libffi-dev \ - liblzma-dev \ - libncurses5-dev \ - libncursesw5-dev \ - libreadline-dev \ - libsqlite3-dev \ - libssl-dev \ - libtool \ - libzmq3-dev \ - llvm \ - make \ - cmake \ - ocl-icd-opencl-dev \ - opencl-headers \ - python3-dev \ - python3-pip \ - tk-dev \ - wget \ - xz-utils \ - zlib1g-dev \ - && rm -rf /var/lib/apt/lists/* - -RUN pip3 install --break-system-packages --no-cache-dir pyyaml Cython scons pycapnp pre-commit ruff parameterized coverage numpy - -WORKDIR /project/ -RUN cd /tmp/ && \ - git clone -b v2.x --depth 1 https://github.com/catchorg/Catch2.git && \ - cd Catch2 && \ - mv single_include/catch2/ /project/ && \ - cd .. \ - rm -rf Catch2 - -WORKDIR /project/cereal - -ENV PYTHONPATH=/project - -COPY . . -RUN rm -rf .git && \ - scons -c && scons -j$(nproc) diff --git a/cereal/LICENSE b/cereal/LICENSE deleted file mode 100644 index f1fd199c6..000000000 --- a/cereal/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (c) 2020, Comma.ai, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cereal/codecov.yml b/cereal/codecov.yml deleted file mode 100644 index 83427c3ee..000000000 --- a/cereal/codecov.yml +++ /dev/null @@ -1,8 +0,0 @@ -comment: false -coverage: - status: - project: - default: - informational: true - patch: off - diff --git a/cereal/messaging/demo.cc b/cereal/messaging/demo.cc deleted file mode 100644 index 5b4d24468..000000000 --- a/cereal/messaging/demo.cc +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include -#include - -#include "cereal/messaging/messaging.h" -#include "cereal/messaging/impl_zmq.h" - -#define MSGS 1e5 - -int main() { - Context * c = Context::create(); - SubSocket * sub_sock = SubSocket::create(c, "controlsState"); - PubSocket * pub_sock = PubSocket::create(c, "controlsState"); - - char data[8]; - - Poller * poller = Poller::create({sub_sock}); - - auto start = std::chrono::steady_clock::now(); - - for (uint64_t i = 0; i < MSGS; i++){ - *(uint64_t*)data = i; - pub_sock->send(data, 8); - - auto r = poller->poll(100); - - for (auto p : r){ - Message * m = p->receive(); - uint64_t ii = *(uint64_t*)m->getData(); - assert(i == ii); - delete m; - } - } - - - auto end = std::chrono::steady_clock::now(); - double elapsed = std::chrono::duration_cast(end - start).count() / 1e9; - double throughput = ((double) MSGS / (double) elapsed); - std::cout << throughput << " msg/s" << std::endl; - - delete poller; - delete sub_sock; - delete pub_sock; - delete c; - - - return 0; -} diff --git a/cereal/messaging/demo.py b/cereal/messaging/demo.py deleted file mode 100644 index e4850e32b..000000000 --- a/cereal/messaging/demo.py +++ /dev/null @@ -1,29 +0,0 @@ -import time - -from messaging_pyx import Context, Poller, SubSocket, PubSocket - -MSGS = 1e5 - -if __name__ == "__main__": - c = Context() - sub_sock = SubSocket() - pub_sock = PubSocket() - - sub_sock.connect(c, "controlsState") - pub_sock.connect(c, "controlsState") - - poller = Poller() - poller.registerSocket(sub_sock) - - t = time.time() - for i in range(int(MSGS)): - bts = i.to_bytes(4, 'little') - pub_sock.send(bts) - - for s in poller.poll(100): - dat = s.receive() - ii = int.from_bytes(dat, 'little') - assert(i == ii) - - dt = time.time() - t - print("%.1f msg/s" % (MSGS / dt)) diff --git a/cereal/messaging/msgq.md b/cereal/messaging/msgq.md deleted file mode 100644 index 34fe35682..000000000 --- a/cereal/messaging/msgq.md +++ /dev/null @@ -1,54 +0,0 @@ -# MSGQ: A lock free single producer multi consumer message queue - -## What is MSGQ? -MSGQ is a system to pass messages from a single producer to multiple consumers. All the consumers need to be able to receive all the messages. It is designed to be a high performance replacement for ZMQ-like SUB/PUB patterns. It uses a ring buffer in shared memory to efficiently read and write data. Each read requires a copy. Writing can be done without a copy, as long as the size of the data is known in advance. - -## Storage -The storage for the queue consists of an area of metadata, and the actual buffer. The metadata contains: - -1. A counter to the number of readers that are active -2. A pointer to the head of the queue for writing. From now on referred to as *write pointer* -3. A cycle counter for the writer. This counter is incremented when the writer wraps around -4. N pointers, pointing to the current read position for all the readers. From now on referred to as *read pointer* -5. N counters, counting the number of cycles for all the readers -6. N booleans, indicating validity for all the readers. From now on referred to as *validity flag* - -The counter and the pointer are both 32 bit values, packed into 64 bit so they can be read and written atomically. - -The data buffer is a ring buffer. All messages are prefixed by an 8 byte size field, followed by the data. A size of -1 indicates a wrap-around, and means the next message is stored at the beginning of the buffer. - - -## Writing -Writing involves the following steps: - -1. Check if the area that is to be written overlaps with any of the read pointers, mark those readers as invalid by clearing the validity flag. -2. Write the message -3. Increase the write pointer by the size of the message - -In case there is not enough space at the end of the buffer, a special empty message with a prefix of -1 is written. The cycle counter is incremented by one. In this case step 1 will check there are no read pointers pointing to the remainder of the buffer. Then another write cycle will start with the actual message. - -There always needs to be 8 bytes of empty space at the end of the buffer. By doing this there is always space to write the -1. - -## Reset reader -When the reader is lagging too much behind the read pointer becomes invalid and no longer points to the beginning of a valid message. To reset a reader to the current write pointer, the following steps are performed: - -1. Set valid flag -2. Set read cycle counter to that of the writer -3. Set read pointer to write pointer - -## Reading -Reading involves the following steps: - -1. Read the size field at the current read pointer -2. Read the validity flag -3. Copy the data out of the buffer -4. Increase the read pointer by the size of the message -5. Check the validity flag again - -Before starting the copy, the valid flag is checked. This is to prevent a race condition where the size prefix was invalid, and the read could read outside of the buffer. Make sure that step 1 and 2 are not reordered by your compiler or CPU. - -If a writer overwrites the data while it's being copied out, the data will be invalid. Therefore the validity flag is also checked after reading it. The order of step 4 and 5 does not matter. - -If at steps 2 or 5 the validity flag is not set, the reader is reset. Any data that was already read is discarded. After the reader is reset, the reading starts from the beginning. - -If a message with size -1 is encountered, step 3 and 4 are replaced by increasing the cycle counter and setting the read pointer to the beginning of the buffer. After that another read is performed. diff --git a/cereal/messaging/msgq_tests.cc b/cereal/messaging/msgq_tests.cc deleted file mode 100644 index d33facbc0..000000000 --- a/cereal/messaging/msgq_tests.cc +++ /dev/null @@ -1,394 +0,0 @@ -#include "catch2/catch.hpp" -#include "cereal/messaging/msgq.h" - -TEST_CASE("ALIGN"){ - REQUIRE(ALIGN(0) == 0); - REQUIRE(ALIGN(1) == 8); - REQUIRE(ALIGN(7) == 8); - REQUIRE(ALIGN(8) == 8); - REQUIRE(ALIGN(99999) == 100000); -} - -TEST_CASE("msgq_msg_init_size"){ - const size_t msg_size = 30; - msgq_msg_t msg; - - msgq_msg_init_size(&msg, msg_size); - REQUIRE(msg.size == msg_size); - - msgq_msg_close(&msg); -} - -TEST_CASE("msgq_msg_init_data"){ - const size_t msg_size = 30; - char * data = new char[msg_size]; - - for (size_t i = 0; i < msg_size; i++){ - data[i] = i; - } - - msgq_msg_t msg; - msgq_msg_init_data(&msg, data, msg_size); - - REQUIRE(msg.size == msg_size); - REQUIRE(memcmp(msg.data, data, msg_size) == 0); - - delete[] data; - msgq_msg_close(&msg); -} - - -TEST_CASE("msgq_init_subscriber"){ - remove("/dev/shm/test_queue"); - msgq_queue_t q; - msgq_new_queue(&q, "test_queue", 1024); - REQUIRE(*q.num_readers == 0); - - q.reader_id = 1; - *q.read_valids[0] = false; - *q.read_pointers[0] = ((uint64_t)1 << 32); - - *q.write_pointer = 255; - - msgq_init_subscriber(&q); - REQUIRE(q.read_conflate == false); - REQUIRE(*q.read_valids[0] == true); - REQUIRE((*q.read_pointers[0] >> 32) == 0); - REQUIRE((*q.read_pointers[0] & 0xFFFFFFFF) == 255); -} - -TEST_CASE("msgq_msg_send first message"){ - remove("/dev/shm/test_queue"); - msgq_queue_t q; - msgq_new_queue(&q, "test_queue", 1024); - msgq_init_publisher(&q); - - REQUIRE(*q.write_pointer == 0); - - size_t msg_size = 128; - - SECTION("Aligned message size"){ - } - SECTION("Unaligned message size"){ - msg_size--; - } - - char * data = new char[msg_size]; - - for (size_t i = 0; i < msg_size; i++){ - data[i] = i; - } - - msgq_msg_t msg; - msgq_msg_init_data(&msg, data, msg_size); - - - msgq_msg_send(&msg, &q); - REQUIRE(*(int64_t*)q.data == msg_size); // Check size tag - REQUIRE(*q.write_pointer == 128 + sizeof(int64_t)); - REQUIRE(memcmp(q.data + sizeof(int64_t), data, msg_size) == 0); - - delete[] data; - msgq_msg_close(&msg); -} - -TEST_CASE("msgq_msg_send test wraparound"){ - remove("/dev/shm/test_queue"); - msgq_queue_t q; - msgq_new_queue(&q, "test_queue", 1024); - msgq_init_publisher(&q); - - REQUIRE((*q.write_pointer & 0xFFFFFFFF) == 0); - REQUIRE((*q.write_pointer >> 32) == 0); - - const size_t msg_size = 120; - msgq_msg_t msg; - msgq_msg_init_size(&msg, msg_size); - - for (int i = 0; i < 8; i++) { - msgq_msg_send(&msg, &q); - } - // Check 8th message was written at the beginning - REQUIRE((*q.write_pointer & 0xFFFFFFFF) == msg_size + sizeof(int64_t)); - - // Check cycle count - REQUIRE((*q.write_pointer >> 32) == 1); - - // Check wraparound tag - char * tag_location = q.data; - tag_location += 7 * (msg_size + sizeof(int64_t)); - REQUIRE(*(int64_t*)tag_location == -1); - - msgq_msg_close(&msg); -} - -TEST_CASE("msgq_msg_recv test wraparound"){ - remove("/dev/shm/test_queue"); - msgq_queue_t q_pub, q_sub; - msgq_new_queue(&q_pub, "test_queue", 1024); - msgq_new_queue(&q_sub, "test_queue", 1024); - - msgq_init_publisher(&q_pub); - msgq_init_subscriber(&q_sub); - - REQUIRE((*q_pub.write_pointer >> 32) == 0); - REQUIRE((*q_sub.read_pointers[0] >> 32) == 0); - - const size_t msg_size = 120; - msgq_msg_t msg1; - msgq_msg_init_size(&msg1, msg_size); - - - SECTION("Check cycle counter after reset") { - for (int i = 0; i < 8; i++) { - msgq_msg_send(&msg1, &q_pub); - } - - msgq_msg_t msg2; - msgq_msg_recv(&msg2, &q_sub); - REQUIRE(msg2.size == 0); // Reader had to reset - msgq_msg_close(&msg2); - } - SECTION("Check cycle counter while keeping up with writer") { - for (int i = 0; i < 8; i++) { - msgq_msg_send(&msg1, &q_pub); - - msgq_msg_t msg2; - msgq_msg_recv(&msg2, &q_sub); - REQUIRE(msg2.size > 0); - msgq_msg_close(&msg2); - } - } - - REQUIRE((*q_sub.read_pointers[0] >> 32) == 1); - msgq_msg_close(&msg1); -} - -TEST_CASE("msgq_msg_send test invalidation"){ - remove("/dev/shm/test_queue"); - msgq_queue_t q_pub, q_sub; - msgq_new_queue(&q_pub, "test_queue", 1024); - msgq_new_queue(&q_sub, "test_queue", 1024); - - msgq_init_publisher(&q_pub); - msgq_init_subscriber(&q_sub); - *q_sub.write_pointer = (uint64_t)1 << 32; - - REQUIRE(*q_sub.read_valids[0] == true); - - SECTION("read pointer in tag"){ - *q_sub.read_pointers[0] = 0; - } - SECTION("read pointer in data section"){ - *q_sub.read_pointers[0] = 64; - } - SECTION("read pointer in wraparound section"){ - *q_pub.write_pointer = ((uint64_t)1 << 32) | 1000; // Writer is one cycle ahead - *q_sub.read_pointers[0] = 1020; - } - - msgq_msg_t msg; - msgq_msg_init_size(&msg, 128); - msgq_msg_send(&msg, &q_pub); - - REQUIRE(*q_sub.read_valids[0] == false); - - msgq_msg_close(&msg); -} - -TEST_CASE("msgq_init_subscriber init 2 subscribers"){ - remove("/dev/shm/test_queue"); - msgq_queue_t q1, q2; - msgq_new_queue(&q1, "test_queue", 1024); - msgq_new_queue(&q2, "test_queue", 1024); - - *q1.num_readers = 0; - - REQUIRE(*q1.num_readers == 0); - REQUIRE(*q2.num_readers == 0); - - msgq_init_subscriber(&q1); - REQUIRE(*q1.num_readers == 1); - REQUIRE(*q2.num_readers == 1); - REQUIRE(q1.reader_id == 0); - - msgq_init_subscriber(&q2); - REQUIRE(*q1.num_readers == 2); - REQUIRE(*q2.num_readers == 2); - REQUIRE(q2.reader_id == 1); -} - - -TEST_CASE("Write 1 msg, read 1 msg", "[integration]"){ - remove("/dev/shm/test_queue"); - const size_t msg_size = 128; - msgq_queue_t writer, reader; - - msgq_new_queue(&writer, "test_queue", 1024); - msgq_new_queue(&reader, "test_queue", 1024); - - msgq_init_publisher(&writer); - msgq_init_subscriber(&reader); - - // Build 128 byte message - msgq_msg_t outgoing_msg; - msgq_msg_init_size(&outgoing_msg, msg_size); - - for (size_t i = 0; i < msg_size; i++){ - outgoing_msg.data[i] = i; - } - - REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); - - msgq_msg_t incoming_msg1; - REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size); - REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0); - - // Verify that there are no more messages - msgq_msg_t incoming_msg2; - REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == 0); - - msgq_msg_close(&outgoing_msg); - msgq_msg_close(&incoming_msg1); - msgq_msg_close(&incoming_msg2); -} - -TEST_CASE("Write 2 msg, read 2 msg - conflate = false", "[integration]"){ - remove("/dev/shm/test_queue"); - const size_t msg_size = 128; - msgq_queue_t writer, reader; - - msgq_new_queue(&writer, "test_queue", 1024); - msgq_new_queue(&reader, "test_queue", 1024); - - msgq_init_publisher(&writer); - msgq_init_subscriber(&reader); - - // Build 128 byte message - msgq_msg_t outgoing_msg; - msgq_msg_init_size(&outgoing_msg, msg_size); - - for (size_t i = 0; i < msg_size; i++){ - outgoing_msg.data[i] = i; - } - - REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); - REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); - - msgq_msg_t incoming_msg1; - REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size); - REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0); - - msgq_msg_t incoming_msg2; - REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == msg_size); - REQUIRE(memcmp(incoming_msg2.data, outgoing_msg.data, msg_size) == 0); - - msgq_msg_close(&outgoing_msg); - msgq_msg_close(&incoming_msg1); - msgq_msg_close(&incoming_msg2); -} - -TEST_CASE("Write 2 msg, read 2 msg - conflate = true", "[integration]"){ - remove("/dev/shm/test_queue"); - const size_t msg_size = 128; - msgq_queue_t writer, reader; - - msgq_new_queue(&writer, "test_queue", 1024); - msgq_new_queue(&reader, "test_queue", 1024); - - msgq_init_publisher(&writer); - msgq_init_subscriber(&reader); - reader.read_conflate = true; - - // Build 128 byte message - msgq_msg_t outgoing_msg; - msgq_msg_init_size(&outgoing_msg, msg_size); - - for (size_t i = 0; i < msg_size; i++){ - outgoing_msg.data[i] = i; - } - - REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); - REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size); - - msgq_msg_t incoming_msg1; - REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size); - REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0); - - // Verify that there are no more messages - msgq_msg_t incoming_msg2; - REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == 0); - - msgq_msg_close(&outgoing_msg); - msgq_msg_close(&incoming_msg1); - msgq_msg_close(&incoming_msg2); -} - -TEST_CASE("1 publisher, 1 slow subscriber", "[integration]"){ - remove("/dev/shm/test_queue"); - msgq_queue_t writer, reader; - - msgq_new_queue(&writer, "test_queue", 1024); - msgq_new_queue(&reader, "test_queue", 1024); - - msgq_init_publisher(&writer); - msgq_init_subscriber(&reader); - - int n_received = 0; - int n_skipped = 0; - - for (uint64_t i = 0; i < 1e5; i++) { - msgq_msg_t outgoing_msg; - msgq_msg_init_data(&outgoing_msg, (char*)&i, sizeof(uint64_t)); - msgq_msg_send(&outgoing_msg, &writer); - msgq_msg_close(&outgoing_msg); - - if (i % 10 == 0){ - msgq_msg_t msg1; - msgq_msg_recv(&msg1, &reader); - - if (msg1.size == 0){ - n_skipped++; - } else { - n_received++; - } - msgq_msg_close(&msg1); - } - } - - // TODO: verify these numbers by hand - REQUIRE(n_received == 8572); - REQUIRE(n_skipped == 1428); -} - -TEST_CASE("1 publisher, 2 subscribers", "[integration]"){ - remove("/dev/shm/test_queue"); - msgq_queue_t writer, reader1, reader2; - - msgq_new_queue(&writer, "test_queue", 1024); - msgq_new_queue(&reader1, "test_queue", 1024); - msgq_new_queue(&reader2, "test_queue", 1024); - - msgq_init_publisher(&writer); - msgq_init_subscriber(&reader1); - msgq_init_subscriber(&reader2); - - for (uint64_t i = 0; i < 1024 * 3; i++) { - msgq_msg_t outgoing_msg; - msgq_msg_init_data(&outgoing_msg, (char*)&i, sizeof(uint64_t)); - msgq_msg_send(&outgoing_msg, &writer); - - msgq_msg_t msg1, msg2; - msgq_msg_recv(&msg1, &reader1); - msgq_msg_recv(&msg2, &reader2); - - REQUIRE(msg1.size == sizeof(uint64_t)); - REQUIRE(msg2.size == sizeof(uint64_t)); - REQUIRE(*(uint64_t*)msg1.data == i); - REQUIRE(*(uint64_t*)msg2.data == i); - - msgq_msg_close(&outgoing_msg); - msgq_msg_close(&msg1); - msgq_msg_close(&msg2); - } -} diff --git a/cereal/messaging/test_runner.cc b/cereal/messaging/test_runner.cc deleted file mode 100644 index 62bf7476a..000000000 --- a/cereal/messaging/test_runner.cc +++ /dev/null @@ -1,2 +0,0 @@ -#define CATCH_CONFIG_MAIN -#include "catch2/catch.hpp" diff --git a/msgq b/msgq index 6d2cc6e22..615aea9b5 160000 --- a/msgq +++ b/msgq @@ -1 +1 @@ -Subproject commit 6d2cc6e22229a9c855d8474e5643b26fbf2b5976 +Subproject commit 615aea9b5519d2a3631fce4753bed29287fc4f9b From 280a284b760c2a0519ffedcdb7228be23c90edf9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 6 Jun 2024 16:24:09 -0700 Subject: [PATCH 159/220] update TOTAL_SCONS_NODES from https://github.com/commaai/openpilot/commit/fe7d3429abd85c120f0205093149eb9eabc81cb1 --- system/manager/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/manager/build.py b/system/manager/build.py index ac7822d51..956336a60 100755 --- a/system/manager/build.py +++ b/system/manager/build.py @@ -14,7 +14,7 @@ from openpilot.system.version import get_build_metadata MAX_CACHE_SIZE = 4e9 if "CI" in os.environ else 2e9 CACHE_DIR = Path("/data/scons_cache" if AGNOS else "/tmp/scons_cache") -TOTAL_SCONS_NODES = 2410 +TOTAL_SCONS_NODES = 2820 MAX_BUILD_PROGRESS = 100 def build(spinner: Spinner, dirty: bool = False, minimal: bool = False) -> None: From a7ed190df4665a7f972862c992455bfd7daa6eab Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 6 Jun 2024 16:46:27 -0700 Subject: [PATCH 160/220] controlsd: remove last mention of CAN (#32646) --- selfdrive/controls/controlsd.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index bc79c1fb4..4f5bd1940 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -317,19 +317,18 @@ class Controls: # generic catch-all. ideally, a more specific event should be added above instead has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE)) no_system_errors = (not has_disable_events) or (len(self.events) == num_events) - if (not self.sm.all_checks() or CS.canRcvTimeout) and no_system_errors: + if not self.sm.all_checks() and no_system_errors: if not self.sm.all_alive(): self.events.add(EventName.commIssue) elif not self.sm.all_freq_ok(): self.events.add(EventName.commIssueAvgFreq) - else: # invalid or can_rcv_timeout. + else: self.events.add(EventName.commIssue) logs = { 'invalid': [s for s, valid in self.sm.valid.items() if not valid], 'not_alive': [s for s, alive in self.sm.alive.items() if not alive], 'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok], - 'can_rcv_timeout': CS.canRcvTimeout, } if logs != self.logged_comm_issue: cloudlog.event("commIssue", error=True, **logs) From ccd26de097dbdbc82af799d22eb2f4b6c92defcc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 6 Jun 2024 21:12:21 -0700 Subject: [PATCH 161/220] update msgq repo url (#32647) --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index ee65939b6..4952fcbea 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,7 @@ url = ../../commaai/opendbc.git [submodule "msgq"] path = msgq - url = ../../commaai/cereal.git + url = ../../commaai/msgq.git [submodule "rednose_repo"] path = rednose_repo url = ../../commaai/rednose.git From e6caaf40fb16e7c27221e1353d0e903d5c805918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 6 Jun 2024 23:35:13 -0700 Subject: [PATCH 162/220] More cereal cleanups (#32644) * rm generate_javascript.sh * Unused --- cereal/generate_javascript.sh | 26 -------------------------- cereal/messaging/stress.py | 14 -------------- 2 files changed, 40 deletions(-) delete mode 100755 cereal/generate_javascript.sh delete mode 100644 cereal/messaging/stress.py diff --git a/cereal/generate_javascript.sh b/cereal/generate_javascript.sh deleted file mode 100755 index d6525a64d..000000000 --- a/cereal/generate_javascript.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -rm -r gen/ts -rm -r gen/js - -mkdir gen/ts -mkdir gen/js - -echo "Installing needed npm modules" -npm i capnpc-ts capnp-ts - -capnpc -o node_modules/.bin/capnpc-ts:gen/ts log.capnp car.capnp -capnpc -o node_modules/.bin/capnpc-ts:gen/ts car.capnp - -cat log.capnp | egrep '\([a-zA-Z]*\.[^\s]+\.[^s]+\)' | sed 's/^.*([a-zA-Z]*\.\([a-zA-Z.]*\)).*/\1/' | while read line -do - TOKEN=`echo $line | sed 's/\./_/g'` - ROOT=`echo $line | sed 's/\..*$//g'` - cat gen/ts/log.capnp.ts | grep '^import.*'${TOKEN} - if [[ "$?" == "1" ]] - then - sed -i 's/^\(import {.*\)'${ROOT}'\(,*\) \(.*\)$/\1'${ROOT}', '${TOKEN}'\2 \3/' ./gen/ts/log.capnp.ts - fi -done - -tsc ./gen/ts/* --lib es2015 --outDir ./gen/js diff --git a/cereal/messaging/stress.py b/cereal/messaging/stress.py deleted file mode 100644 index 1a27e520e..000000000 --- a/cereal/messaging/stress.py +++ /dev/null @@ -1,14 +0,0 @@ -from messaging_pyx import Context, SubSocket, PubSocket - -if __name__ == "__main__": - c = Context() - pub_sock = PubSocket() - pub_sock.connect(c, "controlsState") - - for i in range(int(1e10)): - print(i) - sub_sock = SubSocket() - sub_sock.connect(c, "controlsState") - - pub_sock.send(b'a') - print(sub_sock.receive()) From 5c3c06dfdf087c74214a6cfc350cbcc02346b41e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 7 Jun 2024 15:26:55 -0700 Subject: [PATCH 163/220] blacklist more files from release (#32616) * blacklist more files from release * dbcs * fix * just use the lfs * rm that too * cleanup * cleanup --- SConstruct | 2 +- release/release_files.py | 68 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/SConstruct b/SConstruct index ba49d926a..e827d6641 100644 --- a/SConstruct +++ b/SConstruct @@ -67,7 +67,7 @@ AddOption('--pc-thneed', AddOption('--minimal', action='store_false', dest='extras', - default=os.path.islink(Dir('#rednose/').abspath), # minimal by default on release branch (where rednose is not a link) + default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS) help='the minimum build to run openpilot. no tests, tools, etc.') ## Architecture name breakdown (arch) diff --git a/release/release_files.py b/release/release_files.py index a6fb7d648..2d279e97a 100755 --- a/release/release_files.py +++ b/release/release_files.py @@ -10,13 +10,25 @@ ROOT = HERE + "/.." # - minimizing release download size # - keeping the diff readable blacklist = [ - "^scripts/", "body/STL/", - "tools/cabana/", + + "panda/drivers/", "panda/examples/", + "panda/tests/safety/", + + "opendbc/.*.dbc$", "opendbc/generator/", + "cereal/.*test.*", + "^common/tests/", + + # particularly large text files + "poetry.lock", + "third_party/catch2", + "selfdrive/car/tests/test_models.*", + "^tools/", + "^scripts/", "^tinygrad_repo/", "matlab.*.md", @@ -56,8 +68,60 @@ whitelist = [ "tinygrad_repo/tinygrad/runtime/ops_gpu.py", "tinygrad_repo/tinygrad/shape/*", "tinygrad_repo/tinygrad/.*.py", + + # TODO: do this automatically + "opendbc/comma_body.dbc", + "opendbc/chrysler_ram_hd_generated.dbc", + "opendbc/chrysler_ram_dt_generated.dbc", + "opendbc/chrysler_pacifica_2017_hybrid_generated.dbc", + "opendbc/chrysler_pacifica_2017_hybrid_private_fusion.dbc", + "opendbc/gm_global_a_powertrain_generated.dbc", + "opendbc/gm_global_a_object.dbc", + "opendbc/gm_global_a_chassis.dbc", + "opendbc/FORD_CADS.dbc", + "opendbc/ford_fusion_2018_adas.dbc", + "opendbc/ford_lincoln_base_pt.dbc", + "opendbc/honda_accord_2018_can_generated.dbc", + "opendbc/acura_ilx_2016_can_generated.dbc", + "opendbc/acura_rdx_2018_can_generated.dbc", + "opendbc/acura_rdx_2020_can_generated.dbc", + "opendbc/honda_civic_touring_2016_can_generated.dbc", + "opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc", + "opendbc/honda_crv_touring_2016_can_generated.dbc", + "opendbc/honda_crv_ex_2017_can_generated.dbc", + "opendbc/honda_crv_ex_2017_body_generated.dbc", + "opendbc/honda_crv_executive_2016_can_generated.dbc", + "opendbc/honda_fit_ex_2018_can_generated.dbc", + "opendbc/honda_odyssey_exl_2018_generated.dbc", + "opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc", + "opendbc/honda_insight_ex_2019_can_generated.dbc", + "opendbc/acura_ilx_2016_nidec.dbc", + "opendbc/honda_civic_ex_2022_can_generated.dbc", + "opendbc/hyundai_canfd.dbc", + "opendbc/hyundai_kia_generic.dbc", + "opendbc/hyundai_kia_mando_front_radar_generated.dbc", + "opendbc/mazda_2017.dbc", + "opendbc/nissan_x_trail_2017_generated.dbc", + "opendbc/nissan_leaf_2018_generated.dbc", + "opendbc/subaru_global_2017_generated.dbc", + "opendbc/subaru_global_2020_hybrid_generated.dbc", + "opendbc/subaru_outback_2015_generated.dbc", + "opendbc/subaru_outback_2019_generated.dbc", + "opendbc/subaru_forester_2017_generated.dbc", + "opendbc/toyota_tnga_k_pt_generated.dbc", + "opendbc/toyota_new_mc_pt_generated.dbc", + "opendbc/toyota_nodsu_pt_generated.dbc", + "opendbc/toyota_adas.dbc", + "opendbc/toyota_tss2_adas.dbc", + "opendbc/vw_golf_mk4.dbc", + "opendbc/vw_mqb_2010.dbc", + "opendbc/tesla_can.dbc", + "opendbc/tesla_radar_bosch_generated.dbc", + "opendbc/tesla_radar_continental_generated.dbc", + "opendbc/tesla_powertrain.dbc", ] + if __name__ == "__main__": for f in Path(ROOT).rglob("**/*"): if not (f.is_file() or f.is_symlink()): From 2bad3c29d99ed6f037e40489f450d72e1e28dd27 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 7 Jun 2024 15:46:32 -0700 Subject: [PATCH 164/220] build_release: run tests with pytest --- release/build_release.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/build_release.sh b/release/build_release.sh index b68ae455c..510df75e5 100755 --- a/release/build_release.sh +++ b/release/build_release.sh @@ -90,9 +90,9 @@ TEST_FILES="tools/" cd $SOURCE_DIR cp -pR -n --parents $TEST_FILES $BUILD_DIR/ cd $BUILD_DIR -RELEASE=1 selfdrive/test/test_onroad.py +RELEASE=1 pytest -n0 -s selfdrive/test/test_onroad.py #system/manager/test/test_manager.py -selfdrive/car/tests/test_car_interfaces.py +pytest selfdrive/car/tests/test_car_interfaces.py rm -rf $TEST_FILES if [ ! -z "$RELEASE_BRANCH" ]; then From b42b156fcd8d98adee9e6b5384558cfabd4f2165 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 7 Jun 2024 17:03:17 -0700 Subject: [PATCH 165/220] card: remove old canRcvtimeout field (#32650) * card: remove old canRcvtimeout field * deprecate --- cereal/car.capnp | 2 +- selfdrive/car/card.py | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/cereal/car.capnp b/cereal/car.capnp index d7ec1b248..8d76f0ead 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -156,7 +156,6 @@ struct CarState { canValid @26 :Bool; # invalid counter/checksums canTimeout @40 :Bool; # CAN bus dropped out canErrorCounter @48 :UInt32; - canRcvTimeout @49 :Bool; # car speed vEgo @1 :Float32; # best estimate of speed @@ -282,6 +281,7 @@ struct CarState { brakeLightsDEPRECATED @19 :Bool; steeringRateLimitedDEPRECATED @29 :Bool; canMonoTimesDEPRECATED @12: List(UInt64); + canRcvTimeoutDEPRECATED @49 :Bool; } # ******* radar state @ 20hz ******* diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 330ad40e0..d9ee020ba 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -29,8 +29,7 @@ class Car: self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents']) self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput']) - self.can_rcv_timeout_counter = 0 # consecutive timeout count - self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count + self.can_rcv_cum_timeout_counter = 0 self.CC_prev = car.CarControl.new_message() self.CS_prev = car.CarState.new_message() @@ -96,12 +95,7 @@ class Car: # Check for CAN timeout if not can_rcv_valid: - self.can_rcv_timeout_counter += 1 self.can_rcv_cum_timeout_counter += 1 - else: - self.can_rcv_timeout_counter = 0 - - self.can_rcv_timeout = self.can_rcv_timeout_counter >= 5 if can_rcv_valid and REPLAY: self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime @@ -141,7 +135,6 @@ class Car: cs_send = messaging.new_message('carState') cs_send.valid = CS.canValid cs_send.carState = CS - cs_send.carState.canRcvTimeout = self.can_rcv_timeout cs_send.carState.canErrorCounter = self.can_rcv_cum_timeout_counter cs_send.carState.cumLagMs = -self.rk.remaining * 1000. self.pm.send('carState', cs_send) From 9ce380d3ce515f7065e27df3e7b155164bcdb56a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 7 Jun 2024 21:12:10 -0700 Subject: [PATCH 166/220] bump opendbc (#32651) * bump * bump2 * bump3 --- opendbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc b/opendbc index f58bc3392..776bca184 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit f58bc3392cfffd25b311e093aa72f0ef3a89f6e8 +Subproject commit 776bca184bc997b587afb20df71bc56a4890c4d8 From 451e171ad9bef27d87f4124dbf032881d3ccc485 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 7 Jun 2024 21:24:32 -0700 Subject: [PATCH 167/220] remove old cache wrapper (#32653) * remove wrapper that is functools.cache * format --- common/git.py | 2 +- common/utils.py | 12 ------------ system/version.py | 3 +-- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/common/git.py b/common/git.py index bfb18ce25..4406bf96b 100644 --- a/common/git.py +++ b/common/git.py @@ -1,5 +1,5 @@ +from functools import cache import subprocess -from openpilot.common.utils import cache from openpilot.common.run import run_cmd, run_cmd_default diff --git a/common/utils.py b/common/utils.py index e37f2448c..b9de020ee 100644 --- a/common/utils.py +++ b/common/utils.py @@ -1,11 +1,3 @@ -from collections.abc import Callable -from functools import lru_cache -from typing import TypeVar - - -_RT = TypeVar("_RT") - - class Freezable: _frozen: bool = False @@ -17,7 +9,3 @@ class Freezable: if self._frozen: raise Exception("cannot modify frozen object") super().__setattr__(*args, **kwargs) - - -def cache(user_function: Callable[..., _RT], /) -> Callable[..., _RT]: - return lru_cache(maxsize=None)(user_function) diff --git a/system/version.py b/system/version.py index d258fe049..94964526b 100755 --- a/system/version.py +++ b/system/version.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 from dataclasses import dataclass +from functools import cache import json import os import pathlib import subprocess - from openpilot.common.basedir import BASEDIR from openpilot.common.swaglog import cloudlog -from openpilot.common.utils import cache from openpilot.common.git import get_commit, get_origin, get_branch, get_short_branch, get_commit_date RELEASE_BRANCHES = ['release3-staging', 'release3', 'nightly'] From b51472048ce5b37f4069ad14a60fc911e47b724e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 7 Jun 2024 23:09:41 -0700 Subject: [PATCH 168/220] test_encoder: adjust file size tolerance --- system/loggerd/tests/test_encoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/loggerd/tests/test_encoder.py b/system/loggerd/tests/test_encoder.py index 7289d9ede..75862a9d4 100644 --- a/system/loggerd/tests/test_encoder.py +++ b/system/loggerd/tests/test_encoder.py @@ -27,7 +27,7 @@ CAMERAS = [ ] # we check frame count, so we don't have to be too strict on size -FILE_SIZE_TOLERANCE = 0.5 +FILE_SIZE_TOLERANCE = 0.7 @pytest.mark.tici # TODO: all of loggerd should work on PC From 90523b3b000e355599a1f2c7d3c90cb6b8498c66 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 7 Jun 2024 23:38:51 -0700 Subject: [PATCH 169/220] remove old fingerprints test (#32654) * is this even used? * remove --- selfdrive/car/tests/test_fingerprints.py | 95 ------------------------ 1 file changed, 95 deletions(-) delete mode 100644 selfdrive/car/tests/test_fingerprints.py diff --git a/selfdrive/car/tests/test_fingerprints.py b/selfdrive/car/tests/test_fingerprints.py deleted file mode 100644 index 6575d3e5c..000000000 --- a/selfdrive/car/tests/test_fingerprints.py +++ /dev/null @@ -1,95 +0,0 @@ -import os -import sys - -from openpilot.common.basedir import BASEDIR - -# messages reserved for CAN based ignition (see can_ignition_hook function in panda/board/drivers/can) -# (addr, len) -CAN_IGNITION_MSGS = { - 'gm': [(0x1F1, 8), (0x160, 5)], - #'tesla' : [(0x348, 8)], -} - -def _get_fingerprints(): - # read all the folders in selfdrive/car and return a dict where: - # - keys are all the car names that which we have a fingerprint dict for - # - values are dicts of fingeprints for each trim - fingerprints = {} - for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]: - car_name = car_folder.split('/')[-1] - try: - fingerprints[car_name] = __import__(f'selfdrive.car.{car_name}.values', fromlist=['FINGERPRINTS']).FINGERPRINTS - except (ImportError, OSError, AttributeError): - pass - - return fingerprints - - -def check_fingerprint_consistency(f1, f2): - # return false if it finds a fingerprint fully included in another - # max message worth checking is 1800, as above that they usually come too infrequently and not - # usable for fingerprinting - - max_msg = 1800 - - is_f1_in_f2 = True - for k in f1: - if (k not in f2 or f1[k] != f2[k]) and k < max_msg: - is_f1_in_f2 = False - - is_f2_in_f1 = True - for k in f2: - if (k not in f1 or f2[k] != f1[k]) and k < max_msg: - is_f2_in_f1 = False - - return not is_f1_in_f2 and not is_f2_in_f1 - - -def check_can_ignition_conflicts(fingerprints, brands): - # loops through all the fingerprints and exits if CAN ignition dedicated messages - # are found in unexpected fingerprints - - for brand_can, msgs_can in CAN_IGNITION_MSGS.items(): - for i, f in enumerate(fingerprints): - for msg_can in msgs_can: - if brand_can != brands[i] and msg_can[0] in f and msg_can[1] == f[msg_can[0]]: - print("CAN ignition dedicated msg %d with len %d found in %s fingerprints!" % (msg_can[0], msg_can[1], brands[i])) - print("TEST FAILED") - sys.exit(1) - - - -if __name__ == "__main__": - fingerprints = _get_fingerprints() - - fingerprints_flat: list[dict] = [] - car_names = [] - brand_names = [] - for brand in fingerprints: - for car in fingerprints[brand]: - fingerprints_flat += fingerprints[brand][car] - for _ in range(len(fingerprints[brand][car])): - car_names.append(car) - brand_names.append(brand) - - # first check if CAN ignition specific messages are unexpectedly included in other fingerprints - check_can_ignition_conflicts(fingerprints_flat, brand_names) - - valid = True - for idx1, f1 in enumerate(fingerprints_flat): - for idx2, f2 in enumerate(fingerprints_flat): - if idx1 < idx2 and not check_fingerprint_consistency(f1, f2): - valid = False - print(f"Those two fingerprints are inconsistent {car_names[idx1]} {car_names[idx2]}") - print("") - print(', '.join("%d: %d" % v for v in sorted(f1.items()))) - print("") - print(', '.join("%d: %d" % v for v in sorted(f2.items()))) - print("") - - print(f"Found {len(fingerprints_flat)} individual fingerprints") - if not valid or len(fingerprints_flat) == 0: - print("TEST FAILED") - sys.exit(1) - else: - print("TEST SUCCESSFUL") From 57f21abb4fe3ae81842adc07fb79a1d2c056fee0 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 7 Jun 2024 23:58:14 -0700 Subject: [PATCH 170/220] pandad: fix loopback test (#32656) * pandad: fix loopback test * clear all params * try this --------- Co-authored-by: Comma Device --- selfdrive/pandad/tests/test_pandad_loopback.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/selfdrive/pandad/tests/test_pandad_loopback.py b/selfdrive/pandad/tests/test_pandad_loopback.py index 365bb7611..d2b6d047d 100644 --- a/selfdrive/pandad/tests/test_pandad_loopback.py +++ b/selfdrive/pandad/tests/test_pandad_loopback.py @@ -20,10 +20,11 @@ from openpilot.selfdrive.test.helpers import phone_only, with_processes @retry(attempts=3) def setup_pandad(num_pandas): params = Params() + params.clear_all() params.put_bool("IsOnroad", False) + sm = messaging.SubMaster(['pandaStates']) with Timeout(90, "pandad didn't start"): - sm = messaging.SubMaster(['pandaStates']) while sm.recv_frame['pandaStates'] < 1 or len(sm['pandaStates']) == 0 or \ any(ps.pandaType == log.PandaState.PandaType.unknown for ps in sm['pandaStates']): sm.update(1000) @@ -44,6 +45,9 @@ def setup_pandad(num_pandas): params.put_bool("ControlsReady", True) params.put("CarParams", cp.to_bytes()) + with Timeout(90, "pandad didn't set safety mode"): + while any(ps.safetyModel != car.CarParams.SafetyModel.allOutput for ps in sm['pandaStates']): + sm.update(1000) def send_random_can_messages(sendcan, count, num_pandas=1): sent_msgs = defaultdict(set) @@ -73,10 +77,11 @@ class TestBoarddLoopback: def test_loopback(self): num_pandas = 2 if TICI and "SINGLE_PANDA" not in os.environ else 1 setup_pandad(num_pandas) + sendcan = messaging.pub_sock('sendcan') can = messaging.sub_sock('can', conflate=False, timeout=100) sm = messaging.SubMaster(['pandaStates']) - time.sleep(0.5) + time.sleep(1) n = 200 for i in range(n): From 3b6862030a550b92e8ecc5a51de61811ad12d6b9 Mon Sep 17 00:00:00 2001 From: Nelson Chen Date: Sat, 8 Jun 2024 09:18:00 -0700 Subject: [PATCH 171/220] Change the term "Non-US" to "South America" for the "Corolla Hybrid (Non-US only) 2020-23" entry (#32658) The term "Non-US" in cars.md for the "Corolla Hybrid (Non-US only) 2020-23" is not precise enough and should be changed to South America Users may think "Non-US" includes Europe or Canada, which is not the case for this entry. It has two issues: * The 2023 Corolla Hybrid in Europe and Canada include a new Toyota Safety Sense 3.0 that has yet to be supported due to it being a new version and the presence of Toyota Security Key. * The 2020-2022 Corolla Hybrid in Europe is the same as the 2020-2022 Corolla Hybrid in North America, which is supported by Openpilot and has full-speed ACC due to the presence of an electronic parking brake which is not present in the 2020-2022 Corolla Hybrid in South America and the reason why it is listed as not having full-speed ACC. The entry should be reverted to at least "Corolla Hybrid (South America) 2020-23" which was proposed but not merged in the pull request: https://github.com/commaai/openpilot/commit/28454c04cc93dc241da3b004a7154e44313e85c9 Pull request for that change that does not include that commit: https://github.com/commaai/openpilot/pull/26943 Examples of confusion throughout the community: comma.ai Discord: https://discord.com/channels/469524606043160576/524327905937850394/1235264758580772996 https://discord.com/channels/469524606043160576/524327905937850394/1228090600272691370 https://discord.com/channels/469524606043160576/954493346250887168/1209952008329633813 https://discord.com/channels/469524606043160576/524327905937850394/1182093384647721140 https://discord.com/channels/469524606043160576/954493346250887168/1147751657543848017 openpilot community Discord: https://discord.com/channels/771493367246094347/771495215570747403/1247737844727021629 > I think that the supported cars list (https://github.com/commaai/openpilot/blob/master/docs/CARS.md) is incorrect. > > I have a UK 2020 Toyota Corolla Hybrid > > In the cars list it's listed as "no accel below" 17 mph and no resume from > stop. > > This is not my experience. For me it works just fine down to a complete stop and it can resume from a stop too. > > CC: @AlexandreSato --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 7861bb654..c79206f84 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -237,7 +237,7 @@ A supported vehicle is one that just works when you install a comma device. All |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Toyota|Corolla Hybrid (South America only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index dbab2e925..2e781ad0a 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -161,7 +161,7 @@ class CAR(Platforms): ToyotaCarDocs("Toyota Corolla Hatchback 2019-22", video_link="https://www.youtube.com/watch?v=_66pXk0CBYA"), # Hybrid platforms ToyotaCarDocs("Toyota Corolla Hybrid 2020-22"), - ToyotaCarDocs("Toyota Corolla Hybrid (Non-US only) 2020-23", min_enable_speed=7.5), + ToyotaCarDocs("Toyota Corolla Hybrid (South America only) 2020-23", min_enable_speed=7.5), ToyotaCarDocs("Toyota Corolla Cross Hybrid (Non-US only) 2020-22", min_enable_speed=7.5), ToyotaCarDocs("Lexus UX Hybrid 2019-23"), ], From 541b5cbf1387df07e76da55d3e332170d9e756f0 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 8 Jun 2024 09:18:28 -0700 Subject: [PATCH 172/220] tools/sim: remove special docker image (#32659) --- .github/workflows/tools_tests.yaml | 19 --------------- selfdrive/test/docker_common.sh | 3 --- tools/sim/Dockerfile.sim | 38 ------------------------------ 3 files changed, 60 deletions(-) delete mode 100644 tools/sim/Dockerfile.sim diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 10c5b7091..ba597f700 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -20,25 +20,6 @@ env: jobs: - simulator_build: - name: simulator docker build - runs-on: ubuntu-latest - if: github.repository == 'commaai/openpilot' - timeout-minutes: 45 - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: Setup to push to repo - if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' - run: | - echo "PUSH_IMAGE=true" >> "$GITHUB_ENV" - $DOCKER_LOGIN - - name: Build and push sim image - run: | - selfdrive/test/docker_build.sh sim - simulator_driving: name: simulator driving runs-on: ubuntu-latest diff --git a/selfdrive/test/docker_common.sh b/selfdrive/test/docker_common.sh index f8a423762..2887fff74 100644 --- a/selfdrive/test/docker_common.sh +++ b/selfdrive/test/docker_common.sh @@ -1,9 +1,6 @@ if [ "$1" = "base" ]; then export DOCKER_IMAGE=openpilot-base export DOCKER_FILE=Dockerfile.openpilot_base -elif [ "$1" = "sim" ]; then - export DOCKER_IMAGE=openpilot-sim - export DOCKER_FILE=tools/sim/Dockerfile.sim elif [ "$1" = "prebuilt" ]; then export DOCKER_IMAGE=openpilot-prebuilt export DOCKER_FILE=Dockerfile.openpilot diff --git a/tools/sim/Dockerfile.sim b/tools/sim/Dockerfile.sim deleted file mode 100644 index bd83c119b..000000000 --- a/tools/sim/Dockerfile.sim +++ /dev/null @@ -1,38 +0,0 @@ -FROM ghcr.io/commaai/openpilot-base:latest - -RUN apt-get update && apt-get install -y --no-install-recommends \ - tmux \ - vim \ - && rm -rf /var/lib/apt/lists/* - -# get same tmux config used on NEOS for debugging -RUN cd $HOME && \ - curl -O https://raw.githubusercontent.com/commaai/eon-neos-builder/master/devices/eon/home/.tmux.conf - -ENV OPENPILOT_PATH /tmp/openpilot -ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} - -RUN mkdir -p ${OPENPILOT_PATH} -WORKDIR ${OPENPILOT_PATH} - -COPY SConstruct ${OPENPILOT_PATH} - -COPY ./openpilot ${OPENPILOT_PATH}/openpilot -COPY ./body ${OPENPILOT_PATH}/body -COPY ./third_party ${OPENPILOT_PATH}/third_party -COPY ./site_scons ${OPENPILOT_PATH}/site_scons -COPY ./rednose ${OPENPILOT_PATH}/rednose -COPY ./rednose_repo/site_scons ${OPENPILOT_PATH}/rednose_repo/site_scons -COPY ./common ${OPENPILOT_PATH}/common -COPY ./opendbc ${OPENPILOT_PATH}/opendbc -COPY ./cereal ${OPENPILOT_PATH}/cereal -COPY ./msgq ${OPENPILOT_PATH}/msgq -COPY ./panda ${OPENPILOT_PATH}/panda -COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive -COPY ./system ${OPENPILOT_PATH}/system -COPY ./tools ${OPENPILOT_PATH}/tools -COPY ./release ${OPENPILOT_PATH}/release - -RUN --mount=type=bind,source=.ci_cache/scons_cache,target=/tmp/scons_cache,rw scons -j$(nproc) --cache-readonly - -RUN python -c "from openpilot.selfdrive.test.helpers import set_params_enabled; set_params_enabled()" From 5265d13fe087972311592febd4071c16cece65e0 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 8 Jun 2024 15:39:26 -0700 Subject: [PATCH 173/220] Replace markdown-it-py with small function in common/ (#32664) * Replace markdown-it-py with small function in common/ * simple test * unused * lock * linting fixes --- common/markdown.py | 45 +++++++++++++++++++++++++++++++++++ common/tests/test_markdown.py | 15 ++++++++++++ poetry.lock | 4 ++-- pyproject.toml | 1 - system/updated/updated.py | 4 ++-- 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 common/markdown.py create mode 100644 common/tests/test_markdown.py diff --git a/common/markdown.py b/common/markdown.py new file mode 100644 index 000000000..f0f056d96 --- /dev/null +++ b/common/markdown.py @@ -0,0 +1,45 @@ +HTML_REPLACEMENTS = [ + (r'&', r'&'), + (r'"', r'"'), +] + +def parse_markdown(text: str, tab_length: int = 2) -> str: + lines = text.split("\n") + output: list[str] = [] + list_level = 0 + + def end_outstanding_lists(level: int, end_level: int) -> int: + while level > end_level: + level -= 1 + output.append("") + if level > 0: + output.append("") + return end_level + + for i, line in enumerate(lines): + if i + 1 < len(lines) and lines[i + 1].startswith("==="): # heading + output.append(f"

{line}

") + elif line.startswith("==="): + pass + elif line.lstrip().startswith("* "): # list + line_level = 1 + line.count(" " * tab_length, 0, line.index("*")) + if list_level >= line_level: + list_level = end_outstanding_lists(list_level, line_level) + else: + list_level += 1 + if list_level > 1: + output[-1] = output[-1].replace("", "") + output.append("
    ") + output.append(f"
  • {line.replace('*', '', 1).lstrip()}
  • ") + else: + list_level = end_outstanding_lists(list_level, 0) + if len(line) > 0: + output.append(line) + + end_outstanding_lists(list_level, 0) + output_str = "\n".join(output) + "\n" + + for (fr, to) in HTML_REPLACEMENTS: + output_str = output_str.replace(fr, to) + + return output_str diff --git a/common/tests/test_markdown.py b/common/tests/test_markdown.py new file mode 100644 index 000000000..d3c7e02c6 --- /dev/null +++ b/common/tests/test_markdown.py @@ -0,0 +1,15 @@ +import os + +from openpilot.common.basedir import BASEDIR +from openpilot.common.markdown import parse_markdown + + +class TestMarkdown: + def test_all_release_notes(self): + with open(os.path.join(BASEDIR, "RELEASES.md")) as f: + release_notes = f.read().split("\n\n") + assert len(release_notes) > 10 + + for rn in release_notes: + md = parse_markdown(rn) + assert len(md) > 0 diff --git a/poetry.lock b/poetry.lock index 062d14fdc..7023c19f1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohttp" @@ -8064,4 +8064,4 @@ test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-it [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "804b6450fde7f96b7bd127d8598d24645bf048aa094c625c3c0e43a3460fcf5e" +content-hash = "e2473a1aa0d28b72f8a0816bb3335a2e48e526e39f038387194948965fffd72e" diff --git a/pyproject.toml b/pyproject.toml index 8642eff4c..34f1e97ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -121,7 +121,6 @@ casadi = "*" future-fstrings = "*" # these should be removed -markdown-it-py = "*" timezonefinder = "*" setproctitle = "*" diff --git a/system/updated/updated.py b/system/updated/updated.py index c1af41bd9..d43f439af 100755 --- a/system/updated/updated.py +++ b/system/updated/updated.py @@ -11,11 +11,11 @@ import time import threading from collections import defaultdict from pathlib import Path -from markdown_it import MarkdownIt from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params from openpilot.common.time import system_time_valid +from openpilot.common.markdown import parse_markdown from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.controls.lib.alertmanager import set_offroad_alert from openpilot.system.hardware import AGNOS, HARDWARE @@ -89,7 +89,7 @@ def parse_release_notes(basedir: str) -> bytes: with open(os.path.join(basedir, "RELEASES.md"), "rb") as f: r = f.read().split(b'\n\n', 1)[0] # Slice latest release notes try: - return bytes(MarkdownIt().render(r.decode("utf-8")), encoding="utf-8") + return bytes(parse_markdown(r.decode("utf-8")), encoding="utf-8") except Exception: return r + b"\n" except FileNotFoundError: From 5e1c54a887e28edc555369df89d5082850237834 Mon Sep 17 00:00:00 2001 From: Nelson Chen Date: Sat, 8 Jun 2024 16:10:58 -0700 Subject: [PATCH 174/220] Update BOUNTIES.md re. Toyota SecOC and community bounty. (#32661) --- docs/BOUNTIES.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/BOUNTIES.md b/docs/BOUNTIES.md index 9d0718c57..31e19e120 100644 --- a/docs/BOUNTIES.md +++ b/docs/BOUNTIES.md @@ -57,10 +57,6 @@ The control doesn't have to be perfect, but it should generally do what it's sup Get a Rivian driving with openpilot. Requires a merged port with lateral control and at least a POC of longitudinal control. -#### Toyota SecOc - $5000 - -We're contributing $5k to the [community-organized bounty](https://github.com/commaai/openpilot/discussions/19932). - #### Chevy Bolt with SuperCruise - $2500 The Bolt is already supported on the trim with standard ACC. Get openpilot working on the trim with SuperCruise. It must be a normal install: no extra pandas or other hardware, no ECU reflashes, etc. The full bounty is for a port with lateral and longitudinal control. $1500 of the bounty can be claimed with a lateral-only port. From 284512b2cae581e004fb56291fb8c2eb7c737bf6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 8 Jun 2024 16:29:41 -0700 Subject: [PATCH 175/220] python dependency notes (#32668) --- poetry.lock | 2 ++ pyproject.toml | 53 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7023c19f1..7d9b0acb0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2730,6 +2730,7 @@ optional = false python-versions = ">=3.6" files = [ {file = "opencv-python-4.10.0.82.tar.gz", hash = "sha256:dbc021eaa310c4145c47cd648cb973db69bb5780d6e635386cd53d3ea76bd2d5"}, + {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:5f78652339957ec24b80a782becfb32f822d2008a865512121fad8c3ce233e9a"}, {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:e6be19a0615aa8c4e0d34e0c7b133e26e386f4b7e9b557b69479104ab2c133ec"}, {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b49e530f7fd86f671514b39ffacdf5d14ceb073bc79d0de46bbb6b0cad78eaf"}, {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955c5ce8ac90c9e4636ad7f5c0d9c75b80abbe347182cfd09b0e3eec6e50472c"}, @@ -2748,6 +2749,7 @@ optional = false python-versions = ">=3.6" files = [ {file = "opencv-python-headless-4.10.0.82.tar.gz", hash = "sha256:de9e742c1b9540816fbd115b0b03841d41ed0c65566b0d7a5371f98b131b7e6d"}, + {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a09ed50ba21cc5bf5d436cb0e784ad09c692d6b1d1454252772f6c8f2c7b4088"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:977a5fd21e1fe0d3d2134887db4441f8725abeae95150126302f31fcd9f548fa"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4ec6755838b0be12510bfc9ffb014779c612418f11f4f7e6f505c36124a3aa"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a37fa5276967ecf6eb297295b16b28b7a2eb3b568ca0ee469fb1a5954de298"}, diff --git a/pyproject.toml b/pyproject.toml index 34f1e97ab..4ac01f658 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,34 +86,47 @@ readme = "README.md" repository = "https://github.com/commaai/openpilot" documentation = "https://docs.comma.ai" - [tool.poetry.dependencies] python = "~3.11" + +# multiple users +sounddevice = "*" # micd + soundd +pyserial = "*" # pigeond + qcomgpsd +requests = "*" # many one-off uses +sympy = "*" # rednose + friends +crcmod = "*" # cars + qcomgpsd + +# hardwared +smbus2 = "*" # configuring amp + +# core +cffi = "*" +scons = "*" +pycapnp = "*" +Cython = "*" +numpy = "*" + +# body / webrtcd aiohttp = "*" aiortc = "*" -cffi = "*" -crcmod = "*" -Cython = "*" -json-rpc = "*" +pyaudio = "*" + +# panda libusb1 = "*" -numpy = "*" +spidev = { version = "*", platform = "linux" } + +# modeld onnx = ">=1.14.0" onnxruntime = { version = ">=1.16.3", platform = "linux", markers = "platform_machine == 'aarch64'" } onnxruntime-gpu = { version = ">=1.16.3", platform = "linux", markers = "platform_machine == 'x86_64'" } -psutil = "*" -pyaudio = "*" -pycapnp = "*" -pycryptodome = "*" -PyJWT = "*" -pyserial = "*" + +# logging pyzmq = "*" -requests = "*" -scons = "*" sentry-sdk = "*" -smbus2 = "*" -sounddevice = "*" -spidev = { version = "*", platform = "linux" } -sympy = "*" + +# athena +PyJWT = "*" +json-rpc = "*" websocket_client = "*" # acados deps @@ -121,8 +134,10 @@ casadi = "*" future-fstrings = "*" # these should be removed -timezonefinder = "*" +psutil = "*" +timezonefinder = "*" # just used for nav ETA setproctitle = "*" +pycryptodome = "*" # used in updated/casync, panda, body, and a test [tool.poetry.group.dev.dependencies] av = "*" From 1093a4ac8217030ae4a0c73ba54bc734a6010acc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 8 Jun 2024 20:43:25 -0700 Subject: [PATCH 176/220] pandad: fix receive buffer size on failed transfer (#32670) --- selfdrive/pandad/panda.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/selfdrive/pandad/panda.cc b/selfdrive/pandad/panda.cc index f0645584a..4ec5b79f1 100644 --- a/selfdrive/pandad/panda.cc +++ b/selfdrive/pandad/panda.cc @@ -220,12 +220,13 @@ bool Panda::can_receive(std::vector& out_vec) { if (!comms_healthy()) { return false; } - if (recv == RECV_SIZE) { - LOGW("Panda receive buffer full"); - } - receive_buffer_size += recv; - return (recv <= 0) ? true : unpack_can_buffer(receive_buffer, receive_buffer_size, out_vec); + bool ret = true; + if (recv > 0) { + receive_buffer_size += recv; + ret = unpack_can_buffer(receive_buffer, receive_buffer_size, out_vec); + } + return ret; } void Panda::can_reset_communications() { From 20a44bb4e9e36e525e0caa6694c6cb863a23b538 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 8 Jun 2024 21:01:39 -0700 Subject: [PATCH 177/220] debug: add summary to check_timings --- selfdrive/debug/check_timings.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/selfdrive/debug/check_timings.py b/selfdrive/debug/check_timings.py index 24c467659..fc527cd81 100755 --- a/selfdrive/debug/check_timings.py +++ b/selfdrive/debug/check_timings.py @@ -1,25 +1,36 @@ #!/usr/bin/env python3 - import sys import time import numpy as np +import datetime from collections.abc import MutableSequence -from collections import defaultdict, deque +from collections import defaultdict import cereal.messaging as messaging -socks = {s: messaging.sub_sock(s, conflate=False) for s in sys.argv[1:]} -ts: defaultdict[str, MutableSequence[float]] = defaultdict(lambda: deque(maxlen=100)) if __name__ == "__main__": - while True: - print() + ts: defaultdict[str, MutableSequence[float]] = defaultdict(list) + socks = {s: messaging.sub_sock(s, conflate=False) for s in sys.argv[1:]} + try: + st = time.monotonic() + while True: + print() + for s, sock in socks.items(): + msgs = messaging.drain_sock(sock) + for m in msgs: + ts[s].append(m.logMonoTime / 1e6) + + if len(ts[s]) > 2: + d = np.diff(ts[s])[-100:] + print(f"{s:25} {np.mean(d):7.2f} {np.std(d):7.2f} {np.max(d):7.2f} {np.min(d):7.2f}") + time.sleep(1) + except KeyboardInterrupt: + print("\n") + print("="*5, "timing summary", "="*5) for s, sock in socks.items(): msgs = messaging.drain_sock(sock) - for m in msgs: - ts[s].append(m.logMonoTime / 1e6) - if len(ts[s]) > 2: d = np.diff(ts[s]) print(f"{s:25} {np.mean(d):7.2f} {np.std(d):7.2f} {np.max(d):7.2f} {np.min(d):7.2f}") - time.sleep(1) + print("="*5, datetime.timedelta(seconds=time.monotonic()-st), "="*5) From 6688d7b91c2ee6fad93d292edc0661a4522e9b10 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 10 Jun 2024 02:04:10 +0800 Subject: [PATCH 178/220] cabana: fix potential dangling pointer Issue (#32672) Fix Potential Dangling Pointer Issue --- tools/cabana/videowidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index cd412f727..7fca45c39 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -151,7 +151,7 @@ QWidget *VideoWidget::createCameraWidget() { setMaximumTime(can->totalSeconds()); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->currentSecond()); }); QObject::connect(slider, &Slider::updateMaximumTime, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection); - QObject::connect(can, &AbstractStream::eventsMerged, [this]() { slider->update(); }); + QObject::connect(can, &AbstractStream::eventsMerged, this, [this]() { slider->update(); }); QObject::connect(static_cast(can), &ReplayStream::qLogLoaded, slider, &Slider::parseQLog); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(cam_widget, &CameraWidget::vipcAvailableStreamsUpdated, this, &VideoWidget::vipcAvailableStreamsUpdated); From 3f84fe3557099ba74895241e8f4059b1001cd6ec Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 10 Jun 2024 02:04:21 +0800 Subject: [PATCH 179/220] replay: add stop() function (#32673) add stop() func --- tools/cabana/streams/replaystream.cc | 4 +++- tools/replay/replay.cc | 6 +++++- tools/replay/replay.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index b1768fcdc..5fda6b048 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -65,7 +65,9 @@ void ReplayStream::start() { } void ReplayStream::stop() { - replay.reset(nullptr); + if (replay) { + replay->stop(); + } } bool ReplayStream::eventFilter(const Event *event) { diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index f477e327e..861643718 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -46,11 +46,15 @@ Replay::Replay(QString route, QStringList allow, QStringList block, SubMaster *s } Replay::~Replay() { + stop(); +} + +void Replay::stop() { if (!stream_thread_ && segments_.empty()) return; rInfo("shutdown: in progress..."); if (stream_thread_ != nullptr) { - exit_ =true; + exit_ = true; paused_ = true; stream_cv_.notify_one(); stream_thread_->quit(); diff --git a/tools/replay/replay.h b/tools/replay/replay.h index e3f321e1d..4adbc14df 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -54,6 +54,7 @@ public: ~Replay(); bool load(); void start(int seconds = 0); + void stop(); void pause(bool pause); void seekToFlag(FindFlag flag); void seekTo(double seconds, bool relative); From 2cfb4df82c973fd93bc6750227e5628f1eb9bf2d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 9 Jun 2024 11:18:47 -0700 Subject: [PATCH 180/220] bump version to 0.9.8 --- RELEASES.md | 4 ++++ common/version.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 31fdd1561..aa0ab182e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,7 @@ +Version 0.9.8 (2024-XX-XX) +======================== +* Always on driver monitoring toggle + Version 0.9.7 (2024-06-11) ======================== * New driving model diff --git a/common/version.h b/common/version.h index 177882e31..1f651fb39 100644 --- a/common/version.h +++ b/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.9.7" +#define COMMA_VERSION "0.9.8" From da1cb2276bf28ee906e61a717da2e2699bdba34d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 9 Jun 2024 11:51:43 -0700 Subject: [PATCH 181/220] tici: improve power save test (#32674) * tici: improve power save test * Update system/hardware/tici/tests/test_hardware.py --- system/hardware/tici/tests/test_hardware.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/system/hardware/tici/tests/test_hardware.py b/system/hardware/tici/tests/test_hardware.py index 30eed7e0d..75f53e7cd 100644 --- a/system/hardware/tici/tests/test_hardware.py +++ b/system/hardware/tici/tests/test_hardware.py @@ -11,12 +11,16 @@ HARDWARE = Tici() class TestHardware: def test_power_save_time(self): - ts = [] + ts = {True: [], False: []} for _ in range(5): for on in (True, False): st = time.monotonic() HARDWARE.set_power_save(on) - ts.append(time.monotonic() - st) + ts[on].append(time.monotonic() - st) - assert 0.1 < np.mean(ts) < 0.25 - assert max(ts) < 0.3 + # disabling power save is the main time-critical one + assert 0.1 < np.mean(ts[False]) < 0.15 + assert max(ts[False]) < 0.2 + + assert 0.1 < np.mean(ts[True]) < 0.35 + assert max(ts[True]) < 0.4 From 43a97c590723f61cf049cd95f2edd9aea8f2c346 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 9 Jun 2024 12:02:55 -0700 Subject: [PATCH 182/220] CI: move build_release to a namespace runner (#32675) --- .github/workflows/selfdrive_tests.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 0ccf1844d..417fe2044 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -26,7 +26,9 @@ env: jobs: build_release: name: build release - runs-on: ubuntu-latest + runs-on: ${{ ((github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }} env: STRIPPED_DIR: /tmp/releasepilot steps: From b573a4cc48e4508a37f01a800b09b1fa8895d367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sun, 9 Jun 2024 14:49:20 -0700 Subject: [PATCH 183/220] Sim: don't need nvidia docker anymore (#32676) Dont need nvidia docker anymore --- tools/sim/Dockerfile.sim_nvidia | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 tools/sim/Dockerfile.sim_nvidia diff --git a/tools/sim/Dockerfile.sim_nvidia b/tools/sim/Dockerfile.sim_nvidia deleted file mode 100644 index 5e5dd263d..000000000 --- a/tools/sim/Dockerfile.sim_nvidia +++ /dev/null @@ -1,21 +0,0 @@ -FROM ubuntu:20.04 - -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - apt-utils \ - sudo \ - ssh \ - curl \ - ca-certificates \ - git \ - git-lfs && \ - rm -rf /var/lib/apt/lists/* - -RUN curl -fsSL https://get.docker.com -o get-docker.sh && \ - sudo sh get-docker.sh && \ - distribution=$(. /etc/os-release;echo $ID$VERSION_ID) && \ - curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - && \ - curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list && \ - sudo apt-get update && \ - sudo apt-get install -y nvidia-docker2 From e70dc90a452e7c045d9a207f3680d846406ef789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sun, 9 Jun 2024 17:44:34 -0700 Subject: [PATCH 184/220] Restructure msgq (#32652) * Update ref * Compiles * compiles * Refactor rest of libs * import all * small fiex * cleanup import * Need msgq simlink too * Add to openpilot docker too * try repo * Updates * Fix lint * fix docs * Try blank slate * Revert "Try blank slate" This reverts commit f078ce04acacfe115c19e23e86038b01e2b84a6d. * Maybe scons needs this to clear cache * fix tests * Disable test for now * Update SConstruct Co-authored-by: Adeeb Shihadeh * Fix whitespace * Write skip normal * small fixes * add test path * Revert repo * linting * whitespace * Bump msgq --------- Co-authored-by: Adeeb Shihadeh --- .gitmodules | 2 +- Dockerfile.openpilot | 1 + SConstruct | 8 +- cereal/SConscript | 6 +- cereal/messaging/__init__.py | 60 +----- cereal/messaging/bridge.cc | 4 +- cereal/messaging/messaging.h | 2 +- cereal/messaging/tests/test_fake.py | 193 ------------------ cereal/messaging/tests/test_messaging.py | 54 +---- cereal/messaging/tests/test_poller.py | 142 ------------- docs/c_docs.rst | 4 +- msgq | 2 +- msgq_repo | 1 + pyproject.toml | 3 +- .../controls/lib/lateral_mpc_lib/SConscript | 4 +- .../lib/longitudinal_mpc_lib/SConscript | 4 +- selfdrive/locationd/SConscript | 4 +- selfdrive/navd/SConscript | 6 +- selfdrive/pandad/SConscript | 4 +- selfdrive/ui/SConscript | 12 +- system/camerad/SConscript | 4 +- system/logcatd/SConscript | 4 +- system/loggerd/SConscript | 9 +- system/proclogd/SConscript | 4 +- system/sensord/SConscript | 4 +- system/ubloxd/SConscript | 4 +- system/webrtc/tests/test_stream_session.py | 4 +- system/webrtc/tests/test_webrtcd.py | 1 + tools/cabana/SConscript | 4 +- tools/replay/SConscript | 6 +- tools/sim/Dockerfile.sim | 39 ++++ 31 files changed, 103 insertions(+), 496 deletions(-) delete mode 100644 cereal/messaging/tests/test_fake.py delete mode 100644 cereal/messaging/tests/test_poller.py mode change 160000 => 120000 msgq create mode 160000 msgq_repo create mode 100644 tools/sim/Dockerfile.sim diff --git a/.gitmodules b/.gitmodules index 4952fcbea..e33902db5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,7 +5,7 @@ path = opendbc url = ../../commaai/opendbc.git [submodule "msgq"] - path = msgq + path = msgq_repo url = ../../commaai/msgq.git [submodule "rednose_repo"] path = rednose_repo diff --git a/Dockerfile.openpilot b/Dockerfile.openpilot index 9aa1aa8b7..5d8f958c4 100644 --- a/Dockerfile.openpilot +++ b/Dockerfile.openpilot @@ -20,6 +20,7 @@ COPY ./release ${OPENPILOT_PATH}/release COPY ./common ${OPENPILOT_PATH}/common COPY ./opendbc ${OPENPILOT_PATH}/opendbc COPY ./cereal ${OPENPILOT_PATH}/cereal +COPY ./msgq_repo ${OPENPILOT_PATH}/msgq_repo COPY ./msgq ${OPENPILOT_PATH}/msgq COPY ./panda ${OPENPILOT_PATH}/panda COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive diff --git a/SConstruct b/SConstruct index e827d6641..1b6b9464c 100644 --- a/SConstruct +++ b/SConstruct @@ -358,9 +358,13 @@ gpucommon = [_gpucommon] Export('common', 'gpucommon') -# Build cereal and messaging -SConscript(['msgq/SConscript']) +# Build messaging (cereal + msgq + socketmaster + their dependencies) +SConscript(['msgq_repo/SConscript']) SConscript(['cereal/SConscript']) +Import('socketmaster', 'msgq') +messaging = [socketmaster, msgq, 'zmq', 'capnp', 'kj',] +Export('messaging') + # Build other submodules SConscript([ diff --git a/cereal/SConscript b/cereal/SConscript index 5a71abbb8..be5f161de 100644 --- a/cereal/SConscript +++ b/cereal/SConscript @@ -1,10 +1,10 @@ -Import('env', 'envCython', 'arch', 'common', 'messaging') +Import('env', 'envCython', 'arch', 'common', 'msgq') import shutil cereal_dir = Dir('.') gen_dir = Dir('gen') -other_dir = Dir('#msgq/messaging') +other_dir = Dir('#msgq') # Build cereal schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp'] @@ -22,7 +22,7 @@ env.SharedLibrary('cereal_shared', cereal_objects) # Build messaging services_h = env.Command(['services.h'], ['services.py'], 'python3 ' + cereal_dir.path + '/services.py > $TARGET') -env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[messaging, 'zmq', common]) +env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[msgq, 'zmq', common]) socketmaster = env.SharedObject(['messaging/socketmaster.cc']) diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py index d8115d181..4ba55cf7b 100644 --- a/cereal/messaging/__init__.py +++ b/cereal/messaging/__init__.py @@ -1,7 +1,8 @@ # must be built with scons -from msgq.messaging.messaging_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \ +from msgq.ipc_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \ set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event -from msgq.messaging.messaging_pyx import MultiplePublishersError, MessagingError +from msgq.ipc_pyx import MultiplePublishersError, IpcError +from msgq import fake_event_handle, pub_sock, sub_sock, drain_sock_raw, context import os import capnp @@ -13,27 +14,8 @@ from collections import deque from cereal import log from cereal.services import SERVICE_LIST -assert MultiplePublishersError -assert MessagingError -assert toggle_fake_events -assert set_fake_prefix -assert get_fake_prefix -assert delete_fake_prefix -assert wait_for_one_event - NO_TRAVERSAL_LIMIT = 2**64-1 -context = Context() - - -def fake_event_handle(endpoint: str, identifier: Optional[str] = None, override: bool = True, enable: bool = False) -> SocketEventHandle: - identifier = identifier or get_fake_prefix() - handle = SocketEventHandle(endpoint, identifier, override) - if override: - handle.enabled = enable - - return handle - def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader: with log.Event.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg: @@ -55,42 +37,6 @@ def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> return dat -def pub_sock(endpoint: str) -> PubSocket: - sock = PubSocket() - sock.connect(context, endpoint) - return sock - - -def sub_sock(endpoint: str, poller: Optional[Poller] = None, addr: str = "127.0.0.1", - conflate: bool = False, timeout: Optional[int] = None) -> SubSocket: - sock = SubSocket() - sock.connect(context, endpoint, addr.encode('utf8'), conflate) - - if timeout is not None: - sock.setTimeout(timeout) - - if poller is not None: - poller.registerSocket(sock) - return sock - - -def drain_sock_raw(sock: SubSocket, wait_for_one: bool = False) -> List[bytes]: - """Receive all message currently available on the queue""" - ret: List[bytes] = [] - while 1: - if wait_for_one and len(ret) == 0: - dat = sock.receive() - else: - dat = sock.receive(non_blocking=True) - - if dat is None: - break - - ret.append(dat) - - return ret - - def drain_sock(sock: SubSocket, wait_for_one: bool = False) -> List[capnp.lib.capnp._DynamicStructReader]: """Receive all message currently available on the queue""" msgs = drain_sock_raw(sock, wait_for_one=wait_for_one) diff --git a/cereal/messaging/bridge.cc b/cereal/messaging/bridge.cc index b16548314..8619c1e22 100644 --- a/cereal/messaging/bridge.cc +++ b/cereal/messaging/bridge.cc @@ -8,8 +8,8 @@ typedef void (*sighandler_t)(int sig); #include "cereal/services.h" -#include "msgq/messaging/impl_msgq.h" -#include "msgq/messaging/impl_zmq.h" +#include "msgq/impl_msgq.h" +#include "msgq/impl_zmq.h" std::atomic do_exit = false; static void set_do_exit(int sig) { diff --git a/cereal/messaging/messaging.h b/cereal/messaging/messaging.h index b0f8b5535..f3850130e 100644 --- a/cereal/messaging/messaging.h +++ b/cereal/messaging/messaging.h @@ -10,7 +10,7 @@ #include #include "cereal/gen/cpp/log.capnp.h" -#include "msgq/messaging/messaging.h" +#include "msgq/ipc.h" #ifdef __APPLE__ #define CLOCK_BOOTTIME CLOCK_MONOTONIC diff --git a/cereal/messaging/tests/test_fake.py b/cereal/messaging/tests/test_fake.py deleted file mode 100644 index 1d3521745..000000000 --- a/cereal/messaging/tests/test_fake.py +++ /dev/null @@ -1,193 +0,0 @@ -import os -import unittest -import multiprocessing -import platform -from parameterized import parameterized_class -from typing import Optional - -import cereal.messaging as messaging - -WAIT_TIMEOUT = 5 - - -@unittest.skipIf(platform.system() == "Darwin", "Events not supported on macOS") -class TestEvents(unittest.TestCase): - - def test_mutation(self): - handle = messaging.fake_event_handle("carState") - event = handle.recv_called_event - - self.assertFalse(event.peek()) - event.set() - self.assertTrue(event.peek()) - event.clear() - self.assertFalse(event.peek()) - - del event - - def test_wait(self): - handle = messaging.fake_event_handle("carState") - event = handle.recv_called_event - - event.set() - try: - event.wait(WAIT_TIMEOUT) - self.assertTrue(event.peek()) - except RuntimeError: - self.fail("event.wait() timed out") - - def test_wait_multiprocess(self): - handle = messaging.fake_event_handle("carState") - event = handle.recv_called_event - - def set_event_run(): - event.set() - - try: - p = multiprocessing.Process(target=set_event_run) - p.start() - event.wait(WAIT_TIMEOUT) - self.assertTrue(event.peek()) - except RuntimeError: - self.fail("event.wait() timed out") - - p.kill() - - def test_wait_zero_timeout(self): - handle = messaging.fake_event_handle("carState") - event = handle.recv_called_event - - try: - event.wait(0) - self.fail("event.wait() did not time out") - except RuntimeError: - self.assertFalse(event.peek()) - - -@unittest.skipIf(platform.system() == "Darwin", "FakeSockets not supported on macOS") -@unittest.skipIf("ZMQ" in os.environ, "FakeSockets not supported on ZMQ") -@parameterized_class([{"prefix": None}, {"prefix": "test"}]) -class TestFakeSockets(unittest.TestCase): - prefix: Optional[str] = None - - def setUp(self): - messaging.toggle_fake_events(True) - if self.prefix is not None: - messaging.set_fake_prefix(self.prefix) - else: - messaging.delete_fake_prefix() - - def tearDown(self): - messaging.toggle_fake_events(False) - messaging.delete_fake_prefix() - - def test_event_handle_init(self): - handle = messaging.fake_event_handle("controlsState", override=True) - - self.assertFalse(handle.enabled) - self.assertGreaterEqual(handle.recv_called_event.fd, 0) - self.assertGreaterEqual(handle.recv_ready_event.fd, 0) - - def test_non_managed_socket_state(self): - # non managed socket should have zero state - _ = messaging.pub_sock("ubloxGnss") - - handle = messaging.fake_event_handle("ubloxGnss", override=False) - - self.assertFalse(handle.enabled) - self.assertEqual(handle.recv_called_event.fd, 0) - self.assertEqual(handle.recv_ready_event.fd, 0) - - def test_managed_socket_state(self): - # managed socket should not change anything about the state - handle = messaging.fake_event_handle("ubloxGnss") - handle.enabled = True - - expected_enabled = handle.enabled - expected_recv_called_fd = handle.recv_called_event.fd - expected_recv_ready_fd = handle.recv_ready_event.fd - - _ = messaging.pub_sock("ubloxGnss") - - self.assertEqual(handle.enabled, expected_enabled) - self.assertEqual(handle.recv_called_event.fd, expected_recv_called_fd) - self.assertEqual(handle.recv_ready_event.fd, expected_recv_ready_fd) - - def test_sockets_enable_disable(self): - carState_handle = messaging.fake_event_handle("ubloxGnss", enable=True) - recv_called = carState_handle.recv_called_event - recv_ready = carState_handle.recv_ready_event - - pub_sock = messaging.pub_sock("ubloxGnss") - sub_sock = messaging.sub_sock("ubloxGnss") - - try: - carState_handle.enabled = True - recv_ready.set() - pub_sock.send(b"test") - _ = sub_sock.receive() - self.assertTrue(recv_called.peek()) - recv_called.clear() - - carState_handle.enabled = False - recv_ready.set() - pub_sock.send(b"test") - _ = sub_sock.receive() - self.assertFalse(recv_called.peek()) - except RuntimeError: - self.fail("event.wait() timed out") - - def test_synced_pub_sub(self): - def daemon_repub_process_run(): - pub_sock = messaging.pub_sock("ubloxGnss") - sub_sock = messaging.sub_sock("carState") - - frame = -1 - while True: - frame += 1 - msg = sub_sock.receive(non_blocking=True) - if msg is None: - print("none received") - continue - - bts = frame.to_bytes(8, 'little') - pub_sock.send(bts) - - carState_handle = messaging.fake_event_handle("carState", enable=True) - recv_called = carState_handle.recv_called_event - recv_ready = carState_handle.recv_ready_event - - p = multiprocessing.Process(target=daemon_repub_process_run) - p.start() - - pub_sock = messaging.pub_sock("carState") - sub_sock = messaging.sub_sock("ubloxGnss") - - try: - for i in range(10): - recv_called.wait(WAIT_TIMEOUT) - recv_called.clear() - - if i == 0: - sub_sock.receive(non_blocking=True) - - bts = i.to_bytes(8, 'little') - pub_sock.send(bts) - - recv_ready.set() - recv_called.wait(WAIT_TIMEOUT) - - msg = sub_sock.receive(non_blocking=True) - self.assertIsNotNone(msg) - self.assertEqual(len(msg), 8) - - frame = int.from_bytes(msg, 'little') - self.assertEqual(frame, i) - except RuntimeError: - self.fail("event.wait() timed out") - finally: - p.kill() - - -if __name__ == "__main__": - unittest.main() diff --git a/cereal/messaging/tests/test_messaging.py b/cereal/messaging/tests/test_messaging.py index 381cec03f..429c2d3c5 100755 --- a/cereal/messaging/tests/test_messaging.py +++ b/cereal/messaging/tests/test_messaging.py @@ -34,6 +34,7 @@ def zmq_expected_failure(func): else: return func + # TODO: this should take any capnp struct and returrn a msg with random populated data def random_carstate(): fields = ["vEgo", "aEgo", "gas", "steeringAngleDeg"] @@ -56,61 +57,8 @@ def delayed_send(delay, sock, dat): sock.send(dat) threading.Timer(delay, send_func).start() -class TestPubSubSockets(unittest.TestCase): - - def setUp(self): - # ZMQ pub socket takes too long to die - # sleep to prevent multiple publishers error between tests - zmq_sleep() - - def test_pub_sub(self): - sock = random_sock() - pub_sock = messaging.pub_sock(sock) - sub_sock = messaging.sub_sock(sock, conflate=False, timeout=None) - zmq_sleep(3) - - for _ in range(1000): - msg = random_bytes() - pub_sock.send(msg) - recvd = sub_sock.receive() - self.assertEqual(msg, recvd) - - def test_conflate(self): - sock = random_sock() - pub_sock = messaging.pub_sock(sock) - for conflate in [True, False]: - for _ in range(10): - num_msgs = random.randint(3, 10) - sub_sock = messaging.sub_sock(sock, conflate=conflate, timeout=None) - zmq_sleep() - - sent_msgs = [] - for __ in range(num_msgs): - msg = random_bytes() - pub_sock.send(msg) - sent_msgs.append(msg) - time.sleep(0.1) - recvd_msgs = messaging.drain_sock_raw(sub_sock) - if conflate: - self.assertEqual(len(recvd_msgs), 1) - else: - # TODO: compare actual data - self.assertEqual(len(recvd_msgs), len(sent_msgs)) - - def test_receive_timeout(self): - sock = random_sock() - for _ in range(10): - timeout = random.randrange(200) - sub_sock = messaging.sub_sock(sock, timeout=timeout) - zmq_sleep() - - start_time = time.monotonic() - recvd = sub_sock.receive() - self.assertLess(time.monotonic() - start_time, 0.2) - assert recvd is None class TestMessaging(unittest.TestCase): - def setUp(self): # TODO: ZMQ tests are too slow; all sleeps will need to be # replaced with logic to block on the necessary condition diff --git a/cereal/messaging/tests/test_poller.py b/cereal/messaging/tests/test_poller.py deleted file mode 100644 index bcff5e40c..000000000 --- a/cereal/messaging/tests/test_poller.py +++ /dev/null @@ -1,142 +0,0 @@ -import unittest -import time -import cereal.messaging as messaging - -import concurrent.futures - - -def poller(): - context = messaging.Context() - - p = messaging.Poller() - - sub = messaging.SubSocket() - sub.connect(context, 'controlsState') - p.registerSocket(sub) - - socks = p.poll(10000) - r = [s.receive(non_blocking=True) for s in socks] - - return r - - -class TestPoller(unittest.TestCase): - def test_poll_once(self): - context = messaging.Context() - - pub = messaging.PubSocket() - pub.connect(context, 'controlsState') - - with concurrent.futures.ThreadPoolExecutor() as e: - poll = e.submit(poller) - - time.sleep(0.1) # Slow joiner syndrome - - # Send message - pub.send(b"a") - - # Wait for poll result - result = poll.result() - - del pub - context.term() - - self.assertEqual(result, [b"a"]) - - def test_poll_and_create_many_subscribers(self): - context = messaging.Context() - - pub = messaging.PubSocket() - pub.connect(context, 'controlsState') - - with concurrent.futures.ThreadPoolExecutor() as e: - poll = e.submit(poller) - - time.sleep(0.1) # Slow joiner syndrome - c = messaging.Context() - for _ in range(10): - messaging.SubSocket().connect(c, 'controlsState') - - time.sleep(0.1) - - # Send message - pub.send(b"a") - - # Wait for poll result - result = poll.result() - - del pub - context.term() - - self.assertEqual(result, [b"a"]) - - def test_multiple_publishers_exception(self): - context = messaging.Context() - - with self.assertRaises(messaging.MultiplePublishersError): - pub1 = messaging.PubSocket() - pub1.connect(context, 'controlsState') - - pub2 = messaging.PubSocket() - pub2.connect(context, 'controlsState') - - pub1.send(b"a") - - del pub1 - del pub2 - context.term() - - def test_multiple_messages(self): - context = messaging.Context() - - pub = messaging.PubSocket() - pub.connect(context, 'controlsState') - - sub = messaging.SubSocket() - sub.connect(context, 'controlsState') - - time.sleep(0.1) # Slow joiner - - for i in range(1, 100): - pub.send(b'a'*i) - - msg_seen = False - i = 1 - while True: - r = sub.receive(non_blocking=True) - - if r is not None: - self.assertEqual(b'a'*i, r) - - msg_seen = True - i += 1 - - if r is None and msg_seen: # ZMQ sometimes receives nothing on the first receive - break - - del pub - del sub - context.term() - - def test_conflate(self): - context = messaging.Context() - - pub = messaging.PubSocket() - pub.connect(context, 'controlsState') - - sub = messaging.SubSocket() - sub.connect(context, 'controlsState', conflate=True) - - time.sleep(0.1) # Slow joiner - pub.send(b'a') - pub.send(b'b') - - self.assertEqual(b'b', sub.receive()) - - del pub - del sub - context.term() - - -if __name__ == "__main__": - unittest.main() diff --git a/docs/c_docs.rst b/docs/c_docs.rst index 1027bac1b..3b89fe987 100644 --- a/docs/c_docs.rst +++ b/docs/c_docs.rst @@ -14,12 +14,12 @@ cereal messaging ^^^^^^^^^ .. autodoxygenindex:: - :project: msgq_messaging + :project: msgq_repo_msgq visionipc ^^^^^^^^^ .. autodoxygenindex:: - :project: msgq_visionipc + :project: msgq_repo_msgq_visionipc selfdrive diff --git a/msgq b/msgq deleted file mode 160000 index 615aea9b5..000000000 --- a/msgq +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 615aea9b5519d2a3631fce4753bed29287fc4f9b diff --git a/msgq b/msgq new file mode 120000 index 000000000..df09146f6 --- /dev/null +++ b/msgq @@ -0,0 +1 @@ +msgq_repo/msgq \ No newline at end of file diff --git a/msgq_repo b/msgq_repo new file mode 160000 index 000000000..381fc3d9d --- /dev/null +++ b/msgq_repo @@ -0,0 +1 @@ +Subproject commit 381fc3d9dfe7d2ff40a075ff8c1f980ae2a62d19 diff --git a/pyproject.toml b/pyproject.toml index 4ac01f658..6bc567921 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,8 @@ testpaths = [ "system/webrtc", "tools/lib/tests", "tools/replay", - "tools/cabana" + "tools/cabana", + "cereal/messaging/tests", ] [tool.mypy] diff --git a/selfdrive/controls/lib/lateral_mpc_lib/SConscript b/selfdrive/controls/lib/lateral_mpc_lib/SConscript index b6603e69f..630f87334 100644 --- a/selfdrive/controls/lib/lateral_mpc_lib/SConscript +++ b/selfdrive/controls/lib/lateral_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'messaging_python', 'common_python', 'opendbc_python') +Import('env', 'envCython', 'arch', 'messaging', 'msgq_python', 'common_python', 'opendbc_python') gen = "c_generated_code" @@ -60,7 +60,7 @@ lenv.Clean(generated_files, Dir(gen)) generated_lat = lenv.Command(generated_files, source_list, f"cd {Dir('.').abspath} && python3 lat_mpc.py") -lenv.Depends(generated_lat, [messaging_python, common_python, opendbc_python]) +lenv.Depends(generated_lat, [msgq_python, common_python, opendbc_python]) lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index c00d5cb5a..852631c5a 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'messaging_python', 'common_python', 'opendbc_python') +Import('env', 'envCython', 'arch', 'messaging', 'msgq_python', 'common_python', 'opendbc_python') gen = "c_generated_code" @@ -66,7 +66,7 @@ lenv.Clean(generated_files, Dir(gen)) generated_long = lenv.Command(generated_files, source_list, f"cd {Dir('.').abspath} && python3 long_mpc.py") -lenv.Depends(generated_long, [messaging_python, common_python, opendbc_python]) +lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python]) lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") diff --git a/selfdrive/locationd/SConscript b/selfdrive/locationd/SConscript index d3cfeb2c3..27cd4d5b4 100644 --- a/selfdrive/locationd/SConscript +++ b/selfdrive/locationd/SConscript @@ -1,6 +1,6 @@ -Import('env', 'arch', 'common', 'cereal', 'messaging', 'rednose', 'transformations', 'socketmaster') +Import('env', 'arch', 'common', 'messaging', 'rednose', 'transformations') -loc_libs = [cereal, socketmaster, messaging, 'zmq', common, 'capnp', 'kj', 'pthread', 'dl'] +loc_libs = [messaging, common, 'pthread', 'dl'] # build ekf models rednose_gen_dir = 'models/generated' diff --git a/selfdrive/navd/SConscript b/selfdrive/navd/SConscript index 7f5d948b7..295e8127d 100644 --- a/selfdrive/navd/SConscript +++ b/selfdrive/navd/SConscript @@ -1,8 +1,8 @@ -Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'transformations', 'socketmaster') +Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations') map_env = qt_env.Clone() -libs = ['qt_widgets', 'qt_util', 'QMapLibre', common, socketmaster, messaging, cereal, visionipc, transformations, - 'zmq', 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread', 'json11'] + map_env["LIBS"] +libs = ['qt_widgets', 'qt_util', 'QMapLibre', common, messaging, visionipc, transformations, + 'm', 'OpenCL', 'ssl', 'crypto', 'pthread', 'json11'] + map_env["LIBS"] if arch == 'larch64': libs.append(':libEGL_mesa.so.0') diff --git a/selfdrive/pandad/SConscript b/selfdrive/pandad/SConscript index 48187c432..63a2c1e65 100644 --- a/selfdrive/pandad/SConscript +++ b/selfdrive/pandad/SConscript @@ -1,6 +1,6 @@ -Import('env', 'envCython', 'common', 'cereal', 'messaging', 'socketmaster') +Import('env', 'envCython', 'common', 'messaging') -libs = ['usb-1.0', common, cereal, messaging, socketmaster, 'pthread', 'zmq', 'capnp', 'kj'] +libs = ['usb-1.0', common, messaging, 'pthread'] panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc']) env.Program('pandad', ['main.cc', 'pandad.cc'], LIBS=[panda] + libs) diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 5bd33f35f..f59da1bce 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,10 +1,9 @@ import os import json -Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', - 'cereal', 'transformations', 'socketmaster') +Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations') -base_libs = [common, socketmaster, messaging, cereal, visionipc, transformations, 'zmq', - 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] +base_libs = [common, messaging, visionipc, transformations, + 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] if arch == 'larch64': base_libs.append('EGL') @@ -126,5 +125,6 @@ if GetOption('extras') and arch != "Darwin": assert f[0].get_size() < 350*1e3 # build watch3 -if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): - qt_env.Program("watch3", ["watch3.cc"], LIBS=qt_libs + ['common', 'json11', 'zmq', 'visionipc', 'messaging']) +#FIXME +#if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): +# qt_env.Program("watch3", ["watch3.cc"], LIBS=qt_libs + ['common', 'json11', 'zmq', 'visionipc', 'msgq']) diff --git a/system/camerad/SConscript b/system/camerad/SConscript index 67530c57e..511664c27 100644 --- a/system/camerad/SConscript +++ b/system/camerad/SConscript @@ -1,6 +1,6 @@ -Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc', 'socketmaster') +Import('env', 'arch', 'messaging', 'common', 'gpucommon', 'visionipc') -libs = ['m', 'pthread', common, 'jpeg', 'OpenCL', 'yuv', cereal, socketmaster, messaging, 'zmq', 'capnp', 'kj', visionipc, gpucommon, 'atomic'] +libs = ['m', 'pthread', common, 'jpeg', 'OpenCL', 'yuv', messaging, visionipc, gpucommon, 'atomic'] camera_obj = env.Object(['cameras/camera_qcom2.cc', 'cameras/camera_common.cc', 'cameras/camera_util.cc', 'sensors/ar0231.cc', 'sensors/ox03c10.cc', 'sensors/os04c10.cc']) diff --git a/system/logcatd/SConscript b/system/logcatd/SConscript index cd34e3956..ac2a79a1f 100644 --- a/system/logcatd/SConscript +++ b/system/logcatd/SConscript @@ -1,3 +1,3 @@ -Import('env', 'cereal', 'messaging', 'common', 'socketmaster') +Import('env', 'messaging', 'common') -env.Program('logcatd', 'logcatd_systemd.cc', LIBS=[cereal, socketmaster, messaging, common, 'zmq', 'capnp', 'kj', 'systemd', 'json11']) +env.Program('logcatd', 'logcatd_systemd.cc', LIBS=[messaging, common, 'systemd', 'json11']) diff --git a/system/loggerd/SConscript b/system/loggerd/SConscript index bcf941655..196d18476 100644 --- a/system/loggerd/SConscript +++ b/system/loggerd/SConscript @@ -1,9 +1,8 @@ -Import('env', 'arch', 'cereal', 'messaging', 'common', 'visionipc', 'socketmaster') +Import('env', 'arch', 'messaging', 'common', 'visionipc') -libs = [common, cereal, socketmaster, messaging, visionipc, - 'zmq', 'capnp', 'kj', 'z', - 'avformat', 'avcodec', 'swscale', 'avutil', - 'yuv', 'OpenCL', 'pthread'] +libs = [common, messaging, visionipc, + 'z', 'avformat', 'avcodec', 'swscale', + 'avutil', 'yuv', 'OpenCL', 'pthread'] src = ['logger.cc', 'video_writer.cc', 'encoder/encoder.cc', 'encoder/v4l_encoder.cc'] if arch != "larch64": diff --git a/system/proclogd/SConscript b/system/proclogd/SConscript index 05cdb73c6..9ca8e7354 100644 --- a/system/proclogd/SConscript +++ b/system/proclogd/SConscript @@ -1,5 +1,5 @@ -Import('env', 'cereal', 'messaging', 'common', 'socketmaster') -libs = [cereal, socketmaster, messaging, 'pthread', 'zmq', 'capnp', 'kj', 'common', 'zmq', 'json11'] +Import('env', 'messaging', 'common') +libs = [messaging, 'pthread', 'common', 'zmq', 'json11'] env.Program('proclogd', ['main.cc', 'proclog.cc'], LIBS=libs) if GetOption('extras'): diff --git a/system/sensord/SConscript b/system/sensord/SConscript index 1808a3154..e2dfb522c 100644 --- a/system/sensord/SConscript +++ b/system/sensord/SConscript @@ -1,4 +1,4 @@ -Import('env', 'arch', 'common', 'cereal', 'messaging', 'socketmaster') +Import('env', 'arch', 'common', 'messaging') sensors = [ 'sensors/i2c_sensor.cc', @@ -11,7 +11,7 @@ sensors = [ 'sensors/lsm6ds3_temp.cc', 'sensors/mmc5603nj_magn.cc', ] -libs = [common, socketmaster, cereal, messaging, 'capnp', 'zmq', 'kj', 'pthread'] +libs = [common, messaging, 'pthread'] if arch == "larch64": libs.append('i2c') env.Program('sensord', ['sensors_qcom2.cc'] + sensors, LIBS=libs) diff --git a/system/ubloxd/SConscript b/system/ubloxd/SConscript index d6bea5723..ce09e235e 100644 --- a/system/ubloxd/SConscript +++ b/system/ubloxd/SConscript @@ -1,6 +1,6 @@ -Import('env', 'common', 'cereal', 'messaging', 'socketmaster') +Import('env', 'common', 'messaging') -loc_libs = [cereal, messaging, socketmaster, 'zmq', common, 'capnp', 'kj', 'kaitai', 'pthread'] +loc_libs = [messaging, common, 'kaitai', 'pthread'] if GetOption('kaitai'): generated = Dir('generated').srcnode().abspath diff --git a/system/webrtc/tests/test_stream_session.py b/system/webrtc/tests/test_stream_session.py index fa22915db..bcc9d6492 100644 --- a/system/webrtc/tests/test_stream_session.py +++ b/system/webrtc/tests/test_stream_session.py @@ -8,7 +8,7 @@ from aiortc import RTCDataChannel from aiortc.mediastreams import VIDEO_CLOCK_RATE, VIDEO_TIME_BASE import capnp import pyaudio - +import pytest from cereal import messaging, log from openpilot.system.webrtc.webrtcd import CerealOutgoingMessageProxy, CerealIncomingMessageProxy @@ -68,6 +68,8 @@ class TestStreamSession: mocked_pubmaster.reset_mock() + # FIXME, hangs for some reason + @pytest.mark.skip("Hangs forever") def test_livestream_track(self, mocker): fake_msg = messaging.new_message("livestreamDriverEncodeData") diff --git a/system/webrtc/tests/test_webrtcd.py b/system/webrtc/tests/test_webrtcd.py index 309058fb7..d4b659a3a 100644 --- a/system/webrtc/tests/test_webrtcd.py +++ b/system/webrtc/tests/test_webrtcd.py @@ -61,3 +61,4 @@ class TestWebrtcdProc: assert mock_request.app["streams"].__setitem__.called, "Implementation changed, please update this test" _, session = mock_request.app["streams"].__setitem__.call_args.args await self.assertCompletesWithTimeout(session.post_run_cleanup()) + diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 4ce4c27a0..ba4a14245 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -1,7 +1,7 @@ -Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', 'cereal', 'widgets', 'socketmaster') +Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', 'cereal', 'widgets') base_frameworks = qt_env['FRAMEWORKS'] -base_libs = [common, messaging, cereal, visionipc, socketmaster, 'qt_util', 'zmq', 'capnp', 'kj', 'm', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] +base_libs = [common, messaging, cereal, visionipc, 'qt_util', 'm', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] if arch == "Darwin": base_frameworks.append('OpenCL') diff --git a/tools/replay/SConscript b/tools/replay/SConscript index 813f7808f..cf9d74a89 100644 --- a/tools/replay/SConscript +++ b/tools/replay/SConscript @@ -1,8 +1,8 @@ -Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'socketmaster') +Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal') base_frameworks = qt_env['FRAMEWORKS'] -base_libs = [common, socketmaster, messaging, cereal, visionipc, 'zmq', - 'capnp', 'kj', 'm', 'ssl', 'crypto', 'pthread', 'qt_util'] + qt_env["LIBS"] +base_libs = [common, messaging, cereal, visionipc, + 'm', 'ssl', 'crypto', 'pthread', 'qt_util'] + qt_env["LIBS"] if arch == "Darwin": base_frameworks.append('OpenCL') diff --git a/tools/sim/Dockerfile.sim b/tools/sim/Dockerfile.sim new file mode 100644 index 000000000..e0d38596c --- /dev/null +++ b/tools/sim/Dockerfile.sim @@ -0,0 +1,39 @@ +FROM ghcr.io/commaai/openpilot-base:latest + +RUN apt-get update && apt-get install -y --no-install-recommends \ + tmux \ + vim \ + && rm -rf /var/lib/apt/lists/* + +# get same tmux config used on NEOS for debugging +RUN cd $HOME && \ + curl -O https://raw.githubusercontent.com/commaai/eon-neos-builder/master/devices/eon/home/.tmux.conf + +ENV OPENPILOT_PATH /tmp/openpilot +ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} + +RUN mkdir -p ${OPENPILOT_PATH} +WORKDIR ${OPENPILOT_PATH} + +COPY SConstruct ${OPENPILOT_PATH} + +COPY ./openpilot ${OPENPILOT_PATH}/openpilot +COPY ./body ${OPENPILOT_PATH}/body +COPY ./third_party ${OPENPILOT_PATH}/third_party +COPY ./site_scons ${OPENPILOT_PATH}/site_scons +COPY ./rednose ${OPENPILOT_PATH}/rednose +COPY ./rednose_repo/site_scons ${OPENPILOT_PATH}/rednose_repo/site_scons +COPY ./common ${OPENPILOT_PATH}/common +COPY ./opendbc ${OPENPILOT_PATH}/opendbc +COPY ./cereal ${OPENPILOT_PATH}/cereal +COPY ./msgq_repo ${OPENPILOT_PATH}/msgq_repo +COPY ./msgq ${OPENPILOT_PATH}/msgq +COPY ./panda ${OPENPILOT_PATH}/panda +COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive +COPY ./system ${OPENPILOT_PATH}/system +COPY ./tools ${OPENPILOT_PATH}/tools +COPY ./release ${OPENPILOT_PATH}/release + +RUN --mount=type=bind,source=.ci_cache/scons_cache,target=/tmp/scons_cache,rw scons -j$(nproc) --cache-readonly + +RUN python -c "from openpilot.selfdrive.test.helpers import set_params_enabled; set_params_enabled()" From 19e0fa3094ca407f0c6023b0e26aebb7068db3fa Mon Sep 17 00:00:00 2001 From: Metalbird1997 <45519048+Metalbird1997@users.noreply.github.com> Date: Mon, 10 Jun 2024 09:22:34 +0200 Subject: [PATCH 185/220] Update fingerprints.py for 2024 MAN TGE (#32657) * Update fingerprints.py for 2024 MAN TGE * add TGE chassis codes * unsure about the others --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/volkswagen/fingerprints.py | 2 ++ selfdrive/car/volkswagen/values.py | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c79206f84..c0070f18f 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -186,7 +186,7 @@ A supported vehicle is one that just works when you install a comma device. All |Lincoln|Aviator 2020-23|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 Ford Q3 connector
    - 1 RJ45 cable (7 ft)
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Lincoln|Aviator Plug-in Hybrid 2020-23|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 Ford Q3 connector
    - 1 RJ45 cable (7 ft)
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || -|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || +|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Mazda|CX-5 2022-24|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 Mazda connector
    - 1 RJ45 cable (7 ft)
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 Mazda connector
    - 1 RJ45 cable (7 ft)
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
    Parts- 1 Nissan B connector
    - 1 RJ45 cable (7 ft)
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || diff --git a/selfdrive/car/volkswagen/fingerprints.py b/selfdrive/car/volkswagen/fingerprints.py index fdc375fc8..68f6d8f6a 100644 --- a/selfdrive/car/volkswagen/fingerprints.py +++ b/selfdrive/car/volkswagen/fingerprints.py @@ -119,6 +119,7 @@ FW_VERSIONS = { b'\xf1\x8704L906056BP\xf1\x894729', b'\xf1\x8704L906056EK\xf1\x896391', b'\xf1\x8705L906023BC\xf1\x892688', + b'\xf1\x8705L906023MH\xf1\x892588', ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655AL\xf1\x890505\xf1\x82\x0e1411001413001203151311031100', @@ -128,6 +129,7 @@ FW_VERSIONS = { (Ecu.eps, 0x712, None): [ b'\xf1\x872N0909143D\x00\xf1\x897010\xf1\x82\x05183AZ306A2', b'\xf1\x872N0909143E \xf1\x897021\xf1\x82\x05163AZ306A2', + b'\xf1\x872N0909143H \xf1\x897045\xf1\x82\x05263AZ309A2', b'\xf1\x872N0909144K \xf1\x897045\xf1\x82\x05233AZ810A2', ], (Ecu.fwdRadar, 0x757, None): [ diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 4d317176b..51346e072 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -247,11 +247,11 @@ class CAR(Platforms): VWCarDocs("Volkswagen Crafter 2017-23", video_link="https://youtu.be/4100gLeabmo"), VWCarDocs("Volkswagen e-Crafter 2018-23", video_link="https://youtu.be/4100gLeabmo"), VWCarDocs("Volkswagen Grand California 2019-23", video_link="https://youtu.be/4100gLeabmo"), - VWCarDocs("MAN TGE 2017-23", video_link="https://youtu.be/4100gLeabmo"), + VWCarDocs("MAN TGE 2017-24", video_link="https://youtu.be/4100gLeabmo"), VWCarDocs("MAN eTGE 2020-23", video_link="https://youtu.be/4100gLeabmo"), ], VolkswagenCarSpecs(mass=2100, wheelbase=3.64, minSteerSpeed=50 * CV.KPH_TO_MS), - chassis_codes={"SY", "SZ"}, + chassis_codes={"SY", "SZ", "UY", "UZ"}, wmis={WMI.VOLKSWAGEN_COMMERCIAL, WMI.MAN}, ) VOLKSWAGEN_GOLF_MK7 = VolkswagenMQBPlatformConfig( From 43ebf367ef37d949952301f2e240359b451a7043 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 10 Jun 2024 00:28:43 -0700 Subject: [PATCH 186/220] fix hypothesis warning (#32678) fix --- selfdrive/test/fuzzy_generation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/fuzzy_generation.py b/selfdrive/test/fuzzy_generation.py index 0dc2e44ee..94eb0dfaa 100644 --- a/selfdrive/test/fuzzy_generation.py +++ b/selfdrive/test/fuzzy_generation.py @@ -16,7 +16,7 @@ class FuzzyGenerator: def generate_native_type(self, field: str) -> st.SearchStrategy[bool | int | float | str | bytes]: value_func = self.native_type_map.get(field) - if value_func: + if value_func is not None: return value_func else: raise NotImplementedError(f'Invalid type: {field}') From 1b2bd205b81bb473bbe176b58250fe038963d1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 10 Jun 2024 13:18:47 -0700 Subject: [PATCH 187/220] MSGQ refactor: cleanup outstanding issues (#32685) * Rm sim dockerfile from bad merge * Add watch back * Fix watch3 compilation --- SConstruct | 4 +- .../controls/lib/lateral_mpc_lib/SConscript | 2 +- .../lib/longitudinal_mpc_lib/SConscript | 2 +- selfdrive/ui/SConscript | 5 +-- tools/sim/Dockerfile.sim | 39 ------------------- 5 files changed, 5 insertions(+), 47 deletions(-) delete mode 100644 tools/sim/Dockerfile.sim diff --git a/SConstruct b/SConstruct index 1b6b9464c..944d650d7 100644 --- a/SConstruct +++ b/SConstruct @@ -224,10 +224,8 @@ env = Environment( CFLAGS=["-std=gnu11"] + cflags, CXXFLAGS=["-std=c++1z"] + cxxflags, LIBPATH=libpath + [ - "#cereal", - "#msgq", + "#msgq_repo", "#third_party", - "#opendbc/can", "#selfdrive/pandad", "#common", "#rednose/helpers", diff --git a/selfdrive/controls/lib/lateral_mpc_lib/SConscript b/selfdrive/controls/lib/lateral_mpc_lib/SConscript index 630f87334..73242cb8f 100644 --- a/selfdrive/controls/lib/lateral_mpc_lib/SConscript +++ b/selfdrive/controls/lib/lateral_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'messaging', 'msgq_python', 'common_python', 'opendbc_python') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python') gen = "c_generated_code" diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index 852631c5a..592c1c2c2 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'messaging', 'msgq_python', 'common_python', 'opendbc_python') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python') gen = "c_generated_code" diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index f59da1bce..e181cb9ab 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -125,6 +125,5 @@ if GetOption('extras') and arch != "Darwin": assert f[0].get_size() < 350*1e3 # build watch3 -#FIXME -#if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): -# qt_env.Program("watch3", ["watch3.cc"], LIBS=qt_libs + ['common', 'json11', 'zmq', 'visionipc', 'msgq']) +if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): + qt_env.Program("watch3", ["watch3.cc"], LIBS=qt_libs + ['common', 'json11', 'msgq', 'visionipc']) diff --git a/tools/sim/Dockerfile.sim b/tools/sim/Dockerfile.sim deleted file mode 100644 index e0d38596c..000000000 --- a/tools/sim/Dockerfile.sim +++ /dev/null @@ -1,39 +0,0 @@ -FROM ghcr.io/commaai/openpilot-base:latest - -RUN apt-get update && apt-get install -y --no-install-recommends \ - tmux \ - vim \ - && rm -rf /var/lib/apt/lists/* - -# get same tmux config used on NEOS for debugging -RUN cd $HOME && \ - curl -O https://raw.githubusercontent.com/commaai/eon-neos-builder/master/devices/eon/home/.tmux.conf - -ENV OPENPILOT_PATH /tmp/openpilot -ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} - -RUN mkdir -p ${OPENPILOT_PATH} -WORKDIR ${OPENPILOT_PATH} - -COPY SConstruct ${OPENPILOT_PATH} - -COPY ./openpilot ${OPENPILOT_PATH}/openpilot -COPY ./body ${OPENPILOT_PATH}/body -COPY ./third_party ${OPENPILOT_PATH}/third_party -COPY ./site_scons ${OPENPILOT_PATH}/site_scons -COPY ./rednose ${OPENPILOT_PATH}/rednose -COPY ./rednose_repo/site_scons ${OPENPILOT_PATH}/rednose_repo/site_scons -COPY ./common ${OPENPILOT_PATH}/common -COPY ./opendbc ${OPENPILOT_PATH}/opendbc -COPY ./cereal ${OPENPILOT_PATH}/cereal -COPY ./msgq_repo ${OPENPILOT_PATH}/msgq_repo -COPY ./msgq ${OPENPILOT_PATH}/msgq -COPY ./panda ${OPENPILOT_PATH}/panda -COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive -COPY ./system ${OPENPILOT_PATH}/system -COPY ./tools ${OPENPILOT_PATH}/tools -COPY ./release ${OPENPILOT_PATH}/release - -RUN --mount=type=bind,source=.ci_cache/scons_cache,target=/tmp/scons_cache,rw scons -j$(nproc) --cache-readonly - -RUN python -c "from openpilot.selfdrive.test.helpers import set_params_enabled; set_params_enabled()" From a09ccd59cba03ac0824ad1b900116c364f93d591 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:37:39 -0700 Subject: [PATCH 188/220] [bot] Bump submodules (#32681) bump submodules Co-authored-by: Vehicle Researcher --- teleoprtc_repo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/teleoprtc_repo b/teleoprtc_repo index f2e5a6dd9..fdcff87aa 160000 --- a/teleoprtc_repo +++ b/teleoprtc_repo @@ -1 +1 @@ -Subproject commit f2e5a6dd9e13a184b2f0e95a6c8afd308ec2da89 +Subproject commit fdcff87aaf2b1ca099be4fc820044334cec02cc5 From a4f0f6ca3627c9a8a805ec3f20c17d68a710b7f8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 11 Jun 2024 04:37:50 +0800 Subject: [PATCH 189/220] common/ratekeeper: change frame() return type from double to uint64_t (#32679) --- common/ratekeeper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/ratekeeper.h b/common/ratekeeper.h index b6e8ac66a..e7323c6ec 100644 --- a/common/ratekeeper.h +++ b/common/ratekeeper.h @@ -9,7 +9,7 @@ public: ~RateKeeper() {} bool keepTime(); bool monitorTime(); - inline double frame() const { return frame_; } + inline uint64_t frame() const { return frame_; } inline double remaining() const { return remaining_; } private: From cf100f740e07824e1367a65c74e2b99f5c3b4458 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 10 Jun 2024 13:39:02 -0700 Subject: [PATCH 190/220] [bot] Fingerprints: add missing FW versions from new users (#32683) --- selfdrive/car/chrysler/fingerprints.py | 1 + selfdrive/car/subaru/fingerprints.py | 7 ++++++- selfdrive/car/volkswagen/fingerprints.py | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 01faa49bf..5072aad5c 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -410,6 +410,7 @@ FW_VERSIONS = { b'68453483AD', b'68453487AD', b'68453491AC', + b'68453491AD', b'68453499AD', b'68453503AC', b'68453503AD', diff --git a/selfdrive/car/subaru/fingerprints.py b/selfdrive/car/subaru/fingerprints.py index 10c713501..b53ac8ac6 100644 --- a/selfdrive/car/subaru/fingerprints.py +++ b/selfdrive/car/subaru/fingerprints.py @@ -112,6 +112,7 @@ FW_VERSIONS = { b'\x00\x00d\xb5\x1f@ \x0e', b'\x00\x00d\xdc\x00\x00\x00\x00', b'\x00\x00d\xdc\x1f@ \x0e', + b'\x00\x00e\x02\x00\x00\x00\x00', b'\x00\x00e\x02\x1f@ \x14', b'\x00\x00e\x1c\x00\x00\x00\x00', b'\x00\x00e\x1c\x1f@ \x14', @@ -125,6 +126,7 @@ FW_VERSIONS = { b'\xaa!au\x07', b'\xaa!av\x07', b'\xaa!aw\x07', + b'\xaa!dp\x07', b'\xaa!dq\x07', b'\xaa!ds\x07', b'\xaa!dt\x07', @@ -179,6 +181,7 @@ FW_VERSIONS = { b'\x00\x00eb\x1f@ "', b'\x00\x00eq\x00\x00\x00\x00', b'\x00\x00eq\x1f@ "', + b'\x00\x00e\x87\x1f@ "', b'\x00\x00e\x8f\x00\x00\x00\x00', b'\x00\x00e\x8f\x1f@ )', b'\x00\x00e\x92\x00\x00\x00\x00', @@ -196,6 +199,7 @@ FW_VERSIONS = { b'\xcc!fp\x07', b'\xcc"f0\x07', b'\xe6!`@\x07', + b'\xe6!`p\x07', b'\xe6!fp\x07', b'\xe6"f0\x07', b'\xe6"fp\x07', @@ -319,8 +323,8 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x7e1, None): [ b'\x1a\xf6F`\x00', - b'\xda\xf2`\x80\x00', b'\xda\xf2`p\x00', + b'\xda\xf2`\x80\x00', b'\xda\xfd\xe0\x80\x00', b'\xdc\xf2@`\x00', b'\xdc\xf2``\x00', @@ -486,6 +490,7 @@ FW_VERSIONS = { ], (Ecu.engine, 0x7e0, None): [ b'\xbc"`@\x07', + b'\xbc"`p\x07', b'\xbc"`q\x07', b'\xbc,\xa0q\x07', b'\xbc,\xa0u\x07', diff --git a/selfdrive/car/volkswagen/fingerprints.py b/selfdrive/car/volkswagen/fingerprints.py index 68f6d8f6a..fea530b29 100644 --- a/selfdrive/car/volkswagen/fingerprints.py +++ b/selfdrive/car/volkswagen/fingerprints.py @@ -591,6 +591,7 @@ FW_VERSIONS = { b'\xf1\x8783A907115Q \xf1\x890001', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x8709G927158DS\xf1\x893699', b'\xf1\x8709G927158DT\xf1\x893698', b'\xf1\x8709G927158FM\xf1\x893757', b'\xf1\x8709G927158GC\xf1\x893821', From 26e52a4aedb172999ce796bd39df5ba5594a3cf7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 10 Jun 2024 13:42:27 -0700 Subject: [PATCH 191/220] Revert "[bot] Fingerprints: add missing FW versions from new users" (#32688) Revert "[bot] Fingerprints: add missing FW versions from new users (#32683)" This reverts commit cf100f740e07824e1367a65c74e2b99f5c3b4458. --- selfdrive/car/chrysler/fingerprints.py | 1 - selfdrive/car/subaru/fingerprints.py | 7 +------ selfdrive/car/volkswagen/fingerprints.py | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 5072aad5c..01faa49bf 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -410,7 +410,6 @@ FW_VERSIONS = { b'68453483AD', b'68453487AD', b'68453491AC', - b'68453491AD', b'68453499AD', b'68453503AC', b'68453503AD', diff --git a/selfdrive/car/subaru/fingerprints.py b/selfdrive/car/subaru/fingerprints.py index b53ac8ac6..10c713501 100644 --- a/selfdrive/car/subaru/fingerprints.py +++ b/selfdrive/car/subaru/fingerprints.py @@ -112,7 +112,6 @@ FW_VERSIONS = { b'\x00\x00d\xb5\x1f@ \x0e', b'\x00\x00d\xdc\x00\x00\x00\x00', b'\x00\x00d\xdc\x1f@ \x0e', - b'\x00\x00e\x02\x00\x00\x00\x00', b'\x00\x00e\x02\x1f@ \x14', b'\x00\x00e\x1c\x00\x00\x00\x00', b'\x00\x00e\x1c\x1f@ \x14', @@ -126,7 +125,6 @@ FW_VERSIONS = { b'\xaa!au\x07', b'\xaa!av\x07', b'\xaa!aw\x07', - b'\xaa!dp\x07', b'\xaa!dq\x07', b'\xaa!ds\x07', b'\xaa!dt\x07', @@ -181,7 +179,6 @@ FW_VERSIONS = { b'\x00\x00eb\x1f@ "', b'\x00\x00eq\x00\x00\x00\x00', b'\x00\x00eq\x1f@ "', - b'\x00\x00e\x87\x1f@ "', b'\x00\x00e\x8f\x00\x00\x00\x00', b'\x00\x00e\x8f\x1f@ )', b'\x00\x00e\x92\x00\x00\x00\x00', @@ -199,7 +196,6 @@ FW_VERSIONS = { b'\xcc!fp\x07', b'\xcc"f0\x07', b'\xe6!`@\x07', - b'\xe6!`p\x07', b'\xe6!fp\x07', b'\xe6"f0\x07', b'\xe6"fp\x07', @@ -323,8 +319,8 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x7e1, None): [ b'\x1a\xf6F`\x00', - b'\xda\xf2`p\x00', b'\xda\xf2`\x80\x00', + b'\xda\xf2`p\x00', b'\xda\xfd\xe0\x80\x00', b'\xdc\xf2@`\x00', b'\xdc\xf2``\x00', @@ -490,7 +486,6 @@ FW_VERSIONS = { ], (Ecu.engine, 0x7e0, None): [ b'\xbc"`@\x07', - b'\xbc"`p\x07', b'\xbc"`q\x07', b'\xbc,\xa0q\x07', b'\xbc,\xa0u\x07', diff --git a/selfdrive/car/volkswagen/fingerprints.py b/selfdrive/car/volkswagen/fingerprints.py index fea530b29..68f6d8f6a 100644 --- a/selfdrive/car/volkswagen/fingerprints.py +++ b/selfdrive/car/volkswagen/fingerprints.py @@ -591,7 +591,6 @@ FW_VERSIONS = { b'\xf1\x8783A907115Q \xf1\x890001', ], (Ecu.transmission, 0x7e1, None): [ - b'\xf1\x8709G927158DS\xf1\x893699', b'\xf1\x8709G927158DT\xf1\x893698', b'\xf1\x8709G927158FM\xf1\x893757', b'\xf1\x8709G927158GC\xf1\x893821', From 2b1ac1ffa145543ac62075479123d71806bd3f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Mon, 10 Jun 2024 14:22:47 -0700 Subject: [PATCH 192/220] webrtc: fix patch in tests (#32686) * Fix patch * Fix it again --- system/webrtc/tests/test_stream_session.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/system/webrtc/tests/test_stream_session.py b/system/webrtc/tests/test_stream_session.py index bcc9d6492..e89e42e44 100644 --- a/system/webrtc/tests/test_stream_session.py +++ b/system/webrtc/tests/test_stream_session.py @@ -8,7 +8,6 @@ from aiortc import RTCDataChannel from aiortc.mediastreams import VIDEO_CLOCK_RATE, VIDEO_TIME_BASE import capnp import pyaudio -import pytest from cereal import messaging, log from openpilot.system.webrtc.webrtcd import CerealOutgoingMessageProxy, CerealIncomingMessageProxy @@ -68,13 +67,11 @@ class TestStreamSession: mocked_pubmaster.reset_mock() - # FIXME, hangs for some reason - @pytest.mark.skip("Hangs forever") def test_livestream_track(self, mocker): fake_msg = messaging.new_message("livestreamDriverEncodeData") config = {"receive.return_value": fake_msg.to_bytes()} - mocker.patch("cereal.messaging.SubSocket", spec=True, **config) + mocker.patch("msgq.SubSocket", spec=True, **config) track = LiveStreamVideoStreamTrack("driver") assert track.id.startswith("driver") From c514ee7212f7ef43c7451d6e638dd54ec0643dcc Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 10 Jun 2024 14:36:42 -0700 Subject: [PATCH 193/220] [bot] Fingerprints: add missing FW versions from new users (#32689) Export fingerprints --- selfdrive/car/chrysler/fingerprints.py | 1 + selfdrive/car/subaru/fingerprints.py | 2 +- selfdrive/car/volkswagen/fingerprints.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 01faa49bf..5072aad5c 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -410,6 +410,7 @@ FW_VERSIONS = { b'68453483AD', b'68453487AD', b'68453491AC', + b'68453491AD', b'68453499AD', b'68453503AC', b'68453503AD', diff --git a/selfdrive/car/subaru/fingerprints.py b/selfdrive/car/subaru/fingerprints.py index 10c713501..7f3ae7316 100644 --- a/selfdrive/car/subaru/fingerprints.py +++ b/selfdrive/car/subaru/fingerprints.py @@ -319,8 +319,8 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x7e1, None): [ b'\x1a\xf6F`\x00', - b'\xda\xf2`\x80\x00', b'\xda\xf2`p\x00', + b'\xda\xf2`\x80\x00', b'\xda\xfd\xe0\x80\x00', b'\xdc\xf2@`\x00', b'\xdc\xf2``\x00', diff --git a/selfdrive/car/volkswagen/fingerprints.py b/selfdrive/car/volkswagen/fingerprints.py index 68f6d8f6a..fea530b29 100644 --- a/selfdrive/car/volkswagen/fingerprints.py +++ b/selfdrive/car/volkswagen/fingerprints.py @@ -591,6 +591,7 @@ FW_VERSIONS = { b'\xf1\x8783A907115Q \xf1\x890001', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x8709G927158DS\xf1\x893699', b'\xf1\x8709G927158DT\xf1\x893698', b'\xf1\x8709G927158FM\xf1\x893757', b'\xf1\x8709G927158GC\xf1\x893821', From 1f7c5bcd50ae64281ea9cb1de48131b59efdeb1f Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Mon, 10 Jun 2024 16:06:37 -0700 Subject: [PATCH 194/220] Pin pytools (#32684) * bump opencl * pin pytools --- poetry.lock | 178 ++++++++++++++++++++++++------------------------- pyproject.toml | 1 + 2 files changed, 90 insertions(+), 89 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7d9b0acb0..e62446c60 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "aiohttp" @@ -262,13 +262,13 @@ files = [ [[package]] name = "azure-core" -version = "1.30.1" +version = "1.30.2" description = "Microsoft Azure Core Library for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "azure-core-1.30.1.tar.gz", hash = "sha256:26273a254131f84269e8ea4464f3560c731f29c0c1f69ac99010845f239c1a8f"}, - {file = "azure_core-1.30.1-py3-none-any.whl", hash = "sha256:7c5ee397e48f281ec4dd773d67a0a47a0962ed6fa833036057f9ea067f688e74"}, + {file = "azure-core-1.30.2.tar.gz", hash = "sha256:a14dc210efcd608821aa472d9fb8e8d035d29b68993819147bc290a8ac224472"}, + {file = "azure_core-1.30.2-py3-none-any.whl", hash = "sha256:cf019c1ca832e96274ae85abd3d9f752397194d9fea3b41487290562ac8abe4a"}, ] [package.dependencies] @@ -837,43 +837,43 @@ files = [ [[package]] name = "cryptography" -version = "42.0.7" +version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"}, - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"}, - {file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"}, - {file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"}, - {file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"}, - {file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"}, - {file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"}, - {file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, ] [package.dependencies] @@ -2557,13 +2557,13 @@ icu = ["PyICU (>=1.0.0)"] [[package]] name = "nodeenv" -version = "1.9.0" +version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.9.0-py2.py3-none-any.whl", hash = "sha256:508ecec98f9f3330b636d4448c0f1a56fc68017c68f1e7857ebc52acf0eb879a"}, - {file = "nodeenv-1.9.0.tar.gz", hash = "sha256:07f144e90dae547bf0d4ee8da0ee42664a42a04e02ed68e06324348dafe4bdb1"}, + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] [[package]] @@ -2762,13 +2762,13 @@ numpy = {version = ">=1.23.5", markers = "python_version >= \"3.11\""} [[package]] name = "packaging" -version = "24.0" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -3163,22 +3163,22 @@ files = [ [[package]] name = "protobuf" -version = "5.27.0" +version = "5.27.1" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-5.27.0-cp310-abi3-win32.whl", hash = "sha256:2f83bf341d925650d550b8932b71763321d782529ac0eaf278f5242f513cc04e"}, - {file = "protobuf-5.27.0-cp310-abi3-win_amd64.whl", hash = "sha256:b276e3f477ea1eebff3c2e1515136cfcff5ac14519c45f9b4aa2f6a87ea627c4"}, - {file = "protobuf-5.27.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:744489f77c29174328d32f8921566fb0f7080a2f064c5137b9d6f4b790f9e0c1"}, - {file = "protobuf-5.27.0-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:f51f33d305e18646f03acfdb343aac15b8115235af98bc9f844bf9446573827b"}, - {file = "protobuf-5.27.0-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:56937f97ae0dcf4e220ff2abb1456c51a334144c9960b23597f044ce99c29c89"}, - {file = "protobuf-5.27.0-cp38-cp38-win32.whl", hash = "sha256:a17f4d664ea868102feaa30a674542255f9f4bf835d943d588440d1f49a3ed15"}, - {file = "protobuf-5.27.0-cp38-cp38-win_amd64.whl", hash = "sha256:aabbbcf794fbb4c692ff14ce06780a66d04758435717107c387f12fb477bf0d8"}, - {file = "protobuf-5.27.0-cp39-cp39-win32.whl", hash = "sha256:587be23f1212da7a14a6c65fd61995f8ef35779d4aea9e36aad81f5f3b80aec5"}, - {file = "protobuf-5.27.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cb65fc8fba680b27cf7a07678084c6e68ee13cab7cace734954c25a43da6d0f"}, - {file = "protobuf-5.27.0-py3-none-any.whl", hash = "sha256:673ad60f1536b394b4fa0bcd3146a4130fcad85bfe3b60eaa86d6a0ace0fa374"}, - {file = "protobuf-5.27.0.tar.gz", hash = "sha256:07f2b9a15255e3cf3f137d884af7972407b556a7a220912b252f26dc3121e6bf"}, + {file = "protobuf-5.27.1-cp310-abi3-win32.whl", hash = "sha256:3adc15ec0ff35c5b2d0992f9345b04a540c1e73bfee3ff1643db43cc1d734333"}, + {file = "protobuf-5.27.1-cp310-abi3-win_amd64.whl", hash = "sha256:25236b69ab4ce1bec413fd4b68a15ef8141794427e0b4dc173e9d5d9dffc3bcd"}, + {file = "protobuf-5.27.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4e38fc29d7df32e01a41cf118b5a968b1efd46b9c41ff515234e794011c78b17"}, + {file = "protobuf-5.27.1-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:917ed03c3eb8a2d51c3496359f5b53b4e4b7e40edfbdd3d3f34336e0eef6825a"}, + {file = "protobuf-5.27.1-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:ee52874a9e69a30271649be88ecbe69d374232e8fd0b4e4b0aaaa87f429f1631"}, + {file = "protobuf-5.27.1-cp38-cp38-win32.whl", hash = "sha256:7a97b9c5aed86b9ca289eb5148df6c208ab5bb6906930590961e08f097258107"}, + {file = "protobuf-5.27.1-cp38-cp38-win_amd64.whl", hash = "sha256:f6abd0f69968792da7460d3c2cfa7d94fd74e1c21df321eb6345b963f9ec3d8d"}, + {file = "protobuf-5.27.1-cp39-cp39-win32.whl", hash = "sha256:dfddb7537f789002cc4eb00752c92e67885badcc7005566f2c5de9d969d3282d"}, + {file = "protobuf-5.27.1-cp39-cp39-win_amd64.whl", hash = "sha256:39309898b912ca6febb0084ea912e976482834f401be35840a008da12d189340"}, + {file = "protobuf-5.27.1-py3-none-any.whl", hash = "sha256:4ac7249a1530a2ed50e24201d6630125ced04b30619262f06224616e0030b6cf"}, + {file = "protobuf-5.27.1.tar.gz", hash = "sha256:df5e5b8e39b7d1c25b186ffdf9f44f40f810bbcc9d2b71d9d3156fee5a9adf15"}, ] [[package]] @@ -6645,13 +6645,13 @@ cp2110 = ["hidapi"] [[package]] name = "pytest" -version = "8.2.1" +version = "8.2.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, - {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, + {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, + {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, ] [package.dependencies] @@ -7171,28 +7171,28 @@ docs = ["furo (==2024.4.27)", "pyenchant (==3.2.2)", "sphinx (==7.1.2)", "sphinx [[package]] name = "ruff" -version = "0.4.7" +version = "0.4.8" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.4.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e089371c67892a73b6bb1525608e89a2aca1b77b5440acf7a71dda5dac958f9e"}, - {file = "ruff-0.4.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:10f973d521d910e5f9c72ab27e409e839089f955be8a4c8826601a6323a89753"}, - {file = "ruff-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c3d110970001dfa494bcd95478e62286c751126dfb15c3c46e7915fc49694f"}, - {file = "ruff-0.4.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa9773c6c00f4958f73b317bc0fd125295110c3776089f6ef318f4b775f0abe4"}, - {file = "ruff-0.4.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07fc80bbb61e42b3b23b10fda6a2a0f5a067f810180a3760c5ef1b456c21b9db"}, - {file = "ruff-0.4.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:fa4dafe3fe66d90e2e2b63fa1591dd6e3f090ca2128daa0be33db894e6c18648"}, - {file = "ruff-0.4.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7c0083febdec17571455903b184a10026603a1de078428ba155e7ce9358c5f6"}, - {file = "ruff-0.4.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad1b20e66a44057c326168437d680a2166c177c939346b19c0d6b08a62a37589"}, - {file = "ruff-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf5d818553add7511c38b05532d94a407f499d1a76ebb0cad0374e32bc67202"}, - {file = "ruff-0.4.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50e9651578b629baec3d1513b2534de0ac7ed7753e1382272b8d609997e27e83"}, - {file = "ruff-0.4.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8874a9df7766cb956b218a0a239e0a5d23d9e843e4da1e113ae1d27ee420877a"}, - {file = "ruff-0.4.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b9de9a6e49f7d529decd09381c0860c3f82fa0b0ea00ea78409b785d2308a567"}, - {file = "ruff-0.4.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:13a1768b0691619822ae6d446132dbdfd568b700ecd3652b20d4e8bc1e498f78"}, - {file = "ruff-0.4.7-py3-none-win32.whl", hash = "sha256:769e5a51df61e07e887b81e6f039e7ed3573316ab7dd9f635c5afaa310e4030e"}, - {file = "ruff-0.4.7-py3-none-win_amd64.whl", hash = "sha256:9e3ab684ad403a9ed1226894c32c3ab9c2e0718440f6f50c7c5829932bc9e054"}, - {file = "ruff-0.4.7-py3-none-win_arm64.whl", hash = "sha256:10f2204b9a613988e3484194c2c9e96a22079206b22b787605c255f130db5ed7"}, - {file = "ruff-0.4.7.tar.gz", hash = "sha256:2331d2b051dc77a289a653fcc6a42cce357087c5975738157cd966590b18b5e1"}, + {file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"}, + {file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"}, + {file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"}, + {file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"}, + {file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"}, + {file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"}, ] [[package]] @@ -7271,13 +7271,13 @@ stats = ["scipy (>=1.7)", "statsmodels (>=0.12)"] [[package]] name = "sentry-sdk" -version = "2.3.1" +version = "2.5.1" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" files = [ - {file = "sentry_sdk-2.3.1-py2.py3-none-any.whl", hash = "sha256:c5aeb095ba226391d337dd42a6f9470d86c9fc236ecc71cfc7cd1942b45010c6"}, - {file = "sentry_sdk-2.3.1.tar.gz", hash = "sha256:139a71a19f5e9eb5d3623942491ce03cf8ebc14ea2e39ba3e6fe79560d8a5b1f"}, + {file = "sentry_sdk-2.5.1-py2.py3-none-any.whl", hash = "sha256:1f87acdce4a43a523ae5aa21a3fc37522d73ebd9ec04b1dbf01aa3d173852def"}, + {file = "sentry_sdk-2.5.1.tar.gz", hash = "sha256:fbc40a78a8a9c6675133031116144f0d0940376fa6e4e1acd5624c90b0aaf58b"}, ] [package.dependencies] @@ -7856,13 +7856,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.12.1" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, - {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -8050,20 +8050,20 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.19.1" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.1-py3-none-any.whl", hash = "sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091"}, - {file = "zipp-3.19.1.tar.gz", hash = "sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "e2473a1aa0d28b72f8a0816bb3335a2e48e526e39f038387194948965fffd72e" +content-hash = "a09744c1ac37507bef4de0c210f7321722a2852798ca366d04dfec9329190202" diff --git a/pyproject.toml b/pyproject.toml index 6bc567921..007245540 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -166,6 +166,7 @@ pprofile = "*" polyline = "*" pre-commit = "*" pyautogui = "*" +pytools = "<=2024.1.3" # our pinned version of pyopencl use a broken version of pytools pyopencl = "==2023.1.4" # 2024.1 is broken on arm64 pygame = "*" pywinctl = "*" From e3f18b9f95fc4de2a71127d87bc262ee698ae0a0 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 10 Jun 2024 16:23:20 -0700 Subject: [PATCH 195/220] VW: bump model year of all CRAFTER_MK2 models --- docs/CARS.md | 8 ++++---- selfdrive/car/volkswagen/values.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c0070f18f..3b163dcee 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -185,7 +185,7 @@ A supported vehicle is one that just works when you install a comma device. All |Lexus|UX Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 RJ45 cable (7 ft)
    - 1 Toyota A connector
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Lincoln|Aviator 2020-23|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 Ford Q3 connector
    - 1 RJ45 cable (7 ft)
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Lincoln|Aviator Plug-in Hybrid 2020-23|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 Ford Q3 connector
    - 1 RJ45 cable (7 ft)
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || -|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || +|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Mazda|CX-5 2022-24|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 Mazda connector
    - 1 RJ45 cable (7 ft)
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 Mazda connector
    - 1 RJ45 cable (7 ft)
    - 1 comma 3X
    - 1 comma power v2
    - 1 harness box
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || @@ -269,8 +269,8 @@ A supported vehicle is one that just works when you install a comma device. All |Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || -|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || -|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || +|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || +|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || @@ -279,7 +279,7 @@ A supported vehicle is one that just works when you install a comma device. All |Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || -|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || +|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 angled mount (8 degrees)
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|Jetta 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|Jetta GLI 2021-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || |Volkswagen|Passat 2015-22[10](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
    Parts- 1 J533 connector
    - 1 USB-C coupler
    - 1 comma 3X
    - 1 harness box
    - 1 long OBD-C cable
    - 1 mount
    - 1 right angle OBD-C cable (1.5 ft)
    Buy Here
    || diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 51346e072..8b58769b3 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -244,11 +244,11 @@ class CAR(Platforms): ) VOLKSWAGEN_CRAFTER_MK2 = VolkswagenMQBPlatformConfig( [ - VWCarDocs("Volkswagen Crafter 2017-23", video_link="https://youtu.be/4100gLeabmo"), - VWCarDocs("Volkswagen e-Crafter 2018-23", video_link="https://youtu.be/4100gLeabmo"), - VWCarDocs("Volkswagen Grand California 2019-23", video_link="https://youtu.be/4100gLeabmo"), + VWCarDocs("Volkswagen Crafter 2017-24", video_link="https://youtu.be/4100gLeabmo"), + VWCarDocs("Volkswagen e-Crafter 2018-24", video_link="https://youtu.be/4100gLeabmo"), + VWCarDocs("Volkswagen Grand California 2019-24", video_link="https://youtu.be/4100gLeabmo"), VWCarDocs("MAN TGE 2017-24", video_link="https://youtu.be/4100gLeabmo"), - VWCarDocs("MAN eTGE 2020-23", video_link="https://youtu.be/4100gLeabmo"), + VWCarDocs("MAN eTGE 2020-24", video_link="https://youtu.be/4100gLeabmo"), ], VolkswagenCarSpecs(mass=2100, wheelbase=3.64, minSteerSpeed=50 * CV.KPH_TO_MS), chassis_codes={"SY", "SZ", "UY", "UZ"}, From 1e3d62c88a9805de6799f742ca4998b36b5e51e8 Mon Sep 17 00:00:00 2001 From: Hoang Bui <47828508+bongbui321@users.noreply.github.com> Date: Mon, 10 Jun 2024 19:58:51 -0400 Subject: [PATCH 196/220] tools/rerun: correct reset to defined default blueprint (#32692) --- tools/rerun/run.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/rerun/run.py b/tools/rerun/run.py index 1c3c0a59e..9975478a7 100755 --- a/tools/rerun/run.py +++ b/tools/rerun/run.py @@ -53,9 +53,9 @@ def log_thumbnail(thumbnailMsg): rr.log("/thumbnail", rr.ImageEncoded(contents=bytesImgData)) @rr.shutdown_at_exit -def process(lr): +def process(blueprint, lr): rr.init("rerun_test") - rr.connect() + rr.connect(default_blueprint=blueprint) ret = [] for msg in lr: @@ -80,10 +80,10 @@ if __name__ == '__main__': args = parser.parse_args() blueprint = createBlueprint() - rr.init("rerun_test", default_blueprint=blueprint) + rr.init("rerun_test") rr.spawn(connect=False) # child processes stream data to Viewer route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip() print("Getting route log paths") lr = LogReader(route_or_segment_name) - lr.run_across_segments(NUM_CPUS, partial(process)) + lr.run_across_segments(NUM_CPUS, partial(process, blueprint)) From 71063d66cd526bf1e498618e1aec3440736ab5b7 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 10 Jun 2024 17:19:01 -0700 Subject: [PATCH 197/220] [bot] Update Python packages and pre-commit hooks (#32682) * Update Python packages and pre-commit hooks * fix linter * poetry lock --------- Co-authored-by: Vehicle Researcher Co-authored-by: Maxime Desroches --- .pre-commit-config.yaml | 8 ++++---- poetry.lock | 6 +++--- system/webrtc/webrtcd.py | 2 +- tools/mac_setup.sh | 4 ++-- tools/sim/lib/common.py | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 75ddcfb61..61b782364 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,16 +24,16 @@ repos: - --maxkb=120 - --enforce-all - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 + rev: v2.3.0 hooks: - id: codespell exclude: '^(third_party/)|(body/)|(msgq/)|(panda/)|(opendbc/)|(rednose/)|(rednose_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)' args: # if you've got a short variable name that's getting flagged, add it here - - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints + - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.4 + rev: v0.4.8 hooks: - id: ruff exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' @@ -98,6 +98,6 @@ repos: args: - --lock - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.28.3 + rev: 0.28.4 hooks: - id: check-github-workflows diff --git a/poetry.lock b/poetry.lock index e62446c60..6f0b99863 100644 --- a/poetry.lock +++ b/poetry.lock @@ -281,13 +281,13 @@ aio = ["aiohttp (>=3.0)"] [[package]] name = "azure-identity" -version = "1.16.0" +version = "1.16.1" description = "Microsoft Azure Identity Library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "azure-identity-1.16.0.tar.gz", hash = "sha256:6ff1d667cdcd81da1ceab42f80a0be63ca846629f518a922f7317a7e3c844e1b"}, - {file = "azure_identity-1.16.0-py3-none-any.whl", hash = "sha256:722fdb60b8fdd55fa44dc378b8072f4b419b56a5e54c0de391f644949f3a826f"}, + {file = "azure-identity-1.16.1.tar.gz", hash = "sha256:6d93f04468f240d59246d8afde3091494a5040d4f141cad0f49fc0c399d0d91e"}, + {file = "azure_identity-1.16.1-py3-none-any.whl", hash = "sha256:8fb07c25642cd4ac422559a8b50d3e77f73dcc2bbfaba419d06d6c9d7cff6726"}, ] [package.dependencies] diff --git a/system/webrtc/webrtcd.py b/system/webrtc/webrtcd.py index 76c3cd847..afd346857 100755 --- a/system/webrtc/webrtcd.py +++ b/system/webrtc/webrtcd.py @@ -24,7 +24,7 @@ from cereal import messaging, log class CerealOutgoingMessageProxy: def __init__(self, sm: messaging.SubMaster): self.sm = sm - self.channels: list['RTCDataChannel'] = [] + self.channels: list[RTCDataChannel] = [] def add_channel(self, channel: 'RTCDataChannel'): self.channels.append(channel) diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index d26ec3cfe..b7f7cb93a 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -6,7 +6,7 @@ if [ -z "$SKIP_PROMPT" ]; then echo "--------------- macOS support ---------------" echo "Running openpilot natively on macOS is not officially supported." echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues." - echo + echo echo "Check out devcontainers for a seamless experience (see tools/README.md)." echo "-------------------------------------------------" echo -n "Are you sure you want to continue? [y/N] " @@ -28,7 +28,7 @@ fi # Install brew if required if [[ $(command -v brew) == "" ]]; then - echo "Installing Hombrew" + echo "Installing Homebrew" /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" echo "[ ] installed brew t=$SECONDS" diff --git a/tools/sim/lib/common.py b/tools/sim/lib/common.py index 168b3aa32..132493213 100644 --- a/tools/sim/lib/common.py +++ b/tools/sim/lib/common.py @@ -17,7 +17,7 @@ class GPSState: self.altitude = 0 def from_xy(self, xy): - """Simulates a lat/lon from an xy coordinate on a plane, for simple simlation. TODO: proper global projection?""" + """Simulates a lat/lon from an xy coordinate on a plane, for simple simulation. TODO: proper global projection?""" BASE_LAT = 32.75308505188913 BASE_LON = -117.2095393365393 DEG_TO_METERS = 100000 From f8cb04e4a8b032b72a909f68b808a50936184bee Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 10 Jun 2024 18:04:24 -0700 Subject: [PATCH 198/220] pandad/SPI: ensure slave is in a consistent state (#32645) * maxout * get ready for the next one * really get ready * much better --------- Co-authored-by: Comma Device --- selfdrive/pandad/panda.cc | 5 +++ selfdrive/pandad/spi.cc | 45 ++++++++++++++++------- selfdrive/pandad/tests/test_pandad_spi.py | 2 +- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/selfdrive/pandad/panda.cc b/selfdrive/pandad/panda.cc index 4ec5b79f1..a404ad388 100644 --- a/selfdrive/pandad/panda.cc +++ b/selfdrive/pandad/panda.cc @@ -221,6 +221,11 @@ bool Panda::can_receive(std::vector& out_vec) { return false; } + if (getenv("PANDAD_MAXOUT") != NULL) { + static uint8_t junk[RECV_SIZE]; + handle->bulk_read(0xab, junk, RECV_SIZE - recv); + } + bool ret = true; if (recv > 0) { receive_buffer_size += recv; diff --git a/selfdrive/pandad/spi.cc b/selfdrive/pandad/spi.cc index f4882addf..8f1e29689 100644 --- a/selfdrive/pandad/spi.cc +++ b/selfdrive/pandad/spi.cc @@ -50,8 +50,9 @@ private: #define SPILOG(fn, fmt, ...) do { \ fn(fmt, ## __VA_ARGS__); \ - fn(" %d / 0x%x / %d / %d", \ - xfer_count, header.endpoint, header.tx_len, header.max_rx_len); \ + fn(" %d / 0x%x / %d / %d / tx: %s", \ + xfer_count, header.endpoint, header.tx_len, header.max_rx_len, \ + util::hexdump(tx_buf, std::min((int)header.tx_len, 8)).c_str()); \ } while (0) PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { @@ -238,6 +239,7 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1 // due to full TX buffers nack_count += 1; if (nack_count > 3) { + SPILOG(LOGE, "NACK sleep %d", nack_count); usleep(std::clamp(nack_count*10, 200, 2000)); } } @@ -256,14 +258,14 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout, if (timeout == 0) { timeout = SPI_ACK_TIMEOUT; } - timeout = std::clamp(timeout, 100U, SPI_ACK_TIMEOUT); + timeout = std::clamp(timeout, 20U, SPI_ACK_TIMEOUT); spi_ioc_transfer transfer = { .tx_buf = (uint64_t)tx_buf, .rx_buf = (uint64_t)rx_buf, - .len = length + .len = length, }; - tx_buf[0] = tx; + memset(tx_buf, tx, length); while (true) { int ret = lltransfer(transfer); @@ -275,13 +277,13 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout, if (rx_buf[0] == ack) { break; } else if (rx_buf[0] == SPI_NACK) { - SPILOG(LOGD, "SPI: got NACK"); + SPILOG(LOGD, "SPI: got NACK, waiting for 0x%x", ack); return SpiError::NACK; } // handle timeout if (millis_since_boot() - start_millis > timeout) { - SPILOG(LOGW, "SPI: timed out waiting for ACK"); + SPILOG(LOGW, "SPI: timed out waiting for ACK, waiting for 0x%x", ack); return SpiError::ACK_TIMEOUT; } } @@ -352,13 +354,13 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx ret = lltransfer(transfer); if (ret < 0) { SPILOG(LOGE, "SPI: failed to send header"); - return ret; + goto fail; } // Wait for (N)ACK ret = wait_for_ack(SPI_HACK, 0x11, timeout, 1); if (ret < 0) { - return ret; + goto fail; } // Send data @@ -370,20 +372,20 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx ret = lltransfer(transfer); if (ret < 0) { SPILOG(LOGE, "SPI: failed to send data"); - return ret; + goto fail; } // Wait for (N)ACK ret = wait_for_ack(SPI_DACK, 0x13, timeout, 3); if (ret < 0) { - return ret; + goto fail; } // Read data rx_data_len = *(uint16_t *)(rx_buf+1); if (rx_data_len >= SPI_BUF_SIZE) { SPILOG(LOGE, "SPI: RX data len larger than buf size %d", rx_data_len); - return -1; + goto fail; } transfer.len = rx_data_len + 1; @@ -391,11 +393,11 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx ret = lltransfer(transfer); if (ret < 0) { SPILOG(LOGE, "SPI: failed to read rx data"); - return ret; + goto fail; } if (!check_checksum(rx_buf, rx_data_len + 4)) { SPILOG(LOGE, "SPI: bad checksum"); - return -1; + goto fail; } if (rx_data != NULL) { @@ -403,5 +405,20 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx } return rx_data_len; + +fail: + // ensure slave is in a consistent state + // and ready for the next transfer + int nack_cnt = 0; + while (nack_cnt < 3) { + if (wait_for_ack(SPI_NACK, 0x14, 1, SPI_BUF_SIZE/2) == 0) { + nack_cnt += 1; + } else { + nack_cnt = 0; + } + } + + if (ret > 0) ret = -1; + return ret; } #endif diff --git a/selfdrive/pandad/tests/test_pandad_spi.py b/selfdrive/pandad/tests/test_pandad_spi.py index ed81c1ea2..11e20e72c 100644 --- a/selfdrive/pandad/tests/test_pandad_spi.py +++ b/selfdrive/pandad/tests/test_pandad_spi.py @@ -97,7 +97,7 @@ class TestBoarddSpi: with subtests.test(msg="timing check", service=service): edt = 1e3 / SERVICE_LIST[service].frequency assert edt*0.9 < np.mean(dts) < edt*1.1 - assert np.max(dts) < edt*20 + assert np.max(dts) < edt*8 assert np.min(dts) < edt assert len(dts) >= ((et-0.5)*SERVICE_LIST[service].frequency*0.8) From 3365ed5effa48d34ffe0e2e9bbe9f6941336bed5 Mon Sep 17 00:00:00 2001 From: schlimeszn <138847413+schlimeszn@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:59:01 -0400 Subject: [PATCH 199/220] Custom setproctitle (#32667) * add custom setproctitle * add test * Update poetry.lock * fix lint * support only Linux * test only Linux * final lint * Update test_setproctitle.py * Update setproctitle.py * convert to threadnames * delete proctitles * Check str len and use PR_GET_NAME * fix poetry.lock * lint fix * Update common/threadname.py --------- Co-authored-by: reddyn12 Co-authored-by: Adeeb Shihadeh --- common/realtime.py | 6 +- common/tests/test_threadname.py | 8 +++ common/threadname.py | 19 ++++++ poetry.lock | 102 +------------------------------- pyproject.toml | 1 - scripts/waste.py | 4 +- selfdrive/modeld/modeld.py | 12 ++-- system/manager/process.py | 4 +- 8 files changed, 41 insertions(+), 115 deletions(-) create mode 100644 common/tests/test_threadname.py create mode 100644 common/threadname.py diff --git a/common/realtime.py b/common/realtime.py index dd97ea3d7..e7265406a 100644 --- a/common/realtime.py +++ b/common/realtime.py @@ -4,7 +4,7 @@ import os import time from collections import deque -from setproctitle import getproctitle +from openpilot.common.threadname import getthreadname from openpilot.system.hardware import PC @@ -52,7 +52,7 @@ class Ratekeeper: self._print_delay_threshold = print_delay_threshold self._frame = 0 self._remaining = 0.0 - self._process_name = getproctitle() + self._thread_name = getthreadname() self._dts = deque([self._interval], maxlen=100) self._last_monitor_time = time.monotonic() @@ -87,7 +87,7 @@ class Ratekeeper: remaining = self._next_frame_time - time.monotonic() self._next_frame_time += self._interval if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold: - print(f"{self._process_name} lagging by {-remaining * 1000:.2f} ms") + print(f"{self._thread_name} lagging by {-remaining * 1000:.2f} ms") lagged = True self._frame += 1 self._remaining = remaining diff --git a/common/tests/test_threadname.py b/common/tests/test_threadname.py new file mode 100644 index 000000000..38e5e1d49 --- /dev/null +++ b/common/tests/test_threadname.py @@ -0,0 +1,8 @@ +from openpilot.common.threadname import setthreadname, getthreadname, LINUX + +class TestThreadName: + def test_set_get_threadname(self): + if LINUX: + name = 'TESTING' + setthreadname(name) + assert name == getthreadname() diff --git a/common/threadname.py b/common/threadname.py new file mode 100644 index 000000000..3db7a7d01 --- /dev/null +++ b/common/threadname.py @@ -0,0 +1,19 @@ +import ctypes +import os + +LINUX = os.name == 'posix' and os.uname().sysname == 'Linux' + +if LINUX: + libc = ctypes.CDLL('libc.so.6') + +def setthreadname(name: str) -> None: + if LINUX: + name = name[:15] + '\0' + libc.prctl(15, str.encode(name), 0, 0, 0) + +def getthreadname() -> str: + if LINUX: + name = ctypes.create_string_buffer(16) + libc.prctl(16, name) + return name.value.decode('utf-8') + return "" diff --git a/poetry.lock b/poetry.lock index 6f0b99863..966210936 100644 --- a/poetry.lock +++ b/poetry.lock @@ -7319,106 +7319,6 @@ starlette = ["starlette (>=0.19.1)"] starlite = ["starlite (>=1.48)"] tornado = ["tornado (>=5)"] -[[package]] -name = "setproctitle" -version = "1.3.3" -description = "A Python module to customize the process title" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:897a73208da48db41e687225f355ce993167079eda1260ba5e13c4e53be7f754"}, - {file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c331e91a14ba4076f88c29c777ad6b58639530ed5b24b5564b5ed2fd7a95452"}, - {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbbd6c7de0771c84b4aa30e70b409565eb1fc13627a723ca6be774ed6b9d9fa3"}, - {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c05ac48ef16ee013b8a326c63e4610e2430dbec037ec5c5b58fcced550382b74"}, - {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1342f4fdb37f89d3e3c1c0a59d6ddbedbde838fff5c51178a7982993d238fe4f"}, - {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc74e84fdfa96821580fb5e9c0b0777c1c4779434ce16d3d62a9c4d8c710df39"}, - {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9617b676b95adb412bb69645d5b077d664b6882bb0d37bfdafbbb1b999568d85"}, - {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6a249415f5bb88b5e9e8c4db47f609e0bf0e20a75e8d744ea787f3092ba1f2d0"}, - {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:38da436a0aaace9add67b999eb6abe4b84397edf4a78ec28f264e5b4c9d53cd5"}, - {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:da0d57edd4c95bf221b2ebbaa061e65b1788f1544977288bdf95831b6e44e44d"}, - {file = "setproctitle-1.3.3-cp310-cp310-win32.whl", hash = "sha256:a1fcac43918b836ace25f69b1dca8c9395253ad8152b625064415b1d2f9be4fb"}, - {file = "setproctitle-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:200620c3b15388d7f3f97e0ae26599c0c378fdf07ae9ac5a13616e933cbd2086"}, - {file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:334f7ed39895d692f753a443102dd5fed180c571eb6a48b2a5b7f5b3564908c8"}, - {file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:950f6476d56ff7817a8fed4ab207727fc5260af83481b2a4b125f32844df513a"}, - {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:195c961f54a09eb2acabbfc90c413955cf16c6e2f8caa2adbf2237d1019c7dd8"}, - {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f05e66746bf9fe6a3397ec246fe481096664a9c97eb3fea6004735a4daf867fd"}, - {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5901a31012a40ec913265b64e48c2a4059278d9f4e6be628441482dd13fb8b5"}, - {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64286f8a995f2cd934082b398fc63fca7d5ffe31f0e27e75b3ca6b4efda4e353"}, - {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:184239903bbc6b813b1a8fc86394dc6ca7d20e2ebe6f69f716bec301e4b0199d"}, - {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:664698ae0013f986118064b6676d7dcd28fefd0d7d5a5ae9497cbc10cba48fa5"}, - {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e5119a211c2e98ff18b9908ba62a3bd0e3fabb02a29277a7232a6fb4b2560aa0"}, - {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:417de6b2e214e837827067048f61841f5d7fc27926f2e43954567094051aff18"}, - {file = "setproctitle-1.3.3-cp311-cp311-win32.whl", hash = "sha256:6a143b31d758296dc2f440175f6c8e0b5301ced3b0f477b84ca43cdcf7f2f476"}, - {file = "setproctitle-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a680d62c399fa4b44899094027ec9a1bdaf6f31c650e44183b50d4c4d0ccc085"}, - {file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d4460795a8a7a391e3567b902ec5bdf6c60a47d791c3b1d27080fc203d11c9dc"}, - {file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bdfd7254745bb737ca1384dee57e6523651892f0ea2a7344490e9caefcc35e64"}, - {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477d3da48e216d7fc04bddab67b0dcde633e19f484a146fd2a34bb0e9dbb4a1e"}, - {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ab2900d111e93aff5df9fddc64cf51ca4ef2c9f98702ce26524f1acc5a786ae7"}, - {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088b9efc62d5aa5d6edf6cba1cf0c81f4488b5ce1c0342a8b67ae39d64001120"}, - {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6d50252377db62d6a0bb82cc898089916457f2db2041e1d03ce7fadd4a07381"}, - {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:87e668f9561fd3a457ba189edfc9e37709261287b52293c115ae3487a24b92f6"}, - {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:287490eb90e7a0ddd22e74c89a92cc922389daa95babc833c08cf80c84c4df0a"}, - {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe1c49486109f72d502f8be569972e27f385fe632bd8895f4730df3c87d5ac8"}, - {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4a6ba2494a6449b1f477bd3e67935c2b7b0274f2f6dcd0f7c6aceae10c6c6ba3"}, - {file = "setproctitle-1.3.3-cp312-cp312-win32.whl", hash = "sha256:2df2b67e4b1d7498632e18c56722851ba4db5d6a0c91aaf0fd395111e51cdcf4"}, - {file = "setproctitle-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:f38d48abc121263f3b62943f84cbaede05749047e428409c2c199664feb6abc7"}, - {file = "setproctitle-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:816330675e3504ae4d9a2185c46b573105d2310c20b19ea2b4596a9460a4f674"}, - {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f960bc22d8d8e4ac886d1e2e21ccbd283adcf3c43136161c1ba0fa509088e0"}, - {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e6e7adff74796ef12753ff399491b8827f84f6c77659d71bd0b35870a17d8f"}, - {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53bc0d2358507596c22b02db079618451f3bd720755d88e3cccd840bafb4c41c"}, - {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad6d20f9541f5f6ac63df553b6d7a04f313947f550eab6a61aa758b45f0d5657"}, - {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c1c84beab776b0becaa368254801e57692ed749d935469ac10e2b9b825dbdd8e"}, - {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:507e8dc2891021350eaea40a44ddd887c9f006e6b599af8d64a505c0f718f170"}, - {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b1067647ac7aba0b44b591936118a22847bda3c507b0a42d74272256a7a798e9"}, - {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e71f6365744bf53714e8bd2522b3c9c1d83f52ffa6324bd7cbb4da707312cd8"}, - {file = "setproctitle-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:7f1d36a1e15a46e8ede4e953abb104fdbc0845a266ec0e99cc0492a4364f8c44"}, - {file = "setproctitle-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9a402881ec269d0cc9c354b149fc29f9ec1a1939a777f1c858cdb09c7a261df"}, - {file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ff814dea1e5c492a4980e3e7d094286077054e7ea116cbeda138819db194b2cd"}, - {file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:accb66d7b3ccb00d5cd11d8c6e07055a4568a24c95cf86109894dcc0c134cc89"}, - {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554eae5a5b28f02705b83a230e9d163d645c9a08914c0ad921df363a07cf39b1"}, - {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a911b26264dbe9e8066c7531c0591cfab27b464459c74385b276fe487ca91c12"}, - {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2982efe7640c4835f7355fdb4da313ad37fb3b40f5c69069912f8048f77b28c8"}, - {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df3f4274b80709d8bcab2f9a862973d453b308b97a0b423a501bcd93582852e3"}, - {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:af2c67ae4c795d1674a8d3ac1988676fa306bcfa1e23fddb5e0bd5f5635309ca"}, - {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:af4061f67fd7ec01624c5e3c21f6b7af2ef0e6bab7fbb43f209e6506c9ce0092"}, - {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:37a62cbe16d4c6294e84670b59cf7adcc73faafe6af07f8cb9adaf1f0e775b19"}, - {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a83ca086fbb017f0d87f240a8f9bbcf0809f3b754ee01cec928fff926542c450"}, - {file = "setproctitle-1.3.3-cp38-cp38-win32.whl", hash = "sha256:059f4ce86f8cc92e5860abfc43a1dceb21137b26a02373618d88f6b4b86ba9b2"}, - {file = "setproctitle-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ab92e51cd4a218208efee4c6d37db7368fdf182f6e7ff148fb295ecddf264287"}, - {file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7951820b77abe03d88b114b998867c0f99da03859e5ab2623d94690848d3e45"}, - {file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc94cf128676e8fac6503b37763adb378e2b6be1249d207630f83fc325d9b11"}, - {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f5d9027eeda64d353cf21a3ceb74bb1760bd534526c9214e19f052424b37e42"}, - {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e4a8104db15d3462e29d9946f26bed817a5b1d7a47eabca2d9dc2b995991503"}, - {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32c41ace41f344d317399efff4cffb133e709cec2ef09c99e7a13e9f3b9483c"}, - {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf16381c7bf7f963b58fb4daaa65684e10966ee14d26f5cc90f07049bfd8c1e"}, - {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e18b7bd0898398cc97ce2dfc83bb192a13a087ef6b2d5a8a36460311cb09e775"}, - {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69d565d20efe527bd8a9b92e7f299ae5e73b6c0470f3719bd66f3cd821e0d5bd"}, - {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ddedd300cd690a3b06e7eac90ed4452348b1348635777ce23d460d913b5b63c3"}, - {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:415bfcfd01d1fbf5cbd75004599ef167a533395955305f42220a585f64036081"}, - {file = "setproctitle-1.3.3-cp39-cp39-win32.whl", hash = "sha256:21112fcd2195d48f25760f0eafa7a76510871bbb3b750219310cf88b04456ae3"}, - {file = "setproctitle-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:5a740f05d0968a5a17da3d676ce6afefebeeeb5ce137510901bf6306ba8ee002"}, - {file = "setproctitle-1.3.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6b9e62ddb3db4b5205c0321dd69a406d8af9ee1693529d144e86bd43bcb4b6c0"}, - {file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3b99b338598de0bd6b2643bf8c343cf5ff70db3627af3ca427a5e1a1a90dd9"}, - {file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ae9a02766dad331deb06855fb7a6ca15daea333b3967e214de12cfae8f0ef5"}, - {file = "setproctitle-1.3.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:200ede6fd11233085ba9b764eb055a2a191fb4ffb950c68675ac53c874c22e20"}, - {file = "setproctitle-1.3.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0d3a953c50776751e80fe755a380a64cb14d61e8762bd43041ab3f8cc436092f"}, - {file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e08e232b78ba3ac6bc0d23ce9e2bee8fad2be391b7e2da834fc9a45129eb87"}, - {file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1da82c3e11284da4fcbf54957dafbf0655d2389cd3d54e4eaba636faf6d117a"}, - {file = "setproctitle-1.3.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:aeaa71fb9568ebe9b911ddb490c644fbd2006e8c940f21cb9a1e9425bd709574"}, - {file = "setproctitle-1.3.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:59335d000c6250c35989394661eb6287187854e94ac79ea22315469ee4f4c244"}, - {file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3ba57029c9c50ecaf0c92bb127224cc2ea9fda057b5d99d3f348c9ec2855ad3"}, - {file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d876d355c53d975c2ef9c4f2487c8f83dad6aeaaee1b6571453cb0ee992f55f6"}, - {file = "setproctitle-1.3.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:224602f0939e6fb9d5dd881be1229d485f3257b540f8a900d4271a2c2aa4e5f4"}, - {file = "setproctitle-1.3.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d7f27e0268af2d7503386e0e6be87fb9b6657afd96f5726b733837121146750d"}, - {file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5e7266498cd31a4572378c61920af9f6b4676a73c299fce8ba93afd694f8ae7"}, - {file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33c5609ad51cd99d388e55651b19148ea99727516132fb44680e1f28dd0d1de9"}, - {file = "setproctitle-1.3.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:eae8988e78192fd1a3245a6f4f382390b61bce6cfcc93f3809726e4c885fa68d"}, - {file = "setproctitle-1.3.3.tar.gz", hash = "sha256:c913e151e7ea01567837ff037a23ca8740192880198b7fbb90b16d181607caae"}, -] - -[package.extras] -test = ["pytest"] - [[package]] name = "setuptools" version = "70.0.0" @@ -8066,4 +7966,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "a09744c1ac37507bef4de0c210f7321722a2852798ca366d04dfec9329190202" +content-hash = "1aebbaeb87fb971b11182abcd487743e3bc4f6ee3560923a0d8714cc3d3a4efc" diff --git a/pyproject.toml b/pyproject.toml index 007245540..e1635728f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -137,7 +137,6 @@ future-fstrings = "*" # these should be removed psutil = "*" timezonefinder = "*" # just used for nav ETA -setproctitle = "*" pycryptodome = "*" # used in updated/casync, panda, body, and a test [tool.poetry.group.dev.dependencies] diff --git a/scripts/waste.py b/scripts/waste.py index 0764ff77c..bf92710fe 100755 --- a/scripts/waste.py +++ b/scripts/waste.py @@ -3,7 +3,7 @@ import os import time import numpy as np from multiprocessing import Process -from setproctitle import setproctitle +from openpilot.common.threadname import setthreadname def waste(core): os.sched_setaffinity(0, [core,]) @@ -16,7 +16,7 @@ def waste(core): j = 0 while 1: if (i % 100) == 0: - setproctitle("%3d: %8d" % (core, i)) + setthreadname("%3d: %8d" % (core, i)) lt = time.monotonic() print("%3d: %8d %f %.2f" % (core, i, lt-st, j)) st = lt diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 3ac80aad9..b037d1861 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -6,7 +6,7 @@ import numpy as np import cereal.messaging as messaging from cereal import car, log from pathlib import Path -from setproctitle import setproctitle +from openpilot.common.threadname import setthreadname from cereal.messaging import PubMaster, SubMaster from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.common.swaglog import cloudlog @@ -24,7 +24,7 @@ from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_ from openpilot.selfdrive.modeld.constants import ModelConstants from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext -PROCESS_NAME = "selfdrive.modeld.modeld" +THREAD_NAME = "selfdrive.modeld.modeld" SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') MODEL_PATHS = { @@ -114,9 +114,9 @@ class ModelState: def main(demo=False): cloudlog.warning("modeld init") - sentry.set_tag("daemon", PROCESS_NAME) - cloudlog.bind(daemon=PROCESS_NAME) - setproctitle(PROCESS_NAME) + sentry.set_tag("daemon", THREAD_NAME) + cloudlog.bind(daemon=THREAD_NAME) + setthreadname(THREAD_NAME) config_realtime_process(7, 54) cloudlog.warning("setting up CL context") @@ -286,7 +286,7 @@ if __name__ == "__main__": args = parser.parse_args() main(demo=args.demo) except KeyboardInterrupt: - cloudlog.warning(f"child {PROCESS_NAME} got SIGINT") + cloudlog.warning(f"child {THREAD_NAME} got SIGINT") except Exception: sentry.capture_exception() raise diff --git a/system/manager/process.py b/system/manager/process.py index 36f299ae6..9214e417c 100644 --- a/system/manager/process.py +++ b/system/manager/process.py @@ -8,7 +8,7 @@ from collections.abc import Callable, ValuesView from abc import ABC, abstractmethod from multiprocessing import Process -from setproctitle import setproctitle +from openpilot.common.threadname import setthreadname from cereal import car, log import cereal.messaging as messaging @@ -27,7 +27,7 @@ def launcher(proc: str, name: str) -> None: mod = importlib.import_module(proc) # rename the process - setproctitle(proc) + setthreadname(proc) # create new context since we forked messaging.context = messaging.Context() From efd744e03e53c0069796c9ba65bfe1eb2c532b35 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 10 Jun 2024 19:16:50 -0700 Subject: [PATCH 200/220] always on DM isn't in 0.9.7 --- RELEASES.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index aa0ab182e..18c011e11 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,15 +1,14 @@ Version 0.9.8 (2024-XX-XX) ======================== -* Always on driver monitoring toggle +* Added toggle to enable driver monitoring even when openpilot is not engaged -Version 0.9.7 (2024-06-11) +Version 0.9.7 (2024-06-13) ======================== * New driving model * Inputs the past curvature for smoother and more accurate lateral control * Simplified neural network architecture in the model's last layers * Minor fixes to desire augmentation and weight decay * Adjust driving personality with the follow distance button -* Added toggle to enable driver monitoring even when openpilot is not engaged * Support for hybrid variants of supported Ford models * Fingerprinting without the OBD-II port on all cars From 84dd8ad4a3c0542505f19f73cf95ebae7938b412 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Mon, 10 Jun 2024 19:26:48 -0700 Subject: [PATCH 201/220] Bump pyopencl and disable on arm64 (#32695) bump pyopencl --- poetry.lock | 84 ++++++++++++++++++++------------------------------ pyproject.toml | 3 +- 2 files changed, 35 insertions(+), 52 deletions(-) diff --git a/poetry.lock b/poetry.lock index 966210936..f4933887c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6409,63 +6409,47 @@ pyobjc-framework-Cocoa = ">=10.3" [[package]] name = "pyopencl" -version = "2023.1.4" +version = "2024.2.6" description = "Python wrapper for OpenCL" optional = false python-versions = "~=3.8" files = [ - {file = "pyopencl-2023.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ce71196cee0171a923d9ef6a8c21ce26fd7342ddaee88a29aa372ae3295f5257"}, - {file = "pyopencl-2023.1.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7bdf472b8e36f81145ac526d51f550ba539b765199da9da16732a222c7b85bee"}, - {file = "pyopencl-2023.1.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e99bb71267ce5223814177ff8c73e98057a70d20fc6555050d77d98b01bba5"}, - {file = "pyopencl-2023.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11d8cbe0d2121babf7daf0bcd6ded687c191c6d2effbac85c5421659fbc26947"}, - {file = "pyopencl-2023.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:08ebc3d5776ec2a8853c11234d605754bdf0d5af8322a08d558d661eb85c6fa3"}, - {file = "pyopencl-2023.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f199eff64be353f5badac62576d14cb40cc137c9f92f5260452de097dd9fe7a0"}, - {file = "pyopencl-2023.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:38a0a3c8389f44b51c0a916dc8e532d77ea37ab5a11f10e1ba97cc8f9a634695"}, - {file = "pyopencl-2023.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46a1158956a59e73a57e98acc681ff01a64574d0b3715634703437aa8b7c785c"}, - {file = "pyopencl-2023.1.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55f09e9d12a036830d71f60af9233ff493c83ff2f99b472baa1f779688c816b7"}, - {file = "pyopencl-2023.1.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:742fdb18bcc933f20b795c787fe513c69b83f074626bc62ff3c9cd1c8b243022"}, - {file = "pyopencl-2023.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4102eb3f5b9fe4b08c7900820a908cec3004e9a6990cc7202162ae46e07869d"}, - {file = "pyopencl-2023.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:36d79cd6445a86b4db7399488c301b49bda5fde6c1455c36b1ce58e03c690916"}, - {file = "pyopencl-2023.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4a561e42ee3030b2966e7dc5cc764e705d9ff1bb5aa1124fa7d6ba4009ebfb96"}, - {file = "pyopencl-2023.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:0f7889dce94dba10738225fabec929fa977bfe8777a64f5699f6f2fe2b00742c"}, - {file = "pyopencl-2023.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ab31b35875cecd2b1c10ac47ea06e224c5881cca942fba94387317357d73c0b9"}, - {file = "pyopencl-2023.1.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:230c63354fe6a18043e67042769ddc5e329002fb55fb99f692e4f5c8fcf3007c"}, - {file = "pyopencl-2023.1.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef091d4a4802b267b0aa5ec46c4ebc00fd664d9178ad9866b485006eeff180b4"}, - {file = "pyopencl-2023.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c11fc7445e21dcd97bd8f5534531ed7bbd09ded853b520157623f48fad5b739"}, - {file = "pyopencl-2023.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0b6a0ebbf67b2ef7098bdf3632177b71c7430883b2a48b2b09b84a02d8cbb4b0"}, - {file = "pyopencl-2023.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1767616f795c598531cd19d89f451db7e25393add300204e7d1a7dd2a017709f"}, - {file = "pyopencl-2023.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:8bbb02f230b969109bdf00f36e463fed1de6e1c70e088f2f2f9b41fab128f20c"}, - {file = "pyopencl-2023.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0e444320491744fe52e49f87674c931219a5be254a8a129175db61378f5b6f18"}, - {file = "pyopencl-2023.1.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0649a9d6249612e79cffef46618cccaaa9eac7b0c3f1833a3576ea0bd985d887"}, - {file = "pyopencl-2023.1.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f790dda26812cad5288fe1831158f55c48e6ede46ae4a37db66394645b07ef8e"}, - {file = "pyopencl-2023.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:571c6430c6fb046643040d4a6d99ee677e4c6c99b09577dbb51177001e93c21c"}, - {file = "pyopencl-2023.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0ca2d4f14e1fc716b1928679c3182595a4862f577fa0f4a5d8edf37ef8db059b"}, - {file = "pyopencl-2023.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6ac9e8e84dc11b82df51916cf41f34a9ca327adbaf9f4a03a8d1f4f1e1f35382"}, - {file = "pyopencl-2023.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:802e5eb27fd311af42133bb2da83b5777a84f5c7c11e0a4b8d1d50d265b22e37"}, - {file = "pyopencl-2023.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ae4b7f34aa56a4dc5ce5b4d795dc872f9a1aac66f15ded575aeabdfd15da0bc"}, - {file = "pyopencl-2023.1.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e3f5861de88a7d5054cfc8a0f78c42c7b7cd7c65c43a1426a72411111b024658"}, - {file = "pyopencl-2023.1.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c658eb9198235e8866afedb9b32bad4c6a4988c7dff2103e61794cd9ea261b2a"}, - {file = "pyopencl-2023.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d148b21de9f7aa542b576c09ba3c68106658c8a3429f41c0120c7cd4cb55970f"}, - {file = "pyopencl-2023.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:63be569b566ad627e7a1331db6cfda3eb82a2076872549f1c89f4e24ee12601a"}, - {file = "pyopencl-2023.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d61a6ca8c2d8f2d7bcf106abff6ac58cb79f335303b02b90b66591b25d1af4aa"}, - {file = "pyopencl-2023.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:daeff57a66c7a2be03345dd919507f2a2b2ed4ce64c3d8416fc01fa947807e59"}, - {file = "pyopencl-2023.1.4-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c059f15d71c680e35704650bc02d7026b5566687fd45ca9f4c789567d0731cfc"}, - {file = "pyopencl-2023.1.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38c1ab4ed770eb2b2f9c34bced444fc81e96dddd188848f028d36cd16fe9fcb9"}, - {file = "pyopencl-2023.1.4-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d195dad3d3a0473373bbf173671900d4519662824b5a81ced5b491cfae5c5e23"}, - {file = "pyopencl-2023.1.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c4917db2d0ec5ea7dd3c0cc66dc6a5acadc39a577a6b532293dde57ba3b23fb"}, - {file = "pyopencl-2023.1.4-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c926fb5886a561fe01be907575e396096a75fd35a2a6df5fc080c19959ae8c5c"}, - {file = "pyopencl-2023.1.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35fc3161b2f609018b6e1b22f4aa79fb571a388b61e90177c1d474975af15ce8"}, - {file = "pyopencl-2023.1.4.tar.gz", hash = "sha256:220174efca900e9d5de5aef2aa1b77a6f2550501de92b035a91013aeae4d4c5e"}, + {file = "pyopencl-2024.2.6-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:bb114056d04613c6ba7f92de4c8daa545dbdcca15379a06367d5a3780cf5930d"}, + {file = "pyopencl-2024.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c38d95bac4176e07865f8d750dee66958dced82ca22e3483898f2d43fcf13ae"}, + {file = "pyopencl-2024.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3e8c14ba292be4b9aef8c8f6011ab7344737239478e55076cc71e2f0d0b6a6a"}, + {file = "pyopencl-2024.2.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355b17304784b484e127978bd5fde58c7758734991aa637b579fea4686055b85"}, + {file = "pyopencl-2024.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:96912ca852ca590eb5334615a3d88017b164ef70ca5791605802f83144ffad3f"}, + {file = "pyopencl-2024.2.6-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:688bff1033fd21d420437986db04b8ab11543b23090c90da2963b4ed4fe94e82"}, + {file = "pyopencl-2024.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4750fc441cc599b17c2c7a654420bb17a9818a02fd1541031a2cb9f867ecc6ef"}, + {file = "pyopencl-2024.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb30fea4527db88e1c037712d4bf0bab44cfc2e38265925aaf6fc8c7efe79b9f"}, + {file = "pyopencl-2024.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ad333bfca7f074dd0cf616358408ea69a605e3cab3fdc4d782bcf8c0a78c630a"}, + {file = "pyopencl-2024.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:a538e9551dfacf24f6270bddd581be21abdb1bfbcf64e1b5ba67ff29493ba23d"}, + {file = "pyopencl-2024.2.6-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:a3218b1eafcad4918532aa75f2c9dc0b3491bcf2b602edcdd6e3a4e45a72c68a"}, + {file = "pyopencl-2024.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:30cce55b34bc0a2a4955f3fd37baf34da3969296191f4cd602fd62e320611606"}, + {file = "pyopencl-2024.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:630f48ef777479f1c82b3ad9b3d208abeca2639828defe1c6da01f4d8c8b1ae5"}, + {file = "pyopencl-2024.2.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:725a941be6be4377145f6b9a364221aae397c38b9d475086fa65401a34f39a82"}, + {file = "pyopencl-2024.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:ff7ed484ea950022dcc5ee79fde3c9d9cf6312aa94e010ed462c011062428326"}, + {file = "pyopencl-2024.2.6-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:bc491df0c62cf6d67bdac94bfd892ff4fceb5ec527efac096eeb84ae6cbcaae0"}, + {file = "pyopencl-2024.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:743fdae7648f916826d3dda02df6c4627b6dc3a923b95e658abb53f451418f10"}, + {file = "pyopencl-2024.2.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:175fad6fd79ec23d6822395d274838b42e06a3f4b4bb4f35bef4e9559b5f2767"}, + {file = "pyopencl-2024.2.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:114a2058dfaa70724f1cc5f985d2154e885819180e2f2e1c454d83c5a02d5593"}, + {file = "pyopencl-2024.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:554f529b04534ec80a71d10c41deacc26094b5095c5b850829a2717c86c024f6"}, + {file = "pyopencl-2024.2.6-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:fd06bf87b53b360a5b03ef9b31b730abadffdca5fbd6b6b78425cf3bf0883f90"}, + {file = "pyopencl-2024.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ac3d682d27203a5204769d5590164c482afa03b8434cec1f75d0cb805251c857"}, + {file = "pyopencl-2024.2.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f86d5473c1a564f038f7298c2e176dd28b36610569cdac5d3e9ef02f604d2549"}, + {file = "pyopencl-2024.2.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7f9be442abdfdfce5e1238aadfc23756ac2292dd081cd3d1a653d728397ede78"}, + {file = "pyopencl-2024.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:bb693a20b553453c7e3a2eb5f7a43e6d851644ba76a85ee8e185ece0ecf7933b"}, + {file = "pyopencl-2024.2.6.tar.gz", hash = "sha256:ceb9beeef0b6162e601c05922fede29b5094554a66eb473c610cabc14308ba82"}, ] [package.dependencies] numpy = "*" platformdirs = ">=2.2.0" -pytools = ">=2021.2.7" +pytools = ">=2024.1.5" [package.extras] -oclgrind = ["oclgrind-binary-distribution (>=18.3)"] -pocl = ["pocl-binary-distribution (>=1.2)"] +oclgrind = ["oclgrind_binary_distribution (>=18.3)"] +pocl = ["pocl_binary_distribution (>=1.2)"] test = ["Mako", "pytest (>=7.0.0)"] [[package]] @@ -6848,13 +6832,13 @@ files = [ [[package]] name = "pytools" -version = "2024.1.3" +version = "2024.1.5" description = "A collection of tools for Python" optional = false python-versions = "~=3.8" files = [ - {file = "pytools-2024.1.3-py2.py3-none-any.whl", hash = "sha256:2977a7e9580fac6260d1352ed7a69a12a0c59687f834e0ebaecaf1148eceb7f3"}, - {file = "pytools-2024.1.3.tar.gz", hash = "sha256:cc2db25666aa64094d3fb4532aa8a7deaa2da8edd7340fb270ed1807dcc75202"}, + {file = "pytools-2024.1.5-py2.py3-none-any.whl", hash = "sha256:dd2b4a1cbe078699742ab37ae3a94a81c5cc598c3247536d12e90588c39b0cc6"}, + {file = "pytools-2024.1.5.tar.gz", hash = "sha256:8c377bb1ffdcb5103301b8e7e94f01cbe36573a01e020434fea96291b1f1ac19"}, ] [package.dependencies] @@ -7966,4 +7950,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "1aebbaeb87fb971b11182abcd487743e3bc4f6ee3560923a0d8714cc3d3a4efc" +content-hash = "8ab43c0fd81c48afa1af652f8487d351444e286a7f43c11fb0148199d4cca1ee" diff --git a/pyproject.toml b/pyproject.toml index e1635728f..37dfd8e6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -165,8 +165,7 @@ pprofile = "*" polyline = "*" pre-commit = "*" pyautogui = "*" -pytools = "<=2024.1.3" # our pinned version of pyopencl use a broken version of pytools -pyopencl = "==2023.1.4" # 2024.1 is broken on arm64 +pyopencl = { version = "*", markers = "platform_machine != 'aarch64'" } # broken on arm64 pygame = "*" pywinctl = "*" pyprof2calltree = "*" From 4684651dc55dd0fb95fe33686ad519309f988bfd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 10 Jun 2024 19:45:03 -0700 Subject: [PATCH 202/220] test_onroad: update modeld proc name --- selfdrive/test/test_onroad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 75585e2f1..f80df5ac4 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -309,7 +309,7 @@ class TestOnroad: assert max(mems) - min(mems) <= 3.0 def test_gpu_usage(self): - assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.modeld.modeld"} + assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.model"} def test_camera_processing_time(self): result = "\n" From 5b51f039675edbbdfbeac72cd9c518450a85bc04 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 10 Jun 2024 19:55:41 -0700 Subject: [PATCH 203/220] Revert "Custom setproctitle (#32667)" This reverts commit 3365ed5effa48d34ffe0e2e9bbe9f6941336bed5. --- common/realtime.py | 6 +++--- common/tests/test_threadname.py | 8 -------- common/threadname.py | 19 ------------------- pyproject.toml | 1 + scripts/waste.py | 4 ++-- selfdrive/modeld/modeld.py | 12 ++++++------ system/manager/process.py | 4 ++-- 7 files changed, 14 insertions(+), 40 deletions(-) delete mode 100644 common/tests/test_threadname.py delete mode 100644 common/threadname.py diff --git a/common/realtime.py b/common/realtime.py index e7265406a..dd97ea3d7 100644 --- a/common/realtime.py +++ b/common/realtime.py @@ -4,7 +4,7 @@ import os import time from collections import deque -from openpilot.common.threadname import getthreadname +from setproctitle import getproctitle from openpilot.system.hardware import PC @@ -52,7 +52,7 @@ class Ratekeeper: self._print_delay_threshold = print_delay_threshold self._frame = 0 self._remaining = 0.0 - self._thread_name = getthreadname() + self._process_name = getproctitle() self._dts = deque([self._interval], maxlen=100) self._last_monitor_time = time.monotonic() @@ -87,7 +87,7 @@ class Ratekeeper: remaining = self._next_frame_time - time.monotonic() self._next_frame_time += self._interval if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold: - print(f"{self._thread_name} lagging by {-remaining * 1000:.2f} ms") + print(f"{self._process_name} lagging by {-remaining * 1000:.2f} ms") lagged = True self._frame += 1 self._remaining = remaining diff --git a/common/tests/test_threadname.py b/common/tests/test_threadname.py deleted file mode 100644 index 38e5e1d49..000000000 --- a/common/tests/test_threadname.py +++ /dev/null @@ -1,8 +0,0 @@ -from openpilot.common.threadname import setthreadname, getthreadname, LINUX - -class TestThreadName: - def test_set_get_threadname(self): - if LINUX: - name = 'TESTING' - setthreadname(name) - assert name == getthreadname() diff --git a/common/threadname.py b/common/threadname.py deleted file mode 100644 index 3db7a7d01..000000000 --- a/common/threadname.py +++ /dev/null @@ -1,19 +0,0 @@ -import ctypes -import os - -LINUX = os.name == 'posix' and os.uname().sysname == 'Linux' - -if LINUX: - libc = ctypes.CDLL('libc.so.6') - -def setthreadname(name: str) -> None: - if LINUX: - name = name[:15] + '\0' - libc.prctl(15, str.encode(name), 0, 0, 0) - -def getthreadname() -> str: - if LINUX: - name = ctypes.create_string_buffer(16) - libc.prctl(16, name) - return name.value.decode('utf-8') - return "" diff --git a/pyproject.toml b/pyproject.toml index 37dfd8e6f..01885c7ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -137,6 +137,7 @@ future-fstrings = "*" # these should be removed psutil = "*" timezonefinder = "*" # just used for nav ETA +setproctitle = "*" pycryptodome = "*" # used in updated/casync, panda, body, and a test [tool.poetry.group.dev.dependencies] diff --git a/scripts/waste.py b/scripts/waste.py index bf92710fe..0764ff77c 100755 --- a/scripts/waste.py +++ b/scripts/waste.py @@ -3,7 +3,7 @@ import os import time import numpy as np from multiprocessing import Process -from openpilot.common.threadname import setthreadname +from setproctitle import setproctitle def waste(core): os.sched_setaffinity(0, [core,]) @@ -16,7 +16,7 @@ def waste(core): j = 0 while 1: if (i % 100) == 0: - setthreadname("%3d: %8d" % (core, i)) + setproctitle("%3d: %8d" % (core, i)) lt = time.monotonic() print("%3d: %8d %f %.2f" % (core, i, lt-st, j)) st = lt diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index b037d1861..3ac80aad9 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -6,7 +6,7 @@ import numpy as np import cereal.messaging as messaging from cereal import car, log from pathlib import Path -from openpilot.common.threadname import setthreadname +from setproctitle import setproctitle from cereal.messaging import PubMaster, SubMaster from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.common.swaglog import cloudlog @@ -24,7 +24,7 @@ from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_ from openpilot.selfdrive.modeld.constants import ModelConstants from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext -THREAD_NAME = "selfdrive.modeld.modeld" +PROCESS_NAME = "selfdrive.modeld.modeld" SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') MODEL_PATHS = { @@ -114,9 +114,9 @@ class ModelState: def main(demo=False): cloudlog.warning("modeld init") - sentry.set_tag("daemon", THREAD_NAME) - cloudlog.bind(daemon=THREAD_NAME) - setthreadname(THREAD_NAME) + sentry.set_tag("daemon", PROCESS_NAME) + cloudlog.bind(daemon=PROCESS_NAME) + setproctitle(PROCESS_NAME) config_realtime_process(7, 54) cloudlog.warning("setting up CL context") @@ -286,7 +286,7 @@ if __name__ == "__main__": args = parser.parse_args() main(demo=args.demo) except KeyboardInterrupt: - cloudlog.warning(f"child {THREAD_NAME} got SIGINT") + cloudlog.warning(f"child {PROCESS_NAME} got SIGINT") except Exception: sentry.capture_exception() raise diff --git a/system/manager/process.py b/system/manager/process.py index 9214e417c..36f299ae6 100644 --- a/system/manager/process.py +++ b/system/manager/process.py @@ -8,7 +8,7 @@ from collections.abc import Callable, ValuesView from abc import ABC, abstractmethod from multiprocessing import Process -from openpilot.common.threadname import setthreadname +from setproctitle import setproctitle from cereal import car, log import cereal.messaging as messaging @@ -27,7 +27,7 @@ def launcher(proc: str, name: str) -> None: mod = importlib.import_module(proc) # rename the process - setthreadname(proc) + setproctitle(proc) # create new context since we forked messaging.context = messaging.Context() From 00388ca7958d7dd9b4d505927ee57df77bdb16d7 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 10 Jun 2024 19:55:48 -0700 Subject: [PATCH 204/220] Revert "test_onroad: update modeld proc name" This reverts commit 4684651dc55dd0fb95fe33686ad519309f988bfd. --- selfdrive/test/test_onroad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index f80df5ac4..75585e2f1 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -309,7 +309,7 @@ class TestOnroad: assert max(mems) - min(mems) <= 3.0 def test_gpu_usage(self): - assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.model"} + assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.modeld.modeld"} def test_camera_processing_time(self): result = "\n" From 3e332071e7c6b2ba975de301567e9d25e40d65b5 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 10 Jun 2024 21:52:36 -0700 Subject: [PATCH 205/220] update poetry lock --- poetry.lock | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index f4933887c..9ebc6d870 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohttp" @@ -2730,7 +2730,6 @@ optional = false python-versions = ">=3.6" files = [ {file = "opencv-python-4.10.0.82.tar.gz", hash = "sha256:dbc021eaa310c4145c47cd648cb973db69bb5780d6e635386cd53d3ea76bd2d5"}, - {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:5f78652339957ec24b80a782becfb32f822d2008a865512121fad8c3ce233e9a"}, {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:e6be19a0615aa8c4e0d34e0c7b133e26e386f4b7e9b557b69479104ab2c133ec"}, {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b49e530f7fd86f671514b39ffacdf5d14ceb073bc79d0de46bbb6b0cad78eaf"}, {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955c5ce8ac90c9e4636ad7f5c0d9c75b80abbe347182cfd09b0e3eec6e50472c"}, @@ -2749,7 +2748,6 @@ optional = false python-versions = ">=3.6" files = [ {file = "opencv-python-headless-4.10.0.82.tar.gz", hash = "sha256:de9e742c1b9540816fbd115b0b03841d41ed0c65566b0d7a5371f98b131b7e6d"}, - {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a09ed50ba21cc5bf5d436cb0e784ad09c692d6b1d1454252772f6c8f2c7b4088"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:977a5fd21e1fe0d3d2134887db4441f8725abeae95150126302f31fcd9f548fa"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4ec6755838b0be12510bfc9ffb014779c612418f11f4f7e6f505c36124a3aa"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a37fa5276967ecf6eb297295b16b28b7a2eb3b568ca0ee469fb1a5954de298"}, @@ -7303,6 +7301,106 @@ starlette = ["starlette (>=0.19.1)"] starlite = ["starlite (>=1.48)"] tornado = ["tornado (>=5)"] +[[package]] +name = "setproctitle" +version = "1.3.3" +description = "A Python module to customize the process title" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:897a73208da48db41e687225f355ce993167079eda1260ba5e13c4e53be7f754"}, + {file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c331e91a14ba4076f88c29c777ad6b58639530ed5b24b5564b5ed2fd7a95452"}, + {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbbd6c7de0771c84b4aa30e70b409565eb1fc13627a723ca6be774ed6b9d9fa3"}, + {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c05ac48ef16ee013b8a326c63e4610e2430dbec037ec5c5b58fcced550382b74"}, + {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1342f4fdb37f89d3e3c1c0a59d6ddbedbde838fff5c51178a7982993d238fe4f"}, + {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc74e84fdfa96821580fb5e9c0b0777c1c4779434ce16d3d62a9c4d8c710df39"}, + {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9617b676b95adb412bb69645d5b077d664b6882bb0d37bfdafbbb1b999568d85"}, + {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6a249415f5bb88b5e9e8c4db47f609e0bf0e20a75e8d744ea787f3092ba1f2d0"}, + {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:38da436a0aaace9add67b999eb6abe4b84397edf4a78ec28f264e5b4c9d53cd5"}, + {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:da0d57edd4c95bf221b2ebbaa061e65b1788f1544977288bdf95831b6e44e44d"}, + {file = "setproctitle-1.3.3-cp310-cp310-win32.whl", hash = "sha256:a1fcac43918b836ace25f69b1dca8c9395253ad8152b625064415b1d2f9be4fb"}, + {file = "setproctitle-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:200620c3b15388d7f3f97e0ae26599c0c378fdf07ae9ac5a13616e933cbd2086"}, + {file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:334f7ed39895d692f753a443102dd5fed180c571eb6a48b2a5b7f5b3564908c8"}, + {file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:950f6476d56ff7817a8fed4ab207727fc5260af83481b2a4b125f32844df513a"}, + {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:195c961f54a09eb2acabbfc90c413955cf16c6e2f8caa2adbf2237d1019c7dd8"}, + {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f05e66746bf9fe6a3397ec246fe481096664a9c97eb3fea6004735a4daf867fd"}, + {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5901a31012a40ec913265b64e48c2a4059278d9f4e6be628441482dd13fb8b5"}, + {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64286f8a995f2cd934082b398fc63fca7d5ffe31f0e27e75b3ca6b4efda4e353"}, + {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:184239903bbc6b813b1a8fc86394dc6ca7d20e2ebe6f69f716bec301e4b0199d"}, + {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:664698ae0013f986118064b6676d7dcd28fefd0d7d5a5ae9497cbc10cba48fa5"}, + {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e5119a211c2e98ff18b9908ba62a3bd0e3fabb02a29277a7232a6fb4b2560aa0"}, + {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:417de6b2e214e837827067048f61841f5d7fc27926f2e43954567094051aff18"}, + {file = "setproctitle-1.3.3-cp311-cp311-win32.whl", hash = "sha256:6a143b31d758296dc2f440175f6c8e0b5301ced3b0f477b84ca43cdcf7f2f476"}, + {file = "setproctitle-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a680d62c399fa4b44899094027ec9a1bdaf6f31c650e44183b50d4c4d0ccc085"}, + {file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d4460795a8a7a391e3567b902ec5bdf6c60a47d791c3b1d27080fc203d11c9dc"}, + {file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bdfd7254745bb737ca1384dee57e6523651892f0ea2a7344490e9caefcc35e64"}, + {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477d3da48e216d7fc04bddab67b0dcde633e19f484a146fd2a34bb0e9dbb4a1e"}, + {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ab2900d111e93aff5df9fddc64cf51ca4ef2c9f98702ce26524f1acc5a786ae7"}, + {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088b9efc62d5aa5d6edf6cba1cf0c81f4488b5ce1c0342a8b67ae39d64001120"}, + {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6d50252377db62d6a0bb82cc898089916457f2db2041e1d03ce7fadd4a07381"}, + {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:87e668f9561fd3a457ba189edfc9e37709261287b52293c115ae3487a24b92f6"}, + {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:287490eb90e7a0ddd22e74c89a92cc922389daa95babc833c08cf80c84c4df0a"}, + {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe1c49486109f72d502f8be569972e27f385fe632bd8895f4730df3c87d5ac8"}, + {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4a6ba2494a6449b1f477bd3e67935c2b7b0274f2f6dcd0f7c6aceae10c6c6ba3"}, + {file = "setproctitle-1.3.3-cp312-cp312-win32.whl", hash = "sha256:2df2b67e4b1d7498632e18c56722851ba4db5d6a0c91aaf0fd395111e51cdcf4"}, + {file = "setproctitle-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:f38d48abc121263f3b62943f84cbaede05749047e428409c2c199664feb6abc7"}, + {file = "setproctitle-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:816330675e3504ae4d9a2185c46b573105d2310c20b19ea2b4596a9460a4f674"}, + {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f960bc22d8d8e4ac886d1e2e21ccbd283adcf3c43136161c1ba0fa509088e0"}, + {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e6e7adff74796ef12753ff399491b8827f84f6c77659d71bd0b35870a17d8f"}, + {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53bc0d2358507596c22b02db079618451f3bd720755d88e3cccd840bafb4c41c"}, + {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad6d20f9541f5f6ac63df553b6d7a04f313947f550eab6a61aa758b45f0d5657"}, + {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c1c84beab776b0becaa368254801e57692ed749d935469ac10e2b9b825dbdd8e"}, + {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:507e8dc2891021350eaea40a44ddd887c9f006e6b599af8d64a505c0f718f170"}, + {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b1067647ac7aba0b44b591936118a22847bda3c507b0a42d74272256a7a798e9"}, + {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e71f6365744bf53714e8bd2522b3c9c1d83f52ffa6324bd7cbb4da707312cd8"}, + {file = "setproctitle-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:7f1d36a1e15a46e8ede4e953abb104fdbc0845a266ec0e99cc0492a4364f8c44"}, + {file = "setproctitle-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9a402881ec269d0cc9c354b149fc29f9ec1a1939a777f1c858cdb09c7a261df"}, + {file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ff814dea1e5c492a4980e3e7d094286077054e7ea116cbeda138819db194b2cd"}, + {file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:accb66d7b3ccb00d5cd11d8c6e07055a4568a24c95cf86109894dcc0c134cc89"}, + {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554eae5a5b28f02705b83a230e9d163d645c9a08914c0ad921df363a07cf39b1"}, + {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a911b26264dbe9e8066c7531c0591cfab27b464459c74385b276fe487ca91c12"}, + {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2982efe7640c4835f7355fdb4da313ad37fb3b40f5c69069912f8048f77b28c8"}, + {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df3f4274b80709d8bcab2f9a862973d453b308b97a0b423a501bcd93582852e3"}, + {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:af2c67ae4c795d1674a8d3ac1988676fa306bcfa1e23fddb5e0bd5f5635309ca"}, + {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:af4061f67fd7ec01624c5e3c21f6b7af2ef0e6bab7fbb43f209e6506c9ce0092"}, + {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:37a62cbe16d4c6294e84670b59cf7adcc73faafe6af07f8cb9adaf1f0e775b19"}, + {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a83ca086fbb017f0d87f240a8f9bbcf0809f3b754ee01cec928fff926542c450"}, + {file = "setproctitle-1.3.3-cp38-cp38-win32.whl", hash = "sha256:059f4ce86f8cc92e5860abfc43a1dceb21137b26a02373618d88f6b4b86ba9b2"}, + {file = "setproctitle-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ab92e51cd4a218208efee4c6d37db7368fdf182f6e7ff148fb295ecddf264287"}, + {file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7951820b77abe03d88b114b998867c0f99da03859e5ab2623d94690848d3e45"}, + {file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc94cf128676e8fac6503b37763adb378e2b6be1249d207630f83fc325d9b11"}, + {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f5d9027eeda64d353cf21a3ceb74bb1760bd534526c9214e19f052424b37e42"}, + {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e4a8104db15d3462e29d9946f26bed817a5b1d7a47eabca2d9dc2b995991503"}, + {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32c41ace41f344d317399efff4cffb133e709cec2ef09c99e7a13e9f3b9483c"}, + {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf16381c7bf7f963b58fb4daaa65684e10966ee14d26f5cc90f07049bfd8c1e"}, + {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e18b7bd0898398cc97ce2dfc83bb192a13a087ef6b2d5a8a36460311cb09e775"}, + {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69d565d20efe527bd8a9b92e7f299ae5e73b6c0470f3719bd66f3cd821e0d5bd"}, + {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ddedd300cd690a3b06e7eac90ed4452348b1348635777ce23d460d913b5b63c3"}, + {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:415bfcfd01d1fbf5cbd75004599ef167a533395955305f42220a585f64036081"}, + {file = "setproctitle-1.3.3-cp39-cp39-win32.whl", hash = "sha256:21112fcd2195d48f25760f0eafa7a76510871bbb3b750219310cf88b04456ae3"}, + {file = "setproctitle-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:5a740f05d0968a5a17da3d676ce6afefebeeeb5ce137510901bf6306ba8ee002"}, + {file = "setproctitle-1.3.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6b9e62ddb3db4b5205c0321dd69a406d8af9ee1693529d144e86bd43bcb4b6c0"}, + {file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3b99b338598de0bd6b2643bf8c343cf5ff70db3627af3ca427a5e1a1a90dd9"}, + {file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ae9a02766dad331deb06855fb7a6ca15daea333b3967e214de12cfae8f0ef5"}, + {file = "setproctitle-1.3.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:200ede6fd11233085ba9b764eb055a2a191fb4ffb950c68675ac53c874c22e20"}, + {file = "setproctitle-1.3.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0d3a953c50776751e80fe755a380a64cb14d61e8762bd43041ab3f8cc436092f"}, + {file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e08e232b78ba3ac6bc0d23ce9e2bee8fad2be391b7e2da834fc9a45129eb87"}, + {file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1da82c3e11284da4fcbf54957dafbf0655d2389cd3d54e4eaba636faf6d117a"}, + {file = "setproctitle-1.3.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:aeaa71fb9568ebe9b911ddb490c644fbd2006e8c940f21cb9a1e9425bd709574"}, + {file = "setproctitle-1.3.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:59335d000c6250c35989394661eb6287187854e94ac79ea22315469ee4f4c244"}, + {file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3ba57029c9c50ecaf0c92bb127224cc2ea9fda057b5d99d3f348c9ec2855ad3"}, + {file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d876d355c53d975c2ef9c4f2487c8f83dad6aeaaee1b6571453cb0ee992f55f6"}, + {file = "setproctitle-1.3.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:224602f0939e6fb9d5dd881be1229d485f3257b540f8a900d4271a2c2aa4e5f4"}, + {file = "setproctitle-1.3.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d7f27e0268af2d7503386e0e6be87fb9b6657afd96f5726b733837121146750d"}, + {file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5e7266498cd31a4572378c61920af9f6b4676a73c299fce8ba93afd694f8ae7"}, + {file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33c5609ad51cd99d388e55651b19148ea99727516132fb44680e1f28dd0d1de9"}, + {file = "setproctitle-1.3.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:eae8988e78192fd1a3245a6f4f382390b61bce6cfcc93f3809726e4c885fa68d"}, + {file = "setproctitle-1.3.3.tar.gz", hash = "sha256:c913e151e7ea01567837ff037a23ca8740192880198b7fbb90b16d181607caae"}, +] + +[package.extras] +test = ["pytest"] + [[package]] name = "setuptools" version = "70.0.0" @@ -7950,4 +8048,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "8ab43c0fd81c48afa1af652f8487d351444e286a7f43c11fb0148199d4cca1ee" +content-hash = "8f581b34273378265dba62166f3cd5abbb931b9375d95fb260dcaf192cfacc86" From 965415135ac7db4c67ea248ac52535eac537f3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 10 Jun 2024 22:29:17 -0700 Subject: [PATCH 206/220] Long control: Double delay is super complicated (#32694) * Double delay is super complicated * No more upper bound * DEAD * Update ref --- cereal/car.capnp | 4 ++-- selfdrive/car/gm/interface.py | 2 +- selfdrive/car/honda/interface.py | 2 +- selfdrive/car/hyundai/interface.py | 3 +-- selfdrive/car/interfaces.py | 3 +-- selfdrive/car/tesla/interface.py | 2 +- selfdrive/controls/lib/longcontrol.py | 12 +++--------- selfdrive/test/process_replay/ref_commit | 2 +- 8 files changed, 11 insertions(+), 19 deletions(-) diff --git a/cereal/car.capnp b/cereal/car.capnp index 8d76f0ead..7f3f64c91 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -490,8 +490,7 @@ struct CarParams { startingState @70 :Bool; # Does this car make use of special starting state steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds - longitudinalActuatorDelayLowerBound @61 :Float32; # Gas/Brake actuator delay in seconds, lower bound - longitudinalActuatorDelayUpperBound @58 :Float32; # Gas/Brake actuator delay in seconds, upper bound + longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control? carVin @38 :Text; # VIN number queried during fingerprinting dashcamOnly @41: Bool; @@ -703,4 +702,5 @@ struct CarParams { brakeMaxVDEPRECATED @16 :List(Float32); directAccelControlDEPRECATED @30 :Bool; maxSteeringAngleDegDEPRECATED @54 :Float32; + longitudinalActuatorDelayLowerBoundDEPRECATEDDEPRECATED @61 :Float32; } diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 358bc9e5b..2e194b12f 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -148,7 +148,7 @@ class CarInterface(CarInterfaceBase): ret.steerLimitTimer = 0.4 ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz - ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking + ret.longitudinalActuatorDelay = 0.5 # large delay to initially start braking if candidate == CAR.CHEVROLET_VOLT: ret.lateralTuning.pid.kpBP = [0., 40.] diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 2026c385c..43a4454b9 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -74,7 +74,7 @@ class CarInterface(CarInterfaceBase): if candidate in HONDA_BOSCH: ret.longitudinalTuning.kpV = [0.25] ret.longitudinalTuning.kiV = [0.05] - ret.longitudinalActuatorDelayUpperBound = 0.5 # s + ret.longitudinalActuatorDelay = 0.5 # s if candidate in HONDA_BOSCH_RADARLESS: ret.stopAccel = CarControllerParams.BOSCH_ACCEL_MIN # stock uses -4.0 m/s^2 once stopped but limited by safety model else: diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 22c54bce6..0ba4dcb5e 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -94,8 +94,7 @@ class CarInterface(CarInterfaceBase): ret.startingState = True ret.vEgoStarting = 0.1 ret.startAccel = 1.0 - ret.longitudinalActuatorDelayLowerBound = 0.5 - ret.longitudinalActuatorDelayUpperBound = 0.5 + ret.longitudinalActuatorDelay = 0.5 # *** feature detection *** if candidate in CANFD_CAR: diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index a3572238b..5eac6062a 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -210,8 +210,7 @@ class CarInterfaceBase(ABC): ret.longitudinalTuning.kiBP = [0.] ret.longitudinalTuning.kiV = [1.] # TODO estimate car specific lag, use .15s for now - ret.longitudinalActuatorDelayLowerBound = 0.15 - ret.longitudinalActuatorDelayUpperBound = 0.15 + ret.longitudinalActuatorDelay = 0.15 ret.steerLimitTimer = 1.0 return ret diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py index e03985926..09de10b54 100755 --- a/selfdrive/car/tesla/interface.py +++ b/selfdrive/car/tesla/interface.py @@ -23,7 +23,7 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kpV = [0] ret.longitudinalTuning.kiBP = [0] ret.longitudinalTuning.kiV = [0] - ret.longitudinalActuatorDelayUpperBound = 0.5 # s + ret.longitudinalActuatorDelay = 0.5 # s ret.radarTimeStep = (1.0 / 8) # 8Hz # Check if we have messages on an auxiliary panda, and that 0x2bf (DAS_control) is present on the AP powertrain bus diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index d08ee0503..a619c4763 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -73,16 +73,10 @@ class LongControl: v_target_now = interp(t_since_plan, CONTROL_N_T_IDX, speeds) a_target_now = interp(t_since_plan, CONTROL_N_T_IDX, long_plan.accels) - v_target_lower = interp(self.CP.longitudinalActuatorDelayLowerBound + t_since_plan, CONTROL_N_T_IDX, speeds) - a_target_lower = 2 * (v_target_lower - v_target_now) / self.CP.longitudinalActuatorDelayLowerBound - a_target_now + v_target = interp(self.CP.longitudinalActuatorDelay + t_since_plan, CONTROL_N_T_IDX, speeds) + a_target = 2 * (v_target - v_target_now) / self.CP.longitudinalActuatorDelay - a_target_now - v_target_upper = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan, CONTROL_N_T_IDX, speeds) - a_target_upper = 2 * (v_target_upper - v_target_now) / self.CP.longitudinalActuatorDelayUpperBound - a_target_now - - v_target = min(v_target_lower, v_target_upper) - a_target = min(a_target_lower, a_target_upper) - - v_target_1sec = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan + 1.0, CONTROL_N_T_IDX, speeds) + v_target_1sec = interp(self.CP.longitudinalActuatorDelay + t_since_plan + 1.0, CONTROL_N_T_IDX, speeds) else: v_target = 0.0 v_target_now = 0.0 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 70178b8ea..eaf61ccb8 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -e536df5586a71b22baa789dc584d7eab67f1fbbb +0ba779ec9f624872b1d038acb15095b726ff8983 From 4581f6c36812c535b3e63b258296ed920fb486e6 Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Tue, 11 Jun 2024 17:57:56 +0300 Subject: [PATCH 207/220] compressed_vipc.py fixes (#32699) * Restored VISION_STREAM_* to original index order * Register exit handler --- tools/camerastream/compressed_vipc.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/camerastream/compressed_vipc.py b/tools/camerastream/compressed_vipc.py index ea427816e..6c27e861f 100755 --- a/tools/camerastream/compressed_vipc.py +++ b/tools/camerastream/compressed_vipc.py @@ -6,6 +6,7 @@ import argparse import numpy as np import multiprocessing import time +import signal import cereal.messaging as messaging from msgq.visionipc import VisionIpcServer, VisionStreamType @@ -18,8 +19,8 @@ V4L2_BUF_FLAG_KEYFRAME = 8 ENCODE_SOCKETS = { VisionStreamType.VISION_STREAM_ROAD: "roadEncodeData", - VisionStreamType.VISION_STREAM_WIDE_ROAD: "wideRoadEncodeData", VisionStreamType.VISION_STREAM_DRIVER: "driverEncodeData", + VisionStreamType.VISION_STREAM_WIDE_ROAD: "wideRoadEncodeData", } def decoder(addr, vipc_server, vst, nvidia, W, H, debug=False): @@ -147,10 +148,14 @@ if __name__ == "__main__": vision_streams = [ VisionStreamType.VISION_STREAM_ROAD, - VisionStreamType.VISION_STREAM_WIDE_ROAD, VisionStreamType.VISION_STREAM_DRIVER, + VisionStreamType.VISION_STREAM_WIDE_ROAD, ] vsts = [vision_streams[int(x)] for x in args.cams.split(",")] cvipc = CompressedVipc(args.addr, vsts, args.nvidia, debug=(not args.silent)) + + # register exit handler + signal.signal(signal.SIGINT, lambda sig, frame: cvipc.kill()) + cvipc.join() From 6fa5d7c3b575faf90e4edadd35e8f2f8cfbe42a5 Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:03:47 -0700 Subject: [PATCH 208/220] Update `.gitignore` with recommended VSCode config (#32696) * add .vscode into .gitignore * use recommended gitignore config for .vscode --- .gitignore | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.gitignore b/.gitignore index 370335e6a..f067893c7 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,22 @@ build/ poetry.toml Pipfile + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide \ No newline at end of file From c2be8a55533c7d9efb0a7b1510a839289bda3584 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 11 Jun 2024 11:29:39 -0700 Subject: [PATCH 209/220] little more release blacklist --- release/release_files.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/release/release_files.py b/release/release_files.py index 2d279e97a..031b51737 100755 --- a/release/release_files.py +++ b/release/release_files.py @@ -33,16 +33,22 @@ blacklist = [ "matlab.*.md", - ".git$", # for submodules ".git/", ".github/", ".devcontainer/", "Darwin/", ".vscode", - # no LFS + # common things + "LICENSE", + "Dockerfile", + ".pre-commit", + + # no LFS or submodules in release ".lfsconfig", ".gitattributes", + ".git$", + ".gitmodules", ] # gets you through the blacklist From 148eaf8fa6c9b23cdd346e926f58fad61f79ff1d Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Tue, 11 Jun 2024 13:45:15 -0700 Subject: [PATCH 210/220] Update to Python 3.12 (#32548) * 3.12 * pprofile is broken * use modified metadrivepy3-12 * 0.3.0 metadrive * add metadrive/commaai git dependency * metadrive git set * pin sounddevice 0.4.6 * datetime.utcnow() deprecation * poetry lock * make datetime not aware * poetry lock * pin pytools * google_crc32c wheel * unpin sounddevice * clean metadrive * use python crc * mypy * 3.12.4 * allow python3.11 * test * no pip * poetry * better * better * merge * remove * try * test * try this * snok * python * simpler * setuptools * lower * try * try * work? * ubuntu deps * ubuntu * try * remove * move * remove this * names * Update .github/workflows/tools_tests.yaml Co-authored-by: Adeeb Shihadeh * python<4 * <3.13 --------- Co-authored-by: Adeeb Shihadeh Co-authored-by: Maxime Desroches --- .github/workflows/tools_tests.yaml | 19 + .python-version | 2 +- Dockerfile.openpilot_base | 4 +- common/api/__init__.py | 4 +- poetry.lock | 2726 ++++++++++---------- pyproject.toml | 7 +- selfdrive/test/test_updated.py | 2 +- system/athena/registration.py | 4 +- system/manager/manager.py | 2 +- system/qcomgpsd/qcomgpsd.py | 2 +- system/qcomgpsd/tests/test_qcomgpsd.py | 2 +- system/statsd.py | 2 +- system/ubloxd/pigeond.py | 4 +- system/updated/updated.py | 10 +- system/webrtc/tests/test_stream_session.py | 1 + system/webrtc/tests/test_webrtcd.py | 1 + system/webrtc/webrtcd.py | 1 + tools/lib/azure_container.py | 4 +- 18 files changed, 1442 insertions(+), 1355 deletions(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index ba597f700..c2f7d86e6 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -39,6 +39,25 @@ jobs: source selfdrive/test/setup_vsound.sh && \ CI=1 pytest tools/sim/tests/test_metadrive_bridge.py" + test_python311: + name: test python3.11 support + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - name: Installing ubuntu dependencies + run: INSTALL_EXTRA_PACKAGES=no tools/install_ubuntu_dependencies.sh + - name: Installing python + uses: actions/setup-python@v5 + with: + python-version: '3.11.4' + - name: Installing pip + run: pip install pip==24.0 + - name: Installing poetry + run: pip install poetry==1.7.0 + - name: Installing python dependencies + run: poetry install --no-cache --no-root + devcontainer: name: devcontainer runs-on: ubuntu-latest diff --git a/.python-version b/.python-version index 0c7d5f5f5..455808f8e 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.11.4 +3.12.4 diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index 0789a39c3..6818195d7 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -64,7 +64,7 @@ RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER $USER ENV POETRY_VIRTUALENVS_CREATE=false -ENV PYENV_VERSION=3.11.4 +ENV PYENV_VERSION=3.12.4 ENV PYENV_ROOT="/home/$USER/pyenv" ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" @@ -76,7 +76,7 @@ RUN cd /tmp && \ rm -rf /tmp/* && \ rm -rf /home/$USER/.cache && \ find /home/$USER/pyenv -type d -name ".git" | xargs rm -rf && \ - rm -rf /home/$USER/pyenv/versions/3.11.4/lib/python3.11/test + rm -rf /home/$USER/pyenv/versions/3.12.4/lib/python3.12/test USER root RUN sudo git config --global --add safe.directory /tmp/openpilot diff --git a/common/api/__init__.py b/common/api/__init__.py index f3a7d8384..ac231400a 100644 --- a/common/api/__init__.py +++ b/common/api/__init__.py @@ -1,7 +1,7 @@ import jwt import os import requests -from datetime import datetime, timedelta +from datetime import datetime, timedelta, UTC from openpilot.system.hardware.hw import Paths from openpilot.system.version import get_version @@ -23,7 +23,7 @@ class Api: return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params) def get_token(self, expiry_hours=1): - now = datetime.utcnow() + now = datetime.now(UTC).replace(tzinfo=None) payload = { 'identity': self.dongle_id, 'nbf': now, diff --git a/poetry.lock b/poetry.lock index 9ebc6d870..f4925a17f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "aiohttp" @@ -2234,7 +2234,7 @@ name = "metadrive-simulator" version = "0.4.2.3" description = "An open-ended driving simulator with infinite scenes" optional = false -python-versions = ">=3.6, <3.12" +python-versions = ">=3.6, <4" files = [] develop = false @@ -2246,7 +2246,7 @@ lxml = "*" matplotlib = "*" numpy = ">=1.21.6" opencv-python = "*" -panda3d = "1.10.13" +panda3d = "1.10.14" panda3d-gltf = "0.13" pandas = "*" pillow = "*" @@ -2269,9 +2269,9 @@ ros = ["zmq"] [package.source] type = "git" -url = "https://github.com/metadriverse/metadrive.git" -reference = "233a3a1698be7038ec3dd050ca10b547b4b3324c" -resolved_reference = "233a3a1698be7038ec3dd050ca10b547b4b3324c" +url = "https://github.com/commaai/metadrive.git" +reference = "python3.12" +resolved_reference = "0823c7491a1ab870bcd53d10a41e985a3ad1b968" [[package]] name = "mouseinfo" @@ -2322,22 +2322,22 @@ tests = ["pytest (>=4.6)"] [[package]] name = "msal" -version = "1.28.0" +version = "1.28.1" description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = ">=3.7" files = [ - {file = "msal-1.28.0-py3-none-any.whl", hash = "sha256:3064f80221a21cd535ad8c3fafbb3a3582cd9c7e9af0bb789ae14f726a0ca99b"}, - {file = "msal-1.28.0.tar.gz", hash = "sha256:80bbabe34567cb734efd2ec1869b2d98195c927455369d8077b3c542088c5c9d"}, + {file = "msal-1.28.1-py3-none-any.whl", hash = "sha256:563c2d70de77a2ca9786aab84cb4e133a38a6897e6676774edc23d610bfc9e7b"}, + {file = "msal-1.28.1.tar.gz", hash = "sha256:d72bbfe2d5c2f2555f4bc6205be4450ddfd12976610dd9a16a9ab0f05c68b64d"}, ] [package.dependencies] -cryptography = ">=0.6,<45" +cryptography = ">=2.5,<45" PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} requests = ">=2.0.0,<3" [package.extras] -broker = ["pymsalruntime (>=0.13.2,<0.15)"] +broker = ["pymsalruntime (>=0.13.2,<0.17)"] [[package]] name = "msal-extensions" @@ -2730,6 +2730,7 @@ optional = false python-versions = ">=3.6" files = [ {file = "opencv-python-4.10.0.82.tar.gz", hash = "sha256:dbc021eaa310c4145c47cd648cb973db69bb5780d6e635386cd53d3ea76bd2d5"}, + {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:5f78652339957ec24b80a782becfb32f822d2008a865512121fad8c3ce233e9a"}, {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:e6be19a0615aa8c4e0d34e0c7b133e26e386f4b7e9b557b69479104ab2c133ec"}, {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b49e530f7fd86f671514b39ffacdf5d14ceb073bc79d0de46bbb6b0cad78eaf"}, {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955c5ce8ac90c9e4636ad7f5c0d9c75b80abbe347182cfd09b0e3eec6e50472c"}, @@ -2738,7 +2739,10 @@ files = [ ] [package.dependencies] -numpy = {version = ">=1.23.5", markers = "python_version >= \"3.11\""} +numpy = [ + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, +] [[package]] name = "opencv-python-headless" @@ -2748,6 +2752,7 @@ optional = false python-versions = ">=3.6" files = [ {file = "opencv-python-headless-4.10.0.82.tar.gz", hash = "sha256:de9e742c1b9540816fbd115b0b03841d41ed0c65566b0d7a5371f98b131b7e6d"}, + {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a09ed50ba21cc5bf5d436cb0e784ad09c692d6b1d1454252772f6c8f2c7b4088"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:977a5fd21e1fe0d3d2134887db4441f8725abeae95150126302f31fcd9f548fa"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4ec6755838b0be12510bfc9ffb014779c612418f11f4f7e6f505c36124a3aa"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a37fa5276967ecf6eb297295b16b28b7a2eb3b568ca0ee469fb1a5954de298"}, @@ -2756,7 +2761,10 @@ files = [ ] [package.dependencies] -numpy = {version = ">=1.23.5", markers = "python_version >= \"3.11\""} +numpy = [ + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, +] [[package]] name = "packaging" @@ -2771,87 +2779,79 @@ files = [ [[package]] name = "panda3d" -version = "1.10.13" +version = "1.10.14" description = "Panda3D is a framework for 3D rendering and game development for Python and C++ programs." optional = false python-versions = "*" files = [ - {file = "panda3d-1.10.13-cp27-cp27m-macosx_10_6_i386.whl", hash = "sha256:697555595a01c3f5468d49a1ee1f05f57df31e63a251a9ba47a8f534faf0ba15"}, - {file = "panda3d-1.10.13-cp27-cp27m-macosx_10_6_x86_64.whl", hash = "sha256:ccfa288a3575c2996ad7f409f14e8ceb8541a9b1b39bb0162e30f73b1fa0884b"}, - {file = "panda3d-1.10.13-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b2d9870c044e8ac0f6a65e96b6814d122a560adfe045b6ad500bc107aa361726"}, - {file = "panda3d-1.10.13-cp27-cp27m-win32.whl", hash = "sha256:1c35d8676caa1a2c11f91592a6abd8cf18c3ac9496437082e79b4b0671603857"}, - {file = "panda3d-1.10.13-cp27-cp27m-win_amd64.whl", hash = "sha256:f7423bf86d3369f5f7578ec70199f6674ba9f81f80f3eea83d0b27ec7d2522fc"}, - {file = "panda3d-1.10.13-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:017c2a9d40c024de3d68359926dfbb0fef51e219bd2bc6d021464051bba9c80e"}, - {file = "panda3d-1.10.13-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8028fd67c0fc524eae3b7dbfba0b433e3d811e386ba51adbccf1f95a79ef32cb"}, - {file = "panda3d-1.10.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50427b08d6dcbe91e95c719b3eb32abe5e806fe265a2cfa66f5b704d22776409"}, - {file = "panda3d-1.10.13-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:597332377b09cb97a1699fed2514c99bcc4241924ce7c21e7577685164576afc"}, - {file = "panda3d-1.10.13-cp310-cp310-manylinux2010_i686.whl", hash = "sha256:fd64c7995fc9d3f07100d4fe225498106cf3851f77bd54be3131193965768041"}, - {file = "panda3d-1.10.13-cp310-cp310-manylinux2010_x86_64.whl", hash = "sha256:acbcdf204ff75abe75b66af5c025b2f42e7777c2acb6cb17375cf7c66751a062"}, - {file = "panda3d-1.10.13-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:73905d348b486675706ac53e454b34138a3ab12faa1058720b6bf40110973be1"}, - {file = "panda3d-1.10.13-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:870da8fb7654f60d04ff5a85c75e80f89f14406c7f8812f4916f5781d1caeb25"}, - {file = "panda3d-1.10.13-cp310-cp310-win32.whl", hash = "sha256:5f75c18323ba3d36236e4756a98cba68268b0dd4ac6e4b889d87904a65b4fbbc"}, - {file = "panda3d-1.10.13-cp310-cp310-win_amd64.whl", hash = "sha256:7d8a28b10167990d55ac696275b08b21b06fb35e7f5f64d482c9b76410373e96"}, - {file = "panda3d-1.10.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:52f4b9014235ef5abbd6b5714389dc887ad45828316c42c83af53937179360d8"}, - {file = "panda3d-1.10.13-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:d4cbd179bf442fab572bd9a486f866147ce38579e78dd5c01e1f59887bea64b8"}, - {file = "panda3d-1.10.13-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b4419faa2ca1747fccca8e76ca37700c1e011a38a8bad5be104fc703d1216bc3"}, - {file = "panda3d-1.10.13-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:68e9e215c4192ca14ab1304be79f86657f43d6d663b3dbe3af209caf8eb9793c"}, - {file = "panda3d-1.10.13-cp311-cp311-win32.whl", hash = "sha256:3a4df33d18fad4bfbc70907e6f7d6ef27f20ef4d0f3dfb3c17d7e4d46abd78f5"}, - {file = "panda3d-1.10.13-cp311-cp311-win_amd64.whl", hash = "sha256:55efa8ae9a04260358257e94f29c506e338af0197c5b75dae29b0112dfdd67ac"}, - {file = "panda3d-1.10.13-cp34-cp34m-macosx_10_6_i386.whl", hash = "sha256:f6f016870c22ba0a250958fb09c49843eb17d5620dd1bfa86f38dfd200af9401"}, - {file = "panda3d-1.10.13-cp34-cp34m-macosx_10_6_x86_64.whl", hash = "sha256:fd901d3a822824a9b288392ba6ade77143c8024e208d3ce73a554e364f03cadb"}, - {file = "panda3d-1.10.13-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:4e46ad41febad38f57e4948912f9642838f5bff196c7c336194904e13165172d"}, - {file = "panda3d-1.10.13-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:dc7cd2ee0bd8ca9f7e957b2672f2d8ee1132cd6ddc2f8287d9579efa682b8b01"}, - {file = "panda3d-1.10.13-cp34-cp34m-win32.whl", hash = "sha256:190bd5c58184cae94cf158900106215f20d579f84a1b7ce1474bfbcb797b4a0b"}, - {file = "panda3d-1.10.13-cp34-cp34m-win_amd64.whl", hash = "sha256:372ac3770ada07f1c92848f36f13359c2c00f3eefa525b0b3cad4804ec64c6ca"}, - {file = "panda3d-1.10.13-cp35-cp35m-macosx_10_6_i386.whl", hash = "sha256:496147561f15a738a9a212a69ce3dda340ff1d8ae8bfd0501507945a94153bd8"}, - {file = "panda3d-1.10.13-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:b78acc42a2ee7006dd9618d52ea2657e03d6e39fe4d8c9b4c48342a1d866bbfd"}, - {file = "panda3d-1.10.13-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:35bb1a847a9012e218b1fa768632e4e52644e87ac8daf08fbd4c49feff0672b4"}, - {file = "panda3d-1.10.13-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:fdd564b7f154a78310d6d08920a9a6f405d9e7e9f74fd4b53c9eb73a007d2dea"}, - {file = "panda3d-1.10.13-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:730e5c6b8fb20448478ac1af117cc4aadd8e9dfa2558b5f9e89a69f83ce5f284"}, - {file = "panda3d-1.10.13-cp35-cp35m-win32.whl", hash = "sha256:4da16ba0a2c9615c9d68afdee47681454ece21bf252039078b4662dca856b8f0"}, - {file = "panda3d-1.10.13-cp35-cp35m-win_amd64.whl", hash = "sha256:526a1db71fcf1a2b4eaafb36642c710eb5d2425c9ec96d1afb7fadde4b1af619"}, - {file = "panda3d-1.10.13-cp36-cp36m-macosx_10_6_i386.whl", hash = "sha256:3298dcbfc8a9e87565d35129e3942ba0d076c6c7a504b32f656ccea39b876eb4"}, - {file = "panda3d-1.10.13-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:36c55f8aeb1b4eb305c3f76e0704678bdad80e37d46db71d3f723cbe4aa1eecf"}, - {file = "panda3d-1.10.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e4a7549e3583cd009a1a3ce33f84ed68f9ffd5b3f34f67606af6e8d6dafa32d5"}, - {file = "panda3d-1.10.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1711c7edc7620a8ca2f4fee2e6e448522726678cc5318d59de00d0d1e3f35ea6"}, - {file = "panda3d-1.10.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4c9da46324813e23b1108c0c3906460aa73a052c2934643a0e4a406a1a93dc03"}, - {file = "panda3d-1.10.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:c1c77315e2a998f9173fe86d3af63b0affc1e7399a03226881d39ff758cc6b2d"}, - {file = "panda3d-1.10.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:017fdcb16c1a786f12b45a39bd33666423689a94060d1fc6135539d826146eb3"}, - {file = "panda3d-1.10.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b112c8d0ecdc85b14a93f6bae57dbb31043a3bbf1cd3ce3905b143e76ffbfc84"}, - {file = "panda3d-1.10.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:1e18194c78b9b519da885620ddcc7f6709e139645f665f08309b7eff58a5a0ee"}, - {file = "panda3d-1.10.13-cp36-cp36m-win32.whl", hash = "sha256:8eda3bd2402d75fb52962051c157f9495742f1f85c49c38b9bc47091fc0639b0"}, - {file = "panda3d-1.10.13-cp36-cp36m-win_amd64.whl", hash = "sha256:39652709ae0b8167aaf253edacc78898109cce96e872d9e7be33257dd5f98485"}, - {file = "panda3d-1.10.13-cp37-cp37m-macosx_10_6_i386.whl", hash = "sha256:d8c9668f257da744f301bf83ff44b2cdc8bd635e732fadf2f9b09200655cd3e4"}, - {file = "panda3d-1.10.13-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:ece8eb268a0be1fa45b6ef1e6cfa1ae89f25ee926e866893baf8bf391708c02d"}, - {file = "panda3d-1.10.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:508df5128cb63163eeee8f3cb6cb2984aefe473ee7e8e328f25a8bf205d54de2"}, - {file = "panda3d-1.10.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:d8a7beb7b88f1fc4ec0061be28018f6da1511783eb6a9911442d2a3435e50f7d"}, - {file = "panda3d-1.10.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a1cae74294394aa4afe93414c799798be77777e5bba77a45368bb1973ca65d2e"}, - {file = "panda3d-1.10.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:94d59874924de7b6765d427ea833ffea38fbb1b72a35679f81ef76c34ddf584d"}, - {file = "panda3d-1.10.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:23806bb1b289ad31f1ec1c206ddbdddd484ecdf8fdb09a4f89bc1c61af6b19ba"}, - {file = "panda3d-1.10.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6013bf0049bb6b30b0ff17ca5dc6bde621b553f0d1815481ced186ba710aa3b6"}, - {file = "panda3d-1.10.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:e208d1ac385acb48e24f557badfdb6244b0122bc25511c512b893c55ccb1bed3"}, - {file = "panda3d-1.10.13-cp37-cp37m-win32.whl", hash = "sha256:1dea56806643077e863abd8735e7056019ffd2b935990670607b44f996ef8456"}, - {file = "panda3d-1.10.13-cp37-cp37m-win_amd64.whl", hash = "sha256:08f7729e3b13d7417a07b14a3532ee93e4c50293de45392d9783038dcc24cfd4"}, - {file = "panda3d-1.10.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8099b2bc211a98ff1d26a91c26d126d538896a59ad29d4de50dea19ccaf31b1b"}, - {file = "panda3d-1.10.13-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:bc41bd97e3a2dd04d0f664ae0ea1a7677ce7c6a718ab4d3b3ff79ef06f0a22c9"}, - {file = "panda3d-1.10.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2027d6d8ac86db0989fbcbafa9f4f1e1a4de79a94f087325e43ccf9e65da12a9"}, - {file = "panda3d-1.10.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:dbfccaf3ff52b4e5de66d33bf06aa489af43cb139367b77fa6bc79ac774d23dc"}, - {file = "panda3d-1.10.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c0785bfa3ad3e87f837433737679dce5e0d1a33accbfcb0dcb0393ce3a7a68f2"}, - {file = "panda3d-1.10.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:e384ed11490d479095cbad2f27ad61f536ca75aeb702557ce83b67381d4448bd"}, - {file = "panda3d-1.10.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8cd5e47e18f56dd6dab7ed1acb21c07f356b7220db72b820f02363050ee3bdfd"}, - {file = "panda3d-1.10.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:094ccf20cdfb2a2f44cde56a1ab9a1287a09cfd33dd4fe094cb255aaacfb678f"}, - {file = "panda3d-1.10.13-cp38-cp38-win32.whl", hash = "sha256:83c39308ee95951616dd5ab1e2ee730853fca9b4331a7c9ea9d92c9af3321aa9"}, - {file = "panda3d-1.10.13-cp38-cp38-win_amd64.whl", hash = "sha256:2ae1bd477a8882c80bdb6d63d6738ae2c4c335f0d88af592a051a9705434c75d"}, - {file = "panda3d-1.10.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:df904a0ca374fd7667727a3d3743c386e913e6e80b8efe67fe0fcd01f904e4c3"}, - {file = "panda3d-1.10.13-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:db8cc33163112722cdf313d06939ff30b260c7a5e2a404b38bddc7558e6e8a26"}, - {file = "panda3d-1.10.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:029d7c698114da30d0d5ecd57e0c92423d319848e4197e6a86ac54b9ae43c424"}, - {file = "panda3d-1.10.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4927f23e8c1469e6a17c3f05a81ac0c6fa7c23b2d39bffee5277ecabfb2da10f"}, - {file = "panda3d-1.10.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2683fc8ad1e98a98ae692dbd82896c3f055743351e7a61a8ecd22557ddef643e"}, - {file = "panda3d-1.10.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:809881853087d36211f380245499778a4838f2f1748a4f8d90546debed294f8b"}, - {file = "panda3d-1.10.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:05be45eeddc81fb4879b0e6b206422b810e2de0f6639ab04522f660270eb202a"}, - {file = "panda3d-1.10.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:a00823d1ae2490dba0643109f10e7347b15e6c2554de0b1bed0a085950fa6ed0"}, - {file = "panda3d-1.10.13-cp39-cp39-win32.whl", hash = "sha256:2d5d3e2160d8fa667ef548171695be84e7de25f51817ae31c61cf2e869a2f6c6"}, - {file = "panda3d-1.10.13-cp39-cp39-win_amd64.whl", hash = "sha256:839d8b2724a149d56a31f621c6397a1fed597a7dacee478922c711426160990e"}, + {file = "panda3d-1.10.14-cp27-cp27m-macosx_10_6_i386.whl", hash = "sha256:cf47bcbe5d6270107e80f5f18b88186cc40de83e4e90c86e7e516d2289a68dd1"}, + {file = "panda3d-1.10.14-cp27-cp27m-macosx_10_6_x86_64.whl", hash = "sha256:c371a3df183b2e382cb6dbf07efb744b05bdb0d89101457f350ea9a7a9a481f1"}, + {file = "panda3d-1.10.14-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ba49c6f213a5f0287e4cbdb66714cdf3b4aa5bdbe4e1a55034e74d0dda9f0250"}, + {file = "panda3d-1.10.14-cp27-cp27m-win32.whl", hash = "sha256:adb54216a9234f3736693d49032783d7fb8952a15510f1397f992a5c94cdf897"}, + {file = "panda3d-1.10.14-cp27-cp27m-win_amd64.whl", hash = "sha256:f94dd5f557166b6571969883bd2ffd3a555e8ac720f0f3e347d2081222bc0997"}, + {file = "panda3d-1.10.14-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c98d2143755e52d4be3b474b932207c830e473aa0e10052831bc82784f1dd17c"}, + {file = "panda3d-1.10.14-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:b7f8c6524e1381bd28a15e5e2ed7aaba8ed3b6fa29d4ea5a4b215c4639b49438"}, + {file = "panda3d-1.10.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b0e2aacb148b7033c08929bbf89bb497c2bed1811aa9f7e5efc167dbf57c90ae"}, + {file = "panda3d-1.10.14-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:2c60139139654a51dab213ce1c9f67abd73153fc9e0a0514c0758741b2d2bd96"}, + {file = "panda3d-1.10.14-cp310-cp310-manylinux2010_i686.whl", hash = "sha256:f5da02fb5735294193eb1794ecbe619f20f87712f1b2c5d6e4d1a269f652ebeb"}, + {file = "panda3d-1.10.14-cp310-cp310-manylinux2010_x86_64.whl", hash = "sha256:d6a65b1930e144d5901cdd20d2779dc157897a730f0c9674692d61ad50e31213"}, + {file = "panda3d-1.10.14-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:182a309537cd76c514b9f4d0dfd54bc9cb35d06a32234084bab6f3f0b0db3985"}, + {file = "panda3d-1.10.14-cp310-cp310-win32.whl", hash = "sha256:2a2b872a180ed84ff337147d6d46c14aceccbcfd1149135ba57e15136350d87f"}, + {file = "panda3d-1.10.14-cp310-cp310-win_amd64.whl", hash = "sha256:385d12a1f0924e91a39ebd6053104712a1acd91e089638d292b533e36f402c48"}, + {file = "panda3d-1.10.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54b8ef9fe3684960a2c7d47b0d63c0354c17bc516795e59db6c1e5bda8c16c1c"}, + {file = "panda3d-1.10.14-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:93414675894b18eea8d27edc1bbd1dc719eae207d45ec263d47195504bc4705f"}, + {file = "panda3d-1.10.14-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:d1bc0d926f90c8fa14a1587fa9dbe5f89a4eda8c9684fa183a8eaa35fc8e891a"}, + {file = "panda3d-1.10.14-cp311-cp311-win32.whl", hash = "sha256:1039340a4a7965fe4c3e904edb4fff691584df435a154fecccf534587cd07a34"}, + {file = "panda3d-1.10.14-cp311-cp311-win_amd64.whl", hash = "sha256:1ddf01040b9c5497fb8659e3c5ef793a26c869cfdfb1b75e6d04d6fba0c03b73"}, + {file = "panda3d-1.10.14-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1bfbcee77779f12ecce6a3d5a856e573b25d6343f8c4b107e814d9702e70a65d"}, + {file = "panda3d-1.10.14-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:bc6540c5559d7e14a8992eff7de0157b7c42406b7ba221941ed224289496841c"}, + {file = "panda3d-1.10.14-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:143daab1ce6bedcba711ea3f6cab0ebe5082f22c5f43e7178fadd2dd01209da7"}, + {file = "panda3d-1.10.14-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:3c4399a286a142de7ff86f9356d7e526bbbd38892d7f7d39fecb5c33064972bc"}, + {file = "panda3d-1.10.14-cp312-cp312-win32.whl", hash = "sha256:e92e0dd907e2af33085a2c31ca2263dc8023b1b7bc70ce1b9fbc84631e130e51"}, + {file = "panda3d-1.10.14-cp312-cp312-win_amd64.whl", hash = "sha256:a5f2defd822d38848f8ae1956115adcb6cc7f464f03a67e73681cc72df125ef4"}, + {file = "panda3d-1.10.14-cp34-cp34m-macosx_10_6_i386.whl", hash = "sha256:84ca5855e03173f521a2b4edc84e62ad5ffb31e9454bd809efb8e71a5c32df4f"}, + {file = "panda3d-1.10.14-cp34-cp34m-macosx_10_6_x86_64.whl", hash = "sha256:9082e3d66a653589ffab7c5bd7a50eb46ab168104e08a86c77b58bbd77030d50"}, + {file = "panda3d-1.10.14-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:f1a46ca8427ffb9267b3951af81f6774b7259b7e8f89210af6366b208e5762e6"}, + {file = "panda3d-1.10.14-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:c23694788696d7bfe291ced98dd87e57532a23f821e71f7b2d0c2004a4648c8f"}, + {file = "panda3d-1.10.14-cp34-cp34m-win32.whl", hash = "sha256:f14455c459730f396e524d8b9e62875438481e1dc7dfd2083e9522a3bad45f28"}, + {file = "panda3d-1.10.14-cp34-cp34m-win_amd64.whl", hash = "sha256:110a33b20f15aa6333c8e72e30bcf0dc9afaef809a325d247bb7470de3942dae"}, + {file = "panda3d-1.10.14-cp35-cp35m-macosx_10_6_i386.whl", hash = "sha256:d91e37d43242d5132886c3850aa4a2f3ee7401de2360cb8313616b45ab78ecba"}, + {file = "panda3d-1.10.14-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:f4bcf78223df3c13e9a627a25856c91bdbf28f75b021630e5ca37a961eeabb27"}, + {file = "panda3d-1.10.14-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:e0a7a1d7cbe10474cad720898b384d642dcd3d7a07b3dbe09154107a5651be49"}, + {file = "panda3d-1.10.14-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:78404da82a5d93641b0f2a89790cad235b087e7e2e37bbe83c995e99495635cd"}, + {file = "panda3d-1.10.14-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aa1381f4c06b789b8a725185773397b0c7a2508eeb8156874537c07171e5cb99"}, + {file = "panda3d-1.10.14-cp35-cp35m-win32.whl", hash = "sha256:8a497dd7401b50fa372664c724f1cb949b8d8bc3ed6d9b6433af19086bcf9325"}, + {file = "panda3d-1.10.14-cp35-cp35m-win_amd64.whl", hash = "sha256:293c5441e4f2720da480abdb3c99e55e96a7616d8867ac9c7b94526694a5812e"}, + {file = "panda3d-1.10.14-cp36-cp36m-macosx_10_6_i386.whl", hash = "sha256:15083e9c82d884c279bca897576ed91848323f951617f7bbb43d2dba32e6d662"}, + {file = "panda3d-1.10.14-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:b8a20828a45a9215f7ecb59baec18a79adda56ad1b25eb99b9958d26d8ab2a40"}, + {file = "panda3d-1.10.14-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d4c555a5c47ffcaaed518c52b3bb9d5729a5dc4492f51e8a46b076ca54adcae0"}, + {file = "panda3d-1.10.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0c43a4dfd6b12323359439ea7c60e8fbf84ff0aa75abaccd5179cc6b27baa2b7"}, + {file = "panda3d-1.10.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:06a4595f1737170d316829b451cbfb01a130918a04481b1f217212c485c64586"}, + {file = "panda3d-1.10.14-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:24d2a38f9068f868ac23101a8601d88f3c137ededed2be222d5e711a4b114467"}, + {file = "panda3d-1.10.14-cp36-cp36m-win32.whl", hash = "sha256:d7d722fb5a62531e62f6b98db2b3e399deddde945f84c954aefac73989c75e4c"}, + {file = "panda3d-1.10.14-cp36-cp36m-win_amd64.whl", hash = "sha256:7d17fe989aaed3f35a7992742a4c4536936fb0a70a87d4625b92f185f0318c45"}, + {file = "panda3d-1.10.14-cp37-cp37m-macosx_10_6_i386.whl", hash = "sha256:0ab75f828daef54678e9f2a15bccfe4e7b090991ee025689be324194266fd82e"}, + {file = "panda3d-1.10.14-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:f04af7a7becaf30c0c256a0177a7493ab91247ea5a2798345b2df2ec71aeff23"}, + {file = "panda3d-1.10.14-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d41579867cb2998f4273bdece282c641dac6f40ca2e713dafa3fb9ce3ef12162"}, + {file = "panda3d-1.10.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4db1b920d501d3524e92467a21ecb08cc0063566a681991cc683f2070068f128"}, + {file = "panda3d-1.10.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:db28161d1f40adf0b0998f7064ac784e49a2f2ec3bb04810c2757ba938c7d2cf"}, + {file = "panda3d-1.10.14-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:0cbdbc41229fa7d075925a716477e7a8d1a17a2523fc88e97fa010c4e0706442"}, + {file = "panda3d-1.10.14-cp37-cp37m-win32.whl", hash = "sha256:145cd28de41261e0ac2bc24323417f8b21623f48de0bb7a9e0d70ff386c34c84"}, + {file = "panda3d-1.10.14-cp37-cp37m-win_amd64.whl", hash = "sha256:fadb6eb4106dc3fecea81a1e81186b3cc3ee0019d0b5435273113a18aec2352c"}, + {file = "panda3d-1.10.14-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a61c973d8d58305a502d05a82dc3ec6cf2b5e01ada7151a83415c51a959ff774"}, + {file = "panda3d-1.10.14-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:3e82b2f904efb9f7f78dbf6d88bc5ebc83c5c0fbc9e477a8ef2b154bd7935591"}, + {file = "panda3d-1.10.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:96d1ce3483a51ec5aebc43f3e30e552deacb660606d2b36e86ed3a9756e3eccf"}, + {file = "panda3d-1.10.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b658d75a5342ff175703ce780e8b383da438ff68ea941d0e5dff68c5189d38ec"}, + {file = "panda3d-1.10.14-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:3e564c44d879b01d01a7fcdc03977affcf3b1dabcf2d6e5c678e06b9de8855ac"}, + {file = "panda3d-1.10.14-cp38-cp38-win32.whl", hash = "sha256:06007592951730b52852771e98b306b3c1de9dc51abf0bab183c3ec3ac404131"}, + {file = "panda3d-1.10.14-cp38-cp38-win_amd64.whl", hash = "sha256:b05713b5acfcfcbf1dc87c19b1d5babf926d21f83b3772180e7a5de83f45b454"}, + {file = "panda3d-1.10.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d55c7d52bd07e54a16219bb88a7cf34a5b9e7c720dce585e9de8427cc54d9dd2"}, + {file = "panda3d-1.10.14-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:39abf9330ebcfcff07c29ebcf397cf43c2e5be6c148cf45a0a025d3297c43289"}, + {file = "panda3d-1.10.14-cp39-cp39-manylinux1_i686.whl", hash = "sha256:0f69c7232713f50a552b00ada4cbb03780bb97ec1ddb640e5162df61d1b26a2b"}, + {file = "panda3d-1.10.14-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:9dda6736e8c180fa9caab70aa9461d7042b74764f73e4d2c59fe560751989341"}, + {file = "panda3d-1.10.14-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:a91ab520fa8bd206460f0b7acfa6329440d72669048bac3eab4bb4d8dcd09991"}, + {file = "panda3d-1.10.14-cp39-cp39-win32.whl", hash = "sha256:2de074b0a3e0f243e4c1fba0376a26489d585cc71fd79986de274e282e3913d8"}, + {file = "panda3d-1.10.14-cp39-cp39-win_amd64.whl", hash = "sha256:356c55c25c2227bb2cf20a9613410c470f4e9de887543ec8b3765c848af4bff0"}, ] [[package]] @@ -2926,7 +2926,10 @@ files = [ ] [package.dependencies] -numpy = {version = ">=1.23.2", markers = "python_version == \"3.11\""} +numpy = [ + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, +] python-dateutil = ">=2.8.2" pytz = ">=2020.1" tzdata = ">=2022.7" @@ -3121,16 +3124,6 @@ docs = ["sphinx (>=1.7.1)"] redis = ["redis"] tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)", "types-redis"] -[[package]] -name = "pprofile" -version = "2.1.0" -description = "Line-granularity, thread-aware deterministic and statistic pure-python profiler" -optional = false -python-versions = "*" -files = [ - {file = "pprofile-2.1.0.tar.gz", hash = "sha256:b2bb56603dadf40c0bc0f61621f22c20e41638425f729945d9b7f8e4ae8cdd4a"}, -] - [[package]] name = "pre-commit" version = "3.7.1" @@ -3630,2780 +3623,2853 @@ files = [ [[package]] name = "pyobjc" -version = "10.3" +version = "10.3.1" description = "Python<->ObjC Interoperability Module" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-10.3-py3-none-any.whl", hash = "sha256:80068513b43c4a7950d41931f2fb53599ddfefd7e3961976cb8a65a01d2bb2d7"}, - {file = "pyobjc-10.3.tar.gz", hash = "sha256:4af8a73bf5d73fc62f6cceb8826d6fc86db63017bf75450140a4fa7ec263db6b"}, + {file = "pyobjc-10.3.1-py3-none-any.whl", hash = "sha256:dfa9ff44a353b9d0bf1245c25c94d1eee6d0cb26d9c5433bbcd67a265f7654ae"}, + {file = "pyobjc-10.3.1.tar.gz", hash = "sha256:476dd5c72394e4cfcdac6dfd756839011a0159353247f45e3e07cc0b3536c9d4"}, ] [package.dependencies] -pyobjc-core = "10.3" -pyobjc-framework-Accessibility = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-Accounts = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-AddressBook = "10.3" -pyobjc-framework-AdServices = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-AdSupport = {version = "10.3", markers = "platform_release >= \"18.0\""} -pyobjc-framework-AppleScriptKit = "10.3" -pyobjc-framework-AppleScriptObjC = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-ApplicationServices = "10.3" -pyobjc-framework-AppTrackingTransparency = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-AudioVideoBridging = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-AuthenticationServices = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-AutomaticAssessmentConfiguration = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-Automator = "10.3" -pyobjc-framework-AVFoundation = {version = "10.3", markers = "platform_release >= \"11.0\""} -pyobjc-framework-AVKit = {version = "10.3", markers = "platform_release >= \"13.0\""} -pyobjc-framework-AVRouting = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-BackgroundAssets = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-BrowserEngineKit = {version = "10.3", markers = "platform_release >= \"23.4\""} -pyobjc-framework-BusinessChat = {version = "10.3", markers = "platform_release >= \"18.0\""} -pyobjc-framework-CalendarStore = {version = "10.3", markers = "platform_release >= \"9.0\""} -pyobjc-framework-CallKit = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-CFNetwork = "10.3" -pyobjc-framework-Cinematic = {version = "10.3", markers = "platform_release >= \"23.0\""} -pyobjc-framework-ClassKit = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-CloudKit = {version = "10.3", markers = "platform_release >= \"14.0\""} -pyobjc-framework-Cocoa = "10.3" -pyobjc-framework-Collaboration = {version = "10.3", markers = "platform_release >= \"9.0\""} -pyobjc-framework-ColorSync = {version = "10.3", markers = "platform_release >= \"17.0\""} -pyobjc-framework-Contacts = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-ContactsUI = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-CoreAudio = "10.3" -pyobjc-framework-CoreAudioKit = "10.3" -pyobjc-framework-CoreBluetooth = {version = "10.3", markers = "platform_release >= \"14.0\""} -pyobjc-framework-CoreData = "10.3" -pyobjc-framework-CoreHaptics = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-CoreLocation = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-CoreMedia = {version = "10.3", markers = "platform_release >= \"11.0\""} -pyobjc-framework-CoreMediaIO = {version = "10.3", markers = "platform_release >= \"11.0\""} -pyobjc-framework-CoreMIDI = "10.3" -pyobjc-framework-CoreML = {version = "10.3", markers = "platform_release >= \"17.0\""} -pyobjc-framework-CoreMotion = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-CoreServices = "10.3" -pyobjc-framework-CoreSpotlight = {version = "10.3", markers = "platform_release >= \"17.0\""} -pyobjc-framework-CoreText = "10.3" -pyobjc-framework-CoreWLAN = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-CryptoTokenKit = {version = "10.3", markers = "platform_release >= \"14.0\""} -pyobjc-framework-DataDetection = {version = "10.3", markers = "platform_release >= \"21.0\""} -pyobjc-framework-DeviceCheck = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-DictionaryServices = {version = "10.3", markers = "platform_release >= \"9.0\""} -pyobjc-framework-DiscRecording = "10.3" -pyobjc-framework-DiscRecordingUI = "10.3" -pyobjc-framework-DiskArbitration = "10.3" -pyobjc-framework-DVDPlayback = "10.3" -pyobjc-framework-EventKit = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-ExceptionHandling = "10.3" -pyobjc-framework-ExecutionPolicy = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-ExtensionKit = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-ExternalAccessory = {version = "10.3", markers = "platform_release >= \"17.0\""} -pyobjc-framework-FileProvider = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-FileProviderUI = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-FinderSync = {version = "10.3", markers = "platform_release >= \"14.0\""} -pyobjc-framework-FSEvents = {version = "10.3", markers = "platform_release >= \"9.0\""} -pyobjc-framework-GameCenter = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-GameController = {version = "10.3", markers = "platform_release >= \"13.0\""} -pyobjc-framework-GameKit = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-GameplayKit = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-HealthKit = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-ImageCaptureCore = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-InputMethodKit = {version = "10.3", markers = "platform_release >= \"9.0\""} -pyobjc-framework-InstallerPlugins = "10.3" -pyobjc-framework-InstantMessage = {version = "10.3", markers = "platform_release >= \"9.0\""} -pyobjc-framework-Intents = {version = "10.3", markers = "platform_release >= \"16.0\""} -pyobjc-framework-IntentsUI = {version = "10.3", markers = "platform_release >= \"21.0\""} -pyobjc-framework-IOBluetooth = "10.3" -pyobjc-framework-IOBluetoothUI = "10.3" -pyobjc-framework-IOSurface = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-iTunesLibrary = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-KernelManagement = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-LatentSemanticMapping = "10.3" -pyobjc-framework-LaunchServices = "10.3" -pyobjc-framework-libdispatch = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-libxpc = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-LinkPresentation = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-LocalAuthentication = {version = "10.3", markers = "platform_release >= \"14.0\""} -pyobjc-framework-LocalAuthenticationEmbeddedUI = {version = "10.3", markers = "platform_release >= \"21.0\""} -pyobjc-framework-MailKit = {version = "10.3", markers = "platform_release >= \"21.0\""} -pyobjc-framework-MapKit = {version = "10.3", markers = "platform_release >= \"13.0\""} -pyobjc-framework-MediaAccessibility = {version = "10.3", markers = "platform_release >= \"13.0\""} -pyobjc-framework-MediaLibrary = {version = "10.3", markers = "platform_release >= \"13.0\""} -pyobjc-framework-MediaPlayer = {version = "10.3", markers = "platform_release >= \"16.0\""} -pyobjc-framework-MediaToolbox = {version = "10.3", markers = "platform_release >= \"13.0\""} -pyobjc-framework-Metal = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-MetalFX = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-MetalKit = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-MetalPerformanceShaders = {version = "10.3", markers = "platform_release >= \"17.0\""} -pyobjc-framework-MetalPerformanceShadersGraph = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-MetricKit = {version = "10.3", markers = "platform_release >= \"21.0\""} -pyobjc-framework-MLCompute = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-ModelIO = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-MultipeerConnectivity = {version = "10.3", markers = "platform_release >= \"14.0\""} -pyobjc-framework-NaturalLanguage = {version = "10.3", markers = "platform_release >= \"18.0\""} -pyobjc-framework-NetFS = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-Network = {version = "10.3", markers = "platform_release >= \"18.0\""} -pyobjc-framework-NetworkExtension = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-NotificationCenter = {version = "10.3", markers = "platform_release >= \"14.0\""} -pyobjc-framework-OpenDirectory = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-OSAKit = "10.3" -pyobjc-framework-OSLog = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-PassKit = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-PencilKit = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-PHASE = {version = "10.3", markers = "platform_release >= \"21.0\""} -pyobjc-framework-Photos = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-PhotosUI = {version = "10.3", markers = "platform_release >= \"15.0\""} -pyobjc-framework-PreferencePanes = "10.3" -pyobjc-framework-PubSub = {version = "10.3", markers = "platform_release >= \"9.0\" and platform_release < \"18.0\""} -pyobjc-framework-PushKit = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-Quartz = "10.3" -pyobjc-framework-QuickLookThumbnailing = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-ReplayKit = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-SafariServices = {version = "10.3", markers = "platform_release >= \"16.0\""} -pyobjc-framework-SafetyKit = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-SceneKit = {version = "10.3", markers = "platform_release >= \"11.0\""} -pyobjc-framework-ScreenCaptureKit = {version = "10.3", markers = "platform_release >= \"21.4\""} -pyobjc-framework-ScreenSaver = "10.3" -pyobjc-framework-ScreenTime = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-ScriptingBridge = {version = "10.3", markers = "platform_release >= \"9.0\""} -pyobjc-framework-SearchKit = "10.3" -pyobjc-framework-Security = "10.3" -pyobjc-framework-SecurityFoundation = "10.3" -pyobjc-framework-SecurityInterface = "10.3" -pyobjc-framework-SensitiveContentAnalysis = {version = "10.3", markers = "platform_release >= \"23.0\""} -pyobjc-framework-ServiceManagement = {version = "10.3", markers = "platform_release >= \"10.0\""} -pyobjc-framework-SharedWithYou = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-SharedWithYouCore = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-ShazamKit = {version = "10.3", markers = "platform_release >= \"21.0\""} -pyobjc-framework-Social = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-SoundAnalysis = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-Speech = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-SpriteKit = {version = "10.3", markers = "platform_release >= \"13.0\""} -pyobjc-framework-StoreKit = {version = "10.3", markers = "platform_release >= \"11.0\""} -pyobjc-framework-Symbols = {version = "10.3", markers = "platform_release >= \"23.0\""} -pyobjc-framework-SyncServices = "10.3" -pyobjc-framework-SystemConfiguration = "10.3" -pyobjc-framework-SystemExtensions = {version = "10.3", markers = "platform_release >= \"19.0\""} -pyobjc-framework-ThreadNetwork = {version = "10.3", markers = "platform_release >= \"22.0\""} -pyobjc-framework-UniformTypeIdentifiers = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-UserNotifications = {version = "10.3", markers = "platform_release >= \"18.0\""} -pyobjc-framework-UserNotificationsUI = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-VideoSubscriberAccount = {version = "10.3", markers = "platform_release >= \"18.0\""} -pyobjc-framework-VideoToolbox = {version = "10.3", markers = "platform_release >= \"12.0\""} -pyobjc-framework-Virtualization = {version = "10.3", markers = "platform_release >= \"20.0\""} -pyobjc-framework-Vision = {version = "10.3", markers = "platform_release >= \"17.0\""} -pyobjc-framework-WebKit = "10.3" +pyobjc-core = "10.3.1" +pyobjc-framework-Accessibility = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-Accounts = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-AddressBook = "10.3.1" +pyobjc-framework-AdServices = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-AdSupport = {version = "10.3.1", markers = "platform_release >= \"18.0\""} +pyobjc-framework-AppleScriptKit = "10.3.1" +pyobjc-framework-AppleScriptObjC = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-ApplicationServices = "10.3.1" +pyobjc-framework-AppTrackingTransparency = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-AudioVideoBridging = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-AuthenticationServices = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-AutomaticAssessmentConfiguration = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-Automator = "10.3.1" +pyobjc-framework-AVFoundation = {version = "10.3.1", markers = "platform_release >= \"11.0\""} +pyobjc-framework-AVKit = {version = "10.3.1", markers = "platform_release >= \"13.0\""} +pyobjc-framework-AVRouting = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-BackgroundAssets = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-BrowserEngineKit = {version = "10.3.1", markers = "platform_release >= \"23.4\""} +pyobjc-framework-BusinessChat = {version = "10.3.1", markers = "platform_release >= \"18.0\""} +pyobjc-framework-CalendarStore = {version = "10.3.1", markers = "platform_release >= \"9.0\""} +pyobjc-framework-CallKit = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-CFNetwork = "10.3.1" +pyobjc-framework-Cinematic = {version = "10.3.1", markers = "platform_release >= \"23.0\""} +pyobjc-framework-ClassKit = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-CloudKit = {version = "10.3.1", markers = "platform_release >= \"14.0\""} +pyobjc-framework-Cocoa = "10.3.1" +pyobjc-framework-Collaboration = {version = "10.3.1", markers = "platform_release >= \"9.0\""} +pyobjc-framework-ColorSync = {version = "10.3.1", markers = "platform_release >= \"17.0\""} +pyobjc-framework-Contacts = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-ContactsUI = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-CoreAudio = "10.3.1" +pyobjc-framework-CoreAudioKit = "10.3.1" +pyobjc-framework-CoreBluetooth = {version = "10.3.1", markers = "platform_release >= \"14.0\""} +pyobjc-framework-CoreData = "10.3.1" +pyobjc-framework-CoreHaptics = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-CoreLocation = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-CoreMedia = {version = "10.3.1", markers = "platform_release >= \"11.0\""} +pyobjc-framework-CoreMediaIO = {version = "10.3.1", markers = "platform_release >= \"11.0\""} +pyobjc-framework-CoreMIDI = "10.3.1" +pyobjc-framework-CoreML = {version = "10.3.1", markers = "platform_release >= \"17.0\""} +pyobjc-framework-CoreMotion = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-CoreServices = "10.3.1" +pyobjc-framework-CoreSpotlight = {version = "10.3.1", markers = "platform_release >= \"17.0\""} +pyobjc-framework-CoreText = "10.3.1" +pyobjc-framework-CoreWLAN = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-CryptoTokenKit = {version = "10.3.1", markers = "platform_release >= \"14.0\""} +pyobjc-framework-DataDetection = {version = "10.3.1", markers = "platform_release >= \"21.0\""} +pyobjc-framework-DeviceCheck = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-DictionaryServices = {version = "10.3.1", markers = "platform_release >= \"9.0\""} +pyobjc-framework-DiscRecording = "10.3.1" +pyobjc-framework-DiscRecordingUI = "10.3.1" +pyobjc-framework-DiskArbitration = "10.3.1" +pyobjc-framework-DVDPlayback = "10.3.1" +pyobjc-framework-EventKit = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-ExceptionHandling = "10.3.1" +pyobjc-framework-ExecutionPolicy = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-ExtensionKit = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-ExternalAccessory = {version = "10.3.1", markers = "platform_release >= \"17.0\""} +pyobjc-framework-FileProvider = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-FileProviderUI = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-FinderSync = {version = "10.3.1", markers = "platform_release >= \"14.0\""} +pyobjc-framework-FSEvents = {version = "10.3.1", markers = "platform_release >= \"9.0\""} +pyobjc-framework-GameCenter = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-GameController = {version = "10.3.1", markers = "platform_release >= \"13.0\""} +pyobjc-framework-GameKit = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-GameplayKit = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-HealthKit = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-ImageCaptureCore = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-InputMethodKit = {version = "10.3.1", markers = "platform_release >= \"9.0\""} +pyobjc-framework-InstallerPlugins = "10.3.1" +pyobjc-framework-InstantMessage = {version = "10.3.1", markers = "platform_release >= \"9.0\""} +pyobjc-framework-Intents = {version = "10.3.1", markers = "platform_release >= \"16.0\""} +pyobjc-framework-IntentsUI = {version = "10.3.1", markers = "platform_release >= \"21.0\""} +pyobjc-framework-IOBluetooth = "10.3.1" +pyobjc-framework-IOBluetoothUI = "10.3.1" +pyobjc-framework-IOSurface = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-iTunesLibrary = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-KernelManagement = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-LatentSemanticMapping = "10.3.1" +pyobjc-framework-LaunchServices = "10.3.1" +pyobjc-framework-libdispatch = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-libxpc = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-LinkPresentation = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-LocalAuthentication = {version = "10.3.1", markers = "platform_release >= \"14.0\""} +pyobjc-framework-LocalAuthenticationEmbeddedUI = {version = "10.3.1", markers = "platform_release >= \"21.0\""} +pyobjc-framework-MailKit = {version = "10.3.1", markers = "platform_release >= \"21.0\""} +pyobjc-framework-MapKit = {version = "10.3.1", markers = "platform_release >= \"13.0\""} +pyobjc-framework-MediaAccessibility = {version = "10.3.1", markers = "platform_release >= \"13.0\""} +pyobjc-framework-MediaLibrary = {version = "10.3.1", markers = "platform_release >= \"13.0\""} +pyobjc-framework-MediaPlayer = {version = "10.3.1", markers = "platform_release >= \"16.0\""} +pyobjc-framework-MediaToolbox = {version = "10.3.1", markers = "platform_release >= \"13.0\""} +pyobjc-framework-Metal = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-MetalFX = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-MetalKit = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-MetalPerformanceShaders = {version = "10.3.1", markers = "platform_release >= \"17.0\""} +pyobjc-framework-MetalPerformanceShadersGraph = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-MetricKit = {version = "10.3.1", markers = "platform_release >= \"21.0\""} +pyobjc-framework-MLCompute = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-ModelIO = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-MultipeerConnectivity = {version = "10.3.1", markers = "platform_release >= \"14.0\""} +pyobjc-framework-NaturalLanguage = {version = "10.3.1", markers = "platform_release >= \"18.0\""} +pyobjc-framework-NetFS = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-Network = {version = "10.3.1", markers = "platform_release >= \"18.0\""} +pyobjc-framework-NetworkExtension = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-NotificationCenter = {version = "10.3.1", markers = "platform_release >= \"14.0\""} +pyobjc-framework-OpenDirectory = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-OSAKit = "10.3.1" +pyobjc-framework-OSLog = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-PassKit = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-PencilKit = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-PHASE = {version = "10.3.1", markers = "platform_release >= \"21.0\""} +pyobjc-framework-Photos = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-PhotosUI = {version = "10.3.1", markers = "platform_release >= \"15.0\""} +pyobjc-framework-PreferencePanes = "10.3.1" +pyobjc-framework-PubSub = {version = "10.3.1", markers = "platform_release >= \"9.0\" and platform_release < \"18.0\""} +pyobjc-framework-PushKit = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-Quartz = "10.3.1" +pyobjc-framework-QuickLookThumbnailing = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-ReplayKit = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-SafariServices = {version = "10.3.1", markers = "platform_release >= \"16.0\""} +pyobjc-framework-SafetyKit = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-SceneKit = {version = "10.3.1", markers = "platform_release >= \"11.0\""} +pyobjc-framework-ScreenCaptureKit = {version = "10.3.1", markers = "platform_release >= \"21.4\""} +pyobjc-framework-ScreenSaver = "10.3.1" +pyobjc-framework-ScreenTime = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-ScriptingBridge = {version = "10.3.1", markers = "platform_release >= \"9.0\""} +pyobjc-framework-SearchKit = "10.3.1" +pyobjc-framework-Security = "10.3.1" +pyobjc-framework-SecurityFoundation = "10.3.1" +pyobjc-framework-SecurityInterface = "10.3.1" +pyobjc-framework-SensitiveContentAnalysis = {version = "10.3.1", markers = "platform_release >= \"23.0\""} +pyobjc-framework-ServiceManagement = {version = "10.3.1", markers = "platform_release >= \"10.0\""} +pyobjc-framework-SharedWithYou = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-SharedWithYouCore = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-ShazamKit = {version = "10.3.1", markers = "platform_release >= \"21.0\""} +pyobjc-framework-Social = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-SoundAnalysis = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-Speech = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-SpriteKit = {version = "10.3.1", markers = "platform_release >= \"13.0\""} +pyobjc-framework-StoreKit = {version = "10.3.1", markers = "platform_release >= \"11.0\""} +pyobjc-framework-Symbols = {version = "10.3.1", markers = "platform_release >= \"23.0\""} +pyobjc-framework-SyncServices = "10.3.1" +pyobjc-framework-SystemConfiguration = "10.3.1" +pyobjc-framework-SystemExtensions = {version = "10.3.1", markers = "platform_release >= \"19.0\""} +pyobjc-framework-ThreadNetwork = {version = "10.3.1", markers = "platform_release >= \"22.0\""} +pyobjc-framework-UniformTypeIdentifiers = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-UserNotifications = {version = "10.3.1", markers = "platform_release >= \"18.0\""} +pyobjc-framework-UserNotificationsUI = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-VideoSubscriberAccount = {version = "10.3.1", markers = "platform_release >= \"18.0\""} +pyobjc-framework-VideoToolbox = {version = "10.3.1", markers = "platform_release >= \"12.0\""} +pyobjc-framework-Virtualization = {version = "10.3.1", markers = "platform_release >= \"20.0\""} +pyobjc-framework-Vision = {version = "10.3.1", markers = "platform_release >= \"17.0\""} +pyobjc-framework-WebKit = "10.3.1" [package.extras] -allbindings = ["pyobjc-core (==10.3)", "pyobjc-framework-AVFoundation (==10.3)", "pyobjc-framework-AVKit (==10.3)", "pyobjc-framework-AVRouting (==10.3)", "pyobjc-framework-Accessibility (==10.3)", "pyobjc-framework-Accounts (==10.3)", "pyobjc-framework-AdServices (==10.3)", "pyobjc-framework-AdSupport (==10.3)", "pyobjc-framework-AddressBook (==10.3)", "pyobjc-framework-AppTrackingTransparency (==10.3)", "pyobjc-framework-AppleScriptKit (==10.3)", "pyobjc-framework-AppleScriptObjC (==10.3)", "pyobjc-framework-ApplicationServices (==10.3)", "pyobjc-framework-AudioVideoBridging (==10.3)", "pyobjc-framework-AuthenticationServices (==10.3)", "pyobjc-framework-AutomaticAssessmentConfiguration (==10.3)", "pyobjc-framework-Automator (==10.3)", "pyobjc-framework-BackgroundAssets (==10.3)", "pyobjc-framework-BrowserEngineKit (==10.3)", "pyobjc-framework-BusinessChat (==10.3)", "pyobjc-framework-CFNetwork (==10.3)", "pyobjc-framework-CalendarStore (==10.3)", "pyobjc-framework-CallKit (==10.3)", "pyobjc-framework-Cinematic (==10.3)", "pyobjc-framework-ClassKit (==10.3)", "pyobjc-framework-CloudKit (==10.3)", "pyobjc-framework-Cocoa (==10.3)", "pyobjc-framework-Collaboration (==10.3)", "pyobjc-framework-ColorSync (==10.3)", "pyobjc-framework-Contacts (==10.3)", "pyobjc-framework-ContactsUI (==10.3)", "pyobjc-framework-CoreAudio (==10.3)", "pyobjc-framework-CoreAudioKit (==10.3)", "pyobjc-framework-CoreBluetooth (==10.3)", "pyobjc-framework-CoreData (==10.3)", "pyobjc-framework-CoreHaptics (==10.3)", "pyobjc-framework-CoreLocation (==10.3)", "pyobjc-framework-CoreMIDI (==10.3)", "pyobjc-framework-CoreML (==10.3)", "pyobjc-framework-CoreMedia (==10.3)", "pyobjc-framework-CoreMediaIO (==10.3)", "pyobjc-framework-CoreMotion (==10.3)", "pyobjc-framework-CoreServices (==10.3)", "pyobjc-framework-CoreSpotlight (==10.3)", "pyobjc-framework-CoreText (==10.3)", "pyobjc-framework-CoreWLAN (==10.3)", "pyobjc-framework-CryptoTokenKit (==10.3)", "pyobjc-framework-DVDPlayback (==10.3)", "pyobjc-framework-DataDetection (==10.3)", "pyobjc-framework-DeviceCheck (==10.3)", "pyobjc-framework-DictionaryServices (==10.3)", "pyobjc-framework-DiscRecording (==10.3)", "pyobjc-framework-DiscRecordingUI (==10.3)", "pyobjc-framework-DiskArbitration (==10.3)", "pyobjc-framework-EventKit (==10.3)", "pyobjc-framework-ExceptionHandling (==10.3)", "pyobjc-framework-ExecutionPolicy (==10.3)", "pyobjc-framework-ExtensionKit (==10.3)", "pyobjc-framework-ExternalAccessory (==10.3)", "pyobjc-framework-FSEvents (==10.3)", "pyobjc-framework-FileProvider (==10.3)", "pyobjc-framework-FileProviderUI (==10.3)", "pyobjc-framework-FinderSync (==10.3)", "pyobjc-framework-GameCenter (==10.3)", "pyobjc-framework-GameController (==10.3)", "pyobjc-framework-GameKit (==10.3)", "pyobjc-framework-GameplayKit (==10.3)", "pyobjc-framework-HealthKit (==10.3)", "pyobjc-framework-IOBluetooth (==10.3)", "pyobjc-framework-IOBluetoothUI (==10.3)", "pyobjc-framework-IOSurface (==10.3)", "pyobjc-framework-ImageCaptureCore (==10.3)", "pyobjc-framework-InputMethodKit (==10.3)", "pyobjc-framework-InstallerPlugins (==10.3)", "pyobjc-framework-InstantMessage (==10.3)", "pyobjc-framework-Intents (==10.3)", "pyobjc-framework-IntentsUI (==10.3)", "pyobjc-framework-KernelManagement (==10.3)", "pyobjc-framework-LatentSemanticMapping (==10.3)", "pyobjc-framework-LaunchServices (==10.3)", "pyobjc-framework-LinkPresentation (==10.3)", "pyobjc-framework-LocalAuthentication (==10.3)", "pyobjc-framework-LocalAuthenticationEmbeddedUI (==10.3)", "pyobjc-framework-MLCompute (==10.3)", "pyobjc-framework-MailKit (==10.3)", "pyobjc-framework-MapKit (==10.3)", "pyobjc-framework-MediaAccessibility (==10.3)", "pyobjc-framework-MediaLibrary (==10.3)", "pyobjc-framework-MediaPlayer (==10.3)", "pyobjc-framework-MediaToolbox (==10.3)", "pyobjc-framework-Metal (==10.3)", "pyobjc-framework-MetalFX (==10.3)", "pyobjc-framework-MetalKit (==10.3)", "pyobjc-framework-MetalPerformanceShaders (==10.3)", "pyobjc-framework-MetalPerformanceShadersGraph (==10.3)", "pyobjc-framework-MetricKit (==10.3)", "pyobjc-framework-ModelIO (==10.3)", "pyobjc-framework-MultipeerConnectivity (==10.3)", "pyobjc-framework-NaturalLanguage (==10.3)", "pyobjc-framework-NetFS (==10.3)", "pyobjc-framework-Network (==10.3)", "pyobjc-framework-NetworkExtension (==10.3)", "pyobjc-framework-NotificationCenter (==10.3)", "pyobjc-framework-OSAKit (==10.3)", "pyobjc-framework-OSLog (==10.3)", "pyobjc-framework-OpenDirectory (==10.3)", "pyobjc-framework-PHASE (==10.3)", "pyobjc-framework-PassKit (==10.3)", "pyobjc-framework-PencilKit (==10.3)", "pyobjc-framework-Photos (==10.3)", "pyobjc-framework-PhotosUI (==10.3)", "pyobjc-framework-PreferencePanes (==10.3)", "pyobjc-framework-PubSub (==10.3)", "pyobjc-framework-PushKit (==10.3)", "pyobjc-framework-Quartz (==10.3)", "pyobjc-framework-QuickLookThumbnailing (==10.3)", "pyobjc-framework-ReplayKit (==10.3)", "pyobjc-framework-SafariServices (==10.3)", "pyobjc-framework-SafetyKit (==10.3)", "pyobjc-framework-SceneKit (==10.3)", "pyobjc-framework-ScreenCaptureKit (==10.3)", "pyobjc-framework-ScreenSaver (==10.3)", "pyobjc-framework-ScreenTime (==10.3)", "pyobjc-framework-ScriptingBridge (==10.3)", "pyobjc-framework-SearchKit (==10.3)", "pyobjc-framework-Security (==10.3)", "pyobjc-framework-SecurityFoundation (==10.3)", "pyobjc-framework-SecurityInterface (==10.3)", "pyobjc-framework-SensitiveContentAnalysis (==10.3)", "pyobjc-framework-ServiceManagement (==10.3)", "pyobjc-framework-SharedWithYou (==10.3)", "pyobjc-framework-SharedWithYouCore (==10.3)", "pyobjc-framework-ShazamKit (==10.3)", "pyobjc-framework-Social (==10.3)", "pyobjc-framework-SoundAnalysis (==10.3)", "pyobjc-framework-Speech (==10.3)", "pyobjc-framework-SpriteKit (==10.3)", "pyobjc-framework-StoreKit (==10.3)", "pyobjc-framework-Symbols (==10.3)", "pyobjc-framework-SyncServices (==10.3)", "pyobjc-framework-SystemConfiguration (==10.3)", "pyobjc-framework-SystemExtensions (==10.3)", "pyobjc-framework-ThreadNetwork (==10.3)", "pyobjc-framework-UniformTypeIdentifiers (==10.3)", "pyobjc-framework-UserNotifications (==10.3)", "pyobjc-framework-UserNotificationsUI (==10.3)", "pyobjc-framework-VideoSubscriberAccount (==10.3)", "pyobjc-framework-VideoToolbox (==10.3)", "pyobjc-framework-Virtualization (==10.3)", "pyobjc-framework-Vision (==10.3)", "pyobjc-framework-WebKit (==10.3)", "pyobjc-framework-iTunesLibrary (==10.3)", "pyobjc-framework-libdispatch (==10.3)", "pyobjc-framework-libxpc (==10.3)"] +allbindings = ["pyobjc-core (==10.3.1)", "pyobjc-framework-AVFoundation (==10.3.1)", "pyobjc-framework-AVKit (==10.3.1)", "pyobjc-framework-AVRouting (==10.3.1)", "pyobjc-framework-Accessibility (==10.3.1)", "pyobjc-framework-Accounts (==10.3.1)", "pyobjc-framework-AdServices (==10.3.1)", "pyobjc-framework-AdSupport (==10.3.1)", "pyobjc-framework-AddressBook (==10.3.1)", "pyobjc-framework-AppTrackingTransparency (==10.3.1)", "pyobjc-framework-AppleScriptKit (==10.3.1)", "pyobjc-framework-AppleScriptObjC (==10.3.1)", "pyobjc-framework-ApplicationServices (==10.3.1)", "pyobjc-framework-AudioVideoBridging (==10.3.1)", "pyobjc-framework-AuthenticationServices (==10.3.1)", "pyobjc-framework-AutomaticAssessmentConfiguration (==10.3.1)", "pyobjc-framework-Automator (==10.3.1)", "pyobjc-framework-BackgroundAssets (==10.3.1)", "pyobjc-framework-BrowserEngineKit (==10.3.1)", "pyobjc-framework-BusinessChat (==10.3.1)", "pyobjc-framework-CFNetwork (==10.3.1)", "pyobjc-framework-CalendarStore (==10.3.1)", "pyobjc-framework-CallKit (==10.3.1)", "pyobjc-framework-Cinematic (==10.3.1)", "pyobjc-framework-ClassKit (==10.3.1)", "pyobjc-framework-CloudKit (==10.3.1)", "pyobjc-framework-Cocoa (==10.3.1)", "pyobjc-framework-Collaboration (==10.3.1)", "pyobjc-framework-ColorSync (==10.3.1)", "pyobjc-framework-Contacts (==10.3.1)", "pyobjc-framework-ContactsUI (==10.3.1)", "pyobjc-framework-CoreAudio (==10.3.1)", "pyobjc-framework-CoreAudioKit (==10.3.1)", "pyobjc-framework-CoreBluetooth (==10.3.1)", "pyobjc-framework-CoreData (==10.3.1)", "pyobjc-framework-CoreHaptics (==10.3.1)", "pyobjc-framework-CoreLocation (==10.3.1)", "pyobjc-framework-CoreMIDI (==10.3.1)", "pyobjc-framework-CoreML (==10.3.1)", "pyobjc-framework-CoreMedia (==10.3.1)", "pyobjc-framework-CoreMediaIO (==10.3.1)", "pyobjc-framework-CoreMotion (==10.3.1)", "pyobjc-framework-CoreServices (==10.3.1)", "pyobjc-framework-CoreSpotlight (==10.3.1)", "pyobjc-framework-CoreText (==10.3.1)", "pyobjc-framework-CoreWLAN (==10.3.1)", "pyobjc-framework-CryptoTokenKit (==10.3.1)", "pyobjc-framework-DVDPlayback (==10.3.1)", "pyobjc-framework-DataDetection (==10.3.1)", "pyobjc-framework-DeviceCheck (==10.3.1)", "pyobjc-framework-DictionaryServices (==10.3.1)", "pyobjc-framework-DiscRecording (==10.3.1)", "pyobjc-framework-DiscRecordingUI (==10.3.1)", "pyobjc-framework-DiskArbitration (==10.3.1)", "pyobjc-framework-EventKit (==10.3.1)", "pyobjc-framework-ExceptionHandling (==10.3.1)", "pyobjc-framework-ExecutionPolicy (==10.3.1)", "pyobjc-framework-ExtensionKit (==10.3.1)", "pyobjc-framework-ExternalAccessory (==10.3.1)", "pyobjc-framework-FSEvents (==10.3.1)", "pyobjc-framework-FileProvider (==10.3.1)", "pyobjc-framework-FileProviderUI (==10.3.1)", "pyobjc-framework-FinderSync (==10.3.1)", "pyobjc-framework-GameCenter (==10.3.1)", "pyobjc-framework-GameController (==10.3.1)", "pyobjc-framework-GameKit (==10.3.1)", "pyobjc-framework-GameplayKit (==10.3.1)", "pyobjc-framework-HealthKit (==10.3.1)", "pyobjc-framework-IOBluetooth (==10.3.1)", "pyobjc-framework-IOBluetoothUI (==10.3.1)", "pyobjc-framework-IOSurface (==10.3.1)", "pyobjc-framework-ImageCaptureCore (==10.3.1)", "pyobjc-framework-InputMethodKit (==10.3.1)", "pyobjc-framework-InstallerPlugins (==10.3.1)", "pyobjc-framework-InstantMessage (==10.3.1)", "pyobjc-framework-Intents (==10.3.1)", "pyobjc-framework-IntentsUI (==10.3.1)", "pyobjc-framework-KernelManagement (==10.3.1)", "pyobjc-framework-LatentSemanticMapping (==10.3.1)", "pyobjc-framework-LaunchServices (==10.3.1)", "pyobjc-framework-LinkPresentation (==10.3.1)", "pyobjc-framework-LocalAuthentication (==10.3.1)", "pyobjc-framework-LocalAuthenticationEmbeddedUI (==10.3.1)", "pyobjc-framework-MLCompute (==10.3.1)", "pyobjc-framework-MailKit (==10.3.1)", "pyobjc-framework-MapKit (==10.3.1)", "pyobjc-framework-MediaAccessibility (==10.3.1)", "pyobjc-framework-MediaLibrary (==10.3.1)", "pyobjc-framework-MediaPlayer (==10.3.1)", "pyobjc-framework-MediaToolbox (==10.3.1)", "pyobjc-framework-Metal (==10.3.1)", "pyobjc-framework-MetalFX (==10.3.1)", "pyobjc-framework-MetalKit (==10.3.1)", "pyobjc-framework-MetalPerformanceShaders (==10.3.1)", "pyobjc-framework-MetalPerformanceShadersGraph (==10.3.1)", "pyobjc-framework-MetricKit (==10.3.1)", "pyobjc-framework-ModelIO (==10.3.1)", "pyobjc-framework-MultipeerConnectivity (==10.3.1)", "pyobjc-framework-NaturalLanguage (==10.3.1)", "pyobjc-framework-NetFS (==10.3.1)", "pyobjc-framework-Network (==10.3.1)", "pyobjc-framework-NetworkExtension (==10.3.1)", "pyobjc-framework-NotificationCenter (==10.3.1)", "pyobjc-framework-OSAKit (==10.3.1)", "pyobjc-framework-OSLog (==10.3.1)", "pyobjc-framework-OpenDirectory (==10.3.1)", "pyobjc-framework-PHASE (==10.3.1)", "pyobjc-framework-PassKit (==10.3.1)", "pyobjc-framework-PencilKit (==10.3.1)", "pyobjc-framework-Photos (==10.3.1)", "pyobjc-framework-PhotosUI (==10.3.1)", "pyobjc-framework-PreferencePanes (==10.3.1)", "pyobjc-framework-PubSub (==10.3.1)", "pyobjc-framework-PushKit (==10.3.1)", "pyobjc-framework-Quartz (==10.3.1)", "pyobjc-framework-QuickLookThumbnailing (==10.3.1)", "pyobjc-framework-ReplayKit (==10.3.1)", "pyobjc-framework-SafariServices (==10.3.1)", "pyobjc-framework-SafetyKit (==10.3.1)", "pyobjc-framework-SceneKit (==10.3.1)", "pyobjc-framework-ScreenCaptureKit (==10.3.1)", "pyobjc-framework-ScreenSaver (==10.3.1)", "pyobjc-framework-ScreenTime (==10.3.1)", "pyobjc-framework-ScriptingBridge (==10.3.1)", "pyobjc-framework-SearchKit (==10.3.1)", "pyobjc-framework-Security (==10.3.1)", "pyobjc-framework-SecurityFoundation (==10.3.1)", "pyobjc-framework-SecurityInterface (==10.3.1)", "pyobjc-framework-SensitiveContentAnalysis (==10.3.1)", "pyobjc-framework-ServiceManagement (==10.3.1)", "pyobjc-framework-SharedWithYou (==10.3.1)", "pyobjc-framework-SharedWithYouCore (==10.3.1)", "pyobjc-framework-ShazamKit (==10.3.1)", "pyobjc-framework-Social (==10.3.1)", "pyobjc-framework-SoundAnalysis (==10.3.1)", "pyobjc-framework-Speech (==10.3.1)", "pyobjc-framework-SpriteKit (==10.3.1)", "pyobjc-framework-StoreKit (==10.3.1)", "pyobjc-framework-Symbols (==10.3.1)", "pyobjc-framework-SyncServices (==10.3.1)", "pyobjc-framework-SystemConfiguration (==10.3.1)", "pyobjc-framework-SystemExtensions (==10.3.1)", "pyobjc-framework-ThreadNetwork (==10.3.1)", "pyobjc-framework-UniformTypeIdentifiers (==10.3.1)", "pyobjc-framework-UserNotifications (==10.3.1)", "pyobjc-framework-UserNotificationsUI (==10.3.1)", "pyobjc-framework-VideoSubscriberAccount (==10.3.1)", "pyobjc-framework-VideoToolbox (==10.3.1)", "pyobjc-framework-Virtualization (==10.3.1)", "pyobjc-framework-Vision (==10.3.1)", "pyobjc-framework-WebKit (==10.3.1)", "pyobjc-framework-iTunesLibrary (==10.3.1)", "pyobjc-framework-libdispatch (==10.3.1)", "pyobjc-framework-libxpc (==10.3.1)"] [[package]] name = "pyobjc-core" -version = "10.3" +version = "10.3.1" description = "Python<->ObjC Interoperability Module" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_core-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:713dd174e3fd4bfb975949d7314c778d02909d5c017497408d8eedcedab73a42"}, - {file = "pyobjc_core-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eca0c6d3923e8f5c4a86831e446f2995958525ff0c6a01f6f4fa8de0cb25c8a"}, - {file = "pyobjc_core-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:50dfe3bd7295f04445cf3134113578678a188ca4fb0869e821369a2d288492dc"}, - {file = "pyobjc_core-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:13511c0ab3235486d4560e9923ed96db76357e7c7e70e0629fee9425b0a8d901"}, - {file = "pyobjc_core-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a7e3a0625f9370ef86a2529be0d22dd3dc48326a7a28113bc6f24d4bf866d076"}, - {file = "pyobjc_core-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7a17321d2e226ca43a8f70f8bc823cfaa58ff9d9cdedcd16708d4eec9ca808b2"}, - {file = "pyobjc_core-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5c2bfb2f9fcb9f291a64041a336aab1b34a20dbbf4f77fca3057a7d8ef9ce9c5"}, - {file = "pyobjc_core-10.3.tar.gz", hash = "sha256:875f2555b51a8a36cafbdb7d5d36f3452287a81bd5d7dc09aa6c309d638a9275"}, + {file = "pyobjc_core-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ea46d2cda17921e417085ac6286d43ae448113158afcf39e0abe484c58fb3d78"}, + {file = "pyobjc_core-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:899d3c84d2933d292c808f385dc881a140cf08632907845043a333a9d7c899f9"}, + {file = "pyobjc_core-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6ff5823d13d0a534cdc17fa4ad47cf5bee4846ce0fd27fc40012e12b46db571b"}, + {file = "pyobjc_core-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2581e8e68885bcb0e11ec619e81ef28e08ee3fac4de20d8cc83bc5af5bcf4a90"}, + {file = "pyobjc_core-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ea98d4c2ec39ca29e62e0327db21418696161fb138ee6278daf2acbedf7ce504"}, + {file = "pyobjc_core-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4c179c26ee2123d0aabffb9dbc60324b62b6f8614fb2c2328b09386ef59ef6d8"}, + {file = "pyobjc_core-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cb901fce65c9be420c40d8a6ee6fff5ff27c6945f44fd7191989b982baa66dea"}, + {file = "pyobjc_core-10.3.1.tar.gz", hash = "sha256:b204a80ccc070f9ab3f8af423a3a25a6fd787e228508d00c4c30f8ac538ba720"}, ] [[package]] name = "pyobjc-framework-accessibility" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Accessibility on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Accessibility-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6affccae6d0cd6f1061954c9a5c3341f6db3a2358fefa64117ccefd444d2a985"}, - {file = "pyobjc_framework_Accessibility-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:523e031fcb4e06270212c24b93de19df66287fe77bec3d03a27dc1c888da7992"}, - {file = "pyobjc_framework_Accessibility-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b119e3bf3c5173358797d4ed2fddf554b498dd623def8dd2925f7ac27a548655"}, - {file = "pyobjc_framework_accessibility-10.3.tar.gz", hash = "sha256:5be6f066582b4eda8e0c6ffac7d19c9f01835c036f16bed81211c9c7dece9f67"}, + {file = "pyobjc_framework_Accessibility-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4a1b10d2098b5e3887d4e52b13c2d7619f248ceeaa4e78bb21c51c25c7d391c3"}, + {file = "pyobjc_framework_Accessibility-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4926eeef40d750215f0787d2124407a4c65bc03407e402ea47901b713e8765e5"}, + {file = "pyobjc_framework_Accessibility-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b5b9d7373d1a8a06f57baca2f67279c3b0c61ecfb17fa6da964e0e275e7d18ed"}, + {file = "pyobjc_framework_Accessibility-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:94dbc5f223e6485820c14e7dee99d8f4d5cbf0600353033822dcab7ec4bc998e"}, + {file = "pyobjc_framework_accessibility-10.3.1.tar.gz", hash = "sha256:c973306417441e6bed5f9be6154e6399aa7f38fa9b6bcf3368fa42d92ef3030b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-accounts" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Accounts on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Accounts-10.3-py2.py3-none-any.whl", hash = "sha256:09f311f689676805b98e8c848df582ab8a6f2ec30cd2eabfa453340b2f813abe"}, - {file = "pyobjc_framework_accounts-10.3.tar.gz", hash = "sha256:a84a84e82536054403bcf1a990755897d2011848e13377faaedca1333c58d418"}, + {file = "pyobjc_framework_Accounts-10.3.1-py2.py3-none-any.whl", hash = "sha256:451488f91263afd23233287f223ba00c0ee5c93d64cd10e133d72bc6a0fc48aa"}, + {file = "pyobjc_framework_accounts-10.3.1.tar.gz", hash = "sha256:3d55738e7b3290af8cd4993fd2b670242a952deb995a69911be2a1be4c509a86"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-addressbook" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AddressBook on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AddressBook-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3e383caa4af01522cad1336b67339e50786887ce9e5c0a1ccfbcd4949f1930"}, - {file = "pyobjc_framework_AddressBook-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7403df85c541fc2b8569c21fa148a5cf56faff2763466600a7a4953e858ceaed"}, - {file = "pyobjc_framework_AddressBook-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d26655504b723cbf2e9efcd76f937bbe4afe5ce107ec158f96aec9dfd925a2d5"}, - {file = "pyobjc_framework_addressbook-10.3.tar.gz", hash = "sha256:e9488b4fede12f6bbd6215ab3478699c94a257b31983f665ce3cfa76d8249f1d"}, + {file = "pyobjc_framework_AddressBook-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:02ab8cb2300d55beaddee4f113a5c4a78ef737eda6c704678487529e391062e2"}, + {file = "pyobjc_framework_AddressBook-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1cfa893c21920f5420f3e57da314315e92c855a83f0718482dc33bdb859b9f24"}, + {file = "pyobjc_framework_AddressBook-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7aa89a352f1729de1cb4d7841906487d9db752c2802af5695596b1cf5290acfb"}, + {file = "pyobjc_framework_AddressBook-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f25864847b4a81289dd08e7052455699ee011a4df98f4da0b07f46523c212592"}, + {file = "pyobjc_framework_addressbook-10.3.1.tar.gz", hash = "sha256:cde99b855c39b56ca52479b0a1e2daa3ef5de12cebfe780c3c802a5f59a484cc"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-adservices" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AdServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AdServices-10.3-py2.py3-none-any.whl", hash = "sha256:a3d8ed85beb1f75335fb5598eb0d63a76390099bb09735b8a5b37908ddd6ad40"}, - {file = "pyobjc_framework_adservices-10.3.tar.gz", hash = "sha256:c3b8a874a77a346b34439d8fcc6e37fa59836130160a58e848af2b222f476fe5"}, + {file = "pyobjc_framework_AdServices-10.3.1-py2.py3-none-any.whl", hash = "sha256:c839c4267ad8443393e4d138396026764ee43776164da8a8ed9ac248b7d9c0d9"}, + {file = "pyobjc_framework_adservices-10.3.1.tar.gz", hash = "sha256:28123eb111d023f708e1d86f5f3f76bd4f6bb0d932466863f84b3e322b11537a"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-adsupport" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AdSupport on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AdSupport-10.3-py2.py3-none-any.whl", hash = "sha256:e68b2bfcf095fd291fe04b6626d26dc60c17c9e37418b30f977e79a42567d415"}, - {file = "pyobjc_framework_adsupport-10.3.tar.gz", hash = "sha256:fe04f5bdab7d1f56c9c97fadea619576d62774bffb418832b97c9e17ef7cab01"}, + {file = "pyobjc_framework_AdSupport-10.3.1-py2.py3-none-any.whl", hash = "sha256:0e403ec206ada472b2c0b129ed656342a97c20110ca8398ab907100516b0e48c"}, + {file = "pyobjc_framework_adsupport-10.3.1.tar.gz", hash = "sha256:ba85a00cf20c42501d8083092f7ca0fcd1e616b1725e6512e75bcb60a6d58528"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-applescriptkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AppleScriptKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AppleScriptKit-10.3-py2.py3-none-any.whl", hash = "sha256:93f25fe54cf5ea0b389956c3ab7061181373db7aec8beccbc376d0c9e116dc71"}, - {file = "pyobjc_framework_applescriptkit-10.3.tar.gz", hash = "sha256:d6a99ad673ed1feaccc41aa0e082526026b7b43e6b37a018c123577513965767"}, + {file = "pyobjc_framework_AppleScriptKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:97ce878ff334b6853405a62e164debb9e6695110e64db5ed596008c0fde84970"}, + {file = "pyobjc_framework_applescriptkit-10.3.1.tar.gz", hash = "sha256:add2e63598b699666bcf00ac59f6f1046266df1665bec71b142cd21b89037064"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-applescriptobjc" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AppleScriptObjC on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AppleScriptObjC-10.3-py2.py3-none-any.whl", hash = "sha256:97e171fda7473ec09788531b840fd19b26ab64fc8d44dbdf4ec70da2127304c6"}, - {file = "pyobjc_framework_applescriptobjc-10.3.tar.gz", hash = "sha256:9f7fad7bd4f6e4b90800ac87a4f4260e44fd78e052a0c24bef90b797b9cf4159"}, + {file = "pyobjc_framework_AppleScriptObjC-10.3.1-py2.py3-none-any.whl", hash = "sha256:2d64c74a4af48656bb407eb177fe5f1d3c0f7bd9c578e5583dffde8e3d55f5df"}, + {file = "pyobjc_framework_applescriptobjc-10.3.1.tar.gz", hash = "sha256:a87101d86b08e06e2c0e51630ac76d4c70f01cf1ed7af281f3138e63146e279b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-applicationservices" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ApplicationServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ApplicationServices-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6beb4565b5fa17f45828e2957161d4f6991f7bea5da6c44e268d96a7d103bfa7"}, - {file = "pyobjc_framework_ApplicationServices-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe18f999755e15f2c7bc459860e4aac9a78b84208eb1751cbaef83e6ac9f6765"}, - {file = "pyobjc_framework_ApplicationServices-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9cd2b5bae9e0517b453aac7fc15143e9ac5ea607ad6a8fa56d31b58555403bba"}, - {file = "pyobjc_framework_ApplicationServices-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:ea7db447abef7deb8233da00204bc5e76e695e504dcf7ad765c7b5d04d164188"}, - {file = "pyobjc_framework_ApplicationServices-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9381d3c3ad04063d460b5aa9edd8bb1234350833b4decb8dd3df3feefc19c62f"}, - {file = "pyobjc_framework_ApplicationServices-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:cbc55594468cab4df4314b956a0ab9b92395460ede76f874991d6219038c8e2a"}, - {file = "pyobjc_framework_ApplicationServices-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cba0a07176a30b1e3961842195bad2f079f80ec57872d52d705910e18eb23e26"}, - {file = "pyobjc_framework_applicationservices-10.3.tar.gz", hash = "sha256:36ca55df6a9552b7404e1a0799797c15db47faf608050024a898d50d2b1f4351"}, + {file = "pyobjc_framework_ApplicationServices-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b694260d423c470cb90c3a7009cfde93e332ea6fb4b9b9526ad3acbd33460e3d"}, + {file = "pyobjc_framework_ApplicationServices-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d886ba1f65df47b77ff7546f3fc9bc7d08cfb6b3c04433b719f6b0689a2c0d1f"}, + {file = "pyobjc_framework_ApplicationServices-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:be157f2c3ffb254064ef38249670af8cada5e519a714d2aa5da3740934d89bc8"}, + {file = "pyobjc_framework_ApplicationServices-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:57737f41731661e4a3b78793ec9173f61242a32fa560c3e4e58484465d049c32"}, + {file = "pyobjc_framework_ApplicationServices-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c429eca69ee675e781e4e55f79e939196b47f02560ad865b1ba9ac753b90bd77"}, + {file = "pyobjc_framework_ApplicationServices-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4f1814a17041a20adca454044080b52e39a4ebc567ad2c6a48866dd4beaa192a"}, + {file = "pyobjc_framework_ApplicationServices-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1252f1137f83eb2c6b9968d8c591363e8859dd2484bc9441d8f365bcfb43a0e4"}, + {file = "pyobjc_framework_applicationservices-10.3.1.tar.gz", hash = "sha256:f27cb64aa4d129ce671fd42638c985eb2a56d544214a95fe3214a007eacc4790"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreText = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreText = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-apptrackingtransparency" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AppTrackingTransparency on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AppTrackingTransparency-10.3-py2.py3-none-any.whl", hash = "sha256:10774b1e288ee303813f5736569a5f7522c8cde0ad5d787a36f9d4f89da6e2d7"}, - {file = "pyobjc_framework_apptrackingtransparency-10.3.tar.gz", hash = "sha256:8917c06633b9b5b5317945edfbc7064679f096651ae847fd4d186734a256eaac"}, + {file = "pyobjc_framework_AppTrackingTransparency-10.3.1-py2.py3-none-any.whl", hash = "sha256:7c0e3a5cad402e8c3c5da1f070be0f49bb827e6d9e5165744f64e082633a4b45"}, + {file = "pyobjc_framework_apptrackingtransparency-10.3.1.tar.gz", hash = "sha256:2e381db5f7d3985207b5ff2975e41bf0f9147080345b2e1b4b242f8799290d04"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-audiovideobridging" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AudioVideoBridging on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AudioVideoBridging-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b29110d34e79a7ff275628246237de1f497e88db954c0763d1da19874e136639"}, - {file = "pyobjc_framework_AudioVideoBridging-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:21761c9f69813d95243c9ecfa68161468a48cf2eae3bff982c568458f369de52"}, - {file = "pyobjc_framework_AudioVideoBridging-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4683c2f919161178210292f3aff8bf664d402325452be4a7fae419cc02e3f976"}, - {file = "pyobjc_framework_AudioVideoBridging-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:8688210459c3fe3883131c6d91d3ee5e821488215398dd1e3513ca472cc3f335"}, - {file = "pyobjc_framework_AudioVideoBridging-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4bd821fe8da7ee329f96900645515d23689eaea4799ebb4738ab1e0e9fe68d00"}, - {file = "pyobjc_framework_AudioVideoBridging-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:f58c46deb3c75c3c35904ab300986863f0ee0f494919b7bc0f92c6d40873d7e0"}, - {file = "pyobjc_framework_AudioVideoBridging-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5cbe0382f874fd277704b7a539cc401fe915ecdde75e67c719c3e45aef55f911"}, - {file = "pyobjc_framework_audiovideobridging-10.3.tar.gz", hash = "sha256:0125620773157566c34038318b064def855ae096ac601e4482882277e4d913e6"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8accf87f136a6aa71d89d3a2204127b48e64ec25d3e1159f0f23ede0c4d70e59"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f6067b2f50fb48c9ecb521b8865d93dfbd46510a4322cc2041b1e917678f39b"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1aebc6c1aafb3cdfc5f9fad2dfe2dfccfbab159dc8dbfe54cfea777108e80e44"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b1fb0af1df78800205cd7a7cd90e58b640513bbb944fe6a8d89df43e626a27a8"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2cc18c005c72a74654a000a1d6d405b6cb12b1d6c09be9bd6b58502ae06035e7"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:b61dc632c31875cb090521b0139d61f528e5fe5fedf4055524522c0aa808a77d"}, + {file = "pyobjc_framework_AudioVideoBridging-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8de78207e617d4d89c66b4a66ff4ff49b60822249d2a68fc9356dd09475f0103"}, + {file = "pyobjc_framework_audiovideobridging-10.3.1.tar.gz", hash = "sha256:b2c1d5977a92915f6af2203e3b4c9b8a8392bc51e0fc13ccb393589419387119"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-authenticationservices" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AuthenticationServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AuthenticationServices-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6598252867b6578d8f5c6f987299aadcdaa36095c15439318011fb7b3c2e9334"}, - {file = "pyobjc_framework_AuthenticationServices-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cb9d0154a15a8509bb0c4be32138b852802bcf0ad362fe9907038cfe37c5f9b7"}, - {file = "pyobjc_framework_AuthenticationServices-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4f8a1e45db6e61d6e0a18e3182e07cac7e9c09b2b0c5909a74c465938d3cbab5"}, - {file = "pyobjc_framework_authenticationservices-10.3.tar.gz", hash = "sha256:2cbb41260156dc5d2423fd9e3573c04117eca91f765b3c8f9268360d97253a7e"}, + {file = "pyobjc_framework_AuthenticationServices-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:fa0a11fb64e30f14f01ec2d3a2a89a3e1a554db62111b0612f1782722b6dd534"}, + {file = "pyobjc_framework_AuthenticationServices-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e2753cdd5480f97753dc32d9f41d7e6cb75b09f7ce950b2eea4a9851e0a437db"}, + {file = "pyobjc_framework_AuthenticationServices-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:91c2cc0e963d6ac44c3a6014270b54e6499f1aae64d82482d96114c38fb99817"}, + {file = "pyobjc_framework_AuthenticationServices-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d715bbdf1c94ea838830930a41de0554905760943cff1510268d8e485c826ee8"}, + {file = "pyobjc_framework_authenticationservices-10.3.1.tar.gz", hash = "sha256:0ac834f4a5cbe3cf20acd4f6a96df77bc643a1ae248e394d06964db9fe0d6310"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-automaticassessmentconfiguration" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AutomaticAssessmentConfiguration on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fca0e66a78daa4605b056c54a3aadc10772d7d942b3fbc77d1a12fcc5d454bc"}, - {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2af49bd323db3d94421364e2f89bcb38511dcf3bd36688c852ea49619caed9db"}, - {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:03e506e574b75aac0a82d783376b4e2ff1519c31e14dd2b0a978595e27149d0c"}, - {file = "pyobjc_framework_automaticassessmentconfiguration-10.3.tar.gz", hash = "sha256:e31b4f0e4127b5e82f77c7fac73d8168e12df02176ab38b220683c375b8a884f"}, + {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:f717f6df5886123a55584f8dd85626c42387f5b55edcd3d68ff306b3fe56a206"}, + {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ab84a771835f346e8a45d19e05f0c2ef8bb3dca81461fb2acc6c9f031794ec63"}, + {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:66fd582549ef602a8bcaadb57de8a06cb0dc0367c2a508b20c580fde2232daed"}, + {file = "pyobjc_framework_AutomaticAssessmentConfiguration-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:578512ae1443e031c3fbfec7eefa71e5ac5fc8cac892ad7183c5ac0b894d494d"}, + {file = "pyobjc_framework_automaticassessmentconfiguration-10.3.1.tar.gz", hash = "sha256:f7846d04493e90eddbacfb7cffebc11b3f76f0800d3dc2bec39441732a20ac56"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-automator" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Automator on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Automator-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0e63a47fd3a89334de05246e4594f33af13b495ad2b4523a5fa18db445d1015f"}, - {file = "pyobjc_framework_Automator-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:efff1edede64731581026ec4b3f89ec624f1a7fe8652ae435b7a8090ba2e8f47"}, - {file = "pyobjc_framework_Automator-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c303f65a16a09f70bf2b52e0b41270329422c2d8e07c7d4bf16146b4c5db60d7"}, - {file = "pyobjc_framework_automator-10.3.tar.gz", hash = "sha256:18dc4792774e0a7e13c5df62212b73af8fa78a40414f3422e52919145a7a9180"}, + {file = "pyobjc_framework_Automator-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:63632d2c1d069ca29a077b15ab20a0a0acc0a5f33ee322c9c8cc854702c66549"}, + {file = "pyobjc_framework_Automator-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4bc8afe0a52bee09f7f99bdfc62100654f08113de47e74488c0af2afcd646e23"}, + {file = "pyobjc_framework_Automator-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8609e1295030d2a46916965cd070072a90b6528abc25ae4d02e50818d2cb252f"}, + {file = "pyobjc_framework_Automator-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:2f482464b3f91405a5a59e3b96ae89c5062af81023ea0fc803353fdfe8cc4a9d"}, + {file = "pyobjc_framework_automator-10.3.1.tar.gz", hash = "sha256:330042475479f054ac98abd568b523fc0165c39eeefffc23bd65d35780939316"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-avfoundation" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AVFoundation on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AVFoundation-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2692fc423a1fcbcb3f8355d8217d9258cf27c0b2ef6c2362829fdc0b65f262c4"}, - {file = "pyobjc_framework_AVFoundation-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:4a54fc6e34a6045b4b6050699d4724bdb7f1ae8e6355c9646e262db3f9b31dfa"}, - {file = "pyobjc_framework_AVFoundation-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:56989f914e463340eb7d51db63a10dd6b5b5204bb1da528a0602d80072d56788"}, - {file = "pyobjc_framework_avfoundation-10.3.tar.gz", hash = "sha256:0bcccca344f7708416c7d910daab2a7b7f05c51f0efb4eec1860a01ed4862af2"}, + {file = "pyobjc_framework_AVFoundation-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:0896f6650df35f0229d1fb3aa3fbf632647dd815d4921cb61d9eb7fa26be6237"}, + {file = "pyobjc_framework_AVFoundation-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0cb27cc95288d95df7504adf474596f8855de7fa7798bbc1bbfbdfbbcb940952"}, + {file = "pyobjc_framework_AVFoundation-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb606ef0806d952a04db45ae691167678121df1d8d7c2f8cc73745695097033"}, + {file = "pyobjc_framework_AVFoundation-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:00889eb915479aa9ea392cdd241e4b635ae0fa3114f043d08cf3e1d1b5a23bd4"}, + {file = "pyobjc_framework_avfoundation-10.3.1.tar.gz", hash = "sha256:2f94bee3a4217b46d9416cad066e4f357bf0f344079c328736114451ae19ae94"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreAudio = ">=10.3" -pyobjc-framework-CoreMedia = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreAudio = ">=10.3.1" +pyobjc-framework-CoreMedia = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-avkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AVKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AVKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:56555ea3b415c929d0111db2b52961b01bbb6e105d3bf75d9ff84ab1399cf4c9"}, - {file = "pyobjc_framework_AVKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:420e09834e862a13dc0a93debd0a493775bd99ba1a8f7262531d02d755a584d6"}, - {file = "pyobjc_framework_AVKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:de1b117de0490018058c0e159b771bd5e908ac876fe53622a6d1e019f0f99415"}, - {file = "pyobjc_framework_avkit-10.3.tar.gz", hash = "sha256:5b9ab88fde35d45e495efab95ba1fdb1c83f63c35ba71cf2a7312efb9467f0ba"}, + {file = "pyobjc_framework_AVKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:bb6025331e5ed493d5ca0a35fab14026820e0d8b0a091fc6010b4ef77aa4bf16"}, + {file = "pyobjc_framework_AVKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:675832ec9c088c2010bd9cd9f912ff5c45ff608d7d94233347d49f1b91f690ca"}, + {file = "pyobjc_framework_AVKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1d92e1d5d098af87667f3eac0609c39c58320c095cdcb7737958cc4895569f22"}, + {file = "pyobjc_framework_AVKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:91bf61fa8d8ef3764345b085038a4081165a8c54b4f0c2a11ee07f86a1556689"}, + {file = "pyobjc_framework_avkit-10.3.1.tar.gz", hash = "sha256:97ca35b5f0cec98f5c8521fedb8537bb23d82739b7102e4ac732d3c3944c8ccc"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-avrouting" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework AVRouting on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_AVRouting-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f9f1ebc5161758522a0da9336df8f893f0dce50ca130fcf95f222b30f016b51f"}, - {file = "pyobjc_framework_AVRouting-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b071da24ef134447dab23b80f2e6affd3bf2765ecb3633074a5e8724eee2b57c"}, - {file = "pyobjc_framework_AVRouting-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:73ba803f2a448a3af4e7a666998d13aa6200a0812fe7a19d51ef2e1e63b4fdc5"}, - {file = "pyobjc_framework_avrouting-10.3.tar.gz", hash = "sha256:1fa5c727ee8d6903625f5a946c43c53e96b78ec24e96f11b5bf12288e5726365"}, + {file = "pyobjc_framework_AVRouting-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:30b05ea44f21d481e39905684c79176c04060e0e92c1ad31756fed6aa39b07df"}, + {file = "pyobjc_framework_AVRouting-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:af940e322cb9ce9d79b47b829c5df41ac4980aca2cda1fbe1ead4ed0f9f589a4"}, + {file = "pyobjc_framework_AVRouting-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3e5101311ee84c884c0eba201b3b7f92e1a2325132a9e44b9b7ad84cdd28b4c2"}, + {file = "pyobjc_framework_AVRouting-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:186e891c2a271492612b3db2b5c2050c56ed1bfce1f6146de8dbf05e7cd7623b"}, + {file = "pyobjc_framework_avrouting-10.3.1.tar.gz", hash = "sha256:7026059b24daf8e1da05d7867f450e82abe412fe5c438faf9344f46e3b83da39"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-backgroundassets" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework BackgroundAssets on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_BackgroundAssets-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:83c66c350122cbb25d56ddc27a036eb7046eeb9d0411f3bf40b2b76bb0a55e8a"}, - {file = "pyobjc_framework_BackgroundAssets-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1307c0fc2616b5fbf214dd6c906e0da10d8bb25874ec6e8a41d14c7e146d0265"}, - {file = "pyobjc_framework_BackgroundAssets-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6a5ab8be15c98368e60eae602c01baea291c0b05075d89ae6faeb9e48f287c4f"}, - {file = "pyobjc_framework_backgroundassets-10.3.tar.gz", hash = "sha256:4ba4a0a2d5f657ea4f27962686e5eb725408912a1aa3846afafe626653c722d6"}, + {file = "pyobjc_framework_BackgroundAssets-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:f725d33a5d633c514e4973489e1bdca391976a5c04443451acaaacc5ccd4095e"}, + {file = "pyobjc_framework_BackgroundAssets-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:14cc84ad7bef64986fe240d23205870fc40dd7b1d2a1819d3dd7924c4898b5c2"}, + {file = "pyobjc_framework_BackgroundAssets-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e28624ecfba067b5e0fc91d5818cb3d20d0ba189a7e8a724678abbecc233c13e"}, + {file = "pyobjc_framework_BackgroundAssets-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:aed2307c7fdd690e4dd214cbfacf4e7d5dd07e6cdd88ce1c02c4ddde3deea843"}, + {file = "pyobjc_framework_backgroundassets-10.3.1.tar.gz", hash = "sha256:5e1198f81db6f30ead2a55e8ea39264f9fce83dcf8e31a68e5f0ea08c5cfe9b5"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-browserenginekit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework BrowserEngineKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_BrowserEngineKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:799551f5a432a1389bb73b5d580c55d0a75cdedee3fb093fd28164e30fe20f2b"}, - {file = "pyobjc_framework_BrowserEngineKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0a97c27c8a973131d69ef197d6168cd6e0464bc7005fa67a6d14e1fb09d29020"}, - {file = "pyobjc_framework_BrowserEngineKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3836d388413a047bdadfe7cc5350c1c8c6a89514e6e73334519ee967dbaa6e0e"}, - {file = "pyobjc_framework_browserenginekit-10.3.tar.gz", hash = "sha256:730e0c0b8c741f93a74aaba1dca53743922f0e43bbed0c94831bf18dc5683a5b"}, + {file = "pyobjc_framework_BrowserEngineKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:86c92ef4e79db4066f7887426e99cfec8902fc8949fb666359cf2a9e519106fc"}, + {file = "pyobjc_framework_BrowserEngineKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:69766ba235976e0a1961d3925228d2ef12808298acd0cd66fe9e883424f0f9a4"}, + {file = "pyobjc_framework_BrowserEngineKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5394a5a801563834764ae46204f8ce4d61a0e2d4567716361eaf5f5e3a27aba7"}, + {file = "pyobjc_framework_BrowserEngineKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d5aeff43abed7e87f637086a05f1b77083cfc7cab07c09c447ae2b23621b2945"}, + {file = "pyobjc_framework_browserenginekit-10.3.1.tar.gz", hash = "sha256:0f6ea100bcf06f2b3f915dab27cf2f038698b39510fb47d3769f72ff62c1e80b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreAudio = ">=10.3" -pyobjc-framework-CoreMedia = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreAudio = ">=10.3.1" +pyobjc-framework-CoreMedia = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-businesschat" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework BusinessChat on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_BusinessChat-10.3-py2.py3-none-any.whl", hash = "sha256:d5e16558060059784e65e1fd96c7ff52a6bb531179d5e5f55882060adb5f6e6f"}, - {file = "pyobjc_framework_businesschat-10.3.tar.gz", hash = "sha256:a320db015134b7cd200d1ec31ab3edb5c1361eef7dc0232d896da9a292015f80"}, + {file = "pyobjc_framework_BusinessChat-10.3.1-py2.py3-none-any.whl", hash = "sha256:952b60f558e3d3498e6191d717bf62c1803f4e1ad040ae29d130090671ec004f"}, + {file = "pyobjc_framework_businesschat-10.3.1.tar.gz", hash = "sha256:53e52981f9da336fcaf6783e82509e06faf8868931213ac70e6bd7395a5859a4"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-calendarstore" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CalendarStore on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CalendarStore-10.3-py2.py3-none-any.whl", hash = "sha256:ad3aeea3183f172ac2fbcf8bebdbc4b805664b04922b0c162ab0bd2ccff6bcca"}, - {file = "pyobjc_framework_calendarstore-10.3.tar.gz", hash = "sha256:67f9d202adfc1cddb05552a9f7e1e13bf5e7db401df259105a35070d0c17ea61"}, + {file = "pyobjc_framework_CalendarStore-10.3.1-py2.py3-none-any.whl", hash = "sha256:7afb59e793ea6d28706423faa50bb1f25532d8ed7388c8540596ce41891445ca"}, + {file = "pyobjc_framework_calendarstore-10.3.1.tar.gz", hash = "sha256:21f627b0afb9a667794b451dd3a03f12ea3f74358dc5977c33b8ecc8b9736c27"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-callkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CallKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CallKit-10.3-py2.py3-none-any.whl", hash = "sha256:5a54438c22e66328b6cf3a12e138f5531fef5772bb0c8d542848ad21f0d87857"}, - {file = "pyobjc_framework_callkit-10.3.tar.gz", hash = "sha256:8ba5d5174c9090fa6befe2e0840575ff3fff83fb47629047ed1ccf54991e0972"}, + {file = "pyobjc_framework_CallKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:495354bea298efdc81c970154083b83aff985f2c294d4883a62de3cc4129e34e"}, + {file = "pyobjc_framework_callkit-10.3.1.tar.gz", hash = "sha256:350390023e9ac98ff6c91b1f51da2489eef2e23aa649d0f63c13cf1d8be1e0df"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-cfnetwork" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CFNetwork on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CFNetwork-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c52c47463d1e58c56f9d84bb29374ec71ec0b06f68cdb7359ae33c1572a39adc"}, - {file = "pyobjc_framework_CFNetwork-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f73e6da65867a498303ef315f1182b6e88ceca78c03424e17b7a43bbe0199d58"}, - {file = "pyobjc_framework_CFNetwork-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0e1c060b64e865e88af6fd60965f3fc16f31516e2235025e46e985a55c780b6c"}, - {file = "pyobjc_framework_cfnetwork-10.3.tar.gz", hash = "sha256:9dd4700f88575dce21b0827fde79ac29580f0f4f99a725aa910b9aaad47e0b63"}, + {file = "pyobjc_framework_CFNetwork-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:e6027a90c5442e36a4ef91c9e10896efb5bc1bb4743d732adf3422112922f6cf"}, + {file = "pyobjc_framework_CFNetwork-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:dff41296378029f1a5e9cedbc133b243f096a93fcc8d6985c555459328cfe11e"}, + {file = "pyobjc_framework_CFNetwork-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:01f1c4c43792e993c613b5b8923953eea774d4a7567fbc1861edb2c6c0cfa770"}, + {file = "pyobjc_framework_CFNetwork-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f6a5d6fe5e230cc0d53b9673902f1571ab68b542f3630d7c1319ea1e3e480f22"}, + {file = "pyobjc_framework_cfnetwork-10.3.1.tar.gz", hash = "sha256:0e4c51a75dbf4e2b1c0d4ee60a363f9d31d682d2dd2f6b74aded769d2d883aa8"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-cinematic" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Cinematic on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Cinematic-10.3-py2.py3-none-any.whl", hash = "sha256:2705fe6893bf8ac9c836dc5a10abe781e3e00af9b4b6c72eb455a0bee30b1deb"}, - {file = "pyobjc_framework_cinematic-10.3.tar.gz", hash = "sha256:17cfae0f02b382b9a9f69128279cb5c156b1dfbd205a7f87941a28bf9fd72c37"}, + {file = "pyobjc_framework_Cinematic-10.3.1-py2.py3-none-any.whl", hash = "sha256:48bf35d594f4f010266a028bbf93bd953cc78db7658d3c614e219b482c8d73b2"}, + {file = "pyobjc_framework_cinematic-10.3.1.tar.gz", hash = "sha256:7edaaa7e325aeb39cd0c33329c25783dd54af294229884556daad36d1d1b9d72"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-AVFoundation = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreMedia = ">=10.3" -pyobjc-framework-Metal = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-AVFoundation = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreMedia = ">=10.3.1" +pyobjc-framework-Metal = ">=10.3.1" [[package]] name = "pyobjc-framework-classkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ClassKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ClassKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:06b9a516cbdb6d1a18971a872f2a1306b19e3eb6c2ffb1b1fd54f7bcebc2aaf0"}, - {file = "pyobjc_framework_ClassKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:14f2ccd96c893b7f9ad852c19320eeaed09928a4d6a747aaadab136cf13f6fee"}, - {file = "pyobjc_framework_ClassKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5e2b21fa1f6ec371d6fbc25c044c084537823330314d527eac087fb1827ace3d"}, - {file = "pyobjc_framework_classkit-10.3.tar.gz", hash = "sha256:95279d5e21d2f6298b2956d46213c6ec2acf3762e6e1b62ba6b5c240274de5c4"}, + {file = "pyobjc_framework_ClassKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:980d2605296428d177b0111af914d0dd4a0c5116da5ae944cdd8b6bba733e758"}, + {file = "pyobjc_framework_ClassKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:17dec45d5ec7db663bc87ddf80b8185d2134177f265a12a9a6df778901183412"}, + {file = "pyobjc_framework_ClassKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b74155902851e8e2b31b34c606dd33f9e24d9b8992568cc71b60e1ddc553d99e"}, + {file = "pyobjc_framework_ClassKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:776a600182b7de58676ac661b235356f46683e758d99db1cf60f52aac335389f"}, + {file = "pyobjc_framework_classkit-10.3.1.tar.gz", hash = "sha256:e15700d32007bf77c5c740bc9931c864bb7739cdfcd2b0595377c3ed35ecfe25"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-cloudkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CloudKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CloudKit-10.3-py2.py3-none-any.whl", hash = "sha256:cad1645304336e5fafe9ffca3398bf8592c3b477b3ebb3c94c75b47a085d9dde"}, - {file = "pyobjc_framework_cloudkit-10.3.tar.gz", hash = "sha256:72e2dd2f5ea91c4a1dc45e50eac8566ba85f196a7aa14c159c6f079fcb2e67e7"}, + {file = "pyobjc_framework_CloudKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:53670f47320063b80aa60edd2d813308dce85dfd2112461dd13c060aa9e5b47a"}, + {file = "pyobjc_framework_cloudkit-10.3.1.tar.gz", hash = "sha256:4c7db72c2bb2fcf63365df91bf2eefa83cee4004606b901e1da89b75da652309"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Accounts = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreData = ">=10.3" -pyobjc-framework-CoreLocation = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Accounts = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreData = ">=10.3.1" +pyobjc-framework-CoreLocation = ">=10.3.1" [[package]] name = "pyobjc-framework-cocoa" -version = "10.3" +version = "10.3.1" description = "Wrappers for the Cocoa frameworks on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Cocoa-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:745fcd99cc9ca1827a5b6fa2127d12023428f8ce2047afefc57b1e69f185750f"}, - {file = "pyobjc_framework_Cocoa-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:116b79be8e9756047a9b6f90d2f08c0e640ff86fcea85ca553dbbb4b121b390f"}, - {file = "pyobjc_framework_Cocoa-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:08ccc260d3481ddf03784f7dcf2cc7a4e9d8f1ecdf727cb4f80cde7b88416c39"}, - {file = "pyobjc_framework_Cocoa-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:277f5e4d4fab0d431cb5f07fc161a3076cb365099977e748c6a255e94eaad137"}, - {file = "pyobjc_framework_Cocoa-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:008e5ca144a378513ee5f8c5a9009e8b4401ec09edda3648b01f8d8b640b3152"}, - {file = "pyobjc_framework_Cocoa-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:3c3f9806aa04dc1cd08e18a98a97629f0d0581fa0d6a71e739934f02e8b1a8df"}, - {file = "pyobjc_framework_Cocoa-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb89620f96d5d0d52a158faeab1b568bed6fa6d0c4f883198e60e60a14db1360"}, - {file = "pyobjc_framework_cocoa-10.3.tar.gz", hash = "sha256:d39f90ffe04143911060c392e62b9514f14caaba119657d6e2b8b197af49e117"}, + {file = "pyobjc_framework_Cocoa-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4cb4f8491ab4d9b59f5187e42383f819f7a46306a4fa25b84f126776305291d1"}, + {file = "pyobjc_framework_Cocoa-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5f31021f4f8fdf873b57a97ee1f3c1620dbe285e0b4eaed73dd0005eb72fd773"}, + {file = "pyobjc_framework_Cocoa-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11b4e0bad4bbb44a4edda128612f03cdeab38644bbf174de0c13129715497296"}, + {file = "pyobjc_framework_Cocoa-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:de5e62e5ccf2871a94acf3bf79646b20ea893cc9db78afa8d1fe1b0d0f7cbdb0"}, + {file = "pyobjc_framework_Cocoa-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c5af24610ab639bd1f521ce4500484b40787f898f691b7a23da3339e6bc8b90"}, + {file = "pyobjc_framework_Cocoa-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a7151186bb7805deea434fae9a4423335e6371d105f29e73cc2036c6779a9dbc"}, + {file = "pyobjc_framework_Cocoa-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:743d2a1ac08027fd09eab65814c79002a1d0421d7c0074ffd1217b6560889744"}, + {file = "pyobjc_framework_cocoa-10.3.1.tar.gz", hash = "sha256:1cf20714daaa986b488fb62d69713049f635c9d41a60c8da97d835710445281a"}, ] [package.dependencies] -pyobjc-core = ">=10.3" +pyobjc-core = ">=10.3.1" [[package]] name = "pyobjc-framework-collaboration" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Collaboration on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Collaboration-10.3-py2.py3-none-any.whl", hash = "sha256:ebc711c769ed01382fe2f0335aeed57336e8ea6d352ba2ea514387e37e14325a"}, - {file = "pyobjc_framework_collaboration-10.3.tar.gz", hash = "sha256:b07f2b722bb6db94efe32007227d927d50c8ec43114fec31224da703de991bd4"}, + {file = "pyobjc_framework_Collaboration-10.3.1-py2.py3-none-any.whl", hash = "sha256:889b1e00bdea09c2423e9b8d493492ec45a70787ddc533bf67d060c7ec0e1f78"}, + {file = "pyobjc_framework_collaboration-10.3.1.tar.gz", hash = "sha256:bbca3de3679b058cbb89ad911e3bdfe491a02b4fa219d5f9219c022774ba237a"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-colorsync" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ColorSync on Mac OS X" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ColorSync-10.3-py2.py3-none-any.whl", hash = "sha256:4cf483c9c370fda6ea621d7110b676321511c41b52e4ad33e94c98ebadee0094"}, - {file = "pyobjc_framework_colorsync-10.3.tar.gz", hash = "sha256:27990cde04b111087659507b270bbc788b36b693d1dc95be44e469e78f86e2b4"}, + {file = "pyobjc_framework_ColorSync-10.3.1-py2.py3-none-any.whl", hash = "sha256:0c37075e9b0f1dabc0aa1755687e1a5dada08ae0914ebb593c7810bf8090cf83"}, + {file = "pyobjc_framework_colorsync-10.3.1.tar.gz", hash = "sha256:180960ed6f76084b35073eff49fcca41a8fa883c3236949a40f75daa28ee8f94"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-contacts" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Contacts on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Contacts-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:fe73800104eea8d358dc89f68742bcb65cacbb7e7f3b7caafcdd669b13861057"}, - {file = "pyobjc_framework_Contacts-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:77b2efeaf48b1c1ec5a1aec78323842ae23c774b71aa22a306d66b583b1368fd"}, - {file = "pyobjc_framework_Contacts-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0747f0ff0a49daca0c3ddff28bafe6579bdaaa75eeb4d5a97603e204afc8cf84"}, - {file = "pyobjc_framework_contacts-10.3.tar.gz", hash = "sha256:ca2c9a28bcdb3e0bb0dded2a1a34824c0ec64145e4cdd36b0c8e1edcf8ef0e1f"}, + {file = "pyobjc_framework_Contacts-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:401e40ff638712d011fe54c7b1e9929af994e87cb03d129cd95df2fb90439e4e"}, + {file = "pyobjc_framework_Contacts-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:83de186cd4037171c63899987caa66cc01527688b15176e899cf1a06e6baab09"}, + {file = "pyobjc_framework_Contacts-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e0bbffb430505ad3f91fd58f65b0a6e7535ab5bb28c2ca69ee8a6349f3edfe3c"}, + {file = "pyobjc_framework_Contacts-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d47f694977cf33f5d0b73e2f111edcd57f2ef0cd9a6a38e03b1dea965b8657cc"}, + {file = "pyobjc_framework_contacts-10.3.1.tar.gz", hash = "sha256:7120b5593a20e936cb5589b93ef7fd5558c86bd6ec8003f427afb87c04bbea20"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-contactsui" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ContactsUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ContactsUI-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:78497fbb5b3b65b7318680f988919f7862e28ea1da8257a5a068623caeb42675"}, - {file = "pyobjc_framework_ContactsUI-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c5439b1db545c533c3a9578ed2dee39a98c553c7395c9b3ac20e089b1806a312"}, - {file = "pyobjc_framework_ContactsUI-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ba1315b9519930870adb506cb180e967266f30503e645b4974729fdf774a9d1e"}, - {file = "pyobjc_framework_contactsui-10.3.tar.gz", hash = "sha256:312af2525a5a4e45f23c2d9b3817d8ad5bb2395c44f18be3d692ce16e8fe2bb5"}, + {file = "pyobjc_framework_ContactsUI-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:0e939e46ccff1e07e7fa6768a35d646b7302886a99b9efe6b31dea4ea67674ad"}, + {file = "pyobjc_framework_ContactsUI-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4adc77f2fb7ae4e2999cfd72f5d3b8e0e039880f9d60cb8e15050607b249c730"}, + {file = "pyobjc_framework_ContactsUI-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1a605d93b4826cd4646cced6383cb253e65c8babcfd230d5894c1c4d67f6e147"}, + {file = "pyobjc_framework_ContactsUI-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:62ae604a000233c729712e420de734c97afdd9187fdd0bef8e61fbc8c4f6eda0"}, + {file = "pyobjc_framework_contactsui-10.3.1.tar.gz", hash = "sha256:51601501d5bc94c59ad458c7bb1d1994c497b373307dad8bd2ea2aa348f66c4a"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Contacts = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Contacts = ">=10.3.1" [[package]] name = "pyobjc-framework-coreaudio" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreAudio on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreAudio-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce7223a0b0295442a6ffc49c03bae555907ebf4d266ca89446be7db705d17845"}, - {file = "pyobjc_framework_CoreAudio-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40b7236da5349e892fd57e9a777f068c25659ee832c5c3f938acb65be9e3fe80"}, - {file = "pyobjc_framework_CoreAudio-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:17bc91198166232a77c935f449b77d9b72ef742638478ab8e2e92740995041e1"}, - {file = "pyobjc_framework_CoreAudio-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:3444691c03c096902601a52bcf5b985e54d12fea7d9d8f53968a86998876468d"}, - {file = "pyobjc_framework_CoreAudio-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01e21d0352b46ac49b3154f4557d23ec391687f621d210d59f7283855229d1bb"}, - {file = "pyobjc_framework_CoreAudio-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:ed9883f42a001c5795d5e04bb57788acf57700769a31d922b7b1be936757c1b3"}, - {file = "pyobjc_framework_CoreAudio-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2d6d278bb83687dec413f43c568e3ccfea2f1192b53e1f7252bd6bb4fa0a992a"}, - {file = "pyobjc_framework_coreaudio-10.3.tar.gz", hash = "sha256:658af891719c3c60d1e36f77662eaa80f63ecaaabbf029f90f107bc1fc86b9b6"}, + {file = "pyobjc_framework_CoreAudio-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:76a37e27cfdd67e4dcf27f57b680a881c4a2f3bf44ce3b31d7cdb32596e1e269"}, + {file = "pyobjc_framework_CoreAudio-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bd58e69cabbc987d0c2854ab2d13516889cfe4a2094b80296591ad7df0f30e40"}, + {file = "pyobjc_framework_CoreAudio-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e0aeca61a425d846afc92350ffba970e1e503469182f5f0ea436de98cfd00d96"}, + {file = "pyobjc_framework_CoreAudio-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:21cecd1b023b6960d1071c106345656de45a399196701b07c7e5c076321f25ad"}, + {file = "pyobjc_framework_CoreAudio-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:443b14cc6e64e09e6fb4eae61f6ac1ce19618d9074ae1627d75754fa434ef87f"}, + {file = "pyobjc_framework_CoreAudio-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4f8d4c4c4fa0529f178ef6d3676cfe08c9e8ae20c3cdbfe067b562d7395debfa"}, + {file = "pyobjc_framework_CoreAudio-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b93cc6f670feea29f8f4cd2a9511d2220aefde41a89912d5ab8eb06a198e344b"}, + {file = "pyobjc_framework_coreaudio-10.3.1.tar.gz", hash = "sha256:c81c709bf955aea474a4de380b187f3c2e56c864ca7de520b08362b73070c795"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coreaudiokit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreAudioKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreAudioKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:25006ba6109d79532926f9b8c590d386bd2375f411f6adc97f6bb4903a6d78b5"}, - {file = "pyobjc_framework_CoreAudioKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f3f08f32eec59f80784929a372c7bdc4e1c5d4b41cd2889f4fa7af50369854aa"}, - {file = "pyobjc_framework_CoreAudioKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:47b743bdd2ec3d8fec9d6bb7ad08918af016ab8fa55f90808d12427a4b973b4a"}, - {file = "pyobjc_framework_coreaudiokit-10.3.tar.gz", hash = "sha256:7a17534f08a8426e26ee3eec9f80f22aa5be3d6114687344f7545176abd4a705"}, + {file = "pyobjc_framework_CoreAudioKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:dfc967bc448cc0a1fce932e6af15ad42f5ea3eb2f793396e364cf39005c812eb"}, + {file = "pyobjc_framework_CoreAudioKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6634f3f15d257e93cad4644eb08f5b32376e8a8a7ae2e95d99d36d935b5e9ba2"}, + {file = "pyobjc_framework_CoreAudioKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c2bf1b0c9f6c1d27c98b87bf4cf1ba3d0fa550dd771de948614ca21d15779a01"}, + {file = "pyobjc_framework_CoreAudioKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d5b3adabd7278e64a0deab6d0f6912bfcc667bc26054f5141a556897157dd8f9"}, + {file = "pyobjc_framework_coreaudiokit-10.3.1.tar.gz", hash = "sha256:81f35d5dc45cda043e01f0ca045311f4aebc36c51cb71e859b30ea0edf90b3db"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreAudio = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreAudio = ">=10.3.1" [[package]] name = "pyobjc-framework-corebluetooth" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreBluetooth on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreBluetooth-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1da6f13386165f28a55d71ba73fc93e3a731023cd83cbb0846f43aff7135856a"}, - {file = "pyobjc_framework_CoreBluetooth-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:d96c721409979953353e006596f8d646ae35f3a463b2545a4d0083244a81f2a9"}, - {file = "pyobjc_framework_CoreBluetooth-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:439abd4edcbd6f091f4a885afe01f322ca4c879e6eb0edda869f359c5979fef9"}, - {file = "pyobjc_framework_corebluetooth-10.3.tar.gz", hash = "sha256:7ca00c8f96517b4421162846b5f66369360e4523ca917c6e0507d051381fb466"}, + {file = "pyobjc_framework_CoreBluetooth-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c89ee6fba0ed359c46b4908a7d01f88f133be025bd534cbbf4fb9c183e62fc97"}, + {file = "pyobjc_framework_CoreBluetooth-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2f261a386aa6906f9d4601d35ff71a13315dbca1a0698bf1f1ecfe3971de4648"}, + {file = "pyobjc_framework_CoreBluetooth-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5211df0da2e8be511d9a54a48505dd7af0c4d04546fe2027dd723801d633c6ba"}, + {file = "pyobjc_framework_CoreBluetooth-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b8becd4e406be289a2d423611d3ad40730532a1f6728effb2200e68c9c04c3e8"}, + {file = "pyobjc_framework_corebluetooth-10.3.1.tar.gz", hash = "sha256:dc5d326ab5541b8b68e7e920aa8363851e779cb8c33842f6cfeef4674cc62f94"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coredata" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreData on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreData-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:218b64c79a6d2402852c763dd1accff2113ef206676b2b5a0027e875978cc56f"}, - {file = "pyobjc_framework_CoreData-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1fdb6d56d2902b9cafaeec8cc8fc0ea9b98c49abef59ac4afdb37e9672b9bd1a"}, - {file = "pyobjc_framework_CoreData-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:65de27fadc762d72efd559e1e92f5a98831e492500b6dc0ca405810afd5b72aa"}, - {file = "pyobjc_framework_coredata-10.3.tar.gz", hash = "sha256:1101f071d2e4485fcf3a41ec524cc27e4d0e86b19a03cca19a287ad5cbd1ca31"}, + {file = "pyobjc_framework_CoreData-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:2313aba4236f3a909d2747f4327da83be884adadb734a602ed4319addf88edd7"}, + {file = "pyobjc_framework_CoreData-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:065ff3058f4bc8544422ad1f10dff037bdeed25263cc8ec5c609e54231bf9347"}, + {file = "pyobjc_framework_CoreData-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:049acf980e5226b132a4285c3a94cc8266380e57050c8fd4caec3c5df4ef8c4d"}, + {file = "pyobjc_framework_CoreData-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:2f1f4e1217fc02f66435dc2a5cb2e0b41c684c435f13d96bf05cd3d1e0ad4e2c"}, + {file = "pyobjc_framework_coredata-10.3.1.tar.gz", hash = "sha256:8a75094942c8f3ddc1bcbde920c87658d7bb4c7534a4652e60db42d17f4b4a4a"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-corehaptics" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreHaptics on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreHaptics-10.3-py2.py3-none-any.whl", hash = "sha256:48077361a913ef7e9927c0110255c29ba58576a33f31276ac53eed18c50b13da"}, - {file = "pyobjc_framework_corehaptics-10.3.tar.gz", hash = "sha256:59cbdda7c4c77556377e97d47887385f9d641278015118c533165f8dd540910a"}, + {file = "pyobjc_framework_CoreHaptics-10.3.1-py2.py3-none-any.whl", hash = "sha256:163b83ea727cbac5c0963d16ffda89c9f1626ed633d5e52830c7918b8599a693"}, + {file = "pyobjc_framework_corehaptics-10.3.1.tar.gz", hash = "sha256:5a7cc117c0b64428e1f08dc9c8b76dbc5d8f61f80dc41e911d11ddee4e0e2059"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-corelocation" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreLocation on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreLocation-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7bb5bc7835783f20a7262956a276526bc58bd74c1445a1272158c40704ebe3c1"}, - {file = "pyobjc_framework_CoreLocation-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f0de20706d176d118c65b551857d93c2f825a1ebe6aafedaebcae25bde61d917"}, - {file = "pyobjc_framework_CoreLocation-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:80f35e370a047bf67dffb6986adbd5f4dc80301760634722f9375fd2a69d0632"}, - {file = "pyobjc_framework_corelocation-10.3.tar.gz", hash = "sha256:0c48a19d253ac5746327a2bb12216d91972dc409809982f5bc8c03a301baebae"}, + {file = "pyobjc_framework_CoreLocation-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4cc83a730db7f78ca5ceef45ea4c992084d8c90bed189939fa3f51f8e9ea83ae"}, + {file = "pyobjc_framework_CoreLocation-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:97d5aa35214e417c9a03ac7209630dc445b98652932642dd0497f1ec52624bfe"}, + {file = "pyobjc_framework_CoreLocation-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:86d0e00b7eef5a3e2f01ea309cdcf58807b251138008edcfc65d3c31af8a5bd2"}, + {file = "pyobjc_framework_CoreLocation-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5c4ded6388f99a18ce2b9d7082b8a43a19b6d9f8f121e2147d10bb37a25e1714"}, + {file = "pyobjc_framework_corelocation-10.3.1.tar.gz", hash = "sha256:8ae54e5bd4c07f7224639d815f7a6537fadee17c11cb35dd99c2804bac1825ab"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coremedia" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreMedia on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreMedia-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:29d365c3eb9b3d40168c17f55df193c8b1db08668911c78a74d58d3f90ba4881"}, - {file = "pyobjc_framework_CoreMedia-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:efc4f40a216e7a3503ff1f047124ffa3ebbc7d7574128c361ae0c7189aed58d4"}, - {file = "pyobjc_framework_CoreMedia-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:88e934d2231febcfa049a274a6d4db86987c986958adffa5cd972c2b25b7cddf"}, - {file = "pyobjc_framework_CoreMedia-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:52de7b47a04743e12617f9de17216590ff6c5120f610bf962d7851f449309632"}, - {file = "pyobjc_framework_CoreMedia-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b1a93d2535b9f41fbd03a10dc15ea13a8675cae408f18122acce9e10e2e3a2c2"}, - {file = "pyobjc_framework_CoreMedia-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:2567dfafc595c92f5e7c1cd52fd49d7edb6f581a6eb9ae3929d195458097d62f"}, - {file = "pyobjc_framework_CoreMedia-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ee5e0ea21cc43d584cdaf304e5b34b1bf34279e787fc1751bb78cfceada464e"}, - {file = "pyobjc_framework_coremedia-10.3.tar.gz", hash = "sha256:91e9752da6dd04a21349fc5a640c4665357fbcdba45f4800bb634b466fd05173"}, + {file = "pyobjc_framework_CoreMedia-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ef02d87f12ba54e6182ea72fd5732cf6d348982c4263dc9c0b11e4163fbb877"}, + {file = "pyobjc_framework_CoreMedia-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e63b002cf5e34540cba3f3a1704603ea0fb076ffc1ea42c2393a0679f40846de"}, + {file = "pyobjc_framework_CoreMedia-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c6eaf48f202becab10679e3b5dd62607ddec2739495db45882524592cabf3997"}, + {file = "pyobjc_framework_CoreMedia-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:98b8ab02e6ec979007b706e05166e16bd61121e47fbc6e449f4b2de2c58f3cb6"}, + {file = "pyobjc_framework_CoreMedia-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:77ca460cc35e39b9f820d9f20e93bfa89439b23dfb350ba201448b1ee958902c"}, + {file = "pyobjc_framework_CoreMedia-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:6ed3adf48fe3001d1b5acce688ecd5b75e0fa5f56d9f296ec120748cd36f2d24"}, + {file = "pyobjc_framework_CoreMedia-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b5bbed395bb8a8b0b4b8bb5475fd19f2a28d385c4d3a783cb590c9ea5e801baa"}, + {file = "pyobjc_framework_coremedia-10.3.1.tar.gz", hash = "sha256:bc3e0cddf5f546b5d8407d8f46b203f1bd4396ad5dbfdc0d064a560b3fe31221"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coremediaio" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreMediaIO on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreMediaIO-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:25b7359a195e4e9339744d835290a9232a783bc03eb4b21dfe5076e56fde5d05"}, - {file = "pyobjc_framework_CoreMediaIO-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0fdcd3332de8942a39181eca08ac42ab71296275305ca76c9fbdeed9ac020d1c"}, - {file = "pyobjc_framework_CoreMediaIO-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e78950d9d0fa6bcca95fd4f414824da3b722e501be1b2c519d557b69b03dadaf"}, - {file = "pyobjc_framework_coremediaio-10.3.tar.gz", hash = "sha256:d136225bf4fdae1b3962b0b163733e06ff104fd55c424424bdaa93d5acb7507b"}, + {file = "pyobjc_framework_CoreMediaIO-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:07e19e89489a372ebea9e8a5cfaf1ec03fd570e65ed3fa2dfa44719d1e337a36"}, + {file = "pyobjc_framework_CoreMediaIO-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c3bc3d8f3648b6a4126983119d9fc4e21d2c7ec06beb284c57039ca1033ceb03"}, + {file = "pyobjc_framework_CoreMediaIO-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b158612a62cabd7f61c1f2a4d08d4cb4682e1b2ba140a4d09ca88b1ae3014443"}, + {file = "pyobjc_framework_CoreMediaIO-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b3e9a9813bf5331bd0981e0a66ff380c5c927854f644e5cb62a2beaabd73b15f"}, + {file = "pyobjc_framework_coremediaio-10.3.1.tar.gz", hash = "sha256:5da3ed78475223dd3400fdb55fb97d543a248086f5cf8b77bf4aceac3df1513c"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coremidi" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreMIDI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreMIDI-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1a1950ad4effaa46fde70b3c08331ba105b244b3ffb49fb44bf13590883d5af7"}, - {file = "pyobjc_framework_CoreMIDI-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0eda91893eeb21e25e3750a86f2d995d101cb0aa2d3a6620ada7ffbe866592ca"}, - {file = "pyobjc_framework_CoreMIDI-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b9cb89bc18165114a9675891586ca30d572270219b170619ac89f6313a68598d"}, - {file = "pyobjc_framework_coremidi-10.3.tar.gz", hash = "sha256:dd863a02a7cde849fdf1406bc604c86ce03812063fbc3fbb524f77e2b220a145"}, + {file = "pyobjc_framework_CoreMIDI-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:00a6869c2365b90cdf6e1ed0bbde6d87fe4daaa40ed243ee810e3cc3945f185a"}, + {file = "pyobjc_framework_CoreMIDI-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:92d04962f7ea63be03127880d4659f718f5b44b6a57a0e619a96d9def619bddb"}, + {file = "pyobjc_framework_CoreMIDI-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1be5f2d3c0c7c23817ad49a25d8cf8c84b9e420bd5fedc0065ec1322f5d5f2ab"}, + {file = "pyobjc_framework_CoreMIDI-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:bbe2bfb537e8adcca703a2c76b21ca1741d32691205af00a5ec67c025ee5d8e1"}, + {file = "pyobjc_framework_coremidi-10.3.1.tar.gz", hash = "sha256:818454b56edae082a3a4b4366a7e93b8bb54856be01ee21bb8527a22a4732efc"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coreml" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreML on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreML-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:1c2427c9d0150cc270aef9385cfa6dcd47f0264847c07c96aca6f14d3b5015f8"}, - {file = "pyobjc_framework_CoreML-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:403754cd9f5bafdddab8d7227dedc79c4bcbe19887e333103e35a25d3ec2452e"}, - {file = "pyobjc_framework_CoreML-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3e468ca8f2e2430cc4b7e87bb42d5caa15a58f9f9d3df682dc1ac029cfc54113"}, - {file = "pyobjc_framework_coreml-10.3.tar.gz", hash = "sha256:37f86fbf7cf90809a43ad81a8fc31190175b9b78e792351817d124c3daf1302a"}, + {file = "pyobjc_framework_CoreML-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c1fdcc0487807afa9cd0f88f25697e0e2e093d0219e8e1aa42aa3674dd78c2cb"}, + {file = "pyobjc_framework_CoreML-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:21c87e84c807b5dbe61e0f016d9aefa32d3212f175cc4b976b5c08770be7a58c"}, + {file = "pyobjc_framework_CoreML-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a0877aed5d4cdbb63d1246cd5384c09d78a0667e83c435a1257d10017c11c1a4"}, + {file = "pyobjc_framework_CoreML-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4bd3f1acfb3245727727b71cbcf7d21a33d7e00fa488e41ad01527764b969b92"}, + {file = "pyobjc_framework_coreml-10.3.1.tar.gz", hash = "sha256:6b7091142cfaafee76f1a804329e7a4e3aeca921eea8644e9ceba4cc2751f705"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coremotion" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreMotion on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreMotion-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7457a9167f70e5e41055663364431bb66c0995bbf4078183323b0f7492d6f62f"}, - {file = "pyobjc_framework_CoreMotion-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d0e03179739670d0c1a4a7b50a2b652163c16e8ef3a0e88962179430058abbc9"}, - {file = "pyobjc_framework_CoreMotion-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:eaa3fa5638717011f0eb64e2b1e8354574b363780efadd37bdd6490f0a0fa1ca"}, - {file = "pyobjc_framework_CoreMotion-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:f924079954b0035ff95e943c88964879c0cfd35f59b285586fc1034f421c8060"}, - {file = "pyobjc_framework_CoreMotion-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:379f74023ce989df59df8d4fe6a6ff0e6ac5e081ae45ab457c173b301e9a2f87"}, - {file = "pyobjc_framework_CoreMotion-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:39734bd0a2fe727208ecd795edc75ae85cca5745297c7783fd0d9fefd0b8e16d"}, - {file = "pyobjc_framework_CoreMotion-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:731e556f2ba5f24d941d5b36f9c4282e26f78794dc80c4de37dbfd12492dc83f"}, - {file = "pyobjc_framework_coremotion-10.3.tar.gz", hash = "sha256:981c395ba01b5e9cfe1474d8f180b9ccf42b35cf45ed8159b1ee4d1e4bd33721"}, + {file = "pyobjc_framework_CoreMotion-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f8c320df1806ccd8c2b1ac32c9b9a7337816ff13cf338a710a2f15ee550f58cb"}, + {file = "pyobjc_framework_CoreMotion-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a003478eeb520c7f28be4d9dc8f9e02df6ffa8921d46c8879e2b298c9fbc6926"}, + {file = "pyobjc_framework_CoreMotion-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:63c8f831ad522212627f99ae8d6f34161628230afd544203646e7d66596d6437"}, + {file = "pyobjc_framework_CoreMotion-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b78d2bcc71149821a49266eb548faea23abd7a25b7cd3f7a7f20b1d343a8786"}, + {file = "pyobjc_framework_CoreMotion-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28b431e448b884830c846d156d9c6626b265d9ede70ad233d77ceceb67366a17"}, + {file = "pyobjc_framework_CoreMotion-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7d4f95398ac5741a6dd1711e129f6173111385e26d858c59be8462543f62a8a1"}, + {file = "pyobjc_framework_CoreMotion-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:89c78be31e276aa88d848b69a2f8d11360deaa7297222bd5369ecd1910de166d"}, + {file = "pyobjc_framework_coremotion-10.3.1.tar.gz", hash = "sha256:6ba61ffd360473b018702b9ae025eb16b8aaa45c6e533121522f26eef93a9f71"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coreservices" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreServices-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:73b72eb37f7f1ee6f0dd4741adc56549806501c023b50d1425cf0765163caf3f"}, - {file = "pyobjc_framework_CoreServices-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:002139b8bcbb268eaf37c9055efdc9f70d6eab3bc7d36d169162968eff10aaf4"}, - {file = "pyobjc_framework_CoreServices-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:13e4c1a0cd54a557267a86deb47a8c8bc24ef2a4f1b427c2ddc4852f830c96ff"}, - {file = "pyobjc_framework_coreservices-10.3.tar.gz", hash = "sha256:a7c38090c26a2e1b600fb31c3b056ef60e86bacfbb26ecfbcdd997ed61b1cdc8"}, + {file = "pyobjc_framework_CoreServices-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:58d5708ee0a2ad7eea180864fe68123a2464b987ea089d0646ce69e2002500b0"}, + {file = "pyobjc_framework_CoreServices-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9d43b77fa11af139ba39d94921e695cf804226737f68167f8bdb8f1c449c932e"}, + {file = "pyobjc_framework_CoreServices-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e6c7b6bb821cc7fb4f04c08560d460783a7fa08093f5e153241bf10296a16cb4"}, + {file = "pyobjc_framework_CoreServices-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ccb64113ee612a05308ab8ed57ec224e22445d5a125bec11e24c35d58d1f77e4"}, + {file = "pyobjc_framework_coreservices-10.3.1.tar.gz", hash = "sha256:2e46d008ee4ff586420175888c45f8eb0f002ed5b840c8f7893c560af01b2d72"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-FSEvents = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-FSEvents = ">=10.3.1" [[package]] name = "pyobjc-framework-corespotlight" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreSpotlight on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreSpotlight-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:34497a442230e6f98e99374ba5b0694aa36ae730aece3869c022953e54554876"}, - {file = "pyobjc_framework_CoreSpotlight-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ce50141e3b0225d79ec39c99cd1fd5ba71fc02c83e4b87b39a98c6abe1b8764c"}, - {file = "pyobjc_framework_CoreSpotlight-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:07df5335405ccb55a12a44fe9bb7c3104068b5f9340ced6dd0e47a7098fa18c3"}, - {file = "pyobjc_framework_corespotlight-10.3.tar.gz", hash = "sha256:532340debec937393569d27f8f28af16fc46270e47299dad63634e05b58161da"}, + {file = "pyobjc_framework_CoreSpotlight-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4aa9b01b8d722ba9e803ec4a2329ee8da0bdecb9a004a668b793b957544a6d81"}, + {file = "pyobjc_framework_CoreSpotlight-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9684f735fd3d3e8fae447e90a2c246bf6a8d4ca37f619174208d65daa86d9ca0"}, + {file = "pyobjc_framework_CoreSpotlight-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:31b2a1309c747bb6e4d1ddc8368885af2948af55441fbf9817ebac193c1b815b"}, + {file = "pyobjc_framework_CoreSpotlight-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ba5a20e860af7246da67bb00db15d8bd5c5110b8a12a44568bd68030f51db478"}, + {file = "pyobjc_framework_corespotlight-10.3.1.tar.gz", hash = "sha256:6b8ad243a65943d631434a9ff4696458cdd3d0cb631cfeb501a967fe29445c30"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-coretext" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreText on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreText-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6d68d8a4cd2e86a1a6fb748beea20ae5256221ec282c69becb16334ae293c17e"}, - {file = "pyobjc_framework_CoreText-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb7d4e89d7f6d579ec807542cebe815e62fe37a473342c8f026b6b048260d591"}, - {file = "pyobjc_framework_CoreText-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:bc4a53c6e82606e24d4e096f4c503c78ec0171f67cd3214c571ff443c6edaa8f"}, - {file = "pyobjc_framework_CoreText-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:4c2c407a24aa44acc3495098e394e33a332e3ae03d68cc6a045f94ad0a6c51e7"}, - {file = "pyobjc_framework_CoreText-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a43f90662021248c6c9e31a9d9d75a33b9eecb738075998798926ceb5c243455"}, - {file = "pyobjc_framework_CoreText-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:bddc0f7f72a92747d783cecd0a51eb1936d73dd77a5d1de48317d4a7e1293c98"}, - {file = "pyobjc_framework_CoreText-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8a697a4bbd51a45bb1c74baa3f83fd224c01e6352528b1c2485a01359785e695"}, - {file = "pyobjc_framework_coretext-10.3.tar.gz", hash = "sha256:d1c5f4345783451314f6f9725f0d020d02f112eaa8acd2cd15c27ca8e7639a64"}, + {file = "pyobjc_framework_CoreText-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd6123cfccc38e32be884d1a13fb62bd636ecb192b9e8ae2b8011c977dec229e"}, + {file = "pyobjc_framework_CoreText-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:834142a14235bd80edaef8d3a28d1e203ed3c988810a9b78005df7c561390288"}, + {file = "pyobjc_framework_CoreText-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ae6c09d29eeaf30a67aa70e08a465b1f1e47d12e22b3a34ae8bc8fdb7e2e7342"}, + {file = "pyobjc_framework_CoreText-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:51ca95df1db9401366f11a7467f64be57f9a0630d31c357237d4062df0216938"}, + {file = "pyobjc_framework_CoreText-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b75bdc267945b3f33c937c108d79405baf9d7c4cd530f922e5df243082a5031"}, + {file = "pyobjc_framework_CoreText-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:029b24c338f58fc32a004256d8559507e4f366dfe4eb09d3144273d536012d90"}, + {file = "pyobjc_framework_CoreText-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:418a55047dbff999fcd2b78cca167c4105587020b6c51567cfa28993bbfdc8ed"}, + {file = "pyobjc_framework_coretext-10.3.1.tar.gz", hash = "sha256:b8fa2d5078ed774431ae64ba886156e319aec0b8c6cc23dabfd86778265b416f"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-corewlan" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CoreWLAN on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CoreWLAN-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:485ea9c1cbddf8f3d76b162fd1498a5ac882294cb5699d978e3e7e083951cebb"}, - {file = "pyobjc_framework_CoreWLAN-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8ca8fdf5d7d8a1fe96c673c377d8788780d61380565c16a2508736435e0c1a61"}, - {file = "pyobjc_framework_CoreWLAN-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1a41570f7d9c2d298430abb6ee9b631cbbacafca9989627ddb8e8bd97de414d1"}, - {file = "pyobjc_framework_corewlan-10.3.tar.gz", hash = "sha256:1ddc4d9bf0a02f3a8cd2add8721edcc5595dde0660ca02746db3cc0ce2b0af9e"}, + {file = "pyobjc_framework_CoreWLAN-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:0b9b9a6f54c11b6adcb04eb07686c8a8372140619876073d6355498da7ecd074"}, + {file = "pyobjc_framework_CoreWLAN-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8d68dabd2fdb74e5263f1e05fa039621c197907347e045cd672a54b3ac537140"}, + {file = "pyobjc_framework_CoreWLAN-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:995260e02f858ffa0781ec0d632e60e0567c45fd551102d36fe67a351f81697e"}, + {file = "pyobjc_framework_CoreWLAN-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e7120d4f7a73cfc283ca499165e8aaf2628bfb82773917e144c293447cabbdba"}, + {file = "pyobjc_framework_corewlan-10.3.1.tar.gz", hash = "sha256:d340d976b5d072b917c6d3de130cb4e7a944ee0fdf4e1335b2aa6b1d4d6b4e14"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-cryptotokenkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework CryptoTokenKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_CryptoTokenKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9809ea10b0987d01f08d7948cd577a0dbc38f82d400270d8ff5903671bf99ab"}, - {file = "pyobjc_framework_CryptoTokenKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7272b025e56b5623994a629fd67c56ac84ec79976fe198640778f5b92b259c95"}, - {file = "pyobjc_framework_CryptoTokenKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:38d03fbd3348c471e201ea542b170bb633122e05dfb269b17e1d89ea01af2e0e"}, - {file = "pyobjc_framework_cryptotokenkit-10.3.tar.gz", hash = "sha256:d810a0f72cfe0a03ea57ce5efa9b44f1cbf73ea924431710338df8424a0ac4cf"}, + {file = "pyobjc_framework_CryptoTokenKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:6c88948bc8d30cd125ae29ffe551315e08c0fb49654d4f36ba4b3f0fe2f85259"}, + {file = "pyobjc_framework_CryptoTokenKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf0735d5d8e3ff61650deaa9670df62032dc218b865f21cd6b36b0d4c00b88ae"}, + {file = "pyobjc_framework_CryptoTokenKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:bd58e48912a9b044c0203e39938b2108cab9b3a4903134ebb1ef610b45570802"}, + {file = "pyobjc_framework_CryptoTokenKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b53fdc79a095d327dff7e68e2545b0825437520f105b1341e5f638e8e1afb490"}, + {file = "pyobjc_framework_cryptotokenkit-10.3.1.tar.gz", hash = "sha256:ef1c4a3b9bc5429eceda59724279428e1f8740df2c5a511d061b244113b6fd97"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-datadetection" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework DataDetection on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_DataDetection-10.3-py2.py3-none-any.whl", hash = "sha256:50d5c2f6856251ca33d8d82545c2c9f57742f6623857855b1a9e5e52c2dbcef0"}, - {file = "pyobjc_framework_datadetection-10.3.tar.gz", hash = "sha256:eb3f1e8383affbc594b161dd5c73d398a553f03af837eaef13a81fcc6690637f"}, + {file = "pyobjc_framework_DataDetection-10.3.1-py2.py3-none-any.whl", hash = "sha256:618ea90267fd4b83d09b557b67342ad5f3ac579090020e081dca6c664f1ae598"}, + {file = "pyobjc_framework_datadetection-10.3.1.tar.gz", hash = "sha256:5394350cd7e7f40562dc0777f26dd9ddf4a595d20cb6e3cd601938e9490c963e"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-devicecheck" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework DeviceCheck on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_DeviceCheck-10.3-py2.py3-none-any.whl", hash = "sha256:a1982656616dfb4749d0dfb58e8ecc99f382599e678d66c6b3f5da87486dc499"}, - {file = "pyobjc_framework_devicecheck-10.3.tar.gz", hash = "sha256:e75e2261f61686a4590bdceef43357d8ba972b61e34ad9d0c2bf9dd07c405360"}, + {file = "pyobjc_framework_DeviceCheck-10.3.1-py2.py3-none-any.whl", hash = "sha256:9a3b291a2583bac2b65ff902c4b7872c1068736e249765906f530ae5a6eb8085"}, + {file = "pyobjc_framework_devicecheck-10.3.1.tar.gz", hash = "sha256:7f6f95c84dc3d1f62aa07061f79b47d19463390d977e5afb444ef9fdd9177a9d"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-dictionaryservices" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework DictionaryServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_DictionaryServices-10.3-py2.py3-none-any.whl", hash = "sha256:8ed612ff352f943cd9f7f5b77bd1d9da76e8ba2a852eb43c97cbfa692c506396"}, - {file = "pyobjc_framework_dictionaryservices-10.3.tar.gz", hash = "sha256:07ef0bc72a79f9634cd32f2fcd6299b60ae3b0c57e123fa36d298e9390f88351"}, + {file = "pyobjc_framework_DictionaryServices-10.3.1-py2.py3-none-any.whl", hash = "sha256:e40933bc96764450dff16cd8ca8080ec83157a93ed43574441848ea52f24918d"}, + {file = "pyobjc_framework_dictionaryservices-10.3.1.tar.gz", hash = "sha256:c9fb8ed1b92f63c6f568bcdbadf628baab1cb8bb4cd01dbd65424d59c236a552"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-CoreServices = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-CoreServices = ">=10.3.1" [[package]] name = "pyobjc-framework-discrecording" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework DiscRecording on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_DiscRecording-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4059e53356d0c52c8913fe63b440dcfa94312c6d10d0f4473f32a0f32859cab6"}, - {file = "pyobjc_framework_DiscRecording-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:739a8d2463af29f498f7c119084c379d2aa22bb07af837f0a0fe9e4508e7d1de"}, - {file = "pyobjc_framework_DiscRecording-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:0d74a12e75699d99bc4ed3cdc1c06ae8ae31fe15ec3899d238963404bcd0cd43"}, - {file = "pyobjc_framework_discrecording-10.3.tar.gz", hash = "sha256:f56e054af941feafa9b8599dd2e399460d31b96a9ead11ea794057531ed8623d"}, + {file = "pyobjc_framework_DiscRecording-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:99ee7b1762c7e2a4e0b74c36416f4095695ea33505c7de03875a4f46a5729af7"}, + {file = "pyobjc_framework_DiscRecording-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c4233f2649e34be2dd158752f0f0180c7db4ee705cc14aa62bc03c1f77318ca3"}, + {file = "pyobjc_framework_DiscRecording-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54016cd30b81f1f065d3a4d90b008c1bcfa77891cc79c68d72dff65e9d81e083"}, + {file = "pyobjc_framework_DiscRecording-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:da84170af530cda7b1f32023d5e8b98b62914c573c6ef571e562473d0b94fe6f"}, + {file = "pyobjc_framework_discrecording-10.3.1.tar.gz", hash = "sha256:47865c9a0d24366b6ede01d326d57404346c3d01e249f417bd2b0b3de00d6c54"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-discrecordingui" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework DiscRecordingUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_DiscRecordingUI-10.3-py2.py3-none-any.whl", hash = "sha256:65d49b052c1c200b450607f72defa854863a5d8cae21d52acef7099c779d5b27"}, - {file = "pyobjc_framework_discrecordingui-10.3.tar.gz", hash = "sha256:374b4ab5b09f45667f610e2b10a88a7874cff713fba97e46f3dac5c4f324be4b"}, + {file = "pyobjc_framework_DiscRecordingUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:cb25c70117a5c5eeb4ef74a96da48e2da171f01b7e92d1b7bbd7808068e8960c"}, + {file = "pyobjc_framework_discrecordingui-10.3.1.tar.gz", hash = "sha256:4b9c804a97c89001feddb58106cdc3e099e241314f7c4de062842d27b1318b68"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-DiscRecording = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-DiscRecording = ">=10.3.1" [[package]] name = "pyobjc-framework-diskarbitration" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework DiskArbitration on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_DiskArbitration-10.3-py2.py3-none-any.whl", hash = "sha256:cd59193185f064df2a5bb4d79b337efffec81059ff6049b183b72fe287b5c867"}, - {file = "pyobjc_framework_diskarbitration-10.3.tar.gz", hash = "sha256:e02f6b52d6bdce90e151a77cf1e2c41e9d704608a7c8a049d079a78bc1bf1c80"}, + {file = "pyobjc_framework_DiskArbitration-10.3.1-py2.py3-none-any.whl", hash = "sha256:f0f727435da388efd035bdd510607a5f5769b22be2361afc5b8d4ee081c70cce"}, + {file = "pyobjc_framework_diskarbitration-10.3.1.tar.gz", hash = "sha256:0776318cb56f8e095066a880812c4fc5db2071687846e23a000a947a079f6c6c"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-dvdplayback" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework DVDPlayback on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_DVDPlayback-10.3-py2.py3-none-any.whl", hash = "sha256:7d3e2aec568910deb7e9661185ff55e101726280f90a567d93d2cc40de0c24a9"}, - {file = "pyobjc_framework_dvdplayback-10.3.tar.gz", hash = "sha256:0db8a36223e1471cfabe3ee2767e81cac2686ac178fa9549fafa43a2def664a5"}, + {file = "pyobjc_framework_DVDPlayback-10.3.1-py2.py3-none-any.whl", hash = "sha256:c0fb2e96ce4eae8def642f1c4beaec2da3cdf61db1562d4b5199d1334d1a10fe"}, + {file = "pyobjc_framework_dvdplayback-10.3.1.tar.gz", hash = "sha256:1f7c22624dee9b1b54def15f12a3f7cacb28052cd864a845eb24b7f59de12257"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-eventkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Accounts on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_EventKit-10.3-py2.py3-none-any.whl", hash = "sha256:8644a1547b1d1a012306abbc6c5693d3302b98bb5b1098fb81e060885995bc70"}, - {file = "pyobjc_framework_eventkit-10.3.tar.gz", hash = "sha256:a9c7609e6b800d5378bd0fa05e19de878c000882a6b0c9ad716684fa0ca7bff8"}, + {file = "pyobjc_framework_EventKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:ad9f42431bd058ff72feba3bbce6fbd88b2a278c3b2c1cdb4625ea5f60f1ecda"}, + {file = "pyobjc_framework_eventkit-10.3.1.tar.gz", hash = "sha256:3eef14ba439be1c5bc47da561ccea3941daba663577efac7a58e3031d27e056b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-exceptionhandling" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ExceptionHandling on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ExceptionHandling-10.3-py2.py3-none-any.whl", hash = "sha256:5b5148bf5cbf70acc3713e5b8feef4fda3d8b1a9c515b1478143fa65cd6efc0f"}, - {file = "pyobjc_framework_exceptionhandling-10.3.tar.gz", hash = "sha256:7f3d4bca9dd23b1b10ed6174fe39e4c92368bb7e2a85fd237de37196a78dc8c4"}, + {file = "pyobjc_framework_ExceptionHandling-10.3.1-py2.py3-none-any.whl", hash = "sha256:79843a681a1d0f9ee2b7014dcf7e1182c99c83e49cf6cea81df934ebbdf4050b"}, + {file = "pyobjc_framework_exceptionhandling-10.3.1.tar.gz", hash = "sha256:ff6208777739f8a886d0cbfe20692b41cc4e5e0607419c47d2c5d405b6b4c6ee"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-executionpolicy" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ExecutionPolicy on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ExecutionPolicy-10.3-py2.py3-none-any.whl", hash = "sha256:6798cd17078d8a65544367243a432e54947c312885c7b0adf0f5fefe4f156b92"}, - {file = "pyobjc_framework_executionpolicy-10.3.tar.gz", hash = "sha256:16dcde7e8c81af347892b943f9e22633aebe772510bfcea19d688baac5cc1414"}, + {file = "pyobjc_framework_ExecutionPolicy-10.3.1-py2.py3-none-any.whl", hash = "sha256:f2eb203fa4c7dcf18a0ab3a4a94cb30a9f82cf888c237994dbbdb15adf01c8d2"}, + {file = "pyobjc_framework_executionpolicy-10.3.1.tar.gz", hash = "sha256:cc066dc8378fc2a1a4e6129c4d09e2076dc9a5b09925f8dd959aad591cbf9a44"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-extensionkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ExtensionKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ExtensionKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:84d4bd8c753a4c532dd5553e6d2d9900e6b534bff6b8b2f09b55fb85bc13896f"}, - {file = "pyobjc_framework_ExtensionKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:28b4979a1f373b70d0f00e5ed1187d1f28861199373bed607c868c06e634d0cb"}, - {file = "pyobjc_framework_ExtensionKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:65ed21df1e0aabf615be87d3cc985d761ffe88e77ba5e99db214bc48a100c483"}, - {file = "pyobjc_framework_extensionkit-10.3.tar.gz", hash = "sha256:928b7e5e1a1c5bb80b6e7c0b1fda0dda88ea212d15372f3ead7404283138b159"}, + {file = "pyobjc_framework_ExtensionKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:e2b54a5b32c959fc1500936b73c7ebd6d7ffcad23d74b9a6ff3db4ea5660f731"}, + {file = "pyobjc_framework_ExtensionKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f5b1e9c7e3a64224acae7b4c2d26d2a654edc54382e9e88aa3b056f4033508f8"}, + {file = "pyobjc_framework_ExtensionKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:62bc537cbeabb24667434c82515827e64c31d761bdcd02cc3ea6bb6a9a35873e"}, + {file = "pyobjc_framework_ExtensionKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c66797352b71a944810447c81133935656d8ea9bb847775a1532cf06d8deb1d3"}, + {file = "pyobjc_framework_extensionkit-10.3.1.tar.gz", hash = "sha256:91946030195fa17c5248655b10786ea60b9aee7d83a4627ba56768600b4e7674"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-externalaccessory" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ExternalAccessory on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ExternalAccessory-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:833dc91f933f40ef2e54fcaad4328154d1cedde46a289dcecf59ba87554fd344"}, - {file = "pyobjc_framework_ExternalAccessory-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c04f1470aa59c9930d732c04872aa44bd0a0ea6414c5d330e51fd323538f4675"}, - {file = "pyobjc_framework_ExternalAccessory-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b597b2c5c1dbf775cfaa60407bce7c0a7ecdfb40ccd9b0c03413c250b607ae20"}, - {file = "pyobjc_framework_externalaccessory-10.3.tar.gz", hash = "sha256:fa481f7171f7d42bb77e1d5d525798dfed6b6d89e4a789c0d252d9319b13e3b1"}, + {file = "pyobjc_framework_ExternalAccessory-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4395607570f1dd91abd786422fc516f83b4b2a5185321e6581d33dbe74a52c63"}, + {file = "pyobjc_framework_ExternalAccessory-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3fcdbb2338e7bd0fb66e9074dc95f2f989146ae92c66eb4282cfc1a6533cbe6c"}, + {file = "pyobjc_framework_ExternalAccessory-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b076ba07c84b1f4ef9a8a1aa095b66416119b1484b5111b2dd3041f2d301d1a1"}, + {file = "pyobjc_framework_ExternalAccessory-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4771cddfed6422502831a9bf88fa572918d1ca71a3e34e068f442d1197630267"}, + {file = "pyobjc_framework_externalaccessory-10.3.1.tar.gz", hash = "sha256:3ba1a7242448126b4af0fb93963790d0066766bcba2770d935111093e87b7b83"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-fileprovider" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework FileProvider on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_FileProvider-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed3171ca16e0cdeb5d76e557efc622ec30768a236ef3a4eb4245fd2444fd4e3b"}, - {file = "pyobjc_framework_FileProvider-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6fb9753039e37e4762fb42d1f29bf335f56323186913189109480cf849481ff6"}, - {file = "pyobjc_framework_FileProvider-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0c7253a92ed6b739a8cc92f1d874acf9323190a11c3271907cb8446619fa7b66"}, - {file = "pyobjc_framework_FileProvider-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:9991c333d3f7bd0c940c7363a6ab93eeb11cbe5b8795ccf6cfeb80b8197f9758"}, - {file = "pyobjc_framework_FileProvider-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b454f39902b88f840b4042752925e412e0e68ed3f95997ddd0d451481e42e22"}, - {file = "pyobjc_framework_FileProvider-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:16afd455c1a654562bc01ab2d62b4499ebb419991c45142aceb1663dccb375b5"}, - {file = "pyobjc_framework_FileProvider-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bf96275c3d8536af578984b8d2c638362680fb66452a58ba000977da6342a180"}, - {file = "pyobjc_framework_fileprovider-10.3.tar.gz", hash = "sha256:d0def20f2de25465b2d9090ef86063719736ef3e568bf7b2e7e9c3bd2c1fcbec"}, + {file = "pyobjc_framework_FileProvider-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:36f66bbd308fdf80d8fe21b89212af4b89bc80dff8cee5f785d5a6fcce942bec"}, + {file = "pyobjc_framework_FileProvider-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b44bcbf3d826fd8a0cbc53142c65655433d553205fb36811486757e2089e6c5f"}, + {file = "pyobjc_framework_FileProvider-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b28294768dc71190019c2b2638e27b7ebf6edb65a90721b86613083bd86f6b2d"}, + {file = "pyobjc_framework_FileProvider-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bb07a0b7e259030c7bc034c590c77a22e44427320c99bf74e5348551fe0da011"}, + {file = "pyobjc_framework_FileProvider-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e61b20aef5083df2303bf36f181fb83b02b9a7f4868af0e9229d94d7bc1828f"}, + {file = "pyobjc_framework_FileProvider-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:2ad657fa433d1922f40d581e87af1c2f7002c4835fa49235fdb3909eda23e1e8"}, + {file = "pyobjc_framework_FileProvider-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e66548dfc9e81489bc66e245c97760c457371c25ced87a28bdeca655b548447e"}, + {file = "pyobjc_framework_fileprovider-10.3.1.tar.gz", hash = "sha256:63a4160e6cbede0f682145f4303ed889bd9f3c9fccfecdc32636a8d95aeceeab"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-fileproviderui" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework FileProviderUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_FileProviderUI-10.3-py2.py3-none-any.whl", hash = "sha256:b11c922e017c3e11e957b459f3741331ddf3b4403aab7a9a477cfbab40c23e0e"}, - {file = "pyobjc_framework_fileproviderui-10.3.tar.gz", hash = "sha256:44dd84dcdcf187fd45ce34bacacb0eb6797f41767e663675eb37ec25bb2c8544"}, + {file = "pyobjc_framework_FileProviderUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:14be680a7fc78def5174ec5a6d890d407678cff723d6b359bba66bc0a78bd31a"}, + {file = "pyobjc_framework_fileproviderui-10.3.1.tar.gz", hash = "sha256:2a3f3b9b81aff216df76bc72c8e8730d7ba7f3b2412720f68b722bae58f82797"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-FileProvider = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-FileProvider = ">=10.3.1" [[package]] name = "pyobjc-framework-findersync" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework FinderSync on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_FinderSync-10.3-py2.py3-none-any.whl", hash = "sha256:50c0f0da42ecb10174969d41d23051ab0c6a605086e05d9de17f7cd2dcb9e0d8"}, - {file = "pyobjc_framework_findersync-10.3.tar.gz", hash = "sha256:1b15d4aa42d636968a243832777c39c944844a1d7da435da28c9d0a4f78beec8"}, + {file = "pyobjc_framework_FinderSync-10.3.1-py2.py3-none-any.whl", hash = "sha256:d4778de8a9b386c16812d470d1ad44d7370970d1dbc75d8bea390d4f5cd12be4"}, + {file = "pyobjc_framework_findersync-10.3.1.tar.gz", hash = "sha256:b4a08e0a87c54f62623038de1929fab018fe44fca5372a455bb524b9f90e9196"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-fsevents" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework FSEvents on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_FSEvents-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:160483598a4bef081f0acfcfdb51d62eedb07c81adb7614206ffa712b7552256"}, - {file = "pyobjc_framework_FSEvents-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8ca91bc2c90df83438ee839ab8b97d148626c1dba5830f753ff07198923e83bd"}, - {file = "pyobjc_framework_FSEvents-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e987588a3f9d011ea27a5895b7bc3753b052d19ea6e7392b56644ab72f550b34"}, - {file = "pyobjc_framework_fsevents-10.3.tar.gz", hash = "sha256:46fe0220e54f4d2f375d2b98d292d10ad188a797973cf60b64b24336fd1160ad"}, + {file = "pyobjc_framework_FSEvents-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:7348e1aa268819b005e1ab648b5bac348052d3513aacf768c2c3999d6ffbf81e"}, + {file = "pyobjc_framework_FSEvents-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:420736c645e15006c1ed962767bfd164b1d5dba7d9dc3cd9730e4c9922b05c27"}, + {file = "pyobjc_framework_FSEvents-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:56b48def729acaa0b7c27335a40519ca7d17e6d45649ba68e0f9f1c70e902994"}, + {file = "pyobjc_framework_FSEvents-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:282ebeeba0190524fe1d5d21d729ebcb7034e379a8039a6ccdf5f5c6e4470e02"}, + {file = "pyobjc_framework_fsevents-10.3.1.tar.gz", hash = "sha256:6269fd8aa3f62d8a6312e316043aca6d7d792812bff09b617bbd6ca9f0f6e440"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-gamecenter" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework GameCenter on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_GameCenter-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:875fb445aa7916088ffbb556fad915b023978e6dbc56efed054e92bed21acff3"}, - {file = "pyobjc_framework_GameCenter-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9a498dd05ccaf8ddec5e118a1e2142025e5bb29c42fb6c1b3d2918ff77d39252"}, - {file = "pyobjc_framework_GameCenter-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c7701fa23009d04385584b88b9fa6ed248781a1d652d34761169fee807277d61"}, - {file = "pyobjc_framework_gamecenter-10.3.tar.gz", hash = "sha256:6719c88a40ff9958ae836d4da65c81ce61adb5c614f13f3e1849282f7d31c571"}, + {file = "pyobjc_framework_GameCenter-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:eba1058859fb30bef8227ce649dcf7531545aeff81c3cfd3e3b80ef8fe87bf70"}, + {file = "pyobjc_framework_GameCenter-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3329261e8a6a3b0df3abd4a7a3cc66cc8e47be919279a08249e08f94a0e4448f"}, + {file = "pyobjc_framework_GameCenter-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:d2420c7d28f9eab337955a1872179295ba92e3d8db0e5b1b8d40442e7079d711"}, + {file = "pyobjc_framework_GameCenter-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6bd556e798cf52b94434c48cabf299060dd79b668f0021826995ceee520db8af"}, + {file = "pyobjc_framework_gamecenter-10.3.1.tar.gz", hash = "sha256:221ae88ee69816b95861b1a0dc781c1c17775d38fcf0388327620535479b6a07"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-gamecontroller" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework GameController on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_GameController-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a75fcde32187cbcddbc7d0513fd9030e4f97ae9b1515af93a404b0d6be3c08f3"}, - {file = "pyobjc_framework_GameController-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:eadfa2e9c2243eb6e8be4a8ca13fe63aad1e1d96fe9b43d62dc5cb3eff46e8fa"}, - {file = "pyobjc_framework_GameController-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:25010deb72f07978bf343f371237244e35f22f8c494542e14e2c4da0e08841bf"}, - {file = "pyobjc_framework_gamecontroller-10.3.tar.gz", hash = "sha256:dc85c473cafb46ba72cf91e1dadd428f26564c4e331d107b01f78ad450fa74c6"}, + {file = "pyobjc_framework_GameController-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:cfb754d29660e90f295ba443cc84fb189e5ca9d1f019c35a382cb24dd4e08bf8"}, + {file = "pyobjc_framework_GameController-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a7a1e34a4ebcf9f653bc4a066b7d08d9124d462bc7e1c434ead983a6ae093382"}, + {file = "pyobjc_framework_GameController-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a23bb9c97063fb334990cac20dcab1389942495cb028350a232faebb804d73c2"}, + {file = "pyobjc_framework_GameController-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e90afaa5a5d28771e60b4f60ff89b80037d4e9e558d680872810216299aea1a8"}, + {file = "pyobjc_framework_gamecontroller-10.3.1.tar.gz", hash = "sha256:f9f252b5fed5de2a8c7fdd2e302b6ed6e0b82015d7da75b28984c5ea5909345e"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-gamekit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework GameKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_GameKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b997b024f8fbb5bd2d423399d3926fd2fb2e22c162d7f2f49e2616e452b36dfa"}, - {file = "pyobjc_framework_GameKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c289aba92513c3e1c2b3fad33ef32eacb6d987bc08252e5a3e4e6253b7e5ab63"}, - {file = "pyobjc_framework_GameKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:414e3a5c0c3d4cfa7e749fba0f2e83a3ffd29dd4ba87d2e30903780a120fb100"}, - {file = "pyobjc_framework_gamekit-10.3.tar.gz", hash = "sha256:c1aabd78057a95955ccccd8553a13ea554ce1ee2e6fdf5d270f1f5c404f38066"}, + {file = "pyobjc_framework_GameKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:57930e2b65296719b2998c9816ab844983460f3358c57a120f09ebe78013b64c"}, + {file = "pyobjc_framework_GameKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5634ac5f8b3569355f4fe8b2e6a06450d8aee555119607f7d738f5c85900c1b6"}, + {file = "pyobjc_framework_GameKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:83f689c959cdfaa311f6702d9e99402faf47e390334fb3880d255dc72e2d2a90"}, + {file = "pyobjc_framework_GameKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c861e575ed4543241adbc53162fb651395ba73c68a697f4b5aceaa61754e19c1"}, + {file = "pyobjc_framework_gamekit-10.3.1.tar.gz", hash = "sha256:7d21a8f45c32ac94ce0e70b6c6fe72928fe75cb1a6bd6d7715e2bf39b291b70b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-gameplaykit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework GameplayKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_GameplayKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:908e79ef67328c6dea5175896f9a94bf40f4bec185866ec5a0e0936466706487"}, - {file = "pyobjc_framework_GameplayKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a19405a1b3e7a6bd96bbda80208b37c9b261970cd2268b114d256db8113c6316"}, - {file = "pyobjc_framework_GameplayKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d247b11e30f4db7e1c0d1c6430f92afd6fa87ccd70e6ff61e5a4929b7fa33e7d"}, - {file = "pyobjc_framework_gameplaykit-10.3.tar.gz", hash = "sha256:3e0a52b2e7e271e28cb26391e3dd96760a21f8b36124a4c4224a8219d7b783c6"}, + {file = "pyobjc_framework_GameplayKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:cb54cfc4dbc69f1888c59ddce9da97ddc03f5003794fe47d56942a89c478e138"}, + {file = "pyobjc_framework_GameplayKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:eb49a732c82b17ff66f6e878b2cb9ba27e2222be303a337f2af4ed1a34a404bf"}, + {file = "pyobjc_framework_GameplayKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8a0c2148e9b421922accfe565a398effe9622653c71d0bb4eb1b69ac90ee257f"}, + {file = "pyobjc_framework_GameplayKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:628406ca0d0ce283cc0735a4e532dd04a3a4d57a4c22c3ee4338ba64d1b13790"}, + {file = "pyobjc_framework_gameplaykit-10.3.1.tar.gz", hash = "sha256:2035b81f7bc34b93636753cc3f9b06cd08171afc5c95bb2327a82fd3195f3c36"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-SpriteKit = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-SpriteKit = ">=10.3.1" [[package]] name = "pyobjc-framework-healthkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework HealthKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_HealthKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d7267d490329e62a733e50f37a4b5fdb98db8353425f2d193ba3117a80bf9f84"}, - {file = "pyobjc_framework_HealthKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:db1bc0574c32f639ca830fec3885c4774642015b086855a1147c8b2244246e54"}, - {file = "pyobjc_framework_HealthKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:aa51fe233fc95da5b2c0c2726ba5d9c83e5c95312208c033d530ecde9fc75888"}, - {file = "pyobjc_framework_healthkit-10.3.tar.gz", hash = "sha256:ae964ed3d6a2250235bba6f1fcf465d54d9c10854322e82a64b0e06505c264fb"}, + {file = "pyobjc_framework_HealthKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:80aee8bf0e7af6e434e9023c2d2050c2a2fe8e53abbf0e1f2285a932836fdd17"}, + {file = "pyobjc_framework_HealthKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac9abec44c02edfe7f2151f529bac1c9544fb99ee1caffff55b331281b374463"}, + {file = "pyobjc_framework_HealthKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b64d4e61a8009a0a5586d464b591186570f654b20937f78941875ef3b7865505"}, + {file = "pyobjc_framework_HealthKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5bfcaac3a3947d070611d1fed1abe8858e049ef0ab1050f46974a7333b6369f6"}, + {file = "pyobjc_framework_healthkit-10.3.1.tar.gz", hash = "sha256:45622fedb42bbd95dcc096248bbc41dacd857d9db120ff7310f74f3bad4b23e1"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-imagecapturecore" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ImageCaptureCore on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ImageCaptureCore-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:097fb42cc33e9deb84d2afba2f701757a831f31fd031dd4426b6357d20959496"}, - {file = "pyobjc_framework_ImageCaptureCore-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:02c2a1a8aacddd4b2b3842b4b389a8956ceaf26d0a965ece3e9bdca62a3cf8dd"}, - {file = "pyobjc_framework_ImageCaptureCore-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c80fbec0f6f0d7c39f11c0827bc1546badca66c2110e9923bde21b12e531d7da"}, - {file = "pyobjc_framework_imagecapturecore-10.3.tar.gz", hash = "sha256:649fb5676ceb76254c4a3782ac05bdc6c30f4fd69f58652727a4732921e07d64"}, + {file = "pyobjc_framework_ImageCaptureCore-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:649e0b7bf428ad3fe90faaf63dbd09d234563a32b3cee5a6f2d28ab31927bd54"}, + {file = "pyobjc_framework_ImageCaptureCore-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5bab844c665b3ac07b191e94130f543eb23c5cfd014035f025efacb7a48aa68c"}, + {file = "pyobjc_framework_ImageCaptureCore-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0fd14f9183c1fcee67cf09f36ccbe156186da84a83419917fd3ca81a5de23d97"}, + {file = "pyobjc_framework_ImageCaptureCore-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d625d84094f51dd4389d1dea7c53480c3311dd19447d96b3c9eb06be5a935fd6"}, + {file = "pyobjc_framework_imagecapturecore-10.3.1.tar.gz", hash = "sha256:9ce83c38b8ccee6b022faadb9cd7b8716119092cd41b6c2cabce3670101119bf"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-inputmethodkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework InputMethodKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_InputMethodKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:456b2601bf5e0e2b015f146cb4b9ee2083c0891df4b6e4508bbbf9b7d4f1ba2a"}, - {file = "pyobjc_framework_InputMethodKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3a19b34a229a338b1d6496813feb804079b3c84e29556977c43ef861d0540bac"}, - {file = "pyobjc_framework_InputMethodKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5d04033b886c2cb6c2696216ad7d25da67d58890bdec602d25c6b7f2db6317da"}, - {file = "pyobjc_framework_inputmethodkit-10.3.tar.gz", hash = "sha256:e38844bb93276758334f8fbe09e668da12d697e83b4c925850bf0ae7bc9decab"}, + {file = "pyobjc_framework_InputMethodKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:d1c3beb88f94eb6b0bdc458ef49f331d064c0260758134cef1cf941684f46c83"}, + {file = "pyobjc_framework_InputMethodKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d0f7538ac549b61afc93df895375114464f778e06a66a4c2684cbbf247a8f4c7"}, + {file = "pyobjc_framework_InputMethodKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7f5ff42a59209f3ede24181e5d1bb8d69f8ad428189f177c1bfd55d328f85575"}, + {file = "pyobjc_framework_InputMethodKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3fcd444b97cf2343a6c37b828dcc85080cc6a2c5ba508010dae4ebe836480d2b"}, + {file = "pyobjc_framework_inputmethodkit-10.3.1.tar.gz", hash = "sha256:637ba2da38da5f558443b4529b33bab276380336e977807347ee9dad81d42109"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-installerplugins" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework InstallerPlugins on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_InstallerPlugins-10.3-py2.py3-none-any.whl", hash = "sha256:1b577fb5ebe9d4651807798efb056d4cc2a43959bb680a53cdfe25cb185152d5"}, - {file = "pyobjc_framework_installerplugins-10.3.tar.gz", hash = "sha256:69f902733f6e8086c0fa18e6b23a604a759c7d65a7de66a331148afda5f120ec"}, + {file = "pyobjc_framework_InstallerPlugins-10.3.1-py2.py3-none-any.whl", hash = "sha256:2b32cde6fb8bbb3e1ffd04d7acbe3132291ad5937fc7af5820062e8aece7b5cc"}, + {file = "pyobjc_framework_installerplugins-10.3.1.tar.gz", hash = "sha256:280808bbce36090b59197756fdb56c19838845a5fc25966a435dbc5fc4ddbbf0"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-instantmessage" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework InstantMessage on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_InstantMessage-10.3-py2.py3-none-any.whl", hash = "sha256:27e17102aff08bd7016ac092597fd515e690e97ff179fbba8c92f5d1fdd3bf74"}, - {file = "pyobjc_framework_instantmessage-10.3.tar.gz", hash = "sha256:f88992c2ce71efa147d3809d5a0d8a422643e657281c5c72840ad9de5edce732"}, + {file = "pyobjc_framework_InstantMessage-10.3.1-py2.py3-none-any.whl", hash = "sha256:51a096e55a423423dbfbf19cc976a49915987ce68b9038f8ce3db9c3cde11718"}, + {file = "pyobjc_framework_instantmessage-10.3.1.tar.gz", hash = "sha256:bb1560a2f92a2def179b6381c17d406331b7818fa0fd1ba98f09ed94415f8a7b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-intents" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Intents on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Intents-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f68e0fee12cd47c539655a6e5be219c43592e6579542c5059d7ef211f0d4ad04"}, - {file = "pyobjc_framework_Intents-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9d6e972ed2fc5f87dd28313e32fdea137588100a8c9baca645fd53f87cea7541"}, - {file = "pyobjc_framework_Intents-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:9542e410767899ac4723079875e9c3305efccb8266a145711b73e783d8f04c32"}, - {file = "pyobjc_framework_intents-10.3.tar.gz", hash = "sha256:03faf5c52eb8e069fb72065f7a772d51e669a1e3be1d74810a69e05bc2ff7326"}, + {file = "pyobjc_framework_Intents-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4d5a899e8cffd63096aec69edafac78e76d591afd07059a96377d6893ba56649"}, + {file = "pyobjc_framework_Intents-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b6da33ba8a1e6ae169eb67c1c83bf4e0aeb365fb368162ba002ef26cdc9f853f"}, + {file = "pyobjc_framework_Intents-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:332e5b74dceb8315e289d462058b9ec65544562936098b50b8003999954032b6"}, + {file = "pyobjc_framework_Intents-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6e77fea5fc4136888459c8ece7d48fe3eac3a37c665e9ba8aaeb18c1671eb083"}, + {file = "pyobjc_framework_intents-10.3.1.tar.gz", hash = "sha256:89f0ed49c515b75c8811d9f6771ac635e799dfaf11921172729f8e0857c8c0e9"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-intentsui" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Intents on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_IntentsUI-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a25e9cbee40b404299194c3d94895760a9983db6ddafd11124d00905cb9bfe3e"}, - {file = "pyobjc_framework_IntentsUI-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1a27bf62bec02fe499918baefee4418207d138bca83327a3cdd775078c3d06e2"}, - {file = "pyobjc_framework_IntentsUI-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:eb94c897a006bcb11f8c1d521650d11674b3e3a20e8a07ace70fe4994cba5975"}, - {file = "pyobjc_framework_IntentsUI-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:d78ed0172745840561583127c4ae6786670de05aca385ffee167f15354e879a1"}, - {file = "pyobjc_framework_IntentsUI-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81dd968167c3b4a76e55f89b642e7d18dfab0267b2aa8528d7f8d4ac4d64e6ff"}, - {file = "pyobjc_framework_IntentsUI-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:82830c3bfae58f78b085c1c98258db7fb8774f69abf2e56b1b76a20cd23293cb"}, - {file = "pyobjc_framework_IntentsUI-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7d3f575c728688191a197d127940da1171fe91d902d366b9e9570d6dc927c0a"}, - {file = "pyobjc_framework_intentsui-10.3.tar.gz", hash = "sha256:1e791ecef111ba21ce03f779e8d39da5214b6921a2f6625247ee1247e09261be"}, + {file = "pyobjc_framework_IntentsUI-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:23a606af7ea47bd899012b896e0b2d10c677f7facec80197ab45a3bcf899874b"}, + {file = "pyobjc_framework_IntentsUI-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bd2fed37c96f1d97abcbd6d98b2da90ba2c744f968e2c4e0735dce77bbbc95f4"}, + {file = "pyobjc_framework_IntentsUI-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e9fe0ba78c9dd500ef9c13227dd1a60e39df460c84180d8325f5022edd80178b"}, + {file = "pyobjc_framework_IntentsUI-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6c124ceb8e7b7a1f3fb6c2c159e47f9dca42ece6e1645d763235660ea98e7915"}, + {file = "pyobjc_framework_IntentsUI-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bfed2841fc9099cad850e058e3dfa23845a0988e53666f5ffc82cd1b91bbe824"}, + {file = "pyobjc_framework_IntentsUI-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d6a802bc5ccb01a22c312f4dfaf88300a2edd4db2e2f7568b10d29176ae05edd"}, + {file = "pyobjc_framework_IntentsUI-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3ae02ba54c689cd672bfc49c039d18cc5e9515d7d95608bcbb34357ae90fd9ff"}, + {file = "pyobjc_framework_intentsui-10.3.1.tar.gz", hash = "sha256:68f42cabbd36889060d07b21f156f1dae78243d42b34c652448c687d07cbca62"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Intents = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Intents = ">=10.3.1" [[package]] name = "pyobjc-framework-iobluetooth" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework IOBluetooth on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_IOBluetooth-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a55ae467d77ef1482ce93ed0d0847ea86e466b2278b13929ec26cd8a8a609207"}, - {file = "pyobjc_framework_IOBluetooth-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8d671c767fea4e128a38136a24ef1f17a9df96b4578f8d6e56a4752c7b1a6e3c"}, - {file = "pyobjc_framework_IOBluetooth-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:001743ad0dc32a19ccd39d3352adf376f624e51d06d79b7ee9583a9c7090450f"}, - {file = "pyobjc_framework_iobluetooth-10.3.tar.gz", hash = "sha256:49ffbe7464684008b162c3dc025c39b8b943b505e300fc185966c567d7e8f284"}, + {file = "pyobjc_framework_IOBluetooth-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:cdd8bd3da07c6935657bbcf47e6fc6b3b7a2ed9bd7e8ef83bbbd5f4a0e8884f3"}, + {file = "pyobjc_framework_IOBluetooth-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d5c7ca666050b63c5dd87ede54beebdba7fc12a60bd754d77155da9f7e60618c"}, + {file = "pyobjc_framework_IOBluetooth-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9f90d8ea40f770b41ad97e17e19ad10e49daa1684f750e681db42707dbec9768"}, + {file = "pyobjc_framework_IOBluetooth-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:17303009a3c1ac48eaaa2c3a96a114ef47adcb1fffbf965e7538447bb02adde1"}, + {file = "pyobjc_framework_iobluetooth-10.3.1.tar.gz", hash = "sha256:bca424889d7fdd5bcb728d312e91ee681e73c0c2ac16ba37068603d699043d39"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-iobluetoothui" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework IOBluetoothUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_IOBluetoothUI-10.3-py2.py3-none-any.whl", hash = "sha256:4ad16ce48e34b5af186d3b528147e34f772ff5818aa8284390070d3b45cdbf05"}, - {file = "pyobjc_framework_iobluetoothui-10.3.tar.gz", hash = "sha256:9ab371ff6ce1a4f7b3706acc3b430e697aa8816808899e3a709f5504b8c3d36c"}, + {file = "pyobjc_framework_IOBluetoothUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:ae283c3fecbeb99adba9b3c3d5d06caaad741da726fc7a1dd50ecc0376e03ae8"}, + {file = "pyobjc_framework_iobluetoothui-10.3.1.tar.gz", hash = "sha256:6db82aeb360641b878f8ed73c2074db0425664d9411317b2e01962e0929fa29c"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-IOBluetooth = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-IOBluetooth = ">=10.3.1" [[package]] name = "pyobjc-framework-iosurface" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework IOSurface on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_IOSurface-10.3-py2.py3-none-any.whl", hash = "sha256:ed016eeb0fb6b176a002a37da968bee9770ce764e11299dbbef9386a2dd746af"}, - {file = "pyobjc_framework_iosurface-10.3.tar.gz", hash = "sha256:bbb3acb6417e729f27bc4fed1286436aab9242ba750cc61e39cf6994ad26fecc"}, + {file = "pyobjc_framework_IOSurface-10.3.1-py2.py3-none-any.whl", hash = "sha256:4171a33a09ee006ad28ba29e6d12cee821e2c0ba09b4beddae8db16580fb9bc7"}, + {file = "pyobjc_framework_iosurface-10.3.1.tar.gz", hash = "sha256:94e4a109a94f0e365bd60ce68aab6ff166fef6f30a40f7682c76902f5fc3aa34"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-ituneslibrary" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework iTunesLibrary on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_iTunesLibrary-10.3-py2.py3-none-any.whl", hash = "sha256:3cf1062f5e95aa1c2641743fee6d48bcf73235955d40ca843c728690f46f590e"}, - {file = "pyobjc_framework_ituneslibrary-10.3.tar.gz", hash = "sha256:ac4978becfaa69cdb8e6ba2900965bb86dedb1610262acd993cf58dc7d8d33f3"}, + {file = "pyobjc_framework_iTunesLibrary-10.3.1-py2.py3-none-any.whl", hash = "sha256:9485e986f6075d04e10c196e5dc36e4c3b60116a45849683a61c876e5fb45fde"}, + {file = "pyobjc_framework_ituneslibrary-10.3.1.tar.gz", hash = "sha256:3899f8555ae02f6441a711892cdc6537404215b3d5f8a7ea4594f7460c58c9b2"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-kernelmanagement" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework KernelManagement on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_KernelManagement-10.3-py2.py3-none-any.whl", hash = "sha256:87998385a4ba9d7c69afc361aa081f8b980fe14dca0ef04f74a97eb13b133a1b"}, - {file = "pyobjc_framework_kernelmanagement-10.3.tar.gz", hash = "sha256:9619677c9976a9428f0913420c0e939a17f1fa809855bbc3d9bb6a989729d49e"}, + {file = "pyobjc_framework_KernelManagement-10.3.1-py2.py3-none-any.whl", hash = "sha256:e07134bf3815370d3d9c37f9813edec12758f86fdbbbc67036ab72e8b767ddee"}, + {file = "pyobjc_framework_kernelmanagement-10.3.1.tar.gz", hash = "sha256:04c41bc0d0ce014318acf9e333aba302092d2698ec408cbf0b022f3a507ecfa1"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-latentsemanticmapping" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework LatentSemanticMapping on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_LatentSemanticMapping-10.3-py2.py3-none-any.whl", hash = "sha256:fac29c9f90271299fdc6d0f79cd20cbccda2e65d25ebe8eb94b5de16283cf517"}, - {file = "pyobjc_framework_latentsemanticmapping-10.3.tar.gz", hash = "sha256:a3d633158ac9c416617fbe0a64a672c0a56167714774675b7c374d1e712efc5a"}, + {file = "pyobjc_framework_LatentSemanticMapping-10.3.1-py2.py3-none-any.whl", hash = "sha256:c80c709b983273c8f29e86a04c52e98e8e6b0e723a400f7d6036fcabfd850367"}, + {file = "pyobjc_framework_latentsemanticmapping-10.3.1.tar.gz", hash = "sha256:0bca94fd00f59f49874c8266bfacb09a7c56ad13b4d405c241421cef201f8943"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-launchservices" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework LaunchServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_LaunchServices-10.3-py2.py3-none-any.whl", hash = "sha256:2969eed89464e49a38bf1c80829cf0c721ea8bf2e75e67985748bdfb2ba03937"}, - {file = "pyobjc_framework_launchservices-10.3.tar.gz", hash = "sha256:b28b605ed6d5626ce0e48520444cf131d6596ee51b1af56596c0bbe2d1ef996a"}, + {file = "pyobjc_framework_LaunchServices-10.3.1-py2.py3-none-any.whl", hash = "sha256:3ce840027b43c4bd95dc31aaa9b4bfff1d431e782669b4c95e2b12d386c05000"}, + {file = "pyobjc_framework_launchservices-10.3.1.tar.gz", hash = "sha256:7f16af2acabca0c2953eb7333bfe652bf853bb9d9e59b771f9d228468bccdea3"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-CoreServices = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-CoreServices = ">=10.3.1" [[package]] name = "pyobjc-framework-libdispatch" -version = "10.3" +version = "10.3.1" description = "Wrappers for libdispatch on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_libdispatch-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6845f7dcb13cd24e921eed2c9cf5087ce138f69089a05ba0bf9ac9e2d5294930"}, - {file = "pyobjc_framework_libdispatch-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e49c4e6614f53a9c89f0e79abbee3cdcdd6426dd213780ebb9e3eeeb02088c3"}, - {file = "pyobjc_framework_libdispatch-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e71d7bad62be682718035d384aefc7603ec1f350ee7992cf89a3eff797f6e371"}, - {file = "pyobjc_framework_libdispatch-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:df656b26e04bc489f76f96d1748f3349a9fb0a5f6dcd8f0ca686b0bf1c89641f"}, - {file = "pyobjc_framework_libdispatch-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2da791f1515c64c40e2e4de552933f77fdcced8321afa1511eae7c35c0f31a30"}, - {file = "pyobjc_framework_libdispatch-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:c1f46c4dc4816274c890822bb809462cbe8c46b27be24cceb4fa0902b85e8ec0"}, - {file = "pyobjc_framework_libdispatch-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1d47e167bd6e246a1f5c9c780955d5b08ed049f0d71af23314f81715d0e98500"}, - {file = "pyobjc_framework_libdispatch-10.3.tar.gz", hash = "sha256:1f0aa2a1900788368bc8370a631d7ee83e18cd3cacc32bbfb2b3653d9d93d892"}, + {file = "pyobjc_framework_libdispatch-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5543aea8acd53fb02bcf962b003a2a9c2bdacf28dc290c31a3d2de7543ef8392"}, + {file = "pyobjc_framework_libdispatch-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3e0db3138aae333f0b87b42586bc016430a76638af169aab9cef6afee4e5f887"}, + {file = "pyobjc_framework_libdispatch-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b209dbc9338cd87e053ede4d782b8c445bcc0b9a3d0365a6ffa1f9cd5143c301"}, + {file = "pyobjc_framework_libdispatch-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a74e62314376dc2d34bc5d4a86cedaf5795786178ebccd0553c58e8fa73400a3"}, + {file = "pyobjc_framework_libdispatch-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8e8fb27ac86d48605eb2107ac408ed8de281751df81f5430fe66c8228d7626b8"}, + {file = "pyobjc_framework_libdispatch-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0a7a19afef70c98b3b527fb2c9adb025444bcb50f65c8d7b949f1efb51bde577"}, + {file = "pyobjc_framework_libdispatch-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:109044cddecb3332cbb75f14819cd01b98aacfefe91204c776b491eccc58a112"}, + {file = "pyobjc_framework_libdispatch-10.3.1.tar.gz", hash = "sha256:f5c3475498cb32f54d75e21952670e4a32c8517fb2db2e90869f634edc942446"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-libxpc" -version = "10.3" +version = "10.3.1" description = "Wrappers for xpc on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_libxpc-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b64eef0b36efccf926e529f0cfd55d416fee667ee71371679cba8675959947"}, - {file = "pyobjc_framework_libxpc-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:af837591e4a2cd5dfbf37017c92d4f30b448293fe56a7ac10e1033d5aaf692a3"}, - {file = "pyobjc_framework_libxpc-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c10a1a8a5863099b163e71f808c7d42d6e052611e5851924e13ab260fab12b36"}, - {file = "pyobjc_framework_libxpc-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:ff4a24534e7fc6b5da6af2503afc76d33bc8148693f04d9585a1f1062171e21f"}, - {file = "pyobjc_framework_libxpc-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c406f029c57ccead3b0bb53fb20046cbf72552fb3b06e922893cffa2a84b54f3"}, - {file = "pyobjc_framework_libxpc-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7717d83d440d66742d153d081bb52bf8493fce7db21debace77b87012df21bde"}, - {file = "pyobjc_framework_libxpc-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fafaf57f13eb3fe09dd1f93cc7895d2b50178933f2e163fe9abb06940f553d00"}, - {file = "pyobjc_framework_libxpc-10.3.tar.gz", hash = "sha256:b69f3e73ecca92e07ded276544f8cae15f915fda314144dda18fadc7f2f127b9"}, + {file = "pyobjc_framework_libxpc-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9e287591a708f96e4e3d1929425a50c4e83188eb8bf3094b688de149946ac752"}, + {file = "pyobjc_framework_libxpc-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0afba29b6bf5c3de3ef51f60e06c026ab7be7ce44600047dece5d3bf4e758af"}, + {file = "pyobjc_framework_libxpc-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:123b72dff148a56d48120448bd9742190326f87661f4ae6f5363e112de0e554f"}, + {file = "pyobjc_framework_libxpc-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:72a35a21f4bbbfb4a5c4c23e3180c3273b7720fe4cd150b975cb5d08cbc4fe13"}, + {file = "pyobjc_framework_libxpc-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d14f6fa976df50de90affa41b4dc2381554fe1e8503564f54cd71a8c6cc4b0eb"}, + {file = "pyobjc_framework_libxpc-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0d8a5d29952db92d9d7112c642ba7cdc9d8496118ec14e8186f93353b092a818"}, + {file = "pyobjc_framework_libxpc-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f4232996766f4c21f80da51344296651f40ec8fc14f353fca0bc75af718ee950"}, + {file = "pyobjc_framework_libxpc-10.3.1.tar.gz", hash = "sha256:b3c9e9fd281b5610e3bef486e91570b0afa8ab8eb0c01c0baa5e2ec49ccb7329"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-linkpresentation" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework LinkPresentation on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_LinkPresentation-10.3-py2.py3-none-any.whl", hash = "sha256:180cf53bc4149c5873ef9d6c93026ce73c5ae8b522fb7e38850c94243d9879af"}, - {file = "pyobjc_framework_linkpresentation-10.3.tar.gz", hash = "sha256:9a5696d126ded58cf9362b19e8846c51c70ee17d546d3be55ff4d279f791aaf1"}, + {file = "pyobjc_framework_LinkPresentation-10.3.1-py2.py3-none-any.whl", hash = "sha256:e49ac094eb3a60a87f37edc24657feb051614a4d4464ad2580831288ead521f9"}, + {file = "pyobjc_framework_linkpresentation-10.3.1.tar.gz", hash = "sha256:535d452cc33d61074ba9bad7707d6c0a23d474fb045ed4322e5f87bfb0b7e865"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-localauthentication" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework LocalAuthentication on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_LocalAuthentication-10.3-py2.py3-none-any.whl", hash = "sha256:d8dbf68c2073cd5cd3894d6d73f3538bb35afccde4273cdeac45ad1489691c17"}, - {file = "pyobjc_framework_localauthentication-10.3.tar.gz", hash = "sha256:073716dacdc1d8ca28db778ea133c9a4bff8678af9a6066a2a7e7043dc0e0169"}, + {file = "pyobjc_framework_LocalAuthentication-10.3.1-py2.py3-none-any.whl", hash = "sha256:565910d7d2075cd53c6d4ffdbb15d9b93267f1b1ba4c502d354778865d0dc2ec"}, + {file = "pyobjc_framework_localauthentication-10.3.1.tar.gz", hash = "sha256:ad85411f1899a2ba89349df6a92db99fcaa80a4232a4934a1a176c60698d46b1"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Security = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Security = ">=10.3.1" [[package]] name = "pyobjc-framework-localauthenticationembeddedui" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework LocalAuthenticationEmbeddedUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_LocalAuthenticationEmbeddedUI-10.3-py2.py3-none-any.whl", hash = "sha256:481592e8a3ec90f51ff334509d65a5bdb22b07c01239ee47029f9cb78d2bbdd8"}, - {file = "pyobjc_framework_localauthenticationembeddedui-10.3.tar.gz", hash = "sha256:fdd6edc4a286f943d372d4aacc9587284c07efc3df19a6f8642cfff91cb74ba2"}, + {file = "pyobjc_framework_LocalAuthenticationEmbeddedUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:d69ef723f4525e6476e51bd166d56e97c9274500f98aa209a659e7567793dc01"}, + {file = "pyobjc_framework_localauthenticationembeddedui-10.3.1.tar.gz", hash = "sha256:f915190f6106b9f9234750abf48f87445c364ccbca8f8dd565bba1b66ddd55a3"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-LocalAuthentication = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-LocalAuthentication = ">=10.3.1" [[package]] name = "pyobjc-framework-mailkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MailKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MailKit-10.3-py2.py3-none-any.whl", hash = "sha256:4865846f1c6b655901c3248eb2b7ea9115f023a93144ceeb07e67ee9f8229d0c"}, - {file = "pyobjc_framework_mailkit-10.3.tar.gz", hash = "sha256:e097f8db128f927ac2860696cc3326213203526bea070de82aca4e5117c409d4"}, + {file = "pyobjc_framework_MailKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:7c403525e01bed0888946552e512ca4d1b018c3f6ef3d293fff85b90dc02a411"}, + {file = "pyobjc_framework_mailkit-10.3.1.tar.gz", hash = "sha256:90ad82786ae01a275aeec842e73b1fef12d9f91a67edcde8ff6a145859dc9f92"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-mapkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MapKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MapKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:290ce559818baaea69a94817239fef6c211d0d5428ad2d9e31e6aabc06079b11"}, - {file = "pyobjc_framework_MapKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1ed74fc8a5e5989c902c304f6e5ccff7b21f871234ff3797b5903ae00de2e0f4"}, - {file = "pyobjc_framework_MapKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c9f92577550b3cebb61d40755ac3f2946be47d47a2449472495c1589ed0df3a7"}, - {file = "pyobjc_framework_mapkit-10.3.tar.gz", hash = "sha256:321cc41a26df1e4d9676d4c7df5f83ea9239b56da66f4fed077ce8949ae9e315"}, + {file = "pyobjc_framework_MapKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:cfee94ad82e673eaebc3159732b5cff1fc4f7e3bee6f17cc4fabd641c260b769"}, + {file = "pyobjc_framework_MapKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:dd65d6eff1397afc0b2108b0e9387a6c2390b1387731a8e0dd8298b8d0641635"}, + {file = "pyobjc_framework_MapKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ffadc4968c3d815dd8ffc2867e962546a8681620c704888dfe1e7aa718cb3d90"}, + {file = "pyobjc_framework_MapKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f14f90bcb68baee70a838b3cecb9d909da43175da49cbe90dd6cca57c37a6ae5"}, + {file = "pyobjc_framework_mapkit-10.3.1.tar.gz", hash = "sha256:f433228c404b9ef4a66e808995daccc1306f7123296317651078a6a734ac1ab0"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreLocation = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreLocation = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-mediaaccessibility" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MediaAccessibility on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MediaAccessibility-10.3-py2.py3-none-any.whl", hash = "sha256:95b2368b0f0ca17a618d687225d6faf1254b7819cf8762572561ef7986c1025f"}, - {file = "pyobjc_framework_mediaaccessibility-10.3.tar.gz", hash = "sha256:03d7aa15ae9a19b582003144dec91c3d99aa563a58328d559fe1f03b95cfa234"}, + {file = "pyobjc_framework_MediaAccessibility-10.3.1-py2.py3-none-any.whl", hash = "sha256:c4304ea53c7e85320b58d773cce2288f62dcb5b9c5a295be1ecfaa6645a9fea6"}, + {file = "pyobjc_framework_mediaaccessibility-10.3.1.tar.gz", hash = "sha256:c249e1eee636e77b5f00db3bf85174cb3e0cb53ca991a17e53a1f200377f4289"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-medialibrary" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MediaLibrary on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MediaLibrary-10.3-py2.py3-none-any.whl", hash = "sha256:2fa66b8f60aa4dc63ae064555a28bbd247842d5b867de218d1dff43ae6c71357"}, - {file = "pyobjc_framework_medialibrary-10.3.tar.gz", hash = "sha256:5084a082758e9e616789c603da539acfe12d681bb3b633041f53b035797e116f"}, + {file = "pyobjc_framework_MediaLibrary-10.3.1-py2.py3-none-any.whl", hash = "sha256:25f16d610e3ea5d983175a6c07351596bd5dd2fcca194f1eac5686c670bbdb3b"}, + {file = "pyobjc_framework_medialibrary-10.3.1.tar.gz", hash = "sha256:703ffd0904fc86d4fbfbbd4952be43e91a6d477c53ce2868e4c18c3eb295f5c6"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-mediaplayer" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MediaPlayer on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MediaPlayer-10.3-py2.py3-none-any.whl", hash = "sha256:82882aa1e901741e9b976f143cb576668845d45c2a0f51c8d5721c35700f0406"}, - {file = "pyobjc_framework_mediaplayer-10.3.tar.gz", hash = "sha256:b7571fbec3fecf9333e9c0c1a4b21a8c1c6ac4f776d431c3d0f2468ff96595ce"}, + {file = "pyobjc_framework_MediaPlayer-10.3.1-py2.py3-none-any.whl", hash = "sha256:5b428cc28e57c1778bd431156c3adb948650f7503f266689559d0ece94b34e8a"}, + {file = "pyobjc_framework_mediaplayer-10.3.1.tar.gz", hash = "sha256:97043df5ef89d4fbe217813e8f4ee1e226d8a43dee4eac00fff95e6b8a7772be"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-AVFoundation = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-AVFoundation = ">=10.3.1" [[package]] name = "pyobjc-framework-mediatoolbox" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MediaToolbox on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MediaToolbox-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fb293ab6085277b151a289b1fb3f6eec4c0214e2147d3fbeb0a8d9a666808d2"}, - {file = "pyobjc_framework_MediaToolbox-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a7c692ac7dcab5c83c4a01db83400f06ea2c46bb3940ee477d0002a2cc824c6f"}, - {file = "pyobjc_framework_MediaToolbox-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4b0b40879ac673b7211fe6e4363bdf0628ce3dab38d47b94bc83043d155063f5"}, - {file = "pyobjc_framework_mediatoolbox-10.3.tar.gz", hash = "sha256:d63da415403ebb759b604adbefd3abe37ac68c5a301faf2eb8d934a85e3b7d26"}, + {file = "pyobjc_framework_MediaToolbox-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:d4ef616e233c40fcac99298ee4ab95a9b6439cffe28e96ce07b66c00f598bd30"}, + {file = "pyobjc_framework_MediaToolbox-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8acfa377b593b043e8c9ff1aa6cbbde92b7feaea60578ea2d0b61ac3edd15dc"}, + {file = "pyobjc_framework_MediaToolbox-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f989f07304dae82b1307e179f185a80b66ed36b0dd15d1b3bf6ec8092b766100"}, + {file = "pyobjc_framework_MediaToolbox-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4114fb3749dacf6dd83113823b846e77671c0e8b1209ca6e4402f09e6727c185"}, + {file = "pyobjc_framework_mediatoolbox-10.3.1.tar.gz", hash = "sha256:f141056dce0dc16ec21be596fea58acb4a668045f53e12a0f250990d936b44f2"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-metal" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Metal on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Metal-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7a724a98fa6972e237c5aeaee8314b68e8716ff725790587760b1fe0f700e2e7"}, - {file = "pyobjc_framework_Metal-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1c5df37c7e02a29e1b27081bcba7fa86523fce6eddaca08f6935659a2419fd3d"}, - {file = "pyobjc_framework_Metal-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:88989bf43f1443d68fd4692e224cebd68aef6215d0a92e0606c644c2a193ec51"}, - {file = "pyobjc_framework_metal-10.3.tar.gz", hash = "sha256:f137fb82175bf477e56de5c788e96caa2ad1f83b65a4fc374f9dbd1f1f9e91cc"}, + {file = "pyobjc_framework_Metal-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4a42f3aa47eb5e0d3f29bf07f239c2ba33725701546ea6d3c5d019133e0fbce1"}, + {file = "pyobjc_framework_Metal-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:cc33d05e376d3a2f42da24b397f6353d9cb8e5990c79c9255a82637b7b8f256c"}, + {file = "pyobjc_framework_Metal-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:22762ba170d0fc4538dd7f582da1fd7673160e369eca74efe3d6d35bfdd50522"}, + {file = "pyobjc_framework_Metal-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:7fef3ebfd6cfbd7cbfe45aaa86dd32034303d933871d8450f4c990dbdefda176"}, + {file = "pyobjc_framework_metal-10.3.1.tar.gz", hash = "sha256:495307db0bfd2063f28b7c8fa350af71afcfbf5f5f2186a6a751b4cb2ef46a1a"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-metalfx" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MetalFX on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MetalFX-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:980d113befb87cc04d59e821a7a9c8e3f938e2350a644a272132aef964f5d14c"}, - {file = "pyobjc_framework_MetalFX-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9fb93254978f105dd2f3781f8319131a8164c34b90dbf367084beb5fcef11b63"}, - {file = "pyobjc_framework_MetalFX-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:bcf5e8d550e47d5d4aadd7661ea17853ad91e5645aae8674ad4837d649b4b865"}, - {file = "pyobjc_framework_metalfx-10.3.tar.gz", hash = "sha256:a0235e213e7b54db43d2690062d1d938cbe8f3923abd2a61e8b91cf35b57a639"}, + {file = "pyobjc_framework_MetalFX-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:ea4bed69e6a9ab4cd4fa6160554cb7df72316e849a34b839bf8d9c69ab445b24"}, + {file = "pyobjc_framework_MetalFX-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3ecae357688a4730191d57ffbc3db6abb950b756e8b98f23689d4bf08f34c20"}, + {file = "pyobjc_framework_MetalFX-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0179ce8ac828b6d6e2542d2d4f68850290eb3f16112205a758419225dd51b448"}, + {file = "pyobjc_framework_MetalFX-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b3ae624f7e0a5c60b856889753af560b7cbd1a5f47db01f120a668e429afd1c9"}, + {file = "pyobjc_framework_metalfx-10.3.1.tar.gz", hash = "sha256:3ea0f259397523a84a320b3925dcaaa5c039494accc3cb412b63e6f7f66f9513"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Metal = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Metal = ">=10.3.1" [[package]] name = "pyobjc-framework-metalkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MetalKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MetalKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3c5c1e84984d4d8788cdd08eb7c5db8c75a96fbdda72f4ab66d19eb525d9f76a"}, - {file = "pyobjc_framework_MetalKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f8cb173e0fa120f1858cf0ef05ca61f07e84c9636ffe3cd6a34c12d92a511ca9"}, - {file = "pyobjc_framework_MetalKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1426937d86371d9b2371027f70f282e896e39e63a0d6486f0ba7984dfd0b6766"}, - {file = "pyobjc_framework_metalkit-10.3.tar.gz", hash = "sha256:de8cfbc63531e574bc3fef34960590820b3e7ead2efa48a6295c4a7eea20a9d9"}, + {file = "pyobjc_framework_MetalKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c198c61d967812837538a793b1ff862bbd868d954abcd6ee558662c45c4dbf12"}, + {file = "pyobjc_framework_MetalKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7c0155d731766be52cf18de6ad61339c16217bde330e17ef50808366856c1b85"}, + {file = "pyobjc_framework_MetalKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:48ae5e7c81c97e231c52036c8e2acb22bb59feaf0cb13f7678c87b16d9faaf9f"}, + {file = "pyobjc_framework_MetalKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:de632a7cdca1a0a13097a363dd441b9550ad91de6da6c88952c77acfd4b3a100"}, + {file = "pyobjc_framework_metalkit-10.3.1.tar.gz", hash = "sha256:905eaad9dce29082efd5cc56195337d2e8bff86ccfad36ec5127f818155ec038"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Metal = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Metal = ">=10.3.1" [[package]] name = "pyobjc-framework-metalperformanceshaders" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MetalPerformanceShaders on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MetalPerformanceShaders-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3b71ad3993d18564e5566e48c782a06eb4315af9e03c64f8ef6fd20d09d8783e"}, - {file = "pyobjc_framework_MetalPerformanceShaders-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2ea02d5c65a4cda05a66ce7f5642ff3c3942e9a305abbc30a2a3770fdd02d4d3"}, - {file = "pyobjc_framework_MetalPerformanceShaders-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:7cd0e7d0e10f3a2619fc13653eab142c18168fd05718ee0d459a8cb54b68b576"}, - {file = "pyobjc_framework_metalperformanceshaders-10.3.tar.gz", hash = "sha256:602bdc6c2ac75c330897f473661b52cfb1bed32d606a351962fd36180bf09001"}, + {file = "pyobjc_framework_MetalPerformanceShaders-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:a6f72fd528033ff0b176e909394edfc34f90b711fc6dcb225ba41b042929b71a"}, + {file = "pyobjc_framework_MetalPerformanceShaders-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:59c971d79c0d02a451571cd0122296aba05b46d7eecedea75ed8ce892d1119a1"}, + {file = "pyobjc_framework_MetalPerformanceShaders-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:969bc8caea30d71f963fb763c8d837f36d403e47c1ff6ed449ceb09783322944"}, + {file = "pyobjc_framework_MetalPerformanceShaders-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b02da6a5dc9088cadf38dce21aa39027bc668493876d3af684b91f039f123df2"}, + {file = "pyobjc_framework_metalperformanceshaders-10.3.1.tar.gz", hash = "sha256:1a9e91dc9e748834c95b7a596b943203761f6533352631c7abe612f804b23d50"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Metal = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Metal = ">=10.3.1" [[package]] name = "pyobjc-framework-metalperformanceshadersgraph" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MetalPerformanceShadersGraph on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MetalPerformanceShadersGraph-10.3-py2.py3-none-any.whl", hash = "sha256:afb9d542458d98402546700a844b0b93877a71988b3fc4e56109065d2a7652b6"}, - {file = "pyobjc_framework_metalperformanceshadersgraph-10.3.tar.gz", hash = "sha256:fbb3b6f5f91fb4419e7e3023c7b8729eae42aca0d48b2bb985f96af6718ae4a6"}, + {file = "pyobjc_framework_MetalPerformanceShadersGraph-10.3.1-py2.py3-none-any.whl", hash = "sha256:a0288c53a024bc47348da2ccd8dc980d389dacc9d1d33b3412614e88732dc424"}, + {file = "pyobjc_framework_metalperformanceshadersgraph-10.3.1.tar.gz", hash = "sha256:4bf2045036f97dcaabbf16ee8527f1787c7e9366611b9b9ed4bfabc81c19343f"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-MetalPerformanceShaders = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-MetalPerformanceShaders = ">=10.3.1" [[package]] name = "pyobjc-framework-metrickit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MetricKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MetricKit-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6944badc0ea077a1f2e9c9e16137293534a1566e2a2f411ab861d4d21090b2a8"}, - {file = "pyobjc_framework_MetricKit-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a18d89bf6583ea70aa67bc964a48e6c57a12470c5ed2eb0ef1b797368eeba3aa"}, - {file = "pyobjc_framework_MetricKit-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c5fce19ea55a0ef4da7b597626c76553b69b2ca2c87fa33811752e52d8db012d"}, - {file = "pyobjc_framework_MetricKit-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:7a065292b8331bc5fe2e736ebf39ff9edde9fe32994eb32b4987b901d756b36e"}, - {file = "pyobjc_framework_MetricKit-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c6b369b7a0daeb75bc40d05a527953f77162499a25c6fa6b59719ddd4490a556"}, - {file = "pyobjc_framework_MetricKit-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:13c6fd6110e640fee48ad72d0965eabc5049038cf70c3fc1157cd57a9b6812fb"}, - {file = "pyobjc_framework_MetricKit-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:21ad79f98474da198003e32de23a66f10d819e9e572f86ed81d7588ba4e72824"}, - {file = "pyobjc_framework_metrickit-10.3.tar.gz", hash = "sha256:0daaca29f60f0806e3f2a08bfe5ee2dfdbb8bf3ad2c7adef50f90cc523f34530"}, + {file = "pyobjc_framework_MetricKit-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ad28bb10e452b33af285137fb89f573294759571fa02d66201b78304add91513"}, + {file = "pyobjc_framework_MetricKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:59b6959d6f79f71080d386ad08665c19e52d0cc57943716da180bbb3369c9569"}, + {file = "pyobjc_framework_MetricKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f73d240b5e8f2351d6c2258b71a6d06b45ec964523f54acf05af50dc4ffac821"}, + {file = "pyobjc_framework_MetricKit-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:58dbfc7b9ae7701a59b9b2a5a5f874a9e393f10b27f39155714d1b49ea725226"}, + {file = "pyobjc_framework_MetricKit-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f462b68c22632f952d52b7c858d03727315107bb22c0a2152994baec1350534b"}, + {file = "pyobjc_framework_MetricKit-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:321ea41e7dcfb142f6ef91916cdfb5296a9888571f7c1ccd8799e51b1fc4a6c5"}, + {file = "pyobjc_framework_MetricKit-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3460fad9a31f6331884775905bb55d38db621b2f3613f44fd037777eb304d787"}, + {file = "pyobjc_framework_metrickit-10.3.1.tar.gz", hash = "sha256:f0b96fe9da0e26759f38d9e4cdf7d9c8be9c6ba35403bc8e675183a6f81dd0b3"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-mlcompute" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MLCompute on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MLCompute-10.3-py2.py3-none-any.whl", hash = "sha256:5845c232ac703be2e1cd5139e6e4c758493602562565e9b57cc8aec0e8630583"}, - {file = "pyobjc_framework_mlcompute-10.3.tar.gz", hash = "sha256:551139df816a78d0cdb4e70ddf01cd705ecb4b88ba121baebf4db4297c4ca274"}, + {file = "pyobjc_framework_MLCompute-10.3.1-py2.py3-none-any.whl", hash = "sha256:e5f8d98ee43fc795f44dab322299cf8957d7e6acb54139cecebfc7f4b2562b6c"}, + {file = "pyobjc_framework_mlcompute-10.3.1.tar.gz", hash = "sha256:9ac94b0a9511fedceacda846865daa05358eec5a4bf62be534b69eb4d7aced9b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-modelio" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ModelIO on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ModelIO-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d348fb8fa7339e152059ee08ed5ccb70d75bb92db2c4e60aba2ca8be79640c15"}, - {file = "pyobjc_framework_ModelIO-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3f2534d4a3920a77572acc4a6803f7514eabb6ef780c858ed2b63c2b4af502c7"}, - {file = "pyobjc_framework_ModelIO-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ec49cdf8e17f77c3f76ba3f159c7383778dfdfd73330be92c7136244c875e348"}, - {file = "pyobjc_framework_modelio-10.3.tar.gz", hash = "sha256:851e411bb075e0c7f813ee188610d5b87630f8552393657061bc3de58c20655f"}, + {file = "pyobjc_framework_ModelIO-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:e841be15f1847ffe1d30e0efdbc57d3c6f1a2db7553946bc15dde0d8f57b620d"}, + {file = "pyobjc_framework_ModelIO-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:53d4cc794e0dbc94e622ed164556f82db723f9c3b2d9dbf72bdf44468eb4efa5"}, + {file = "pyobjc_framework_ModelIO-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:856e8d63c10238f4b23d30b9fb903d64b9f2b44e4f30f30a28bfc665e1adc5ac"}, + {file = "pyobjc_framework_ModelIO-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b59069c79c0865334e0036b1938e009addf035bfec36f7d4d871037c14c7accd"}, + {file = "pyobjc_framework_modelio-10.3.1.tar.gz", hash = "sha256:b1da37d10c38c63006d5173b49d18891b2db2c9acdbb6dbd21c73f17c0ccab7e"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-multipeerconnectivity" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework MultipeerConnectivity on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_MultipeerConnectivity-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8013e0298f7d98cb060ed7ca491ba393999030c589c86900a143cbcc5ba8767f"}, - {file = "pyobjc_framework_MultipeerConnectivity-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6802c1fc6f77cec5f4a117f8b2bcb4c02d8fe8216278e9dbb49df31ee0626a47"}, - {file = "pyobjc_framework_MultipeerConnectivity-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f38409f8b9c6744222c9f5d4a3a0079ca844a9700b2e9e711f150df317147132"}, - {file = "pyobjc_framework_multipeerconnectivity-10.3.tar.gz", hash = "sha256:ee4ab1f39bcb50354602bf05b0064cf4698db95b504551c0beebda554eef5f8f"}, + {file = "pyobjc_framework_MultipeerConnectivity-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:1c0b65734f1e9b907c6198b035ad47c49819711c49694fe73cdf475be37db82e"}, + {file = "pyobjc_framework_MultipeerConnectivity-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:f0e466da15a3daf2c140be66da99ac0526b584fbd6dc08ed82e542e706964449"}, + {file = "pyobjc_framework_MultipeerConnectivity-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5538caad124908481ee43755d439898f9d7eb0f200856ba246c730ca5fd77e15"}, + {file = "pyobjc_framework_MultipeerConnectivity-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:5350d13115b252bf6fa374dba1ef13ffd746b15b16f45d1b77b9231aebdf5b57"}, + {file = "pyobjc_framework_multipeerconnectivity-10.3.1.tar.gz", hash = "sha256:eb801d44194eb7eafcb0a21094c4ce78bcf41ed727125b048755838b59de3271"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-naturallanguage" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework NaturalLanguage on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_NaturalLanguage-10.3-py2.py3-none-any.whl", hash = "sha256:1c002762da454c59b7465d9bec0337c796f4a255e789c37fc091e734b7ee1f60"}, - {file = "pyobjc_framework_naturallanguage-10.3.tar.gz", hash = "sha256:af031d2e3bf184ad3120f15b99cd9219fb5372372024c50e494767b1dbb2dab7"}, + {file = "pyobjc_framework_NaturalLanguage-10.3.1-py2.py3-none-any.whl", hash = "sha256:d0e47fad66bb74fa68b50093500f5cb49d8a772b522f8c92e725f2e65942dd9c"}, + {file = "pyobjc_framework_naturallanguage-10.3.1.tar.gz", hash = "sha256:49f19d0dba34802696a270d690db310ff03f1c85d6fb411734cb13667db90dd9"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-netfs" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework NetFS on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_NetFS-10.3-py2.py3-none-any.whl", hash = "sha256:3b223f96aeb2e3317e11b9f53fbe4d0c06033279bdef5570cb77ca9c12c0a8f4"}, - {file = "pyobjc_framework_netfs-10.3.tar.gz", hash = "sha256:119a6c4080f9a07d0dd5355bd8eeea1272477b8f128c3d532aa04e883763569c"}, + {file = "pyobjc_framework_NetFS-10.3.1-py2.py3-none-any.whl", hash = "sha256:84faa7325c4ecc2f4ad199d8c52cebcb520ad2e7713f356c7a5a849839398d77"}, + {file = "pyobjc_framework_netfs-10.3.1.tar.gz", hash = "sha256:46466917f7b0aca3772bf4dfd586b583992c60ecd71c39f7d28ff7665d057637"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-network" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Network on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Network-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:40ea746241e8199b793389a17ebb4e699e7d9e9fc17407133bb217ea2aff74f4"}, - {file = "pyobjc_framework_Network-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:951dc751a8f8fe62dcc6f888fd3c53be84835815bc0c3989f3bc9203e482c326"}, - {file = "pyobjc_framework_Network-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c029aab42580af9846a5e97d6afe76a97b870254433900faf55b1b726ce91369"}, - {file = "pyobjc_framework_network-10.3.tar.gz", hash = "sha256:34d63495b8e1bfd8008a55299c3b14a743a082bf1cbce25fb741db57284e2bc4"}, + {file = "pyobjc_framework_Network-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:56df88c10b948b3b09dd6d0e9061da33683e294d0450efd9076354f41e214f58"}, + {file = "pyobjc_framework_Network-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0336fc0b80a2481d3a032b94e7dfddbb8d0f1ec10e36e80ad424a028b00679ac"}, + {file = "pyobjc_framework_Network-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1e2cbc4d209b6789d8a3bd85cfe472bae50ca2d54355beb25b8336ed65d846e0"}, + {file = "pyobjc_framework_Network-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c665f3dcfb1375835dd0c6ce10079f22be73f92213fc3d48b176d9c67fc221a9"}, + {file = "pyobjc_framework_network-10.3.1.tar.gz", hash = "sha256:87a5839d4ab2ae452b4e563bd7a00569557ede4b8cd1eb77c973cdf45fb8f5ab"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-networkextension" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework NetworkExtension on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_NetworkExtension-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2f4a2ef0ac9619052ec2db1681ed5ce7d568ad0c73f570fb6c119ec33b25fee2"}, - {file = "pyobjc_framework_NetworkExtension-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f5f2e8f23f89d754ac82d7db6b607634bb40c390b8507b0367f94d70493eea3b"}, - {file = "pyobjc_framework_NetworkExtension-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:387e2bb13540d66cdd6222f4e3b44f8fa49525c03ec987acaf26a235393c51ed"}, - {file = "pyobjc_framework_networkextension-10.3.tar.gz", hash = "sha256:0798f951be920e4d3a2867d559ea2b2103f2f6f53c03b53cc752915807fb1887"}, + {file = "pyobjc_framework_NetworkExtension-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:baacdb4ad595d5c5ce9660e10ea476fab9bfd1a1def2357eae7918f5019bb8c0"}, + {file = "pyobjc_framework_NetworkExtension-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c1efc35dc4ddced3f0e5400e8ae9b28b7585f0cf5701023dd957f3cbd58d361f"}, + {file = "pyobjc_framework_NetworkExtension-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aeba32d9b9809bb1296d85da00f0c221daf54b25fd864dc9bf03a7007f5ad601"}, + {file = "pyobjc_framework_NetworkExtension-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1c8ef5fce8846fb3bf459bedf7a31ff0428a9c3184c8b26ced8e322c956e8ec0"}, + {file = "pyobjc_framework_networkextension-10.3.1.tar.gz", hash = "sha256:c5a094862061565ca6d37457db42f55f344ec24dd7604ddf5d72e20ae7f63fdd"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-notificationcenter" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework NotificationCenter on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_NotificationCenter-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2ffae68cfe70bf1f1ceee56971fed5f3f1a52ff26a857948923805d4f71b7844"}, - {file = "pyobjc_framework_NotificationCenter-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f3a25f6f7273f875f8e567421708d863a86e6f6f00963c958dfcc31ebbedaed5"}, - {file = "pyobjc_framework_NotificationCenter-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:58627e5236f70cf75ddb75f8ff944749c2b91f89fa7b56a28fe2535192ae831d"}, - {file = "pyobjc_framework_notificationcenter-10.3.tar.gz", hash = "sha256:2a0de17db42fc5a31c097f344ebbe61c3479d7018a6762944d9c387af0e5bf92"}, + {file = "pyobjc_framework_NotificationCenter-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:2818922c2c3f45721515733b452d20a507368a87b793fa976c21945773582abc"}, + {file = "pyobjc_framework_NotificationCenter-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e08264759b84a21631e143afce1696920207d418be7f8853dbde18dbc7881667"}, + {file = "pyobjc_framework_NotificationCenter-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1560edad4e9fe01cbf3a70bb6e2668985e13903497d3fdc92276d6cecf9e4742"}, + {file = "pyobjc_framework_NotificationCenter-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:992ea7c86d0330cf10113b829525d74a95d97d0d7245e4e277f75ecbb37b596e"}, + {file = "pyobjc_framework_notificationcenter-10.3.1.tar.gz", hash = "sha256:3e6efe0fe6389601bb87086f5585fa7e74b2143236b7d5afd02b617a73656419"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-opendirectory" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework OpenDirectory on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_OpenDirectory-10.3-py2.py3-none-any.whl", hash = "sha256:5d9770afc8f5f3293a633ead3bd5e5b843262a515dc37fab99808b3fb111548a"}, - {file = "pyobjc_framework_opendirectory-10.3.tar.gz", hash = "sha256:750a74323a6bdd032bba3ea50dc4b442c92682536cb9a456515c48d2c6e30a13"}, + {file = "pyobjc_framework_OpenDirectory-10.3.1-py2.py3-none-any.whl", hash = "sha256:7e787e65409aad082faed2ed0c2cd52cccea61702d9c83b6acdcac3fa50a562f"}, + {file = "pyobjc_framework_opendirectory-10.3.1.tar.gz", hash = "sha256:cddc25632eebeb6bf0d886ae0fc919d574e458c597691226ba15bbf134ab51a6"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-osakit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework OSAKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_OSAKit-10.3-py2.py3-none-any.whl", hash = "sha256:ffa00d345700c3b75ad4fec6b6cc28b2d34a565d4d611df288c708f5837b664e"}, - {file = "pyobjc_framework_osakit-10.3.tar.gz", hash = "sha256:c784228de4d8838e37ef0d01c031879f863c7839493e227ab3bcc877926dd639"}, + {file = "pyobjc_framework_OSAKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:aaa60e6f455febe45f9be6487c59f11450de81bd7f49a6e4db576a38bcaf1c68"}, + {file = "pyobjc_framework_osakit-10.3.1.tar.gz", hash = "sha256:0af326b831fa29fca11ffe2b641807ad3c233be9eb403e62328fa784528da4ab"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-oslog" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework OSLog on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_OSLog-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e13e40fb8d014b3668777969cf11e5757721d6e35309d60f2fecf0280181a98"}, - {file = "pyobjc_framework_OSLog-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ffca1c49760eb76022ece753d8646162750939583263e2f55ea6bffea6e03c90"}, - {file = "pyobjc_framework_OSLog-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:14e5efaf7f50607c3c43f3dc9eb2d5b6af56ccf3f22b7f65fd1b92cccb9318e1"}, - {file = "pyobjc_framework_oslog-10.3.tar.gz", hash = "sha256:198a582cdaac5306cd7a6ff8c65047602766b18230a953baf95f9e6120709127"}, + {file = "pyobjc_framework_OSLog-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:4799619f9ae12287923e2bc39fc021c75ea4e8bcb0e8ff44201f1018d017db98"}, + {file = "pyobjc_framework_OSLog-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7ff719367249c09318a87df47ef8e1c8d18ab5f4b9e94862e7ca9c8fad21ed9a"}, + {file = "pyobjc_framework_OSLog-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5ae0848bf6de69c95802f11bb4aff5c2edac5c5e6179b9a06a0e4fe05ed48b53"}, + {file = "pyobjc_framework_OSLog-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:cded4c706fcf3fd78ef257ab096f4f8cefc70cca81553d2fae88841aaf5d620d"}, + {file = "pyobjc_framework_oslog-10.3.1.tar.gz", hash = "sha256:592c3e50cf824c2c07779771aa0065de2dbb4c615de43e8949b39d19ba04d744"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreMedia = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreMedia = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-passkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework PassKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_PassKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:88a5a3e57337b8ad7c31499844496932ad25a7b175604c605bedfc02912cff89"}, - {file = "pyobjc_framework_PassKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1e215af948065631c0cc752a2ac5fe2df52eba894cd70cc88caf88a5359e5fe1"}, - {file = "pyobjc_framework_PassKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c1e03659e061d29d6a907642cd5e8829b1e67cf7b36ec94e0c32a44a5edb170f"}, - {file = "pyobjc_framework_passkit-10.3.tar.gz", hash = "sha256:9a4464f1a3359ee7bfff8a60c80dddd07b4519082ffe5316ef8532491ea99a9c"}, + {file = "pyobjc_framework_PassKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:ce09205aae4e15d3639d76a558c072ae106e8c7dafe9a451c5e27967498b74cd"}, + {file = "pyobjc_framework_PassKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:79ff6fa8ad4c0f9b4a992122b22e2b2b4200534221eb1bfe86bf473fb3c7ca23"}, + {file = "pyobjc_framework_PassKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:bbb71ac6fc51da06d0fd6cb4d83eb79b704c2bab694a93899d3f83c753c9740b"}, + {file = "pyobjc_framework_PassKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d41409ee24eee2318023c3ba23218db152fc262ebcbea9021dc533fe80a73f32"}, + {file = "pyobjc_framework_passkit-10.3.1.tar.gz", hash = "sha256:4c3eea19c1ae3edf6e7858ab815bcd8ecf517a146928ce6a843910729372f010"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-pencilkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework PencilKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_PencilKit-10.3-py2.py3-none-any.whl", hash = "sha256:9c0e3d504b55cf7c8a52e8efcca0188b8f7657108d8ef4e41990e99bb3b8ae43"}, - {file = "pyobjc_framework_pencilkit-10.3.tar.gz", hash = "sha256:dd7c9ef5482c975ad4674ec8e9a547b91fc3095e29343fbdfcfecf1b276d4483"}, + {file = "pyobjc_framework_PencilKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:dc05376fbc5887391ff4e778b6f4b2fa20264aac58cd5fe5f47e4930186c1674"}, + {file = "pyobjc_framework_pencilkit-10.3.1.tar.gz", hash = "sha256:4dfd8e0179be5ecf67b768317a88d86d93df1c8674d422afa14957cf80e6e01f"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-phase" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework PHASE on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_PHASE-10.3-py2.py3-none-any.whl", hash = "sha256:947291b108f95008042fbaf9b967f19726e0b2b521d7e8d57b9411b47f0e2ad1"}, - {file = "pyobjc_framework_phase-10.3.tar.gz", hash = "sha256:f38712f38eedc9da80e5e99665f9a5654031886ffeab03879fbf6cb14c5c40b7"}, + {file = "pyobjc_framework_PHASE-10.3.1-py2.py3-none-any.whl", hash = "sha256:eec5a38983d65a4cf022dd01dc6f290ec163399e79592203443b4115ea3c8510"}, + {file = "pyobjc_framework_phase-10.3.1.tar.gz", hash = "sha256:5be2ea5d36ea9620f5278f5ad3b02cc243511be3b137aa28b1523e8f6da54f99"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-AVFoundation = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-AVFoundation = ">=10.3.1" [[package]] name = "pyobjc-framework-photos" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Photos on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Photos-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:eb921df4c5f61f518c156681131159f1a640d2654d98811a129f3df8eef976a2"}, - {file = "pyobjc_framework_Photos-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ba6b9df97e76d5342298ae93d8c6bb2dc0c9561c8b03efd87499512af962f6f6"}, - {file = "pyobjc_framework_Photos-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:26409575fc656b8967e52efb699c1ef2dab57ea60657dab3b7180515029f485f"}, - {file = "pyobjc_framework_photos-10.3.tar.gz", hash = "sha256:621c058e84df654af49a5cfc1e0799b5de07fb37449d83562ff11c4bb40530eb"}, + {file = "pyobjc_framework_Photos-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:9a382201dd14a3f3076d8689267d63520803a1ad1716fb66df5c1bb578bc6384"}, + {file = "pyobjc_framework_Photos-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9c72efff52bed483b0dfaa569a21355f7620f25672a0245c5db8c1df86abc7b8"}, + {file = "pyobjc_framework_Photos-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:4841948ce4fe3d5060ec08e760b0b6e476e923782f32b9af2ffe8eb2a4fbb385"}, + {file = "pyobjc_framework_Photos-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:50710703d18d0b13c48e02ab4edcca72a67ee20aac2a75664bfb725c8cb3a677"}, + {file = "pyobjc_framework_photos-10.3.1.tar.gz", hash = "sha256:8d538c399720062523694f7669aa82dcb75a7b192fb4aca93cf782d04e4c39be"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-photosui" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework PhotosUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_PhotosUI-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2579e6f77668500ae2621f133ceec5bf5931c908a87d53ecd0a0fca0cf32608f"}, - {file = "pyobjc_framework_PhotosUI-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1e2ead7e15aab8fb34aaa55bbd55faa48b3fbc9cb6994af730fad1fe9e8f229d"}, - {file = "pyobjc_framework_PhotosUI-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:9e50ca9c56187e7394def35c57238b556cb48d61c1c7fb59bc4cd2cee1e2e10b"}, - {file = "pyobjc_framework_photosui-10.3.tar.gz", hash = "sha256:1acc78ac2eaa487a63d1e732f22e7cf9a9e620ed7cac1d10af03ad08f125eb9c"}, + {file = "pyobjc_framework_PhotosUI-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:88665561d9ef7e9fd2ceb4e7e5da0fc3412a397d4c48a2121250462781106d30"}, + {file = "pyobjc_framework_PhotosUI-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3254605c33e090742d0303a3b5b8ddab5489dbf28ea8a287566106e6887ee561"}, + {file = "pyobjc_framework_PhotosUI-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9370e36bb4ae1e7128006ff6a6b43448ebf8586784749e2a1fa30bbb2ef8fedf"}, + {file = "pyobjc_framework_PhotosUI-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:a756c3bbf945ceaa7d184c41053c2a9c1a89b32ffcdf752664b1180927b22cb2"}, + {file = "pyobjc_framework_photosui-10.3.1.tar.gz", hash = "sha256:e9eb961c6be1f3e00d76cc0a8ec15b50ac0692bd5b5c86268ad08f6d09cf390d"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-preferencepanes" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework PreferencePanes on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_PreferencePanes-10.3-py2.py3-none-any.whl", hash = "sha256:d82b67f9ba6c4f6524dff93f8bf705ff703d281985d42d85d703743ccf89cf5b"}, - {file = "pyobjc_framework_preferencepanes-10.3.tar.gz", hash = "sha256:39b927fe60ff5883b79df7bf25cba2bfd2b13a33153754a3ecd29e1636ec188c"}, + {file = "pyobjc_framework_PreferencePanes-10.3.1-py2.py3-none-any.whl", hash = "sha256:319b58b6c8f876f67e879b3a4f74afd6d892aa43a7f9ef4320819265b281c9e5"}, + {file = "pyobjc_framework_preferencepanes-10.3.1.tar.gz", hash = "sha256:eef150416a39a0109a8a37e9978ac4a55ad0b125ef6053a7431524ede5c69783"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-pubsub" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework PubSub on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_PubSub-10.3-py2.py3-none-any.whl", hash = "sha256:5da1ab453671d73c801d21e509537492a27d56bd8ea0d4b060a21768594e9ca2"}, - {file = "pyobjc_framework_pubsub-10.3.tar.gz", hash = "sha256:060949b977a647922ca7c92951f0316815a98f54a1293c9733573706907f8041"}, + {file = "pyobjc_framework_PubSub-10.3.1-py2.py3-none-any.whl", hash = "sha256:dd8bc334b3acbdd82163d511bc71af7addc98dfaf473736545487f3168836dcd"}, + {file = "pyobjc_framework_pubsub-10.3.1.tar.gz", hash = "sha256:d123e75288c2f9d785ed1c4d92a96e5118c4b6f1cd9c55605eb4b4a74c2e36f4"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-pushkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework PushKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_PushKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b3ef9d2928d31735c03e909b2a7aabb2b22b4ab962aba15b0c5b1691c5a0197f"}, - {file = "pyobjc_framework_PushKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:262121afe7aa5a44dfcd50b87f0416288907ace5e5dc374fb0cf15ac3c8407ca"}, - {file = "pyobjc_framework_PushKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f98e8abc8e69b48858829f00723c818b579018525cdc89ba7fb2aa8fcbc0f1a1"}, - {file = "pyobjc_framework_pushkit-10.3.tar.gz", hash = "sha256:942d5a77b13cd3f7310cd50ac86fa563c502e5d6a0d4d2eecb3ee67587a8e844"}, + {file = "pyobjc_framework_PushKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:39e21ac2b9a529e99d6d33c439c96d4d2bb97d2c56bd6d92b2c5bd497e925851"}, + {file = "pyobjc_framework_PushKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e20f94ad3fbebf34c613c880e655d0f918d891b0a70763f99bb5d11e0af65c73"}, + {file = "pyobjc_framework_PushKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:79f0e66b88473e7fdef304dce06d7d63c3e5e38b12deafcd06a5bd3506ed9398"}, + {file = "pyobjc_framework_PushKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ee90959fc7b171930cffdf07cb7865d56a2cb4b723c5826ccf95d6e865dee4bd"}, + {file = "pyobjc_framework_pushkit-10.3.1.tar.gz", hash = "sha256:cc4da5382cf48c29637af1c633490203358a6ab0c76f0c006079cf144eeb9568"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-quartz" -version = "10.3" +version = "10.3.1" description = "Wrappers for the Quartz frameworks on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Quartz-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ab809262f8a1a2880a0e9d9e65035992cba684883f422c375bd320848f4e9a43"}, - {file = "pyobjc_framework_Quartz-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2187dd8a8d15fb731c9e3ae24b7311b9e21681a53377650ee6f9b519e1f78432"}, - {file = "pyobjc_framework_Quartz-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:caf489c498b2137bf2909ad19f6461ddfb66106f678694805184daaa0dec7919"}, - {file = "pyobjc_framework_Quartz-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:cca8f2233d93b3b84bca2745ad74b603c23a77c38c1c5847ac590eab0c335fd5"}, - {file = "pyobjc_framework_Quartz-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71d9f590d5842191c68a5a8aee812d5516d61240e5dea8f604d8a9f769bbda4f"}, - {file = "pyobjc_framework_Quartz-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:75094e160492e4724347a7fdde5a6f4c9f186c31d528c247f359e2c1606d9fb2"}, - {file = "pyobjc_framework_Quartz-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:465ae4c1ecceca59831e7698c5fbe62d8e1e987c7fbbb000737954f2085762b9"}, - {file = "pyobjc_framework_quartz-10.3.tar.gz", hash = "sha256:4c4441e5a338ebe2e1d44a3bdf78e6bfb849ac167732814646dc438c3a08f595"}, + {file = "pyobjc_framework_Quartz-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ef4fd315ed2bc42ef77fdeb2bae28a88ec986bd7b8079a87ba3b3475348f96e"}, + {file = "pyobjc_framework_Quartz-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:96578d4a3e70164efe44ad7dc320ecd4e211758ffcde5dcd694de1bbdfe090a4"}, + {file = "pyobjc_framework_Quartz-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ca35f92486869a41847a1703bb176aab8a53dbfd8e678d1f4d68d8e6e1581c71"}, + {file = "pyobjc_framework_Quartz-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:00a0933267e3a46ea4afcc35d117b2efb920f06de797fa66279c52e7057e3590"}, + {file = "pyobjc_framework_Quartz-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a161bedb4c5257a02ad56a910cd7eefb28bdb0ea78607df0d70ed4efe4ea54c1"}, + {file = "pyobjc_framework_Quartz-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d7a8028e117a94923a511944bfa9daf9744e212f06cf89010c60934a479863a5"}, + {file = "pyobjc_framework_Quartz-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:de00c983b3267eb26fa42c6ed9f15e2bf006bde8afa7fe2b390646aa21a5d6fc"}, + {file = "pyobjc_framework_quartz-10.3.1.tar.gz", hash = "sha256:b6d7e346d735c9a7f147cd78e6da79eeae416a0b7d3874644c83a23786c6f886"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-quicklookthumbnailing" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework QuickLookThumbnailing on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_QuickLookThumbnailing-10.3-py2.py3-none-any.whl", hash = "sha256:245970d34a6c2faa591a4f597336591867f1f3577b91ba510cfa74461e50a0d3"}, - {file = "pyobjc_framework_quicklookthumbnailing-10.3.tar.gz", hash = "sha256:657793496b4f906d8d651505f049d624e00b9cd4e12af617f3818d5674cef5db"}, + {file = "pyobjc_framework_QuickLookThumbnailing-10.3.1-py2.py3-none-any.whl", hash = "sha256:e5095c0ad8cf1f91a6ed9aa5c4fb7c9b1da122d495ce131bae8d7faa06da9505"}, + {file = "pyobjc_framework_quicklookthumbnailing-10.3.1.tar.gz", hash = "sha256:ee26be78df9ce46ffa6f971f4ce167a0e98f38167aeb86cfc1b41270f15c96a3"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-replaykit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ReplayKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ReplayKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:429d2b47cd60dd4e7c239ffc3185c93d07f2a78c45b575d0d04af6cafa93e0cc"}, - {file = "pyobjc_framework_ReplayKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0656092eefe1e7484e4f35147d25f037ce22dcbca8ac68489b93fa1827d452d1"}, - {file = "pyobjc_framework_ReplayKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:88e74ce344bf9790d306d30c62789746b5c2fdf8eaf7bf77cfef12961451c9dd"}, - {file = "pyobjc_framework_replaykit-10.3.tar.gz", hash = "sha256:b1c87606d3b90b93d2549b792af2ca1915827788e7c0c3a534df0d068b39c012"}, + {file = "pyobjc_framework_ReplayKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:1d89020e770763947c0e3e3a201b541b81b455656e574d390ad0b0e32a67640a"}, + {file = "pyobjc_framework_ReplayKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b753658337d25964acb83f5edc465b772f276b4c88fc8bd03ad633b4466f6bd4"}, + {file = "pyobjc_framework_ReplayKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fafbc37ef6e44ac5019b4a4b751b3de6d5983500705e8dea2fc62134f8c0dc24"}, + {file = "pyobjc_framework_ReplayKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:22ca748ae8325e41e0526f13822d2c477ab879cb2d454eee1db47ca91353c986"}, + {file = "pyobjc_framework_replaykit-10.3.1.tar.gz", hash = "sha256:21762c8674b629fb670c3cbd515c593f1b5f98ee24ee4834a09055cb08849068"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-safariservices" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SafariServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SafariServices-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:7e2bdd40f0399076840e4f95599d409df2ad7be06ef8593cc59cc12c84b39ca6"}, - {file = "pyobjc_framework_SafariServices-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7ed3bc6b71575082f21b6edb6360a3d3093fb2d40d1f57749f4d25264041e394"}, - {file = "pyobjc_framework_SafariServices-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:8c9ff1b7fbcbdabaeabbd9866e89208d7dfde1e125c372d91d047799e0b3682b"}, - {file = "pyobjc_framework_safariservices-10.3.tar.gz", hash = "sha256:678fd2013ed3451b9c249f6515e8cb712f8c68f76050e2e0b8911dcdd1bb1df0"}, + {file = "pyobjc_framework_SafariServices-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c8afb977b5858d3fd27136146db46a9f2ec43c35f5af269dbcb51c46a422dd7e"}, + {file = "pyobjc_framework_SafariServices-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:adb0332cbfa086892524efa253c873ecc4a8b00c60db45be3362759c4b4ae87d"}, + {file = "pyobjc_framework_SafariServices-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7a171f08527c6bd297633e72bc597d68ec74419b5315f8c8122311537a8a6340"}, + {file = "pyobjc_framework_SafariServices-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:aaba0ea92410820d94fef0b93d337478f0e416967cb2aa4e667dd4d1bb561c1e"}, + {file = "pyobjc_framework_safariservices-10.3.1.tar.gz", hash = "sha256:9c5278576e7c28c3d93e74ebe5d39d07c5c91572ddf03ea01cc45d9a06dc8d0a"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-safetykit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SafetyKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SafetyKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:01da686c3be43dece5935b671335f7567ad02490557d72a273465223c7390444"}, - {file = "pyobjc_framework_SafetyKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7439880b24a51f62520e96597b9cd3cf6f987390fb0c7a6d4c1c756b452e3865"}, - {file = "pyobjc_framework_SafetyKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:9c1a74ab089cc953fc385d47ab1bb2b434f6ae3a5c4bca4856a3df5dec2e2989"}, - {file = "pyobjc_framework_safetykit-10.3.tar.gz", hash = "sha256:4d04ff2919b3061c15bd013d87a88bd532cc76cd7a94ab76d70ac8dc5d63022c"}, + {file = "pyobjc_framework_SafetyKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:e554cb94bc2f89f525ccaa4ed827390d188eba8bb24049acdc764f3dfee9af08"}, + {file = "pyobjc_framework_SafetyKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8eb160cc4f3b7e6d58f2eecc205f016afd5f4278b9641e49d5ef9c4df7b6df8c"}, + {file = "pyobjc_framework_SafetyKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3674b92d8b72d0a6006cb899ec2f605d1d5a6a59ff2d90c51ee2ccfd0f069d10"}, + {file = "pyobjc_framework_SafetyKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ac700aa2cbddc8a31626815886e42d0d1591572914c2b15df2dd07871ee84568"}, + {file = "pyobjc_framework_safetykit-10.3.1.tar.gz", hash = "sha256:8421be801ce29053e67a2c91673913562c3ad9d4bb1fbaa934a3a365d8bff12d"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-scenekit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SceneKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SceneKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:95feb8d312ab140b7e064a2792c477a2f366b184bf89a676f134a9b5c8bad391"}, - {file = "pyobjc_framework_SceneKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:40335d7a8a4e20091e3e34958da779b06a91613736521634c3cb00c83c7d9f17"}, - {file = "pyobjc_framework_SceneKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ac8afdfaf8a4b0352ce53228e3088e52813813a3ea92719f17e12f2f49df607f"}, - {file = "pyobjc_framework_scenekit-10.3.tar.gz", hash = "sha256:aeb4182d2a2d3d2887afe4b4f18f44bb64bf89aff62a22e69522b67bdb1fc6eb"}, + {file = "pyobjc_framework_SceneKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:7a108ef1a660a7928d1d44e415c84f544d296745d5350235addaab82777b080a"}, + {file = "pyobjc_framework_SceneKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:08fb5dd8c10a5624a0bf3dd9f448b2fe4c8b9c7c3c98708d28b0b4c72dd2a107"}, + {file = "pyobjc_framework_SceneKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:08601223416fa048d9468f961b170e3c2009d7e2434eea92c12ee12f6c672961"}, + {file = "pyobjc_framework_SceneKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:2984a543221190547bff603a6a59c931cda7099b91ac7412e11c962e8f6c3bc1"}, + {file = "pyobjc_framework_scenekit-10.3.1.tar.gz", hash = "sha256:99cf0db3055d9bae0a8643400e528a8c012235db8ee6a1864ea0b03a0854c9d0"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-screencapturekit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ScreenCaptureKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11e0804885f3c6d40818a644a2732a1eea8047641b9f6e70cd300f05c5aa5eca"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:496d16ef5fe2ffda8dda6d1d01f9f66e6585194d281fa989dc659646d7661513"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:cbb8583032093e2e1f142c333574d6b9e785aac4186f7f4d25286f0e3545b2f5"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:4885bd0147f08c14430e660280b42bbc00023e5c3ec80605f62f644239a686bd"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6dd224b70f67dda55a53972d6679281d305a787e128206e583ce1ef1acf3c41e"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:136e63f4e1868129cf8f42c81cd84cc03078b098666fb941e068732100563ba9"}, - {file = "pyobjc_framework_ScreenCaptureKit-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa91c9c266d19afbd7e1f2c51015be6d707f645d5a4546ca7d301326a6d18dc"}, - {file = "pyobjc_framework_screencapturekit-10.3.tar.gz", hash = "sha256:96cd9da48212b13c749b9fdfba570c7e374f1cd3b6fa07b89f09c017d3463ca6"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e69a1e15502543c80c084399d7e06d6ebfb089a3afd248860e24dd03e654456a"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0953f8d43bd7f0012decebe34401d361c4a64472190960204b3214e4850e4ef2"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a80928dc483046ac72294fd576c53f793045aad700b740ec9591b23a3ccc011d"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4d8e280a076e7bc40eaa9730f97da84421b891c30f6e3fdea4f6c30bdb298243"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:757a62e30ae68307d4705288bb808d91e10569c8ba3b54192bb5bbaaddcfa802"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:c55a2bdc3ff934841a668db1b5b2f74b9352696419ce87fea31637b89a04b6c7"}, + {file = "pyobjc_framework_ScreenCaptureKit-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a0ccf558123fe0b7fcfbb74280678aa0f0973c96765a03cb658fd4d8c5e732e9"}, + {file = "pyobjc_framework_screencapturekit-10.3.1.tar.gz", hash = "sha256:cb1a2e746e0f98ea14a11ea35d059d38587340beeeb905812085e2c7ceb14e0c"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreMedia = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreMedia = ">=10.3.1" [[package]] name = "pyobjc-framework-screensaver" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ScreenSaver on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ScreenSaver-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9676a820ee37fd570831ff6f55d237e2c7169529dba90efaedc4aca4eb38e687"}, - {file = "pyobjc_framework_ScreenSaver-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c02a8ea32a5361542c7578b836414d08a9f913bdbd1fb3e479be3f55b1f349f3"}, - {file = "pyobjc_framework_ScreenSaver-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:2634591a4c2e689655e3f28023177d36a6e8f287f0b71f51306eab8ebb8ca903"}, - {file = "pyobjc_framework_screensaver-10.3.tar.gz", hash = "sha256:32ad91df0ad95c94f757a48e9338caf92afb90a492e3800de749aa37d4590a63"}, + {file = "pyobjc_framework_ScreenSaver-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:31bffb17ec131509c4cc584e98328497310ea644c764b50fb6bf7850617ec5a5"}, + {file = "pyobjc_framework_ScreenSaver-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ff25ad7cfffa116feaa117989f0a4b68dd6b7318aea4320ece6f75caf0092cfa"}, + {file = "pyobjc_framework_ScreenSaver-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:51e5bce05a3ada526c5c19b21cfb383cd7653d78f175c5abaf500a67ddab1c19"}, + {file = "pyobjc_framework_ScreenSaver-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:616ffb4bac2a56108778e33be6fe75b28f19511157abc411960b72324276635d"}, + {file = "pyobjc_framework_screensaver-10.3.1.tar.gz", hash = "sha256:0bbc5b574f12e95f6f6e48ced40b601e46e560ef6786845c15c57d78e6cd083e"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-screentime" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ScreenTime on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ScreenTime-10.3-py2.py3-none-any.whl", hash = "sha256:79447a4513362d38a9fc691ffa45d37a16daa11fc1c89cc1a93ae13dd8198e3d"}, - {file = "pyobjc_framework_screentime-10.3.tar.gz", hash = "sha256:8698e56883fb58402f912e7d90e833c6092d8345fe53683a6f6f90dc739fbc5d"}, + {file = "pyobjc_framework_ScreenTime-10.3.1-py2.py3-none-any.whl", hash = "sha256:d4f8a0784dc7d7060dadae2e4b5aae5e1afe8bbf453ce49cbb1860b8920114c3"}, + {file = "pyobjc_framework_screentime-10.3.1.tar.gz", hash = "sha256:351179d5bf951aa754c72f50ba8785212adf1b26abe10149c750fafd0a3108ae"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-scriptingbridge" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ScriptingBridge on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ScriptingBridge-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:56c26806bd77d9241773d92f21da6c86eccc82617dc3d4d9f4515e5473d7d253"}, - {file = "pyobjc_framework_ScriptingBridge-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ec2d52aaf0f7dcc07896e0390a37f07bda3f3bfe8ac2f4a26a773409650d5123"}, - {file = "pyobjc_framework_ScriptingBridge-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:19f6a8f5466b65d53f2620f9ef9e9a74a47f23e79ad244efb38fcaf8a3dcb101"}, - {file = "pyobjc_framework_scriptingbridge-10.3.tar.gz", hash = "sha256:d4c33a6c5aca98cae0175821ec8df487d0ed49a8763f046cb0c518d4fe83603f"}, + {file = "pyobjc_framework_ScriptingBridge-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:3a88e1a6c6b7d8935ab4baa9dcdeccb9cb08a44906bdd69b77302f48c88408d9"}, + {file = "pyobjc_framework_ScriptingBridge-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:66b55a9c12572f9bd6c00fd0a5aa5353354e7b717e37ffd1e843614d2fbde3d5"}, + {file = "pyobjc_framework_ScriptingBridge-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:387c0720842a1285afde5b56c43d9ed1332736ff8f6119ba6c6a551018552182"}, + {file = "pyobjc_framework_ScriptingBridge-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:90022f44f2bf0563bf5a75669198b9d778f76ece719f237750e9c5fcb00a601d"}, + {file = "pyobjc_framework_scriptingbridge-10.3.1.tar.gz", hash = "sha256:6bfb45efd0a1cda38a37154afe69f86ea086d5cbdfbc33b3e31c0bda97537fe9"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-searchkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SearchKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SearchKit-10.3-py2.py3-none-any.whl", hash = "sha256:24e883795b2649cfc51bd8b055fbc8565182e7b2396cfba4c8ff3a156c941fde"}, - {file = "pyobjc_framework_searchkit-10.3.tar.gz", hash = "sha256:5e81256dac0bff081dfe3f95c0d7f6fe5d0a4ba7e7ed2cad15edc60348a7f614"}, + {file = "pyobjc_framework_SearchKit-10.3.1-py2.py3-none-any.whl", hash = "sha256:48ec776603e350405c7311f29d5941e0e9d6b6a75e2aec69e0acd28be0979905"}, + {file = "pyobjc_framework_searchkit-10.3.1.tar.gz", hash = "sha256:7efb76b7af9d8f0f08efb91543f4dba0b00261ed41abb121ada80175cc82d65d"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-CoreServices = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-CoreServices = ">=10.3.1" [[package]] name = "pyobjc-framework-security" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Security on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Security-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e4df7ea48f93034dd784277d4456c83abd79060a9a5847c5604f664d39ea45da"}, - {file = "pyobjc_framework_Security-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9dc80b7b694ff5594742624a9fade022829a09a79c1c6b97eef97d33d49f7f4c"}, - {file = "pyobjc_framework_Security-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6d1ddb3fd3cc11aa621f414277c9daf9481894fa5fbe99e2430a3fd2773e81a2"}, - {file = "pyobjc_framework_Security-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:aa8737b6a367550e3d12e0c71c267346b5ec235b62364bc17d0a2b883d175933"}, - {file = "pyobjc_framework_Security-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2fbd7a004361a28cbf4775820589a9b79443f13720d0cf755df066dc3fbbb98b"}, - {file = "pyobjc_framework_Security-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:e3d342a0741bb13da470dda087499a67c9e2bf27ee0d3a490e797ffb88cf9443"}, - {file = "pyobjc_framework_Security-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07b34541ce0960e924be8ef4a40b35a3b85104b61684d67a3063826f657122c2"}, - {file = "pyobjc_framework_security-10.3.tar.gz", hash = "sha256:1be270a9205d9f392a658a267dec9ec602d6a98448419541f0005dc80da97013"}, + {file = "pyobjc_framework_Security-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9de850e5d29cb8605c0d7f7fb4a8d29ad5ece6c58a2ab16fba3f985e6b9ee05a"}, + {file = "pyobjc_framework_Security-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:499372b4b87de0198601e0c6b3d3e43d48605218149a5808c6567b601147a9bf"}, + {file = "pyobjc_framework_Security-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b3daed9661bd80245dd8dbc738a17870226969db27f6dbb3424ec0ebdbb6ba83"}, + {file = "pyobjc_framework_Security-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6120e91282985bcec3b44c1bc4f9c26d40cd07b4ac3dc81f745d73c13f8b5523"}, + {file = "pyobjc_framework_Security-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43450895cd84256b313b547c9b256a4c0dc4b91195ec3e744f4f247d3cda0b77"}, + {file = "pyobjc_framework_Security-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:de52be2ce5ea98f2c224fea248227dcb3e7028d9814d0894ea6ea3c6da0f9160"}, + {file = "pyobjc_framework_Security-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:df39effeeb79482dd5805fd05e34a7c3ab30233a6e06e251cf7f8620430574fe"}, + {file = "pyobjc_framework_security-10.3.1.tar.gz", hash = "sha256:0d4e679a8aebaef9b54bd24e2fe2794ad5c28d601b6d140ed38370594bcb6fa0"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-securityfoundation" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SecurityFoundation on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SecurityFoundation-10.3-py2.py3-none-any.whl", hash = "sha256:6befffef47d857cad2f76087fee8e8648f210803ca883ab2af4aedceb58a9bef"}, - {file = "pyobjc_framework_securityfoundation-10.3.tar.gz", hash = "sha256:aaac1ccfed767de7d4469a46378fa48d29dcf55fa0209fa04b576464481e7ebc"}, + {file = "pyobjc_framework_SecurityFoundation-10.3.1-py2.py3-none-any.whl", hash = "sha256:c352cde672c9c2afa89575c362a0714e589c118485cec49ba230327e92c8a9a6"}, + {file = "pyobjc_framework_securityfoundation-10.3.1.tar.gz", hash = "sha256:414b13acabfae584729cd614e27247d250ec225d31140e8d971aa08536d6150c"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Security = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Security = ">=10.3.1" [[package]] name = "pyobjc-framework-securityinterface" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SecurityInterface on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SecurityInterface-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:91403223d8ed6ebc67b6d641988119b39be5933e477ab2466a56ffefbcf9a94a"}, - {file = "pyobjc_framework_SecurityInterface-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6bb826b244d18350591631434be2ef0a788a9c18421501dd00026c182b43b457"}, - {file = "pyobjc_framework_SecurityInterface-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ab2e22755467ffaddb1ae35115fdac2a6d9a06a49cb682e04b7ec02008ae332e"}, - {file = "pyobjc_framework_securityinterface-10.3.tar.gz", hash = "sha256:e7d002e70f7474205002e13d7689ec464263e29d6021d2753424558420549089"}, + {file = "pyobjc_framework_SecurityInterface-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:7a9bbca70e8a27bd79a0b8846f7d08b693dd309ff780f92f713fee57ff9d3ddf"}, + {file = "pyobjc_framework_SecurityInterface-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b964ecbde276611c14fd70884ab9c08c4aae75633deda1a29813dbe42dc83dd6"}, + {file = "pyobjc_framework_SecurityInterface-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8c2998c09767f0214891c553fadb8ec72a8273c95fca820c44cb11f3b0cdb8a4"}, + {file = "pyobjc_framework_SecurityInterface-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:d913d30d04c9f01679ead33c95ad53dade587995f48c778a6de4d7da239b43e3"}, + {file = "pyobjc_framework_securityinterface-10.3.1.tar.gz", hash = "sha256:cd25f342a2b53cbffd134443506d5e75c96ba7145135debb8932c1252d57269a"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Security = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Security = ">=10.3.1" [[package]] name = "pyobjc-framework-sensitivecontentanalysis" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SensitiveContentAnalysis on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SensitiveContentAnalysis-10.3-py2.py3-none-any.whl", hash = "sha256:4ae985f6412c5cd277fb40fe16c10a4622407a07db8aa476fbf64c140ae0429a"}, - {file = "pyobjc_framework_sensitivecontentanalysis-10.3.tar.gz", hash = "sha256:1989765de0bf77d7578ef45c5d1973b364555bfa26b9fd6c41431646d31a650d"}, + {file = "pyobjc_framework_SensitiveContentAnalysis-10.3.1-py2.py3-none-any.whl", hash = "sha256:6b5cfe771a28300d766ff14ff81313fda946943d54a039d5574478a070933e03"}, + {file = "pyobjc_framework_sensitivecontentanalysis-10.3.1.tar.gz", hash = "sha256:ac8dd18d77ccc0bb4eb24839cf39da9981db64e53f52b09636e47bd7b3066f84"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-servicemanagement" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ServiceManagement on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ServiceManagement-10.3-py2.py3-none-any.whl", hash = "sha256:923baa4178f9c0de6e615ffd5afe35715e9704829eb1d5ae35bbfde711ca0872"}, - {file = "pyobjc_framework_servicemanagement-10.3.tar.gz", hash = "sha256:e874633a4332cab1824aeed8f59eed3700448daea7c2fe9b621e14886894244e"}, + {file = "pyobjc_framework_ServiceManagement-10.3.1-py2.py3-none-any.whl", hash = "sha256:6b7ca0de9cf74439df0947aae29f5f31d58eeacb0ff55e1465faed540d31de4b"}, + {file = "pyobjc_framework_servicemanagement-10.3.1.tar.gz", hash = "sha256:d048a803ad34c997dcc99ba778fca9d91cc5adfa1d115202e4bf22d9b04fd92c"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-sharedwithyou" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SharedWithYou on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SharedWithYou-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a1663d0136b378c4ed6ebdc2536c5f43de576c323af900648f8d2a1cfa07b1f8"}, - {file = "pyobjc_framework_SharedWithYou-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ac3ec93544b4b93a2d40f125ce0242ba4f9d55c62396888347613f5b70e91ae5"}, - {file = "pyobjc_framework_SharedWithYou-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1422bc1df5d89e47573b2ba78b91c390b105a9631f780f14d781e6b51d75a645"}, - {file = "pyobjc_framework_sharedwithyou-10.3.tar.gz", hash = "sha256:a9742bdc4a0449c83dc7f704908da3cd1c64829a00007aad4d999749b20d5ad9"}, + {file = "pyobjc_framework_SharedWithYou-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:175cb32c93c55511f86ccf02b1da2fdcbc2a0f92422d451ff5dd4a864b3f3faf"}, + {file = "pyobjc_framework_SharedWithYou-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:8a1ee78d6220e02e073c5fe6fea8f223ef870086c1afe60f346e7bb3dbdcb165"}, + {file = "pyobjc_framework_SharedWithYou-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:824d56ecf85dbaa938a2db42bf2f5a55a4e9f94019dee2dc90578040cc2bbd3c"}, + {file = "pyobjc_framework_SharedWithYou-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:bc37e1c86f460095085a5060149ca013d4dcb9b54337887bff86a2e07302c0f1"}, + {file = "pyobjc_framework_sharedwithyou-10.3.1.tar.gz", hash = "sha256:7e35b631bc77b040151515e4fee9c8f47bc313924fc3e5970e940f1343db039b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-SharedWithYouCore = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-SharedWithYouCore = ">=10.3.1" [[package]] name = "pyobjc-framework-sharedwithyoucore" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SharedWithYouCore on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SharedWithYouCore-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ba335881c9505832336c53f273d073f146240c3ca4575351a04606273dc19000"}, - {file = "pyobjc_framework_SharedWithYouCore-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0f6ce6989fb3995329516dd08570936c96c848a26430ad54ec2bd0e4b79d4e83"}, - {file = "pyobjc_framework_SharedWithYouCore-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e3ef63867c4f9305b5b9f384f0dce3bb9a4ad14d6aa8a45520ef6eb94f3b0efd"}, - {file = "pyobjc_framework_sharedwithyoucore-10.3.tar.gz", hash = "sha256:862a0b554bed5c944a31e4b14918af49b55fe6497cc8c25956200cbc7bcde811"}, + {file = "pyobjc_framework_SharedWithYouCore-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:b0fb4e84e15765d913d5383b61004b7ff9a637f198ec7c3dee07632f3a4e2b4c"}, + {file = "pyobjc_framework_SharedWithYouCore-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9b480058016216e5a3715e3ff50f5430159ec4235dcd110141f53637f5dbb51d"}, + {file = "pyobjc_framework_SharedWithYouCore-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:17a5e29f832d395030b1ab5dfcf43dad2a9c0f917e6b443ac383dea06e3aa304"}, + {file = "pyobjc_framework_SharedWithYouCore-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:1e51f315b5b16b340a1a12d4a0f3244f1925f14c9e148ca4dfdcfad6baa7ee5a"}, + {file = "pyobjc_framework_sharedwithyoucore-10.3.1.tar.gz", hash = "sha256:e4768b7fdb18730e225bbebc9c9f9acfa7e44e648875816aff8c7e7f0e82afbf"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-shazamkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ShazamKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ShazamKit-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9641a02efdd4c38c35c8c3e684ff66be2aeec6a786819045e4141ff365bec19f"}, - {file = "pyobjc_framework_ShazamKit-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:997eb038d951b850fea3e26151c0815756ed1ca781a8f5af39c0ae94cbbfea85"}, - {file = "pyobjc_framework_ShazamKit-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b08cf45e30625487fcb1e1e253a1e5dba17f2764549a72f1cb1a71266fd76454"}, - {file = "pyobjc_framework_ShazamKit-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:27e567d8ff3cd103accc72695881ba82ef4ef707b176d06726a3f66052e8fa51"}, - {file = "pyobjc_framework_ShazamKit-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9bc70b8d520a27e6c65f1458d28165e4a0d08dd984367ab1b35e4c1412565d32"}, - {file = "pyobjc_framework_ShazamKit-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:501233d67cd0f7d439b8eea2db740a53238d265a96ecca41bd724959406e54ac"}, - {file = "pyobjc_framework_ShazamKit-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cc0bacb7db45b8f88007c718f0c2685a11455992fa0a2bdc2349d457be3ef953"}, - {file = "pyobjc_framework_shazamkit-10.3.tar.gz", hash = "sha256:89467af0f3d353c6ebc3a53995cc01078a8bcbb6ccbb648aa95b7d480fd2c05f"}, + {file = "pyobjc_framework_ShazamKit-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dac6a729d7fed5e96ac4cb2a7894c79002670b4c06559ef4795dfe8c6fa15dda"}, + {file = "pyobjc_framework_ShazamKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cc77fde1503ec1f96d7b9a05ad784d29d94065732f0cfe089321be423e5045f3"}, + {file = "pyobjc_framework_ShazamKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:012560cab1997c1da6e19388b5192f68dcdf806c2f8d7bd1e66da37512d18b30"}, + {file = "pyobjc_framework_ShazamKit-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4356bdcb9ca50da243b9d79da27851b799483865072f7c86a8a9674300d31819"}, + {file = "pyobjc_framework_ShazamKit-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26dafb6ac23c15d8cdee4c2083757aac29fad4f945b97f120f6351aed5cdab72"}, + {file = "pyobjc_framework_ShazamKit-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:95e4e717cb7a675544e08c53fb86d55715aa5d633b4ec35737fb02293098d368"}, + {file = "pyobjc_framework_ShazamKit-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:808bdfe5dcfc44d4c1df3ae3f384396908e9a1d3832e34408950db522859e91e"}, + {file = "pyobjc_framework_shazamkit-10.3.1.tar.gz", hash = "sha256:deef11a43e773b876df31eeadbfc447892fda0607e314ca2afb2c012284cfa32"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-social" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Social on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Social-10.3-py2.py3-none-any.whl", hash = "sha256:5a8eb2b80857912de19677506f834893c9f22351f1c745f93649d964fa4530de"}, - {file = "pyobjc_framework_social-10.3.tar.gz", hash = "sha256:aa7adeaf0849b311236e6f400a65b10aa910b4e6ff202e7b50c6ca0a46de0e9c"}, + {file = "pyobjc_framework_Social-10.3.1-py2.py3-none-any.whl", hash = "sha256:f83617c07db7c8bd15b3b9e0878ab2b6a286dcbd9a8c7f451da204f75db880e9"}, + {file = "pyobjc_framework_social-10.3.1.tar.gz", hash = "sha256:d1303cf3860ad02a8795c099e17888923505a9c45be407da50721a9a8a5b2efd"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-soundanalysis" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SoundAnalysis on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SoundAnalysis-10.3-py2.py3-none-any.whl", hash = "sha256:06ff451ac1fa977d291417a1e2409ee12d28e65a2b45671e52d30e4692c67115"}, - {file = "pyobjc_framework_soundanalysis-10.3.tar.gz", hash = "sha256:ff540b99f9d70aaea1a2dd72fdb76c397fc8b7545f1f66e160e1dff505d04efd"}, + {file = "pyobjc_framework_SoundAnalysis-10.3.1-py2.py3-none-any.whl", hash = "sha256:ef67207ff4045e5db37f017bdcd07d4b42464c86fe6c3b56524f6f22a9cde216"}, + {file = "pyobjc_framework_soundanalysis-10.3.1.tar.gz", hash = "sha256:faa533644231f99dbdc2fcc3ecb9181c5df4f4dc68d42856729214021c83c881"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-speech" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Speech on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Speech-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5838e6fa05aa8d490ae8b508cf0c70321864ca16c7e996c94b1e65236f3a7b9"}, - {file = "pyobjc_framework_Speech-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1c216a7475ee3d0f9614da518897cc30c6911ae71a80188a8b5fe0dadf9aa162"}, - {file = "pyobjc_framework_Speech-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:3e5f7b9cde46a64e753f99baf2ed4901a325c4e52864459735b86743a1077beb"}, - {file = "pyobjc_framework_speech-10.3.tar.gz", hash = "sha256:c720a06da6e57c04757c34fae8f0f02456f8d266d03c66649688f3a7462838d7"}, + {file = "pyobjc_framework_Speech-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:07afd82d76b98b67a78c07098a814a0b862bcf00fc072d49d8da435202008a18"}, + {file = "pyobjc_framework_Speech-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:444994d062286ff2769e07425d511503b2047b381afad1d64c8517ef4e44d01f"}, + {file = "pyobjc_framework_Speech-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e7fad907f9c0c49c5272f316d20e66ba0415038203ca277381753b035c16061a"}, + {file = "pyobjc_framework_Speech-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:2294b60e1ab59b1340b820e6fee67766a959edd580d73e3b938f15653805d64c"}, + {file = "pyobjc_framework_speech-10.3.1.tar.gz", hash = "sha256:5b77b1d1ced0d1ad7244037b865dda2b83e8f9562d76d1e9fa4fea3b89e437b8"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-spritekit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SpriteKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SpriteKit-10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cebd65a82fbbbf992687a6c117213a105360132e6636563f44130b36e2df5176"}, - {file = "pyobjc_framework_SpriteKit-10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bf3b501d579870c17dda4448bd63bf97004b2856cbcecf72493673dd5888932d"}, - {file = "pyobjc_framework_SpriteKit-10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:409a66c21e966593438feec3c156264fbead7adb7133512fc3626e0db586b95b"}, - {file = "pyobjc_framework_SpriteKit-10.3-cp313-cp313-macosx_10_9_universal2.whl", hash = "sha256:d40e89a90a32f7238b75cc6132df86a1280486e8c9b4b778950609926403cabf"}, - {file = "pyobjc_framework_SpriteKit-10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7da06167a43e6ff6548cb68cdbfe200f73c02bd3670f453c9c9a56218f27ae4e"}, - {file = "pyobjc_framework_SpriteKit-10.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:3da69814e8660671dcb336cf8d2639d6187d249574c8ac833583b4c079fdd925"}, - {file = "pyobjc_framework_SpriteKit-10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:34a60b707588808858e43d12bb24fa0e716d450f3787e6474514273b0d8d16bf"}, - {file = "pyobjc_framework_spritekit-10.3.tar.gz", hash = "sha256:52d5a91b13d222757c05c5c0daea629ecc3afca1df9a2b0bf6d7e5b5b1823919"}, + {file = "pyobjc_framework_SpriteKit-10.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:31a5ce3ba471bf12f3e9ae3b5865d400e4e70ab4bb94317880783ee04c07b1f5"}, + {file = "pyobjc_framework_SpriteKit-10.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:af355eccc18437e0932e1b327817e8f50d194bfa471b65b4733185ba606ab792"}, + {file = "pyobjc_framework_SpriteKit-10.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c3fd6aaecd7abd6ebc83d4c37a22950d55b75911fdb99628b2677f44085a0212"}, + {file = "pyobjc_framework_SpriteKit-10.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a1f0537bc0331cca58cc50307f3b114ab8bfd51576df3038b6037353aa77085f"}, + {file = "pyobjc_framework_SpriteKit-10.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ffe7a07c8a3e17552e73b517b4fdcff7b2e6ca7e89b093a5daccfc285708216c"}, + {file = "pyobjc_framework_SpriteKit-10.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:e1d79aab298f7b42436b2468e37ff84718f1b8b579c1440de7002a55d5f8762e"}, + {file = "pyobjc_framework_SpriteKit-10.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cd08925baf8b3f511842f49fb5512ae56875a923d23254fcc022124788180d47"}, + {file = "pyobjc_framework_spritekit-10.3.1.tar.gz", hash = "sha256:2c11f35f48302f487c51ba8030f5cf79493a9dc0993dd901016ae4b8d8047c8b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-storekit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework StoreKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_StoreKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5ba61f886e6a7709e45640d8caee632e8b0ff43082cfaae62660061701a8186f"}, - {file = "pyobjc_framework_StoreKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e999085df79e16dd7ac2963390dadacfbdcb0c9a57ad6b27a4b24fa25ac945c8"}, - {file = "pyobjc_framework_StoreKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4e716f93d14cb4743e90d7eb759359217602119a97e54b0b4a306e018af40306"}, - {file = "pyobjc_framework_storekit-10.3.tar.gz", hash = "sha256:235996fa6270dc8844d9ca447d10833bc835ce842a9f4c4daf71f2bcefd01b9c"}, + {file = "pyobjc_framework_StoreKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:f9c50a980846b236884504ad42690d49935bda3de5d779fca3cdfb16d43fa8d1"}, + {file = "pyobjc_framework_StoreKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:b3846b249a6fc5d26c80320098858978e0a16f46e98fc998075f16f539ac89fc"}, + {file = "pyobjc_framework_StoreKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c3575facbb3d238b8c9f3054c1422488414d89a42906dbcbfdbb47ef8be3da66"}, + {file = "pyobjc_framework_StoreKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:2b5848f0e08b42dd4dabe5822b436b904a697e923f529ccaad910dfb822b2b9d"}, + {file = "pyobjc_framework_storekit-10.3.1.tar.gz", hash = "sha256:913b4aad7dc31df7d8011c54a695da65cc57819f4b48c98abaed4e6d9ff7d323"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-symbols" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Symbols on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Symbols-10.3-py2.py3-none-any.whl", hash = "sha256:51ea45ea4183359f0954be9276a2a7e739791119e6e90a5f9be00c102f8ae43f"}, - {file = "pyobjc_framework_symbols-10.3.tar.gz", hash = "sha256:04187be130368080ac7eed34d452fad485067cbd1cd001354e931c5ea30b4c1f"}, + {file = "pyobjc_framework_Symbols-10.3.1-py2.py3-none-any.whl", hash = "sha256:6e171da5af2612e186cc4cf896ad7f2672c021a1fc18bc8ef49b79c4c831202d"}, + {file = "pyobjc_framework_symbols-10.3.1.tar.gz", hash = "sha256:3e3f35ef3646b5f9c0653d9dbf5693cf87de3df04420cb2679dad74c75965d18"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-syncservices" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SyncServices on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SyncServices-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:15f3beaac7b1a57222812fe75654b465b99684553631ae02042f864518179a74"}, - {file = "pyobjc_framework_SyncServices-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8ac1da78e4b939bfc74378bc0a57584103d164796467054d7a09db32429a32da"}, - {file = "pyobjc_framework_SyncServices-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6715c4b12953629108f35be0029d7f590718c92060359a28915d5c501106bfb6"}, - {file = "pyobjc_framework_syncservices-10.3.tar.gz", hash = "sha256:90140a0a993d5d4fe60be1b378b72cb0d9285a80819a16226bb611aec0c4013b"}, + {file = "pyobjc_framework_SyncServices-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:aa98a38f59f230da7817dc08055c8049fa961193af16caa262c51e4ec8b5de20"}, + {file = "pyobjc_framework_SyncServices-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:9d3798cc745143d44da101bb0eb9d482326b761f48c3699251191e9c3656ee6c"}, + {file = "pyobjc_framework_SyncServices-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:97020a88d743a6f12ed3f72d062ab96712a7cc0e7b0293c7c5860c014002cc73"}, + {file = "pyobjc_framework_SyncServices-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:b9b7bc58b04654172968cdc1cfe74b43ca0ad2e03c24c7921234a57be2c22985"}, + {file = "pyobjc_framework_syncservices-10.3.1.tar.gz", hash = "sha256:1cd5e3eaf85a11996184afad1da47037cd921e302ccb35fe388b19f91a685669"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreData = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreData = ">=10.3.1" [[package]] name = "pyobjc-framework-systemconfiguration" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SystemConfiguration on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SystemConfiguration-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:5aa695972ed09a8d8284e6b1a8019b8958be826a2db7c24ffb8a9b05f73c34d2"}, - {file = "pyobjc_framework_SystemConfiguration-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e474133579db7f5711f876a2f34e433a152d9f51c5df82886729f284836c6ab4"}, - {file = "pyobjc_framework_SystemConfiguration-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:66946d2d8dfd646d37ff066f53267d7bbfeb0ec82b2fef1622eacd23ade6575a"}, - {file = "pyobjc_framework_systemconfiguration-10.3.tar.gz", hash = "sha256:48f8fd81f02891b5431b77fcf11831aab46b093ea56f35a4695cbb63281bf69c"}, + {file = "pyobjc_framework_SystemConfiguration-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:200c4b7d3483e5ccb86d4d5783ace8c26d4b3f9130684280f30080d53f62d4c5"}, + {file = "pyobjc_framework_SystemConfiguration-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:403392b0e2085cf528547d468bc523fbee418381bb61446eb4aa1f9a1c8a8494"}, + {file = "pyobjc_framework_SystemConfiguration-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f38a824261a30dc9961e13a7b9759dd0c77e1c7c4681e3c80c5751c560735289"}, + {file = "pyobjc_framework_SystemConfiguration-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4e8816524cbb6c6ea9e1c596fc9a16c91f2063eba394135be9437bdbd469e125"}, + {file = "pyobjc_framework_systemconfiguration-10.3.1.tar.gz", hash = "sha256:1bf6ffe98faa4e208bf594c857ba23cd56fe404bc579188ff53b704844d9c402"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-systemextensions" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework SystemExtensions on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_SystemExtensions-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:39275100899586ce856b57120bef7582e3e16b33aa8a23d0066881fa2bba37ab"}, - {file = "pyobjc_framework_SystemExtensions-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e50596f8afd14c6f00faac499b1d4904f37fcd48df94e6fbf4a73a920559e20f"}, - {file = "pyobjc_framework_SystemExtensions-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:76b6534e61a19c12ef64a9edf6dde634e29be14e657fb0e63cd28e51fcca99cb"}, - {file = "pyobjc_framework_systemextensions-10.3.tar.gz", hash = "sha256:5811fdbfb1c14f1db288455038bef0c8c61c1266e3b61da4f5cfb2bb6adf0333"}, + {file = "pyobjc_framework_SystemExtensions-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:b24edd33c71cb02a16bdd9b26d3a229a6b2a815c26a4c908b1b8b6cdf4f6c84a"}, + {file = "pyobjc_framework_SystemExtensions-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:e2a24501a782d2b6f7fa339619eb5c988db6b31a6043d029f40f67c54fd9399e"}, + {file = "pyobjc_framework_SystemExtensions-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1cacd2356142307cf221d568f3e7adda654c28c90c223db3830746f4c2b12aea"}, + {file = "pyobjc_framework_SystemExtensions-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6561876b2fd5c40620073fae9b924f2d8e0110e8573756ffc9521e4fbc825249"}, + {file = "pyobjc_framework_systemextensions-10.3.1.tar.gz", hash = "sha256:34412e75c95a585d222ea23efc3eba436210ec0345cec6c7dc78d16e027d03e1"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-threadnetwork" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework ThreadNetwork on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_ThreadNetwork-10.3-py2.py3-none-any.whl", hash = "sha256:84b50c566bcde4d607b0e92fad21b64102032056281ecb83a1ad80acde74aa19"}, - {file = "pyobjc_framework_threadnetwork-10.3.tar.gz", hash = "sha256:d8d1cb19d1426cbc4a531bb047551ff819d57c7c54777d27c4de959b6dbac234"}, + {file = "pyobjc_framework_ThreadNetwork-10.3.1-py2.py3-none-any.whl", hash = "sha256:95ddbed8a114cc1f05db613bb53247465ec48ccaad2b56f5da466317808fc32b"}, + {file = "pyobjc_framework_threadnetwork-10.3.1.tar.gz", hash = "sha256:1038210a8e5dfa86aefd10894563913e767e95d1c1bd4333ae5f9c6cabbb3ce9"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-uniformtypeidentifiers" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework UniformTypeIdentifiers on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_UniformTypeIdentifiers-10.3-py2.py3-none-any.whl", hash = "sha256:2219841495944ba998c3241f7c5b1f0642b1110c46a2731cad42e8d0e203c099"}, - {file = "pyobjc_framework_uniformtypeidentifiers-10.3.tar.gz", hash = "sha256:ec16633648537d2d8017e1151fedb37c344c5f1922bc8b3097616d0b3e3437f1"}, + {file = "pyobjc_framework_UniformTypeIdentifiers-10.3.1-py2.py3-none-any.whl", hash = "sha256:8bd1516ccec1807e2ad92a071242d83e9d1eda08ddbfae04dacc30d76c3d734c"}, + {file = "pyobjc_framework_uniformtypeidentifiers-10.3.1.tar.gz", hash = "sha256:1985fee7e1f1157db36f3c19ee0ad273677eeff10467f575086246bbeffcdf50"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-usernotifications" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework UserNotifications on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_UserNotifications-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:c9a7e745828e3c6df44ebdaea3092ddc3c56f638130e5a0f47a2e0ae3ea405fb"}, - {file = "pyobjc_framework_UserNotifications-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e5bf6e386243eb7ad518b9ba102471713ed5b0bd05ea8a3f62478a7201754e37"}, - {file = "pyobjc_framework_UserNotifications-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:e6ff9ca6de68b7635f111da623c68b533bd78fcf90ae620cfc23825bfc75ec4a"}, - {file = "pyobjc_framework_usernotifications-10.3.tar.gz", hash = "sha256:2e2172f3ca50e083ea6b20f18efb0c23c174cb6be19f91252ab770f51f5e3b06"}, + {file = "pyobjc_framework_UserNotifications-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:d85c293e0520530ac7152b3f293c5606f0495b7727de331ef4e198278bf40e98"}, + {file = "pyobjc_framework_UserNotifications-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:0001bb25f15e6f8cac81bcb58cab8161a15a6fe41f6c475e8da364c913bdb090"}, + {file = "pyobjc_framework_UserNotifications-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0bba49b0f290f5597b94a80608c785b61d61aa3885cdf05529862e47fe1cec67"}, + {file = "pyobjc_framework_UserNotifications-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:59294fa6110778de145c9299c220990d057a6a171d37ab5d8a6ab1780bf7888f"}, + {file = "pyobjc_framework_usernotifications-10.3.1.tar.gz", hash = "sha256:ddb5de88fb659c2241429b6408ddcabbfc0c2c9e4a7f5f543a6fab1c4953403b"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-usernotificationsui" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework UserNotificationsUI on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_UserNotificationsUI-10.3-py2.py3-none-any.whl", hash = "sha256:f809685da10d3eb1b0e659870df7584de79f228d8b49f00167d2a694249ead55"}, - {file = "pyobjc_framework_usernotificationsui-10.3.tar.gz", hash = "sha256:0a843e3dad58650c595097e25cf2ca234216920abb8f92dfbd96822ca3afbb88"}, + {file = "pyobjc_framework_UserNotificationsUI-10.3.1-py2.py3-none-any.whl", hash = "sha256:bc6cb92a6ac947e8fe9685f3c1964c5a9f98e576b936b0bbff8c528f47f976d2"}, + {file = "pyobjc_framework_usernotificationsui-10.3.1.tar.gz", hash = "sha256:80390b5361bb6014dc32d0afbf581280e7762a4f67460a736f461f613d397094"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-UserNotifications = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-UserNotifications = ">=10.3.1" [[package]] name = "pyobjc-framework-videosubscriberaccount" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework VideoSubscriberAccount on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_VideoSubscriberAccount-10.3-py2.py3-none-any.whl", hash = "sha256:0519c0eaec8aabb9d89e6bf1ab968e59ae3434365a0c98e4eeb3c8837a712d76"}, - {file = "pyobjc_framework_videosubscriberaccount-10.3.tar.gz", hash = "sha256:c65a74c087b354b3d73fba2be2396985e9d51bbe5fc42c00acdb4cd3d78aa0ba"}, + {file = "pyobjc_framework_VideoSubscriberAccount-10.3.1-py2.py3-none-any.whl", hash = "sha256:4b489f0007dce8ea17f37316175dac2768cd173a4d4c7a1d5f87fb3991c1e518"}, + {file = "pyobjc_framework_videosubscriberaccount-10.3.1.tar.gz", hash = "sha256:f62509e976b805bc76ff5928444677ac542b52dd9f7781ac0731d7c4b22bed96"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-videotoolbox" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework VideoToolbox on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_VideoToolbox-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e34b41b5816101414e3089b1a770e0bf8831acd62755945a625f7917a49c1bd"}, - {file = "pyobjc_framework_VideoToolbox-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cb5d91a6fc213ad853eeea410289cb5f6e87e7a8c4df2c6e0bb5e9c977b9b010"}, - {file = "pyobjc_framework_VideoToolbox-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:df7047d9f077690fa4f82f33cf82b740c418ebfdb03ac6dcf36e7786ffe6718f"}, - {file = "pyobjc_framework_videotoolbox-10.3.tar.gz", hash = "sha256:801d1140de6acaa62e249fd50e2852c307b3ad461288c348f81c623704138519"}, + {file = "pyobjc_framework_VideoToolbox-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:bc52aa91f568060e0087762f2a4d876bf7b683e5396779e93925252e26f0330b"}, + {file = "pyobjc_framework_VideoToolbox-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:3d20ea92b597f4758f24ed8e19f7a7a372faf6478d739e7cb7f7cd73d3e8617a"}, + {file = "pyobjc_framework_VideoToolbox-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:761e3cd05090f5d9e9fbae2c25e3f352f19aa86a0d02a1189b94ec5c4bc37111"}, + {file = "pyobjc_framework_VideoToolbox-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:7d4fb38f95e91f62d14b05fafcc6197775e9eaf4e5b698bc1fb313756f59b10d"}, + {file = "pyobjc_framework_videotoolbox-10.3.1.tar.gz", hash = "sha256:7ebc281523b2b37aff17ce6eabd0c81081864b3e3e4a83ae72b18fd70c57c521"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreMedia = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreMedia = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-virtualization" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Virtualization on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Virtualization-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca9b15238573459bde886b3d1930a75904f447ee033032c004582b19141b751d"}, - {file = "pyobjc_framework_Virtualization-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6113d9e10f671ea43ac07fdfe91e16f41bdc06fccfd1f8b9ce014ab4e7a08335"}, - {file = "pyobjc_framework_Virtualization-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:f60f3f22cb5d832429fc072368911f6989fc5e66fc164fe0e15b66102e8da7c6"}, - {file = "pyobjc_framework_virtualization-10.3.tar.gz", hash = "sha256:eb40b50a05d8fd574c1cd4265dbe5a6fd19dddd223ae37a22c27279bffc56de3"}, + {file = "pyobjc_framework_Virtualization-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:c046abcebf6a64a47ea50311f3e4aaae424dbac719e847cd15b375ebe99a51ed"}, + {file = "pyobjc_framework_Virtualization-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:dc14f6c3deaf367adff18b509e766dc78c4695a4cd76e4aad3ff4b1e207a4635"}, + {file = "pyobjc_framework_Virtualization-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:bd79c1bb45113957f24cbf8b6d0ff175361c52c97e326313ecd76cfa015f6cef"}, + {file = "pyobjc_framework_Virtualization-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:6e5e6645e31acd07d30b1607c4cdaf0ae0e4d8223471a8a089004c2deb6fdea5"}, + {file = "pyobjc_framework_virtualization-10.3.1.tar.gz", hash = "sha256:8348ddef18eb943d151e5b5977e4d410012ee2e3f6048c16f7cfe0c1a73536cb"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyobjc-framework-vision" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework Vision on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_Vision-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:d89b51e4732ae90ae5640fe68b018d4dbdfd200bc2705663c1e590d1dd8a7863"}, - {file = "pyobjc_framework_Vision-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:22cbb17f3a6b76133357ab427bcf553cb604d2720a80a9b27c0a42f6c2a7138a"}, - {file = "pyobjc_framework_Vision-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:bcb1e04a7248d57bce443ecaec0660e14d2eb635a2deff43d8c03867a3df21c3"}, - {file = "pyobjc_framework_vision-10.3.tar.gz", hash = "sha256:fe82dfbc120d04dbe8771d576f5210dcdb5b981feac7e75fcc2384ab8ffa31eb"}, + {file = "pyobjc_framework_Vision-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:dff3582678930461a0bb11bf070854d49f6944a851dc89edc63fac93c75ddf39"}, + {file = "pyobjc_framework_Vision-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:32626183c51674efb3b5738e2884c3fea37edca010117cf71bd72cb3c49c869a"}, + {file = "pyobjc_framework_Vision-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2473b346a112c51ac485184305bd13c402e0db45f2df3d277315bd49efba18e9"}, + {file = "pyobjc_framework_Vision-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:4302e2c5f68c9667ecd4273809cbc4611af6368b123d69596e5b088f1b1aa16b"}, + {file = "pyobjc_framework_vision-10.3.1.tar.gz", hash = "sha256:aa071656d395afc2d624600a9f30d6a3344aa747bf37f613ff3972158c40881c"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" -pyobjc-framework-CoreML = ">=10.3" -pyobjc-framework-Quartz = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" +pyobjc-framework-CoreML = ">=10.3.1" +pyobjc-framework-Quartz = ">=10.3.1" [[package]] name = "pyobjc-framework-webkit" -version = "10.3" +version = "10.3.1" description = "Wrappers for the framework WebKit on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc_framework_WebKit-10.3-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2f66212dffcf419a7b8a462fca22f76d7a2d534b4deb15a499d38e026f005985"}, - {file = "pyobjc_framework_WebKit-10.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d6d1174d63b6d9ea3247761431812ce30722fbdac93443d6563b4ea45a3323d"}, - {file = "pyobjc_framework_WebKit-10.3-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:ca76f5c17f559c59338cd55342d6bd9d2f24f536c64095383b55802b6639d648"}, - {file = "pyobjc_framework_webkit-10.3.tar.gz", hash = "sha256:600a0033bf42114795b032c23139c0679aad236cb964961130ba3cd96da026ff"}, + {file = "pyobjc_framework_WebKit-10.3.1-cp36-abi3-macosx_10_13_universal2.whl", hash = "sha256:df52913e4c3cb77d4551d9848e30be01b82cace54cede850c88a7e0ab41a20a9"}, + {file = "pyobjc_framework_WebKit-10.3.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:207a7aa57817d3ab3fa033e42ab612f8c00521f13ff2871547c92cd94ed51f85"}, + {file = "pyobjc_framework_WebKit-10.3.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c0d4c1ba0fafae503a8df95e7b6bd4236951ba72508ec62809e37825f382c635"}, + {file = "pyobjc_framework_WebKit-10.3.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:c8e3334978a1bd927ea14ed73f56d6741561a69d31d082d2b23d1b48446917c8"}, + {file = "pyobjc_framework_webkit-10.3.1.tar.gz", hash = "sha256:7ad9f4eb91a6dff39848d9c2ab71f170aeab4b6396bcec8e5a780739f9be4222"}, ] [package.dependencies] -pyobjc-core = ">=10.3" -pyobjc-framework-Cocoa = ">=10.3" +pyobjc-core = ">=10.3.1" +pyobjc-framework-Cocoa = ">=10.3.1" [[package]] name = "pyopencl" @@ -8047,5 +8113,5 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" -python-versions = "~3.11" -content-hash = "8f581b34273378265dba62166f3cd5abbb931b9375d95fb260dcaf192cfacc86" +python-versions = ">=3.11, <3.13" +content-hash = "c5654418f3c97420a4a2195b42ebfec250623b600658aae03385b2bcf4c058bd" diff --git a/pyproject.toml b/pyproject.toml index 01885c7ac..6e4741dda 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,7 @@ repository = "https://github.com/commaai/openpilot" documentation = "https://docs.comma.ai" [tool.poetry.dependencies] -python = "~3.11" +python = ">=3.11, <3.13" # multiple users sounddevice = "*" # micd + soundd @@ -154,15 +154,14 @@ inputs = "*" Jinja2 = "*" lru-dict = "*" matplotlib = "*" -# No release for this fix https://github.com/metadriverse/metadrive/issues/632. Pinned to this commit until next release -metadrive-simulator = {git = "https://github.com/metadriverse/metadrive.git", rev ="233a3a1698be7038ec3dd050ca10b547b4b3324c", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies +metadrive-simulator = { git = "https://github.com/commaai/metadrive.git", branch = "python3.12", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies mpld3 = "*" mypy = "*" myst-parser = "*" natsort = "*" opencv-python-headless = "*" parameterized = "^0.8" -pprofile = "*" +#pprofile = "*" polyline = "*" pre-commit = "*" pyautogui = "*" diff --git a/selfdrive/test/test_updated.py b/selfdrive/test/test_updated.py index f8eae9482..ea945d94c 100644 --- a/selfdrive/test/test_updated.py +++ b/selfdrive/test/test_updated.py @@ -164,7 +164,7 @@ class TestUpdated: # make sure LastUpdateTime is recent t = self._read_param("LastUpdateTime") last_update_time = datetime.datetime.fromisoformat(t) - td = datetime.datetime.utcnow() - last_update_time + td = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_update_time assert td.total_seconds() < 10 self.params.remove("LastUpdateTime") diff --git a/system/athena/registration.py b/system/athena/registration.py index 6574d9ac2..97289e419 100755 --- a/system/athena/registration.py +++ b/system/athena/registration.py @@ -4,7 +4,7 @@ import json import jwt from pathlib import Path -from datetime import datetime, timedelta +from datetime import datetime, timedelta, UTC from openpilot.common.api import api_get from openpilot.common.params import Params from openpilot.common.spinner import Spinner @@ -66,7 +66,7 @@ def register(show_spinner=False) -> str | None: start_time = time.monotonic() while True: try: - register_token = jwt.encode({'register': True, 'exp': datetime.utcnow() + timedelta(hours=1)}, private_key, algorithm='RS256') + register_token = jwt.encode({'register': True, 'exp': datetime.now(UTC).replace(tzinfo=None) + timedelta(hours=1)}, private_key, algorithm='RS256') cloudlog.info("getting pilotauth") resp = api_get("v2/pilotauth/", method='POST', timeout=15, imei=imei1, imei2=imei2, serial=serial, public_key=public_key, register_token=register_token) diff --git a/system/manager/manager.py b/system/manager/manager.py index 6d1b8d9c2..2a173ac90 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -42,7 +42,7 @@ def manager_init() -> None: ("LongitudinalPersonality", str(log.LongitudinalPersonality.standard)), ] if not PC: - default_params.append(("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8'))) + default_params.append(("LastUpdateTime", datetime.datetime.now(datetime.UTC).replace(tzinfo=None).isoformat().encode('utf8'))) if params.get_bool("RecordFrontLock"): params.put_bool("RecordFront", True) diff --git a/system/qcomgpsd/qcomgpsd.py b/system/qcomgpsd/qcomgpsd.py index 21c7995a7..43ddb8993 100755 --- a/system/qcomgpsd/qcomgpsd.py +++ b/system/qcomgpsd/qcomgpsd.py @@ -173,7 +173,7 @@ def setup_quectel(diag: ModemDiag) -> bool: os.remove(ASSIST_DATA_FILE) #at_cmd("AT+QGPSXTRADATA?") if system_time_valid(): - time_str = datetime.datetime.utcnow().strftime("%Y/%m/%d,%H:%M:%S") + time_str = datetime.datetime.now(datetime.UTC).replace(tzinfo=None).strftime("%Y/%m/%d,%H:%M:%S") at_cmd(f"AT+QGPSXTRATIME=0,\"{time_str}\",1,1,1000") at_cmd("AT+QGPSCFG=\"outport\",\"usbnmea\"") diff --git a/system/qcomgpsd/tests/test_qcomgpsd.py b/system/qcomgpsd/tests/test_qcomgpsd.py index ef23737dd..716bc33ed 100644 --- a/system/qcomgpsd/tests/test_qcomgpsd.py +++ b/system/qcomgpsd/tests/test_qcomgpsd.py @@ -85,7 +85,7 @@ class TestRawgpsd: if should_be_loaded: assert valid_duration == "10080" # should be max time injected_time = datetime.datetime.strptime(injected_time_str.replace("\"", ""), "%Y/%m/%d,%H:%M:%S") - assert abs((datetime.datetime.utcnow() - injected_time).total_seconds()) < 60*60*12 + assert abs((datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - injected_time).total_seconds()) < 60*60*12 else: valid_duration, injected_time_str = out.split(",", 1) injected_time_str = injected_time_str.replace('\"', '').replace('\'', '') diff --git a/system/statsd.py b/system/statsd.py index 2b5a7bb3a..5e76b73ae 100755 --- a/system/statsd.py +++ b/system/statsd.py @@ -133,7 +133,7 @@ def main() -> NoReturn: # flush when started state changes or after FLUSH_TIME_S if (time.monotonic() > last_flush_time + STATS_FLUSH_TIME_S) or (sm['deviceState'].started != started_prev): result = "" - current_time = datetime.utcnow().replace(tzinfo=UTC) + current_time = datetime.now(UTC) tags['started'] = sm['deviceState'].started for key, value in gauges.items(): diff --git a/system/ubloxd/pigeond.py b/system/ubloxd/pigeond.py index 5711992cf..8809689dc 100755 --- a/system/ubloxd/pigeond.py +++ b/system/ubloxd/pigeond.py @@ -6,7 +6,7 @@ import serial import struct import requests import urllib.parse -from datetime import datetime +from datetime import datetime, UTC from cereal import messaging from openpilot.common.params import Params @@ -196,7 +196,7 @@ def initialize_pigeon(pigeon: TTYPigeon) -> bool: cloudlog.error(f"failed to restore almanac backup, status: {restore_status}") # sending time to ublox - t_now = datetime.utcnow() + t_now = datetime.now(UTC).replace(tzinfo=None) if t_now >= datetime(2021, 6, 1): cloudlog.warning("Sending current time to ublox") diff --git a/system/updated/updated.py b/system/updated/updated.py index d43f439af..005c52bc8 100755 --- a/system/updated/updated.py +++ b/system/updated/updated.py @@ -60,7 +60,7 @@ class WaitTimeHelper: self.ready_event.wait(timeout=t) def write_time_to_param(params, param) -> None: - t = datetime.datetime.utcnow() + t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) params.put(param, t.isoformat().encode('utf8')) def read_time_from_param(params, param) -> datetime.datetime | None: @@ -279,7 +279,7 @@ class Updater: if len(self.branches): self.params.put("UpdaterAvailableBranches", ','.join(self.branches.keys())) - last_update = datetime.datetime.utcnow() + last_update = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) if update_success: write_time_to_param(self.params, "LastUpdateTime") else: @@ -323,7 +323,7 @@ class Updater: for alert in ("Offroad_UpdateFailed", "Offroad_ConnectivityNeeded", "Offroad_ConnectivityNeededPrompt"): set_offroad_alert(alert, False) - now = datetime.datetime.utcnow() + now = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) dt = now - last_update build_metadata = get_build_metadata() if failed_count > 15 and exception is not None and self.has_internet: @@ -429,7 +429,7 @@ def main() -> None: cloudlog.event("update installed") if not params.get("InstallDate"): - t = datetime.datetime.utcnow().isoformat() + t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None).isoformat() params.put("InstallDate", t.encode('utf8')) updater = Updater() @@ -469,7 +469,7 @@ def main() -> None: # download update last_fetch = read_time_from_param(params, "UpdaterLastFetchTime") - timed_out = last_fetch is None or (datetime.datetime.utcnow() - last_fetch > datetime.timedelta(days=3)) + timed_out = last_fetch is None or (datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_fetch > datetime.timedelta(days=3)) user_requested_fetch = wait_helper.user_request == UserRequest.FETCH if params.get_bool("NetworkMetered") and not timed_out and not user_requested_fetch: cloudlog.info("skipping fetch, connection metered") diff --git a/system/webrtc/tests/test_stream_session.py b/system/webrtc/tests/test_stream_session.py index e89e42e44..46d55ecd9 100644 --- a/system/webrtc/tests/test_stream_session.py +++ b/system/webrtc/tests/test_stream_session.py @@ -3,6 +3,7 @@ import json # for aiortc and its dependencies import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) +warnings.filterwarnings("ignore", category=RuntimeWarning) # TODO: remove this when google-crc32c publish a python3.12 wheel from aiortc import RTCDataChannel from aiortc.mediastreams import VIDEO_CLOCK_RATE, VIDEO_TIME_BASE diff --git a/system/webrtc/tests/test_webrtcd.py b/system/webrtc/tests/test_webrtcd.py index d4b659a3a..4fa6d8953 100644 --- a/system/webrtc/tests/test_webrtcd.py +++ b/system/webrtc/tests/test_webrtcd.py @@ -4,6 +4,7 @@ import json # for aiortc and its dependencies import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) +warnings.filterwarnings("ignore", category=RuntimeWarning) # TODO: remove this when google-crc32c publish a python3.12 wheel from openpilot.system.webrtc.webrtcd import get_stream diff --git a/system/webrtc/webrtcd.py b/system/webrtc/webrtcd.py index afd346857..79c5b4888 100755 --- a/system/webrtc/webrtcd.py +++ b/system/webrtc/webrtcd.py @@ -11,6 +11,7 @@ from typing import Any, TYPE_CHECKING # aiortc and its dependencies have lots of internal warnings :( import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) +warnings.filterwarnings("ignore", category=RuntimeWarning) # TODO: remove this when google-crc32c publish a python3.12 wheel import capnp from aiohttp import web diff --git a/tools/lib/azure_container.py b/tools/lib/azure_container.py index f5a3a8bfb..a5d650e98 100644 --- a/tools/lib/azure_container.py +++ b/tools/lib/azure_container.py @@ -1,5 +1,5 @@ import os -from datetime import datetime, timedelta +from datetime import datetime, timedelta, UTC from functools import lru_cache from pathlib import Path from typing import IO @@ -20,7 +20,7 @@ def get_azure_credential(): @lru_cache def get_container_sas(account_name: str, container_name: str): from azure.storage.blob import BlobServiceClient, ContainerSasPermissions, generate_container_sas - start_time = datetime.utcnow() + start_time = datetime.now(UTC).replace(tzinfo=None) expiry_time = start_time + timedelta(hours=1) blob_service = BlobServiceClient( account_url=f"https://{account_name}.blob.core.windows.net", From c9475ed2f2c2687edc957af8a50d271e043a0bb6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 11 Jun 2024 14:47:39 -0700 Subject: [PATCH 211/220] release checklist (#32709) --- release/README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 release/README.md diff --git a/release/README.md b/release/README.md new file mode 100644 index 000000000..1d3e78493 --- /dev/null +++ b/release/README.md @@ -0,0 +1,36 @@ +# openpilot releases + +## release checklist + +**Go to `devel-staging`** +- [ ] update `devel-staging`: `git reset --hard origin/master-ci` +- [ ] open a pull request from `devel-staging` to `devel` + +**Go to `devel`** +- [ ] update RELEASES.md +- [ ] close out milestone +- [ ] post on Discord dev channel +- [ ] bump version on master: `common/version.h` and `RELEASES.md` +- [ ] merge the pull request + +tests: +- [ ] update from previous release -> new release +- [ ] update from new release -> previous release +- [ ] fresh install with `openpilot-test.comma.ai` +- [ ] drive on fresh install +- [ ] comma body test +- [ ] no submodules or LFS +- [ ] check sentry, MTBF, etc. + +**Go to `release3`** +- [ ] publish the blog post +- [ ] `git reset --hard origin/release3-staging` +- [ ] tag the release +``` +git tag v0.X.X +git push origin v0.X.X +``` +- [ ] create GitHub release +- [ ] final test install on `openpilot.comma.ai` +- [ ] update production +- [ ] Post on Discord, X, etc. From df87ce3709cad7bfa392973c8eee2114d63c6a92 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 11 Jun 2024 14:57:47 -0700 Subject: [PATCH 212/220] add Ford and Volkswagen fuzzy fingerprinting --- RELEASES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASES.md b/RELEASES.md index 18c011e11..21cf208ce 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -11,6 +11,7 @@ Version 0.9.7 (2024-06-13) * Adjust driving personality with the follow distance button * Support for hybrid variants of supported Ford models * Fingerprinting without the OBD-II port on all cars +* Improved fuzzy fingerprinting for Ford and Volkswagen Version 0.9.6 (2024-02-27) ======================== From 0e39d5bcf267b9db53f6e363356d17ca79662210 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Tue, 11 Jun 2024 15:55:18 -0700 Subject: [PATCH 213/220] DM model notes --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 21cf208ce..57f697911 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -8,6 +8,8 @@ Version 0.9.7 (2024-06-13) * Inputs the past curvature for smoother and more accurate lateral control * Simplified neural network architecture in the model's last layers * Minor fixes to desire augmentation and weight decay +* New driver monitoring model + * Improved end-to-end bit for phone detection * Adjust driving personality with the follow distance button * Support for hybrid variants of supported Ford models * Fingerprinting without the OBD-II port on all cars From 188843533f620b8d80c5c21afd17b92224ec112e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 11 Jun 2024 16:14:24 -0700 Subject: [PATCH 214/220] bump msgq: fix body web streaming (#32713) * bump msgq: fix body web streaming * bump msgq --- msgq_repo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgq_repo b/msgq_repo index 381fc3d9d..74074d650 160000 --- a/msgq_repo +++ b/msgq_repo @@ -1 +1 @@ -Subproject commit 381fc3d9dfe7d2ff40a075ff8c1f980ae2a62d19 +Subproject commit 74074d650f5d516a33962c1681a2a15b1d603537 From 05669df1027fbb296884772b15876aff1191f61e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 11 Jun 2024 16:17:25 -0700 Subject: [PATCH 215/220] Update cereal README.md --- cereal/README.md | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/cereal/README.md b/cereal/README.md index e3326aab0..ad940facd 100644 --- a/cereal/README.md +++ b/cereal/README.md @@ -1,11 +1,6 @@ -# What is cereal? [![cereal tests](https://github.com/commaai/cereal/workflows/tests/badge.svg?event=push)](https://github.com/commaai/cereal/actions) [![codecov](https://codecov.io/gh/commaai/cereal/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/cereal) +# What is cereal? -cereal is both a messaging spec for robotics systems as well as generic high performance IPC pub sub messaging with a single publisher and multiple subscribers. - -Imagine this use case: -* A sensor process reads gyro measurements directly from an IMU and publishes a `sensorEvents` packet -* A calibration process subscribes to the `sensorEvents` packet to use the IMU -* A localization process subscribes to the `sensorEvents` packet to use the IMU also +cereal is the messaging system for openpilot. It uses [msgq](https://github.com/commaai/msgq) as a pub/sub backend, and [Cap'n proto](https://capnproto.org/capnp-tool.html) for serialization of the structs. ## Messaging Spec @@ -32,11 +27,7 @@ Forks of [openpilot](https://github.com/commaai/openpilot) might want to add thi spec, however this could conflict with future changes made in mainline cereal/openpilot. Rebasing against mainline openpilot then means breaking backwards-compatibility with all old logs of your fork. So we added reserved events in [custom.capnp](custom.capnp) that we will leave empty in mainline cereal/openpilot. **If you only modify those, you can ensure your -fork will remain backwards-compatible with all versions of mainline cereal/openpilot and your fork.** - -## Pub Sub Backends - -cereal supports two backends, one based on [zmq](https://zeromq.org/) and another called [msgq](messaging/msgq.cc), a custom pub sub based on shared memory that doesn't require the bytes to pass through the kernel. +fork will remain backwards-compatible with all versions of mainline openpilot and your fork.** Example --- From ddfb31f1bfa241aee1c250f5da5f2d364c51f610 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 11 Jun 2024 16:25:24 -0700 Subject: [PATCH 216/220] remove .python-version (#32714) * remove .python-version * no cp --- .python-version | 1 - Dockerfile.openpilot_base | 2 +- tools/install_python_dependencies.sh | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 .python-version diff --git a/.python-version b/.python-version deleted file mode 100644 index 455808f8e..000000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12.4 diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index 6818195d7..45b29bdcb 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -68,7 +68,7 @@ ENV PYENV_VERSION=3.12.4 ENV PYENV_ROOT="/home/$USER/pyenv" ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" -COPY --chown=$USER pyproject.toml poetry.lock .python-version /tmp/ +COPY --chown=$USER pyproject.toml poetry.lock /tmp/ COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/ RUN cd /tmp && \ diff --git a/tools/install_python_dependencies.sh b/tools/install_python_dependencies.sh index df815b582..af25ec642 100755 --- a/tools/install_python_dependencies.sh +++ b/tools/install_python_dependencies.sh @@ -41,7 +41,7 @@ fi export MAKEFLAGS="-j$(nproc)" -PYENV_PYTHON_VERSION=$(cat $ROOT/.python-version) +PYENV_PYTHON_VERSION="3.12.4" if ! pyenv prefix ${PYENV_PYTHON_VERSION} &> /dev/null; then # no pyenv update on mac if [ "$(uname)" == "Linux" ]; then From 0bdab824231a9ba3069777791e7dff76cfce838e Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Tue, 11 Jun 2024 17:27:47 -0700 Subject: [PATCH 217/220] Remove aarch64 ci test (#32715) * remove aarch64 * comment + remove test --- .github/workflows/selfdrive_tests.yaml | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 417fe2044..35bab255c 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -69,11 +69,8 @@ jobs: build: strategy: matrix: - arch: ${{ fromJson( - ((github.repository == 'commaai/openpilot') && - ((github.event_name != 'pull_request') || - (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && '["x86_64", "aarch64"]' || '["x86_64"]' ) }} - runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-latest' }} + arch: ${{ fromJson('["x86_64"]') }} # TODO: Re-add build test for aarch64 once we switched to ubuntu-2404 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: @@ -90,23 +87,6 @@ jobs: - uses: ./.github/workflows/compile-openpilot timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache - docker_push_multiarch: - name: docker push multiarch tag - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' - needs: [build] - steps: - - uses: actions/checkout@v4 - with: - submodules: false - - name: Setup docker - run: | - $DOCKER_LOGIN - - name: Merge x64 and arm64 tags - run: | - export PUSH_IMAGE=true - scripts/retry.sh selfdrive/test/docker_tag_multiarch.sh base x86_64 aarch64 - static_analysis: name: static analysis runs-on: ${{ ((github.repository == 'commaai/openpilot') && From 684209e077d77da0c3a12e8fda528649c5fe9edc Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 11 Jun 2024 21:31:10 -0700 Subject: [PATCH 218/220] remove uiPlan (#32721) * remove uiPlan from ui * remove publishing * Update log.capnp * Update services.py * no uiPlan here * Update ref_commit --- cereal/log.capnp | 2 +- cereal/services.py | 1 - selfdrive/controls/plannerd.py | 14 ++------------ .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/ui/qt/onroad/annotated_camera.cc | 5 ++--- selfdrive/ui/ui.cc | 19 +++++++------------ selfdrive/ui/ui.h | 3 +-- 8 files changed, 15 insertions(+), 33 deletions(-) diff --git a/cereal/log.capnp b/cereal/log.capnp index 36ca692dc..67c6f836a 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -2244,7 +2244,6 @@ struct Event { carControl @23 :Car.CarControl; carOutput @127 :Car.CarOutput; longitudinalPlan @24 :LongitudinalPlan; - uiPlan @106 :UiPlan; ubloxGnss @34 :UbloxGnss; ubloxRaw @39 :Data; qcomGnss @31 :QcomGnss; @@ -2365,5 +2364,6 @@ struct Event { sensorEventsDEPRECATED @11 :List(SensorEventData); lateralPlanDEPRECATED @64 :LateralPlan; navModelDEPRECATED @104 :NavModelData; + uiPlanDEPRECATED @106 :UiPlan; } } diff --git a/cereal/services.py b/cereal/services.py index 2ab28f6d5..ca9139c43 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -66,7 +66,6 @@ _services: dict[str, tuple] = { "navInstruction": (True, 1., 10), "navRoute": (True, 0.), "navThumbnail": (True, 0.), - "uiPlan": (True, 20., 40.), "qRoadEncodeIdx": (False, 20.), "userFlag": (True, 0., 1), "microphone": (True, 10., 10), diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index eeeeda050..681518be1 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -6,16 +6,6 @@ from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner import cereal.messaging as messaging -def publish_ui_plan(sm, pm, longitudinal_planner): - ui_send = messaging.new_message('uiPlan') - ui_send.valid = sm.all_checks(service_list=['carState', 'controlsState', 'modelV2']) - uiPlan = ui_send.uiPlan - uiPlan.frameId = sm['modelV2'].frameId - uiPlan.position.x = list(sm['modelV2'].position.x) - uiPlan.position.y = list(sm['modelV2'].position.y) - uiPlan.position.z = list(sm['modelV2'].position.z) - uiPlan.accel = longitudinal_planner.a_desired_trajectory_full.tolist() - pm.send('uiPlan', ui_send) def plannerd_thread(): config_realtime_process(5, Priority.CTRL_LOW) @@ -27,7 +17,7 @@ def plannerd_thread(): cloudlog.info("plannerd got CarParams: %s", CP.carName) longitudinal_planner = LongitudinalPlanner(CP) - pm = messaging.PubMaster(['longitudinalPlan', 'uiPlan']) + pm = messaging.PubMaster(['longitudinalPlan']) sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'radarState', 'modelV2'], poll='modelV2', ignore_avg_freq=['radarState']) @@ -36,7 +26,7 @@ def plannerd_thread(): if sm.updated['modelV2']: longitudinal_planner.update(sm) longitudinal_planner.publish(sm, pm) - publish_ui_plan(sm, pm, longitudinal_planner) + def main(): plannerd_thread() diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 739efcb98..a55396002 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -505,7 +505,7 @@ CONFIGS = [ ProcessConfig( proc_name="plannerd", pubs=["modelV2", "carControl", "carState", "controlsState", "radarState"], - subs=["longitudinalPlan", "uiPlan"], + subs=["longitudinalPlan"], ignore=["logMonoTime", "longitudinalPlan.processingDelay", "longitudinalPlan.solverExecutionTime"], init_callback=get_car_params_callback, should_recv_callback=FrequencyBasedRcvCallback("modelV2"), diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index eaf61ccb8..227202839 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -0ba779ec9f624872b1d038acb15095b726ff8983 +6438bd5edad674c2de3c7e2d126271cb2576383d diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index f7fb6b480..241bb6ed3 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -235,8 +235,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { QLinearGradient bg(0, height(), 0, 0); if (sm["controlsState"].getControlsState().getExperimentalMode()) { // The first half of track_vertices are the points for the right side of the path - // and the indices match the positions of accel from uiPlan - const auto &acceleration = sm["uiPlan"].getUiPlan().getAccel(); + const auto &acceleration = sm["modelV2"].getModelV2().getAcceleration().getX(); const int max_len = std::min(scene.track_vertices.length() / 2, acceleration.size()); for (int i = 0; i < max_len; ++i) { @@ -403,7 +402,7 @@ void AnnotatedCameraWidget::paintGL() { painter.setPen(Qt::NoPen); if (s->scene.world_objects_visible) { - update_model(s, model, sm["uiPlan"].getUiPlan()); + update_model(s, model); drawLaneLines(painter, s); if (s->scene.longitudinal_control && sm.rcv_frame("radarState") > s->scene.started_frame) { diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index c70b7594c..06b8b13bc 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -77,14 +77,10 @@ void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, } void update_model(UIState *s, - const cereal::ModelDataV2::Reader &model, - const cereal::UiPlan::Reader &plan) { + const cereal::ModelDataV2::Reader &model) { UIScene &scene = s->scene; - auto plan_position = plan.getPosition(); - if (plan_position.getX().size() < model.getPosition().getX().size()) { - plan_position = model.getPosition(); - } - float max_distance = std::clamp(*(plan_position.getX().end() - 1), + auto model_position = model.getPosition(); + float max_distance = std::clamp(*(model_position.getX().end() - 1), MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); // update lane lines @@ -110,8 +106,8 @@ void update_model(UIState *s, const float lead_d = lead_one.getDRel() * 2.; max_distance = std::clamp((float)(lead_d - fmin(lead_d * 0.35, 10.)), 0.0f, max_distance); } - max_idx = get_path_length_idx(plan_position, max_distance); - update_line_data(s, plan_position, 0.9, 1.22, &scene.track_vertices, max_idx, false); + max_idx = get_path_length_idx(model_position, max_distance); + update_line_data(s, model_position, 0.9, 1.22, &scene.track_vertices, max_idx, false); } void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &driverstate, float dm_fade_state, bool is_rhd) { @@ -212,8 +208,7 @@ static void update_state(UIState *s) { scene.world_objects_visible = scene.world_objects_visible || (scene.started && sm.rcv_frame("liveCalibration") > scene.started_frame && - sm.rcv_frame("modelV2") > scene.started_frame && - sm.rcv_frame("uiPlan") > scene.started_frame); + sm.rcv_frame("modelV2") > scene.started_frame); } void ui_update_params(UIState *s) { @@ -249,7 +244,7 @@ UIState::UIState(QObject *parent) : QObject(parent) { sm = std::make_unique>({ "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "driverStateV2", - "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "uiPlan", "clocks", + "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "clocks", }); Params params; diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 7238159dd..9ef79b2ef 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -184,8 +184,7 @@ Device *device(); void ui_update_params(UIState *s); int get_path_length_idx(const cereal::XYZTData::Reader &line, const float path_height); void update_model(UIState *s, - const cereal::ModelDataV2::Reader &model, - const cereal::UiPlan::Reader &plan); + const cereal::ModelDataV2::Reader &model); void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &driverstate, float dm_fade_state, bool is_rhd); void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line); void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, From 81dc33e56994c364a2100978654c5abf4cacbe4e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 11 Jun 2024 21:36:13 -0700 Subject: [PATCH 219/220] Fixup qlog size (#32719) * stash * Revert "stash" This reverts commit 5a22b44919d4cb8681cc08d99656954423abda93. * improvements * rm * method 2 * Revert "method 2" This reverts commit 7112d95b3eead8bfdd8efb1dcefd4edbe9107680. * unreal for now * stash * Revert "stash" This reverts commit a7c5b31d8043b8da96c21a8d40281cece3cada61. * clean up * update description --- selfdrive/debug/internal/qlog_size.py | 39 ++++++++++----------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/selfdrive/debug/internal/qlog_size.py b/selfdrive/debug/internal/qlog_size.py index b51cb3af2..0b816604a 100755 --- a/selfdrive/debug/internal/qlog_size.py +++ b/selfdrive/debug/internal/qlog_size.py @@ -5,24 +5,30 @@ from collections import defaultdict import matplotlib.pyplot as plt -from cereal.services import SERVICE_LIST from openpilot.tools.lib.logreader import LogReader -from openpilot.tools.lib.route import Route MIN_SIZE = 0.5 # Percent size of total to show as separate entry def make_pie(msgs, typ): - compressed_length_by_type = {k: len(bz2.compress(b"".join(v))) for k, v in msgs.items()} + msgs_by_type = defaultdict(list) + for m in msgs: + msgs_by_type[m.which()].append(m.as_builder().to_bytes()) + + length_by_type = {k: len(b"".join(v)) for k, v in msgs_by_type.items()} + compressed_length_by_type = {k: len(bz2.compress(b"".join(v))) for k, v in msgs_by_type.items()} total = sum(compressed_length_by_type.values()) + uncompressed_total = len(b"".join([m.as_builder().to_bytes() for m in msgs])) sizes = sorted(compressed_length_by_type.items(), key=lambda kv: kv[1]) - print(f"{typ} - Total {total / 1024:.2f} kB") + print("name - comp. size (uncomp. size)") for (name, sz) in sizes: - print(f"{name} - {sz / 1024:.2f} kB") + print(f"{name:<22} - {sz / 1024:.2f} kB ({length_by_type[name] / 1024:.2f} kB)") print() + print(f"{typ} - Total {total / 1024:.2f} kB") + print(f"{typ} - Uncompressed total {uncompressed_total / 1024 / 1024:.2f} MB") sizes_large = [(k, sz) for (k, sz) in sizes if sz >= total * MIN_SIZE / 100] sizes_large += [('other', sum(sz for (_, sz) in sizes if sz < total * MIN_SIZE / 100))] @@ -35,28 +41,11 @@ def make_pie(msgs, typ): if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Check qlog size based on a rlog') + parser = argparse.ArgumentParser(description='View log size breakdown by message type') parser.add_argument('route', help='route to use') - parser.add_argument('segment', type=int, help='segment number to use') args = parser.parse_args() - r = Route(args.route) - rlog = r.log_paths()[args.segment] - msgs = list(LogReader(rlog)) + msgs = list(LogReader(args.route)) - msgs_by_type = defaultdict(list) - for m in msgs: - msgs_by_type[m.which()].append(m.as_builder().to_bytes()) - - qlog_by_type = defaultdict(list) - for name, service in SERVICE_LIST.items(): - if service.decimation is None: - continue - - for i, msg in enumerate(msgs_by_type[name]): - if i % service.decimation == 0: - qlog_by_type[name].append(msg) - - make_pie(msgs_by_type, 'rlog') - make_pie(qlog_by_type, 'qlog') + make_pie(msgs, 'qlog') plt.show() From 83ac80c6c899dbf4b5b2d422947b02b57d83bccd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 11 Jun 2024 21:57:32 -0700 Subject: [PATCH 220/220] Remove `setproctitle` (#32716) * Custom setproctitle (#32667) * add custom setproctitle * add test * Update poetry.lock * fix lint * support only Linux * test only Linux * final lint * Update test_setproctitle.py * Update setproctitle.py * convert to threadnames * delete proctitles * Check str len and use PR_GET_NAME * fix poetry.lock * lint fix * Update common/threadname.py --------- Co-authored-by: reddyn12 Co-authored-by: Adeeb Shihadeh * revert that for now * use last 15 * fix * use name * update those * and modeld * rm --------- Co-authored-by: schlimeszn <138847413+schlimeszn@users.noreply.github.com> Co-authored-by: reddyn12 Co-authored-by: Comma Device --- common/realtime.py | 6 +- common/tests/test_threadname.py | 8 +++ common/threadname.py | 19 ++++++ poetry.lock | 112 ++------------------------------ pyproject.toml | 1 - scripts/waste.py | 4 +- selfdrive/modeld/modeld.py | 12 ++-- selfdrive/test/test_onroad.py | 32 ++++----- system/manager/process.py | 4 +- 9 files changed, 61 insertions(+), 137 deletions(-) create mode 100644 common/tests/test_threadname.py create mode 100644 common/threadname.py diff --git a/common/realtime.py b/common/realtime.py index dd97ea3d7..e7265406a 100644 --- a/common/realtime.py +++ b/common/realtime.py @@ -4,7 +4,7 @@ import os import time from collections import deque -from setproctitle import getproctitle +from openpilot.common.threadname import getthreadname from openpilot.system.hardware import PC @@ -52,7 +52,7 @@ class Ratekeeper: self._print_delay_threshold = print_delay_threshold self._frame = 0 self._remaining = 0.0 - self._process_name = getproctitle() + self._thread_name = getthreadname() self._dts = deque([self._interval], maxlen=100) self._last_monitor_time = time.monotonic() @@ -87,7 +87,7 @@ class Ratekeeper: remaining = self._next_frame_time - time.monotonic() self._next_frame_time += self._interval if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold: - print(f"{self._process_name} lagging by {-remaining * 1000:.2f} ms") + print(f"{self._thread_name} lagging by {-remaining * 1000:.2f} ms") lagged = True self._frame += 1 self._remaining = remaining diff --git a/common/tests/test_threadname.py b/common/tests/test_threadname.py new file mode 100644 index 000000000..38e5e1d49 --- /dev/null +++ b/common/tests/test_threadname.py @@ -0,0 +1,8 @@ +from openpilot.common.threadname import setthreadname, getthreadname, LINUX + +class TestThreadName: + def test_set_get_threadname(self): + if LINUX: + name = 'TESTING' + setthreadname(name) + assert name == getthreadname() diff --git a/common/threadname.py b/common/threadname.py new file mode 100644 index 000000000..7c415721f --- /dev/null +++ b/common/threadname.py @@ -0,0 +1,19 @@ +import ctypes +import os + +LINUX = os.name == 'posix' and os.uname().sysname == 'Linux' + +if LINUX: + libc = ctypes.CDLL('libc.so.6') + +def setthreadname(name: str) -> None: + if LINUX: + name = name[-15:] + '\0' + libc.prctl(15, str.encode(name), 0, 0, 0) + +def getthreadname() -> str: + if LINUX: + name = ctypes.create_string_buffer(16) + libc.prctl(16, name) + return name.value.decode('utf-8') + return "" diff --git a/poetry.lock b/poetry.lock index f4925a17f..7e772276e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohttp" @@ -2730,7 +2730,6 @@ optional = false python-versions = ">=3.6" files = [ {file = "opencv-python-4.10.0.82.tar.gz", hash = "sha256:dbc021eaa310c4145c47cd648cb973db69bb5780d6e635386cd53d3ea76bd2d5"}, - {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:5f78652339957ec24b80a782becfb32f822d2008a865512121fad8c3ce233e9a"}, {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:e6be19a0615aa8c4e0d34e0c7b133e26e386f4b7e9b557b69479104ab2c133ec"}, {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b49e530f7fd86f671514b39ffacdf5d14ceb073bc79d0de46bbb6b0cad78eaf"}, {file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955c5ce8ac90c9e4636ad7f5c0d9c75b80abbe347182cfd09b0e3eec6e50472c"}, @@ -2740,8 +2739,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, ] [[package]] @@ -2752,7 +2751,6 @@ optional = false python-versions = ">=3.6" files = [ {file = "opencv-python-headless-4.10.0.82.tar.gz", hash = "sha256:de9e742c1b9540816fbd115b0b03841d41ed0c65566b0d7a5371f98b131b7e6d"}, - {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a09ed50ba21cc5bf5d436cb0e784ad09c692d6b1d1454252772f6c8f2c7b4088"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:977a5fd21e1fe0d3d2134887db4441f8725abeae95150126302f31fcd9f548fa"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4ec6755838b0be12510bfc9ffb014779c612418f11f4f7e6f505c36124a3aa"}, {file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a37fa5276967ecf6eb297295b16b28b7a2eb3b568ca0ee469fb1a5954de298"}, @@ -2762,8 +2760,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, ] [[package]] @@ -2927,8 +2925,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -7367,106 +7365,6 @@ starlette = ["starlette (>=0.19.1)"] starlite = ["starlite (>=1.48)"] tornado = ["tornado (>=5)"] -[[package]] -name = "setproctitle" -version = "1.3.3" -description = "A Python module to customize the process title" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:897a73208da48db41e687225f355ce993167079eda1260ba5e13c4e53be7f754"}, - {file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c331e91a14ba4076f88c29c777ad6b58639530ed5b24b5564b5ed2fd7a95452"}, - {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbbd6c7de0771c84b4aa30e70b409565eb1fc13627a723ca6be774ed6b9d9fa3"}, - {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c05ac48ef16ee013b8a326c63e4610e2430dbec037ec5c5b58fcced550382b74"}, - {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1342f4fdb37f89d3e3c1c0a59d6ddbedbde838fff5c51178a7982993d238fe4f"}, - {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc74e84fdfa96821580fb5e9c0b0777c1c4779434ce16d3d62a9c4d8c710df39"}, - {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9617b676b95adb412bb69645d5b077d664b6882bb0d37bfdafbbb1b999568d85"}, - {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6a249415f5bb88b5e9e8c4db47f609e0bf0e20a75e8d744ea787f3092ba1f2d0"}, - {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:38da436a0aaace9add67b999eb6abe4b84397edf4a78ec28f264e5b4c9d53cd5"}, - {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:da0d57edd4c95bf221b2ebbaa061e65b1788f1544977288bdf95831b6e44e44d"}, - {file = "setproctitle-1.3.3-cp310-cp310-win32.whl", hash = "sha256:a1fcac43918b836ace25f69b1dca8c9395253ad8152b625064415b1d2f9be4fb"}, - {file = "setproctitle-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:200620c3b15388d7f3f97e0ae26599c0c378fdf07ae9ac5a13616e933cbd2086"}, - {file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:334f7ed39895d692f753a443102dd5fed180c571eb6a48b2a5b7f5b3564908c8"}, - {file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:950f6476d56ff7817a8fed4ab207727fc5260af83481b2a4b125f32844df513a"}, - {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:195c961f54a09eb2acabbfc90c413955cf16c6e2f8caa2adbf2237d1019c7dd8"}, - {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f05e66746bf9fe6a3397ec246fe481096664a9c97eb3fea6004735a4daf867fd"}, - {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5901a31012a40ec913265b64e48c2a4059278d9f4e6be628441482dd13fb8b5"}, - {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64286f8a995f2cd934082b398fc63fca7d5ffe31f0e27e75b3ca6b4efda4e353"}, - {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:184239903bbc6b813b1a8fc86394dc6ca7d20e2ebe6f69f716bec301e4b0199d"}, - {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:664698ae0013f986118064b6676d7dcd28fefd0d7d5a5ae9497cbc10cba48fa5"}, - {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e5119a211c2e98ff18b9908ba62a3bd0e3fabb02a29277a7232a6fb4b2560aa0"}, - {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:417de6b2e214e837827067048f61841f5d7fc27926f2e43954567094051aff18"}, - {file = "setproctitle-1.3.3-cp311-cp311-win32.whl", hash = "sha256:6a143b31d758296dc2f440175f6c8e0b5301ced3b0f477b84ca43cdcf7f2f476"}, - {file = "setproctitle-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a680d62c399fa4b44899094027ec9a1bdaf6f31c650e44183b50d4c4d0ccc085"}, - {file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d4460795a8a7a391e3567b902ec5bdf6c60a47d791c3b1d27080fc203d11c9dc"}, - {file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bdfd7254745bb737ca1384dee57e6523651892f0ea2a7344490e9caefcc35e64"}, - {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477d3da48e216d7fc04bddab67b0dcde633e19f484a146fd2a34bb0e9dbb4a1e"}, - {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ab2900d111e93aff5df9fddc64cf51ca4ef2c9f98702ce26524f1acc5a786ae7"}, - {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088b9efc62d5aa5d6edf6cba1cf0c81f4488b5ce1c0342a8b67ae39d64001120"}, - {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6d50252377db62d6a0bb82cc898089916457f2db2041e1d03ce7fadd4a07381"}, - {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:87e668f9561fd3a457ba189edfc9e37709261287b52293c115ae3487a24b92f6"}, - {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:287490eb90e7a0ddd22e74c89a92cc922389daa95babc833c08cf80c84c4df0a"}, - {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe1c49486109f72d502f8be569972e27f385fe632bd8895f4730df3c87d5ac8"}, - {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4a6ba2494a6449b1f477bd3e67935c2b7b0274f2f6dcd0f7c6aceae10c6c6ba3"}, - {file = "setproctitle-1.3.3-cp312-cp312-win32.whl", hash = "sha256:2df2b67e4b1d7498632e18c56722851ba4db5d6a0c91aaf0fd395111e51cdcf4"}, - {file = "setproctitle-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:f38d48abc121263f3b62943f84cbaede05749047e428409c2c199664feb6abc7"}, - {file = "setproctitle-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:816330675e3504ae4d9a2185c46b573105d2310c20b19ea2b4596a9460a4f674"}, - {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f960bc22d8d8e4ac886d1e2e21ccbd283adcf3c43136161c1ba0fa509088e0"}, - {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e6e7adff74796ef12753ff399491b8827f84f6c77659d71bd0b35870a17d8f"}, - {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53bc0d2358507596c22b02db079618451f3bd720755d88e3cccd840bafb4c41c"}, - {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad6d20f9541f5f6ac63df553b6d7a04f313947f550eab6a61aa758b45f0d5657"}, - {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c1c84beab776b0becaa368254801e57692ed749d935469ac10e2b9b825dbdd8e"}, - {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:507e8dc2891021350eaea40a44ddd887c9f006e6b599af8d64a505c0f718f170"}, - {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b1067647ac7aba0b44b591936118a22847bda3c507b0a42d74272256a7a798e9"}, - {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e71f6365744bf53714e8bd2522b3c9c1d83f52ffa6324bd7cbb4da707312cd8"}, - {file = "setproctitle-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:7f1d36a1e15a46e8ede4e953abb104fdbc0845a266ec0e99cc0492a4364f8c44"}, - {file = "setproctitle-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9a402881ec269d0cc9c354b149fc29f9ec1a1939a777f1c858cdb09c7a261df"}, - {file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ff814dea1e5c492a4980e3e7d094286077054e7ea116cbeda138819db194b2cd"}, - {file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:accb66d7b3ccb00d5cd11d8c6e07055a4568a24c95cf86109894dcc0c134cc89"}, - {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554eae5a5b28f02705b83a230e9d163d645c9a08914c0ad921df363a07cf39b1"}, - {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a911b26264dbe9e8066c7531c0591cfab27b464459c74385b276fe487ca91c12"}, - {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2982efe7640c4835f7355fdb4da313ad37fb3b40f5c69069912f8048f77b28c8"}, - {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df3f4274b80709d8bcab2f9a862973d453b308b97a0b423a501bcd93582852e3"}, - {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:af2c67ae4c795d1674a8d3ac1988676fa306bcfa1e23fddb5e0bd5f5635309ca"}, - {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:af4061f67fd7ec01624c5e3c21f6b7af2ef0e6bab7fbb43f209e6506c9ce0092"}, - {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:37a62cbe16d4c6294e84670b59cf7adcc73faafe6af07f8cb9adaf1f0e775b19"}, - {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a83ca086fbb017f0d87f240a8f9bbcf0809f3b754ee01cec928fff926542c450"}, - {file = "setproctitle-1.3.3-cp38-cp38-win32.whl", hash = "sha256:059f4ce86f8cc92e5860abfc43a1dceb21137b26a02373618d88f6b4b86ba9b2"}, - {file = "setproctitle-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ab92e51cd4a218208efee4c6d37db7368fdf182f6e7ff148fb295ecddf264287"}, - {file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7951820b77abe03d88b114b998867c0f99da03859e5ab2623d94690848d3e45"}, - {file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc94cf128676e8fac6503b37763adb378e2b6be1249d207630f83fc325d9b11"}, - {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f5d9027eeda64d353cf21a3ceb74bb1760bd534526c9214e19f052424b37e42"}, - {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e4a8104db15d3462e29d9946f26bed817a5b1d7a47eabca2d9dc2b995991503"}, - {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32c41ace41f344d317399efff4cffb133e709cec2ef09c99e7a13e9f3b9483c"}, - {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf16381c7bf7f963b58fb4daaa65684e10966ee14d26f5cc90f07049bfd8c1e"}, - {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e18b7bd0898398cc97ce2dfc83bb192a13a087ef6b2d5a8a36460311cb09e775"}, - {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69d565d20efe527bd8a9b92e7f299ae5e73b6c0470f3719bd66f3cd821e0d5bd"}, - {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ddedd300cd690a3b06e7eac90ed4452348b1348635777ce23d460d913b5b63c3"}, - {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:415bfcfd01d1fbf5cbd75004599ef167a533395955305f42220a585f64036081"}, - {file = "setproctitle-1.3.3-cp39-cp39-win32.whl", hash = "sha256:21112fcd2195d48f25760f0eafa7a76510871bbb3b750219310cf88b04456ae3"}, - {file = "setproctitle-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:5a740f05d0968a5a17da3d676ce6afefebeeeb5ce137510901bf6306ba8ee002"}, - {file = "setproctitle-1.3.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6b9e62ddb3db4b5205c0321dd69a406d8af9ee1693529d144e86bd43bcb4b6c0"}, - {file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3b99b338598de0bd6b2643bf8c343cf5ff70db3627af3ca427a5e1a1a90dd9"}, - {file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ae9a02766dad331deb06855fb7a6ca15daea333b3967e214de12cfae8f0ef5"}, - {file = "setproctitle-1.3.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:200ede6fd11233085ba9b764eb055a2a191fb4ffb950c68675ac53c874c22e20"}, - {file = "setproctitle-1.3.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0d3a953c50776751e80fe755a380a64cb14d61e8762bd43041ab3f8cc436092f"}, - {file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e08e232b78ba3ac6bc0d23ce9e2bee8fad2be391b7e2da834fc9a45129eb87"}, - {file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1da82c3e11284da4fcbf54957dafbf0655d2389cd3d54e4eaba636faf6d117a"}, - {file = "setproctitle-1.3.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:aeaa71fb9568ebe9b911ddb490c644fbd2006e8c940f21cb9a1e9425bd709574"}, - {file = "setproctitle-1.3.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:59335d000c6250c35989394661eb6287187854e94ac79ea22315469ee4f4c244"}, - {file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3ba57029c9c50ecaf0c92bb127224cc2ea9fda057b5d99d3f348c9ec2855ad3"}, - {file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d876d355c53d975c2ef9c4f2487c8f83dad6aeaaee1b6571453cb0ee992f55f6"}, - {file = "setproctitle-1.3.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:224602f0939e6fb9d5dd881be1229d485f3257b540f8a900d4271a2c2aa4e5f4"}, - {file = "setproctitle-1.3.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d7f27e0268af2d7503386e0e6be87fb9b6657afd96f5726b733837121146750d"}, - {file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5e7266498cd31a4572378c61920af9f6b4676a73c299fce8ba93afd694f8ae7"}, - {file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33c5609ad51cd99d388e55651b19148ea99727516132fb44680e1f28dd0d1de9"}, - {file = "setproctitle-1.3.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:eae8988e78192fd1a3245a6f4f382390b61bce6cfcc93f3809726e4c885fa68d"}, - {file = "setproctitle-1.3.3.tar.gz", hash = "sha256:c913e151e7ea01567837ff037a23ca8740192880198b7fbb90b16d181607caae"}, -] - -[package.extras] -test = ["pytest"] - [[package]] name = "setuptools" version = "70.0.0" @@ -8114,4 +8012,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.11, <3.13" -content-hash = "c5654418f3c97420a4a2195b42ebfec250623b600658aae03385b2bcf4c058bd" +content-hash = "b5c62b81368f0e972fbcf0dbb88746f3ae930ebdc171ad004c926f3588d1f244" diff --git a/pyproject.toml b/pyproject.toml index 6e4741dda..7b780c87f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -137,7 +137,6 @@ future-fstrings = "*" # these should be removed psutil = "*" timezonefinder = "*" # just used for nav ETA -setproctitle = "*" pycryptodome = "*" # used in updated/casync, panda, body, and a test [tool.poetry.group.dev.dependencies] diff --git a/scripts/waste.py b/scripts/waste.py index 0764ff77c..bf92710fe 100755 --- a/scripts/waste.py +++ b/scripts/waste.py @@ -3,7 +3,7 @@ import os import time import numpy as np from multiprocessing import Process -from setproctitle import setproctitle +from openpilot.common.threadname import setthreadname def waste(core): os.sched_setaffinity(0, [core,]) @@ -16,7 +16,7 @@ def waste(core): j = 0 while 1: if (i % 100) == 0: - setproctitle("%3d: %8d" % (core, i)) + setthreadname("%3d: %8d" % (core, i)) lt = time.monotonic() print("%3d: %8d %f %.2f" % (core, i, lt-st, j)) st = lt diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 3ac80aad9..1e33b7b3f 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -6,7 +6,7 @@ import numpy as np import cereal.messaging as messaging from cereal import car, log from pathlib import Path -from setproctitle import setproctitle +from openpilot.common.threadname import setthreadname from cereal.messaging import PubMaster, SubMaster from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.common.swaglog import cloudlog @@ -24,7 +24,7 @@ from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_ from openpilot.selfdrive.modeld.constants import ModelConstants from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext -PROCESS_NAME = "selfdrive.modeld.modeld" +THREAD_NAME = "selfdrive.modeld.modeld" SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') MODEL_PATHS = { @@ -114,9 +114,9 @@ class ModelState: def main(demo=False): cloudlog.warning("modeld init") - sentry.set_tag("daemon", PROCESS_NAME) - cloudlog.bind(daemon=PROCESS_NAME) - setproctitle(PROCESS_NAME) + sentry.set_tag("daemon", THREAD_NAME) + cloudlog.bind(daemon=THREAD_NAME) + setthreadname("modeld") config_realtime_process(7, 54) cloudlog.warning("setting up CL context") @@ -286,7 +286,7 @@ if __name__ == "__main__": args = parser.parse_args() main(demo=args.demo) except KeyboardInterrupt: - cloudlog.warning(f"child {PROCESS_NAME} got SIGINT") + cloudlog.warning(f"child {THREAD_NAME} got SIGINT") except Exception: sentry.capture_exception() raise diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 75585e2f1..7b44a3b80 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -36,26 +36,26 @@ PROCS = { # Baseline CPU usage by process "selfdrive.controls.controlsd": 32.0, "selfdrive.car.card": 22.0, - "./loggerd": 14.0, - "./encoderd": 17.0, - "./camerad": 14.5, - "./locationd": 11.0, + "loggerd": 14.0, + "encoderd": 17.0, + "camerad": 14.5, + "locationd": 11.0, "selfdrive.controls.plannerd": 11.0, - "./ui": 18.0, + "ui": 18.0, "selfdrive.locationd.paramsd": 9.0, - "./sensord": 7.0, + "sensord": 7.0, "selfdrive.controls.radard": 7.0, - "selfdrive.modeld.modeld": 13.0, + "modeld": 13.0, "selfdrive.modeld.dmonitoringmodeld": 8.0, "system.hardware.hardwared": 3.87, "selfdrive.locationd.calibrationd": 2.0, "selfdrive.locationd.torqued": 5.0, "selfdrive.ui.soundd": 3.5, "selfdrive.monitoring.dmonitoringd": 4.0, - "./proclogd": 1.54, + "proclogd": 1.54, "system.logmessaged": 0.2, "system.tombstoned": 0, - "./logcatd": 0, + "logcatd": 0, "system.micd": 6.0, "system.timed": 0, "selfdrive.pandad.pandad": 0, @@ -67,12 +67,12 @@ PROCS = { PROCS.update({ "tici": { - "./pandad": 4.0, - "./ubloxd": 0.02, + "pandad": 4.0, + "ubloxd": 0.02, "system.ubloxd.pigeond": 6.0, }, "tizi": { - "./pandad": 19.0, + "pandad": 19.0, "system.qcomgpsd.qcomgpsd": 1.0, } }.get(HARDWARE.get_device_type(), {})) @@ -247,8 +247,7 @@ class TestOnroad: for pl in self.service_msgs['procLog']: for x in pl.procLog.procs: if len(x.cmdline) > 0: - n = list(x.cmdline)[0] - plogs_by_proc[n].append(x) + plogs_by_proc[x.name].append(x) print(plogs_by_proc.keys()) cpu_ok = True @@ -256,8 +255,9 @@ class TestOnroad: for proc_name, expected_cpu in PROCS.items(): err = "" + exp = "???" cpu_usage = 0. - x = plogs_by_proc[proc_name] + x = plogs_by_proc[proc_name[-15:]] if len(x) > 2: cpu_time = cputime_total(x[-1]) - cputime_total(x[0]) cpu_usage = cpu_time / dt * 100. @@ -309,7 +309,7 @@ class TestOnroad: assert max(mems) - min(mems) <= 3.0 def test_gpu_usage(self): - assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.modeld.modeld"} + assert self.gpu_procs == {"weston", "ui", "camerad", "modeld"} def test_camera_processing_time(self): result = "\n" diff --git a/system/manager/process.py b/system/manager/process.py index 36f299ae6..9214e417c 100644 --- a/system/manager/process.py +++ b/system/manager/process.py @@ -8,7 +8,7 @@ from collections.abc import Callable, ValuesView from abc import ABC, abstractmethod from multiprocessing import Process -from setproctitle import setproctitle +from openpilot.common.threadname import setthreadname from cereal import car, log import cereal.messaging as messaging @@ -27,7 +27,7 @@ def launcher(proc: str, name: str) -> None: mod = importlib.import_module(proc) # rename the process - setproctitle(proc) + setthreadname(proc) # create new context since we forked messaging.context = messaging.Context()