diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 6ede255a00a20c..92c311829c0654 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -18,7 +18,7 @@ concurrency: jobs: docs: name: build docs - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: commaai/timeout@v1 diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 86fad1fca8c941..09fb52b9c2dc3e 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -231,7 +231,7 @@ jobs: uses: actions/cache@v4 with: path: .ci_cache/comma_download_cache - key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/car/tests/routes.py') }}-${{ matrix.job }} + key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'opendbc/car/tests/routes.py') }}-${{ matrix.job }} - name: Build openpilot run: ${{ env.RUN }} "scons -j$(nproc)" - name: Test car models diff --git a/Dockerfile.openpilot b/Dockerfile.openpilot index e26a427eb1aba9..f34caba81ba0ee 100644 --- a/Dockerfile.openpilot +++ b/Dockerfile.openpilot @@ -1,9 +1,9 @@ FROM ghcr.io/commaai/openpilot-base:latest -ENV PYTHONUNBUFFERED 1 +ENV PYTHONUNBUFFERED=1 -ENV OPENPILOT_PATH /home/batman/openpilot -ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} +ENV OPENPILOT_PATH=/home/batman/openpilot +ENV PYTHONPATH=${OPENPILOT_PATH}:${PYTHONPATH} RUN mkdir -p ${OPENPILOT_PATH} WORKDIR ${OPENPILOT_PATH} diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index ae0cda374d9471..44d8d95e95d926 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -1,16 +1,16 @@ FROM ubuntu:24.04 -ENV PYTHONUNBUFFERED 1 +ENV PYTHONUNBUFFERED=1 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ - apt-get install -y --no-install-recommends sudo tzdata locales ssh pulseaudio xvfb x11-xserver-utils gnome-screenshot && \ + apt-get install -y --no-install-recommends sudo tzdata locales ssh pulseaudio xvfb x11-xserver-utils gnome-screenshot python3-tk python3-dev && \ rm -rf /var/lib/apt/lists/* RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 +ENV LANG=en_US.UTF-8 +ENV LANGUAGE=en_US:en +ENV LC_ALL=en_US.UTF-8 COPY tools/install_ubuntu_dependencies.sh /tmp/tools/ RUN /tmp/tools/install_ubuntu_dependencies.sh && \ @@ -55,9 +55,9 @@ RUN mkdir -p /tmp/opencl-driver-intel && \ cd / && \ rm -rf /tmp/opencl-driver-intel -ENV NVIDIA_VISIBLE_DEVICES all -ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute -ENV QTWEBENGINE_DISABLE_SANDBOX 1 +ENV NVIDIA_VISIBLE_DEVICES=all +ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute +ENV QTWEBENGINE_DISABLE_SANDBOX=1 RUN dbus-uuidgen > /etc/machine-id diff --git a/README.md b/README.md index 38d32ec3b69761..77002481d31cb2 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,8 @@ Quick start: `bash <(curl -fsSL openpilot.comma.ai)` -To start using openpilot in a car + +Using openpilot in a car ------ To use openpilot in a car, you need four things: @@ -49,6 +50,14 @@ To use openpilot in a car, you need four things: We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play. +### Branches +| branch | URL | description | +|------------------|----------------------------------------|-------------------------------------------------------------------------------------| +| `release3` | openpilot.comma.ai | This is openpilot's release branch. | +| `release3-staging` | openpilot-test.comma.ai | This is the staging branch for releases. Use it to get new releases slightly early. | +| `nightly` | openpilot-nightly.comma.ai | This is the bleeding edge development branch. Do not expect this to be stable. | +| `nightly-dev` | installer.comma.ai/commaai/nightly-dev | Same as nightly, but includes experimental development features for some cars. | + To start developing openpilot ------ diff --git a/cereal/log.capnp b/cereal/log.capnp index 70508f36e268b9..68ea3099b8f090 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -2440,6 +2440,14 @@ struct Microphone { filteredSoundPressureWeightedDb @2 :Float32; } +struct Touch { + sec @0 :Int64; + usec @1 :Int64; + type @2 :UInt8; + code @3 :Int32; + value @4 :Int32; +} + struct Event { logMonoTime @0 :UInt64; # nanoseconds valid @67 :Bool = true; @@ -2520,6 +2528,9 @@ struct Event { logMessage @18 :Text; errorLogMessage @85 :Text; + # touch frame + touch @135 :List(Touch); + # navigation navInstruction @82 :NavInstruction; navRoute @83 :NavRoute; diff --git a/cereal/services.py b/cereal/services.py index 771338f50780e1..87fdca77b79b15 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -22,6 +22,7 @@ def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] "temperatureSensor2": (True, 2., 200), "gpsNMEA": (True, 9.), "deviceState": (True, 2., 1), + "touch": (True, 20., 1), "can": (True, 100., 2053), # decimation gives ~3 msgs in a full segment "controlsState": (True, 100., 10), "selfdriveState": (True, 100., 10), diff --git a/common/transformations/model.py b/common/transformations/model.py index aaa12d776a8ed0..ea1dff30e8fc4e 100644 --- a/common/transformations/model.py +++ b/common/transformations/model.py @@ -1,7 +1,7 @@ import numpy as np from openpilot.common.transformations.orientation import rot_from_euler -from openpilot.common.transformations.camera import get_view_frame_from_calib_frame, view_frame_from_device_frame +from openpilot.common.transformations.camera import get_view_frame_from_calib_frame, view_frame_from_device_frame, _ar_ox_fisheye # segnet SEGNET_SIZE = (512, 384) @@ -39,6 +39,13 @@ [0.0, sbigmodel_fl, 0.5 * (256 + MEDMODEL_CY)], [0.0, 0.0, 1.0]]) +DM_INPUT_SIZE = (1440, 960) +dmonitoringmodel_fl = _ar_ox_fisheye.focal_length +dmonitoringmodel_intrinsics = np.array([ + [dmonitoringmodel_fl, 0.0, DM_INPUT_SIZE[0]/2], + [0.0, dmonitoringmodel_fl, DM_INPUT_SIZE[1]/2 - (_ar_ox_fisheye.height - DM_INPUT_SIZE[1])/2], + [0.0, 0.0, 1.0]]) + bigmodel_frame_from_calib_frame = np.dot(bigmodel_intrinsics, get_view_frame_from_calib_frame(0, 0, 0, 0)) diff --git a/docs/CARS.md b/docs/CARS.md index 2e2a614a3853c7..c0b0f1706e1b55 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -103,7 +103,7 @@ A supported vehicle is one that just works when you install a comma device. All |Hyundai|Ioniq Plug-in Hybrid 2020-22|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|Kona 2020|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 B 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|Kona Electric 2018-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
|| -|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai O 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|Kona Electric 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 O 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|Kona Electric (with HDA II, Korea 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 R 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|Kona Hybrid 2020|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 I 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|Palisade 2020-22|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
|| diff --git a/docs/css/tooltip.css b/docs/css/tooltip.css new file mode 100644 index 00000000000000..b9a54f793f9fe5 --- /dev/null +++ b/docs/css/tooltip.css @@ -0,0 +1,44 @@ +[data-tooltip] { + position: relative; + display: inline-block; + border-bottom: 1px dotted black; +} + +[data-tooltip] .tooltip-content { + width: max-content; + max-width: 25em; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + background-color: white; + color: #404040; + box-shadow: 0 4px 14px 0 rgba(0,0,0,.2), 0 0 0 1px rgba(0,0,0,.05); + padding: 10px; + font: 14px/1.5 Lato, proxima-nova, Helvetica Neue, Arial, sans-serif; + text-decoration: none; + opacity: 0; + visibility: hidden; + transition: opacity 0.1s, visibility 0s; + z-index: 1000; + pointer-events: none; /* Prevent accidental interaction */ +} + +[data-tooltip]:hover .tooltip-content { + opacity: 1; + visibility: visible; + pointer-events: auto; /* Allow interaction when visible */ +} + +.tooltip-content .tooltip-glossary-link { + display: inline-block; + margin-top: 8px; + font-size: 12px; + color: #007bff; + text-decoration: none; +} + +.tooltip-content .tooltip-glossary-link:hover { + color: #0056b3; + text-decoration: underline; +} diff --git a/docs/glossary.toml b/docs/glossary.toml new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/docs/hooks/glossary.py b/docs/hooks/glossary.py new file mode 100644 index 00000000000000..e2fa3d51e04cb9 --- /dev/null +++ b/docs/hooks/glossary.py @@ -0,0 +1,68 @@ +import re +import tomllib + +def load_glossary(file_path="docs/glossary.toml"): + with open(file_path, "rb") as f: + glossary_data = tomllib.load(f) + return glossary_data.get("glossary", {}) + +def generate_anchor_id(name): + return name.replace(" ", "-").replace("_", "-").lower() + +def format_markdown_term(name, definition): + anchor_id = generate_anchor_id(name) + markdown = f"* [**{name.replace('_', ' ').title()}**](#{anchor_id})" + if definition.get("abbreviation"): + markdown += f" *({definition['abbreviation']})*" + if definition.get("description"): + markdown += f": {definition['description']}\n" + return markdown + +def glossary_markdown(vocabulary): + markdown = "" + for category, terms in vocabulary.items(): + markdown += f"## {category.replace('_', ' ').title()}\n\n" + for name, definition in terms.items(): + markdown += format_markdown_term(name, definition) + return markdown + +def format_tooltip_html(term_key, definition, html): + display_term = term_key.replace("_", " ").title() + clean_description = re.sub(r"\[(.+)]\(.+\)", r"\1", definition["description"]) + glossary_link = ( + f"Glossaryđź”—" + ) + return re.sub( + re.escape(display_term), + lambda + match: f"{match.group(0)}{clean_description} {glossary_link}", + html, + flags=re.IGNORECASE, + ) + +def apply_tooltip(_term_key, _definition, pattern, html): + return re.sub( + pattern, + lambda match: format_tooltip_html(_term_key, _definition, match.group(0)), + html, + flags=re.IGNORECASE, + ) + +def tooltip_html(vocabulary, html): + for _category, terms in vocabulary.items(): + for term_key, definition in terms.items(): + if definition.get("description"): + pattern = rf"(?)(?!\([^)]*\))" + html = apply_tooltip(term_key, definition, pattern, html) + return html + +# Page Hooks +def on_page_markdown(markdown, **kwargs): + glossary = load_glossary() + return markdown.replace("{{GLOSSARY_DEFINITIONS}}", glossary_markdown(glossary)) + +def on_page_content(html, **kwargs): + if kwargs.get("page").title == "Glossary": + return html + glossary = load_glossary() + return tooltip_html(glossary, html) diff --git a/launch_env.sh b/launch_env.sh index 3d2900650b1322..5f67052e67db05 100755 --- a/launch_env.sh +++ b/launch_env.sh @@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1 export VECLIB_MAXIMUM_THREADS=1 if [ -z "$AGNOS_VERSION" ]; then - export AGNOS_VERSION="11.3" + export AGNOS_VERSION="11.4" fi export STAGING_ROOT="/data/safe_staging" diff --git a/mkdocs.yml b/mkdocs.yml index 58527ea7ee021d..a66d1c76d45bba 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,6 +8,10 @@ strict: true docs_dir: docs site_dir: docs_site/ +hooks: + - docs/hooks/glossary.py +extra_css: + - css/tooltip.css theme: name: readthedocs navigation_depth: 3 diff --git a/msgq_repo b/msgq_repo index 434ed2312c980b..5bb86f8bc74340 160000 --- a/msgq_repo +++ b/msgq_repo @@ -1 +1 @@ -Subproject commit 434ed2312c980b5504a4a75001d04c3ecbddf93f +Subproject commit 5bb86f8bc7434048ab2d5ce0243a97d9848b34de diff --git a/opendbc_repo b/opendbc_repo index b89fe79950121c..fd8471dc0d6fbd 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit b89fe79950121ca93d8a1f0d3fd17df31703be2a +Subproject commit fd8471dc0d6fbd7ae009ab6d75036667c5b576a5 diff --git a/panda b/panda index c7cc2deaf04640..4ca9905011ba87 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit c7cc2deaf046403899b5bcc964b9f48bfd508534 +Subproject commit 4ca9905011ba875efa4278b2dcb507a759b0e13e diff --git a/pyproject.toml b/pyproject.toml index ff5c1e239261fd..3d577c7f626e62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openpilot" -requires-python = ">= 3.11, <= 3.12" +requires-python = ">= 3.11, < 3.13" license = {text = "MIT License"} version = "0.1.0" description = "an open source driver assistance system" @@ -118,7 +118,7 @@ dev = [ ] tools = [ - "metadrive-simulator @ https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal/metadrive_simulator-0.4.2.3-py3-none-any.whl ; (platform_machine != 'aarch64')", + "metadrive-simulator @ https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl ; (platform_machine != 'aarch64')", "rerun-sdk >= 0.18", ] diff --git a/selfdrive/car/car_specific.py b/selfdrive/car/car_specific.py index 94afec50e2a390..9477b36bbb8815 100644 --- a/selfdrive/car/car_specific.py +++ b/selfdrive/car/car_specific.py @@ -148,7 +148,8 @@ def update(self, CS: car.CarState, CS_prev: car.CarState, CC: car.CarControl): # To avoid re-engaging when openpilot cancels, check user engagement intention via buttons # Main button also can trigger an engagement on these cars self.cruise_buttons.append(any(ev.type in HYUNDAI_ENABLE_BUTTONS for ev in CS.buttonEvents)) - events = self.create_common_events(CS, CS_prev, pcm_enable=self.CP.pcmCruise, allow_enable=any(self.cruise_buttons)) + events = self.create_common_events(CS, CS_prev, extra_gears=(GearShifter.sport, GearShifter.manumatic), + pcm_enable=self.CP.pcmCruise, allow_enable=any(self.cruise_buttons)) # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s) if CS.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.: diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 64cbf473d63d29..66b92319ca03cc 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -5,12 +5,15 @@ MIN_SPEED = 1.0 CONTROL_N = 17 CAR_ROTATION_RADIUS = 0.0 +# This is a turn radius smaller than most cars can achieve +MAX_CURVATURE = 0.2 # EU guidelines MAX_LATERAL_JERK = 5.0 MAX_VEL_ERR = 5.0 def clip_curvature(v_ego, prev_curvature, new_curvature): + new_curvature = clip(new_curvature, -MAX_CURVATURE, MAX_CURVATURE) v_ego = max(MIN_SPEED, v_ego) max_curvature_rate = MAX_LATERAL_JERK / (v_ego**2) # inexact calculation, check https://github.com/commaai/openpilot/pull/24755 safe_desired_curvature = clip(new_curvature, diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index f1637d960cf58e..eba8019117166b 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -50,24 +50,20 @@ def limit_accel_in_turns(v_ego, angle_steers, a_target, CP): return [a_target[0], min(a_target[1], a_x_allowed)] -def get_accel_from_plan(CP, speeds, accels): +def get_accel_from_plan(speeds, accels, action_t=DT_MDL, vEgoStopping=0.05): if len(speeds) == CONTROL_N: - v_target_now = interp(DT_MDL, CONTROL_N_T_IDX, speeds) - a_target_now = interp(DT_MDL, CONTROL_N_T_IDX, accels) + v_now = speeds[0] + a_now = accels[0] - v_target = interp(CP.longitudinalActuatorDelay + DT_MDL, CONTROL_N_T_IDX, speeds) - if v_target != v_target_now: - a_target = 2 * (v_target - v_target_now) / CP.longitudinalActuatorDelay - a_target_now - else: - a_target = a_target_now - - v_target_1sec = interp(CP.longitudinalActuatorDelay + DT_MDL + 1.0, CONTROL_N_T_IDX, speeds) + v_target = interp(action_t, CONTROL_N_T_IDX, speeds) + a_target = 2 * (v_target - v_now) / (action_t) - a_now + v_target_1sec = interp(action_t + 1.0, CONTROL_N_T_IDX, speeds) else: v_target = 0.0 v_target_1sec = 0.0 a_target = 0.0 - should_stop = (v_target < CP.vEgoStopping and - v_target_1sec < CP.vEgoStopping) + should_stop = (v_target < vEgoStopping and + v_target_1sec < vEgoStopping) return a_target, should_stop @@ -201,7 +197,9 @@ def publish(self, sm, pm): longitudinalPlan.longitudinalPlanSource = self.mpc.source longitudinalPlan.fcw = self.fcw - a_target, should_stop = get_accel_from_plan(self.CP, longitudinalPlan.speeds, longitudinalPlan.accels) + action_t = self.CP.longitudinalActuatorDelay + DT_MDL + a_target, should_stop = get_accel_from_plan(longitudinalPlan.speeds, longitudinalPlan.accels, + action_t=action_t, vEgoStopping=self.CP.vEgoStopping) longitudinalPlan.aTarget = a_target longitudinalPlan.shouldStop = should_stop longitudinalPlan.allowBrake = True diff --git a/selfdrive/debug/touch_replay.py b/selfdrive/debug/touch_replay.py new file mode 100755 index 00000000000000..1e1596d2640817 --- /dev/null +++ b/selfdrive/debug/touch_replay.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +import argparse + +import numpy as np +import matplotlib.pyplot as plt + +from openpilot.tools.lib.logreader import LogReader + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--width', default=2160, type=int) + parser.add_argument('--height', default=1080, type=int) + parser.add_argument('--route', default='rlog', type=str) + args = parser.parse_args() + + w = args.width + h = args.height + route = args.route + + fingers = [[-1, -1]] * 5 + touch_points = [] + current_slot = 0 + + lr = list(LogReader(route)) + for msg in lr: + if msg.which() == 'touch': + for event in msg.touch: + if event.type == 3 and event.code == 47: + current_slot = event.value + elif event.type == 3 and event.code == 57 and event.value == -1: + fingers[current_slot] = [-1, -1] + elif event.type == 3 and event.code == 53: + fingers[current_slot][1] = h - (h - event.value) + if fingers[current_slot][0] != -1: + touch_points.append(fingers[current_slot].copy()) + elif event.type == 3 and event.code == 54: + fingers[current_slot][0] = w - event.value + if fingers[current_slot][1] != -1: + touch_points.append(fingers[current_slot].copy()) + + if not touch_points: + print(f'No touch events found for {route}') + quit() + + unique_points, counts = np.unique(touch_points, axis=0, return_counts=True) + + plt.figure(figsize=(10, 3)) + plt.scatter(unique_points[:, 0], unique_points[:, 1], c=counts, s=counts * 20, edgecolors='red') + plt.colorbar() + plt.title(f'Touches for {route}') + plt.xlim(0, w) + plt.ylim(0, h) + plt.grid(True) + plt.show() diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 2a965b8690e506..ef0fd52f334dcb 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -33,8 +33,7 @@ snpe_rpath = lenvCython['RPATH'] + [snpe_rpath_qcom if arch == "larch64" else sn cython_libs = envCython["LIBS"] + libs commonmodel_lib = lenv.Library('commonmodel', common_src) 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)] +tinygrad_files = ["#"+x for x in glob.glob(env.Dir("#tinygrad_repo").relpath + "/**", recursive=True, root_dir=env.Dir("#").abspath) if 'pycache' not in x] # Get model metadata fn = File("models/supercombo").abspath @@ -42,8 +41,6 @@ cmd = f'python3 {Dir("#selfdrive/modeld").abspath}/get_model_metadata.py {fn}.on lenv.Command(fn + "_metadata.pkl", [fn + ".onnx"] + tinygrad_files, cmd) # Compile tinygrad model -# TODO this is all super hacky - pythonpath_string = 'PYTHONPATH="${PYTHONPATH}:' + env.Dir("#tinygrad_repo").abspath + '"' if arch == 'larch64': device_string = 'QCOM=1' diff --git a/selfdrive/modeld/dmonitoringmodeld.py b/selfdrive/modeld/dmonitoringmodeld.py index 0ac2d4675ce079..ebc24ad0246dec 100755 --- a/selfdrive/modeld/dmonitoringmodeld.py +++ b/selfdrive/modeld/dmonitoringmodeld.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 import os from openpilot.system.hardware import TICI -## TODO this is hack if TICI: + from tinygrad.tensor import Tensor + from tinygrad.dtype import dtypes + from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address os.environ['QCOM'] = '1' else: from openpilot.selfdrive.modeld.runners.ort_helpers import make_onnx_cpu_runner @@ -20,13 +22,13 @@ from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.common.swaglog import cloudlog from openpilot.common.realtime import set_realtime_priority -from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext +from openpilot.common.transformations.model import dmonitoringmodel_intrinsics, DM_INPUT_SIZE +from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye +from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext, MonitoringModelFrame from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid -from tinygrad.tensor import Tensor +MODEL_WIDTH, MODEL_HEIGHT = DM_INPUT_SIZE CALIB_LEN = 3 -MODEL_WIDTH = 1440 -MODEL_HEIGHT = 960 FEATURE_LEN = 512 OUTPUT_SIZE = 84 + FEATURE_LEN @@ -67,26 +69,31 @@ class ModelState: def __init__(self, cl_ctx): assert ctypes.sizeof(DMonitoringModelResult) == OUTPUT_SIZE * ctypes.sizeof(ctypes.c_float) - self.numpy_inputs = {'calib': np.zeros((1, CALIB_LEN), dtype=np.float32), - 'input_img': np.zeros((1,MODEL_HEIGHT * MODEL_WIDTH), dtype=np.uint8)} - self.tensor_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()} + self.frame = MonitoringModelFrame(cl_ctx) + self.numpy_inputs = { + 'calib': np.zeros((1, CALIB_LEN), dtype=np.float32), + } if TICI: + self.tensor_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()} with open(MODEL_PKL_PATH, "rb") as f: self.model_run = pickle.load(f) else: self.onnx_cpu_runner = make_onnx_cpu_runner(MODEL_PATH) - def run(self, buf:VisionBuf, calib:np.ndarray) -> tuple[np.ndarray, float]: + def run(self, buf:VisionBuf, calib:np.ndarray, transform:np.ndarray) -> tuple[np.ndarray, float]: self.numpy_inputs['calib'][0,:] = calib t1 = time.perf_counter() - # TODO use opencl buffer directly to make tensor - v_offset = buf.height - MODEL_HEIGHT - h_offset = (buf.width - MODEL_WIDTH) // 2 - buf_data = buf.data.reshape(-1, buf.stride) - self.numpy_inputs['input_img'][:] = buf_data[v_offset:v_offset+MODEL_HEIGHT, h_offset:h_offset+MODEL_WIDTH].reshape((1, -1)) + + input_img_cl = self.frame.prepare(buf, transform.flatten()) + if TICI: + # The imgs tensors are backed by opencl memory, only need init once + if 'input_img' not in self.tensor_inputs: + self.tensor_inputs['input_img'] = qcom_tensor_from_opencl_address(input_img_cl.mem_address, (1, MODEL_WIDTH*MODEL_HEIGHT), dtype=dtypes.uint8) + else: + self.numpy_inputs['input_img'] = self.frame.buffer_from_cl(input_img_cl).reshape((1, MODEL_WIDTH*MODEL_HEIGHT)) if TICI: output = self.model_run(**self.tensor_inputs).numpy().flatten() @@ -147,18 +154,23 @@ def main(): pm = PubMaster(["driverStateV2"]) calib = np.zeros(CALIB_LEN, dtype=np.float32) + model_transform = None while True: buf = vipc_client.recv() if buf is None: continue + if model_transform is None: + cam = _os_fisheye if buf.width == _os_fisheye.width else _ar_ox_fisheye + model_transform = np.linalg.inv(np.dot(dmonitoringmodel_intrinsics, np.linalg.inv(cam.intrinsics))).astype(np.float32) + sm.update(0) if sm.updated["liveCalibration"]: calib[:] = np.array(sm["liveCalibration"].rpyCalib) t1 = time.perf_counter() - model_output, gpu_execution_time = model.run(buf, calib) + model_output, gpu_execution_time = model.run(buf, calib, model_transform) t2 = time.perf_counter() pm.send("driverStateV2", get_driverstate_packet(model_output, vipc_client.frame_id, vipc_client.timestamp_sof, t2 - t1, gpu_execution_time)) diff --git a/selfdrive/modeld/fill_model_msg.py b/selfdrive/modeld/fill_model_msg.py index 115ec94f88fcbd..a13d632aa676f9 100644 --- a/selfdrive/modeld/fill_model_msg.py +++ b/selfdrive/modeld/fill_model_msg.py @@ -3,11 +3,22 @@ import numpy as np from cereal import log from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta +from openpilot.selfdrive.controls.lib.drive_helpers import MIN_SPEED SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') ConfidenceClass = log.ModelDataV2.ConfidenceClass +def curv_from_psis(psi_target, psi_rate, vego, delay): + vego = np.clip(vego, MIN_SPEED, np.inf) + curv_from_psi = psi_target / (vego * delay) # epsilon to prevent divide-by-zero + return 2*curv_from_psi - psi_rate / vego + +def get_curvature_from_plan(plan, vego, delay): + psi_target = np.interp(delay, ModelConstants.T_IDXS, plan[:, Plan.T_FROM_CURRENT_EULER][:, 2]) + psi_rate = plan[:, Plan.ORIENTATION_RATE][0, 2] + return curv_from_psis(psi_target, psi_rate, vego, delay) + class PublishState: def __init__(self): self.disengage_buffer = np.zeros(ModelConstants.CONFIDENCE_BUFFER_LEN*ModelConstants.DISENGAGE_WIDTH, dtype=np.float32) @@ -55,14 +66,17 @@ def fill_lane_line_meta(builder, lane_lines, lane_line_probs): builder.rightProb = lane_line_probs[2] def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._DynamicStructBuilder, - net_output_data: dict[str, np.ndarray], publish_state: PublishState, - vipc_frame_id: int, vipc_frame_id_extra: int, frame_id: int, frame_drop: float, - timestamp_eof: int, model_execution_time: float, valid: bool) -> None: + net_output_data: dict[str, np.ndarray], v_ego: float, delay: float, + publish_state: PublishState, vipc_frame_id: int, vipc_frame_id_extra: int, + frame_id: int, frame_drop: float, timestamp_eof: int, model_execution_time: float, + valid: bool) -> None: frame_age = frame_id - vipc_frame_id if frame_id > vipc_frame_id else 0 frame_drop_perc = frame_drop * 100 extended_msg.valid = valid base_msg.valid = valid + desired_curv = float(get_curvature_from_plan(net_output_data['plan'][0], v_ego, delay)) + driving_model_data = base_msg.drivingModelData driving_model_data.frameId = vipc_frame_id @@ -71,7 +85,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D driving_model_data.modelExecutionTime = model_execution_time action = driving_model_data.action - action.desiredCurvature = float(net_output_data['desired_curvature'][0,0]) + action.desiredCurvature = desired_curv modelV2 = extended_msg.modelV2 modelV2.frameId = vipc_frame_id @@ -106,7 +120,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D # lateral planning action = modelV2.action - action.desiredCurvature = float(net_output_data['desired_curvature'][0,0]) + action.desiredCurvature = desired_curv # times at X_IDXS according to model plan PLAN_T_IDXS = [np.nan] * ModelConstants.IDX_N diff --git a/selfdrive/modeld/modeld b/selfdrive/modeld/modeld index e1cef4dcc35f18..5ba46885548af1 100755 --- a/selfdrive/modeld/modeld +++ b/selfdrive/modeld/modeld @@ -1,10 +1,4 @@ #!/usr/bin/env bash DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" -cd "$DIR/../../" - -if [ -f "$DIR/libthneed.so" ]; then - export LD_PRELOAD="$DIR/libthneed.so" -fi - exec "$DIR/modeld.py" "$@" diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 4b19d103b4281e..49f8c483f05501 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 import os from openpilot.system.hardware import TICI -## TODO this is hack + +# if TICI: from tinygrad.tensor import Tensor from tinygrad.dtype import dtypes @@ -30,7 +31,7 @@ from openpilot.selfdrive.modeld.parse_model_outputs import Parser from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState from openpilot.selfdrive.modeld.constants import ModelConstants -from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext +from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext PROCESS_NAME = "selfdrive.modeld.modeld" @@ -40,9 +41,6 @@ MODEL_PKL_PATH = Path(__file__).parent / 'models/supercombo_tinygrad.pkl' METADATA_PATH = Path(__file__).parent / 'models/supercombo_metadata.pkl' -# TODO: should not hardcoded -IMG_INPUT_SHAPE = (1, 12, 128, 256) - class FrameMeta: frame_id: int = 0 timestamp_sof: int = 0 @@ -53,31 +51,27 @@ def __init__(self, vipc=None): self.frame_id, self.timestamp_sof, self.timestamp_eof = vipc.frame_id, vipc.timestamp_sof, vipc.timestamp_eof class ModelState: - frame: ModelFrame - wide_frame: ModelFrame + frames: dict[str, DrivingModelFrame] inputs: dict[str, np.ndarray] output: np.ndarray prev_desire: np.ndarray # for tracking the rising edge of the pulse def __init__(self, context: CLContext): - self.frame = ModelFrame(context) - self.wide_frame = ModelFrame(context) + self.frames = {'input_imgs': DrivingModelFrame(context), 'big_input_imgs': DrivingModelFrame(context)} self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32) self.full_features_20Hz = np.zeros((ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32) self.desire_20Hz = np.zeros((ModelConstants.FULL_HISTORY_BUFFER_LEN + 1, ModelConstants.DESIRE_LEN), dtype=np.float32) - self.prev_desired_curv_20hz = np.zeros((ModelConstants.FULL_HISTORY_BUFFER_LEN + 1, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32) # img buffers are managed in openCL transform code self.numpy_inputs = { 'desire': np.zeros((1, (ModelConstants.HISTORY_BUFFER_LEN+1), ModelConstants.DESIRE_LEN), dtype=np.float32), 'traffic_convention': np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32), - 'lateral_control_params': np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32), - 'prev_desired_curv': np.zeros((1,(ModelConstants.HISTORY_BUFFER_LEN+1), ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32), 'features_buffer': np.zeros((1, ModelConstants.HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32), } with open(METADATA_PATH, 'rb') as f: model_metadata = pickle.load(f) + self.input_shapes = model_metadata['input_shapes'] self.output_slices = model_metadata['output_slices'] net_output_size = model_metadata['output_shapes']['outputs'][1] @@ -109,18 +103,17 @@ def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_ self.numpy_inputs['desire'][:] = self.desire_20Hz.reshape((1,25,4,-1)).max(axis=2) self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention'] - self.numpy_inputs['lateral_control_params'][:] = inputs['lateral_control_params'] - input_imgs_cl = self.frame.prepare(buf, transform.flatten()) - big_input_imgs_cl = self.wide_frame.prepare(wbuf, transform_wide.flatten()) + imgs_cl = {'input_imgs': self.frames['input_imgs'].prepare(buf, transform.flatten()), + 'big_input_imgs': self.frames['big_input_imgs'].prepare(wbuf, transform_wide.flatten())} if TICI: # The imgs tensors are backed by opencl memory, only need init once - if 'input_imgs' not in self.tensor_inputs: - self.tensor_inputs['input_imgs'] = qcom_tensor_from_opencl_address(input_imgs_cl.mem_address, IMG_INPUT_SHAPE, dtype=dtypes.uint8) - self.tensor_inputs['big_input_imgs'] = qcom_tensor_from_opencl_address(big_input_imgs_cl.mem_address, IMG_INPUT_SHAPE, dtype=dtypes.uint8) + for key in imgs_cl: + if key not in self.tensor_inputs: + self.tensor_inputs[key] = qcom_tensor_from_opencl_address(imgs_cl[key].mem_address, self.input_shapes[key], dtype=dtypes.uint8) else: - self.numpy_inputs['input_imgs'] = self.frame.buffer_from_cl(input_imgs_cl).reshape(IMG_INPUT_SHAPE) - self.numpy_inputs['big_input_imgs'] = self.wide_frame.buffer_from_cl(big_input_imgs_cl).reshape(IMG_INPUT_SHAPE) + for key in imgs_cl: + self.numpy_inputs[key] = self.frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.input_shapes[key]) if prepare_only: return None @@ -135,13 +128,8 @@ def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_ self.full_features_20Hz[:-1] = self.full_features_20Hz[1:] self.full_features_20Hz[-1] = outputs['hidden_state'][0, :] - self.prev_desired_curv_20hz[:-1] = self.prev_desired_curv_20hz[1:] - self.prev_desired_curv_20hz[-1] = outputs['desired_curvature'][0, :] - idxs = np.arange(-4,-100,-4)[::-1] self.numpy_inputs['features_buffer'][:] = self.full_features_20Hz[idxs] - # TODO model only uses last value now, once that changes we need to input strided action history buffer - self.numpy_inputs['prev_desired_curv'][-ModelConstants.PREV_DESIRED_CURV_LEN:] = 0. * self.prev_desired_curv_20hz[-4, :] return outputs @@ -252,7 +240,6 @@ def main(demo=False): is_rhd = sm["driverMonitoringState"].isRHD frame_id = sm["roadCameraState"].frameId v_ego = max(sm["carState"].vEgo, 0.) - lateral_control_params = np.array([v_ego, steer_delay], dtype=np.float32) if sm.updated["liveCalibration"] and sm.seen['roadCameraState'] and sm.seen['deviceState']: device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32) dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['roadCameraState'].sensor))] @@ -283,7 +270,6 @@ def main(demo=False): inputs:dict[str, np.ndarray] = { 'desire': vec_desire, 'traffic_convention': traffic_convention, - 'lateral_control_params': lateral_control_params, } mt1 = time.perf_counter() @@ -295,7 +281,8 @@ def main(demo=False): modelv2_send = messaging.new_message('modelV2') drivingdata_send = messaging.new_message('drivingModelData') posenet_send = messaging.new_message('cameraOdometry') - fill_model_msg(drivingdata_send, modelv2_send, model_output, publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id, + fill_model_msg(drivingdata_send, modelv2_send, model_output, v_ego, steer_delay, + publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id, frame_drop_ratio, meta_main.timestamp_eof, model_execution_time, live_calib_seen) desire_state = modelv2_send.modelV2.meta.desireState diff --git a/selfdrive/modeld/models/commonmodel.cc b/selfdrive/modeld/models/commonmodel.cc index ef730e01aaaa3a..ad2620c7b4a687 100644 --- a/selfdrive/modeld/models/commonmodel.cc +++ b/selfdrive/modeld/models/commonmodel.cc @@ -1,32 +1,24 @@ #include "selfdrive/modeld/models/commonmodel.h" -#include #include #include #include "common/clutil.h" -ModelFrame::ModelFrame(cl_device_id device_id, cl_context context) { +DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context) : ModelFrame(device_id, context) { input_frames = std::make_unique(buf_size); input_frames_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, buf_size, NULL, &err)); - - q = CL_CHECK_ERR(clCreateCommandQueue(context, device_id, 0, &err)); - y_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, MODEL_WIDTH * MODEL_HEIGHT, NULL, &err)); - u_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, (MODEL_WIDTH / 2) * (MODEL_HEIGHT / 2), NULL, &err)); - v_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, (MODEL_WIDTH / 2) * (MODEL_HEIGHT / 2), NULL, &err)); img_buffer_20hz_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, 5*frame_size_bytes, NULL, &err)); region.origin = 4 * frame_size_bytes; region.size = frame_size_bytes; last_img_cl = CL_CHECK_ERR(clCreateSubBuffer(img_buffer_20hz_cl, CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, ®ion, &err)); - transform_init(&transform, context, device_id); loadyuv_init(&loadyuv, context, device_id, MODEL_WIDTH, MODEL_HEIGHT); + init_transform(device_id, context, MODEL_WIDTH, MODEL_HEIGHT); } -cl_mem* ModelFrame::prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3 &projection) { - transform_queue(&this->transform, q, - yuv_cl, frame_width, frame_height, frame_stride, frame_uv_offset, - y_cl, u_cl, v_cl, MODEL_WIDTH, MODEL_HEIGHT, projection); +cl_mem* DrivingModelFrame::prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection) { + run_transform(yuv_cl, MODEL_WIDTH, MODEL_HEIGHT, frame_width, frame_height, frame_stride, frame_uv_offset, projection); for (int i = 0; i < 4; i++) { CL_CHECK(clEnqueueCopyBuffer(q, img_buffer_20hz_cl, img_buffer_20hz_cl, (i+1)*frame_size_bytes, i*frame_size_bytes, frame_size_bytes, 0, nullptr, nullptr)); @@ -41,19 +33,29 @@ cl_mem* ModelFrame::prepare(cl_mem yuv_cl, int frame_width, int frame_height, in return &input_frames_cl; } -uint8_t* ModelFrame::buffer_from_cl(cl_mem *in_frames) { - CL_CHECK(clEnqueueReadBuffer(q, *in_frames, CL_TRUE, 0, MODEL_FRAME_SIZE * 2 * sizeof(uint8_t), &input_frames[0], 0, nullptr, nullptr)); - clFinish(q); - return &input_frames[0]; -} - -ModelFrame::~ModelFrame() { - transform_destroy(&transform); +DrivingModelFrame::~DrivingModelFrame() { + deinit_transform(); loadyuv_destroy(&loadyuv); CL_CHECK(clReleaseMemObject(img_buffer_20hz_cl)); CL_CHECK(clReleaseMemObject(last_img_cl)); - CL_CHECK(clReleaseMemObject(v_cl)); - CL_CHECK(clReleaseMemObject(u_cl)); - CL_CHECK(clReleaseMemObject(y_cl)); CL_CHECK(clReleaseCommandQueue(q)); -} \ No newline at end of file +} + + +MonitoringModelFrame::MonitoringModelFrame(cl_device_id device_id, cl_context context) : ModelFrame(device_id, context) { + input_frames = std::make_unique(buf_size); + input_frame_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, buf_size, NULL, &err)); + + init_transform(device_id, context, MODEL_WIDTH, MODEL_HEIGHT); +} + +cl_mem* MonitoringModelFrame::prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection) { + run_transform(yuv_cl, MODEL_WIDTH, MODEL_HEIGHT, frame_width, frame_height, frame_stride, frame_uv_offset, projection); + clFinish(q); + return &y_cl; +} + +MonitoringModelFrame::~MonitoringModelFrame() { + deinit_transform(); + CL_CHECK(clReleaseCommandQueue(q)); +} diff --git a/selfdrive/modeld/models/commonmodel.h b/selfdrive/modeld/models/commonmodel.h index 91cbbcddd3c942..14409943e43481 100644 --- a/selfdrive/modeld/models/commonmodel.h +++ b/selfdrive/modeld/models/commonmodel.h @@ -2,6 +2,7 @@ #include #include +#include #include @@ -18,10 +19,54 @@ class ModelFrame { public: - ModelFrame(cl_device_id device_id, cl_context context); - ~ModelFrame(); - cl_mem* prepare(cl_mem yuv_cl, int width, int height, int frame_stride, int frame_uv_offset, const mat3& transform); - uint8_t* buffer_from_cl(cl_mem *in_frames); + ModelFrame(cl_device_id device_id, cl_context context) { + q = CL_CHECK_ERR(clCreateCommandQueue(context, device_id, 0, &err)); + } + virtual ~ModelFrame() {} + virtual cl_mem* prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection) { return NULL; } + uint8_t* buffer_from_cl(cl_mem *in_frames, int buffer_size) { + CL_CHECK(clEnqueueReadBuffer(q, *in_frames, CL_TRUE, 0, buffer_size, input_frames.get(), 0, nullptr, nullptr)); + clFinish(q); + return &input_frames[0]; + } + + int MODEL_WIDTH; + int MODEL_HEIGHT; + int MODEL_FRAME_SIZE; + int buf_size; + +protected: + cl_mem y_cl, u_cl, v_cl; + Transform transform; + cl_command_queue q; + std::unique_ptr input_frames; + + void init_transform(cl_device_id device_id, cl_context context, int model_width, int model_height) { + y_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, model_width * model_height, NULL, &err)); + u_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, (model_width / 2) * (model_height / 2), NULL, &err)); + v_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, (model_width / 2) * (model_height / 2), NULL, &err)); + transform_init(&transform, context, device_id); + } + + void deinit_transform() { + transform_destroy(&transform); + CL_CHECK(clReleaseMemObject(v_cl)); + CL_CHECK(clReleaseMemObject(u_cl)); + CL_CHECK(clReleaseMemObject(y_cl)); + } + + void run_transform(cl_mem yuv_cl, int model_width, int model_height, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection) { + transform_queue(&transform, q, + yuv_cl, frame_width, frame_height, frame_stride, frame_uv_offset, + y_cl, u_cl, v_cl, model_width, model_height, projection); + } +}; + +class DrivingModelFrame : public ModelFrame { +public: + DrivingModelFrame(cl_device_id device_id, cl_context context); + ~DrivingModelFrame(); + cl_mem* prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection); const int MODEL_WIDTH = 512; const int MODEL_HEIGHT = 256; @@ -30,10 +75,22 @@ class ModelFrame { const size_t frame_size_bytes = MODEL_FRAME_SIZE * sizeof(uint8_t); private: - Transform transform; LoadYUVState loadyuv; - cl_command_queue q; - cl_mem y_cl, u_cl, v_cl, img_buffer_20hz_cl, last_img_cl, input_frames_cl; + cl_mem img_buffer_20hz_cl, last_img_cl, input_frames_cl; cl_buffer_region region; - std::unique_ptr input_frames; +}; + +class MonitoringModelFrame : public ModelFrame { +public: + MonitoringModelFrame(cl_device_id device_id, cl_context context); + ~MonitoringModelFrame(); + cl_mem* prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection); + + const int MODEL_WIDTH = 1440; + const int MODEL_HEIGHT = 960; + const int MODEL_FRAME_SIZE = MODEL_WIDTH * MODEL_HEIGHT; + const int buf_size = MODEL_FRAME_SIZE; + +private: + cl_mem input_frame_cl; }; diff --git a/selfdrive/modeld/models/commonmodel.pxd b/selfdrive/modeld/models/commonmodel.pxd index 676defe15c3d1b..d2a8fb4dcd9fd6 100644 --- a/selfdrive/modeld/models/commonmodel.pxd +++ b/selfdrive/modeld/models/commonmodel.pxd @@ -14,6 +14,13 @@ cdef extern from "common/clutil.h": cdef extern from "selfdrive/modeld/models/commonmodel.h": cppclass ModelFrame: int buf_size - ModelFrame(cl_device_id, cl_context) + unsigned char * buffer_from_cl(cl_mem*, int); cl_mem * prepare(cl_mem, int, int, int, int, mat3) - unsigned char * buffer_from_cl(cl_mem*); + + cppclass DrivingModelFrame: + int buf_size + DrivingModelFrame(cl_device_id, cl_context) + + cppclass MonitoringModelFrame: + int buf_size + MonitoringModelFrame(cl_device_id, cl_context) diff --git a/selfdrive/modeld/models/commonmodel_pyx.pyx b/selfdrive/modeld/models/commonmodel_pyx.pyx index e6ae349e005836..b75408654428b1 100644 --- a/selfdrive/modeld/models/commonmodel_pyx.pyx +++ b/selfdrive/modeld/models/commonmodel_pyx.pyx @@ -9,7 +9,7 @@ from libc.stdint cimport uintptr_t 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, ModelFrame as cppModelFrame +from .commonmodel cimport mat3, ModelFrame as cppModelFrame, DrivingModelFrame as cppDrivingModelFrame, MonitoringModelFrame as cppMonitoringModelFrame cdef class CLContext(BaseCLContext): @@ -31,11 +31,10 @@ cdef class CLMem: def cl_from_visionbuf(VisionBuf buf): return CLMem.create(&buf.buf.buf_cl) + cdef class ModelFrame: cdef cppModelFrame * frame - - def __cinit__(self, CLContext context): - self.frame = new cppModelFrame(context.device_id, context.context) + cdef int buf_size def __dealloc__(self): del self.frame @@ -49,5 +48,23 @@ cdef class ModelFrame: def buffer_from_cl(self, CLMem in_frames): cdef unsigned char * data2 - data2 = self.frame.buffer_from_cl(in_frames.mem) - return np.asarray( data2) + data2 = self.frame.buffer_from_cl(in_frames.mem, self.buf_size) + return np.asarray( data2) + + +cdef class DrivingModelFrame(ModelFrame): + cdef cppDrivingModelFrame * _frame + + def __cinit__(self, CLContext context): + self._frame = new cppDrivingModelFrame(context.device_id, context.context) + self.frame = (self._frame) + self.buf_size = self._frame.buf_size + +cdef class MonitoringModelFrame(ModelFrame): + cdef cppMonitoringModelFrame * _frame + + def __cinit__(self, CLContext context): + self._frame = new cppMonitoringModelFrame(context.device_id, context.context) + self.frame = (self._frame) + self.buf_size = self._frame.buf_size + diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index a57e5dd2259b8d..777aa8aa7e4d35 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:9dc64f5d1e7d6b67f1d4659a3483f03b4324b4c7b969a5ba90c4e37e62bf6fce -size 50320584 +oid sha256:72d3d6f8d3c98f5431ec86be77b6350d7d4f43c25075c0106f1d1e7ec7c77668 +size 49096168 diff --git a/selfdrive/modeld/parse_model_outputs.py b/selfdrive/modeld/parse_model_outputs.py index 4367e9db8a2bcd..b699c5fd13593f 100644 --- a/selfdrive/modeld/parse_model_outputs.py +++ b/selfdrive/modeld/parse_model_outputs.py @@ -96,8 +96,6 @@ def parse_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]: out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH)) if 'lat_planner_solution' in outs: self.parse_mdn('lat_planner_solution', outs, in_N=0, out_N=0, out_shape=(ModelConstants.IDX_N,ModelConstants.LAT_PLANNER_SOLUTION_WIDTH)) - if 'desired_curvature' in outs: - self.parse_mdn('desired_curvature', outs, in_N=0, out_N=0, out_shape=(ModelConstants.DESIRED_CURV_WIDTH,)) for k in ['lead_prob', 'lane_lines_prob', 'meta']: self.parse_binary_crossentropy(k, outs) self.parse_categorical_crossentropy('desire_state', outs, out_shape=(ModelConstants.DESIRE_PRED_WIDTH,)) diff --git a/selfdrive/modeld/runners/ort_helpers.py b/selfdrive/modeld/runners/ort_helpers.py index ad6efed397670d..26afb035624a29 100644 --- a/selfdrive/modeld/runners/ort_helpers.py +++ b/selfdrive/modeld/runners/ort_helpers.py @@ -10,8 +10,7 @@ def attributeproto_fp16_to_fp32(attr): attr.data_type = 1 attr.raw_data = float32_list.astype(np.float32).tobytes() -def convert_fp16_to_fp32(onnx_path): - model = onnx.load(onnx_path) +def convert_fp16_to_fp32(model): for i in model.graph.initializer: if i.data_type == 10: attributeproto_fp16_to_fp32(i) @@ -33,6 +32,5 @@ def make_onnx_cpu_runner(model_path): options.intra_op_num_threads = 4 options.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL - model_data = convert_fp16_to_fp32(model_path) + model_data = convert_fp16_to_fp32(onnx.load(model_path)) return ort.InferenceSession(model_data, options, providers=['CPUExecutionProvider']) - diff --git a/selfdrive/pandad/panda_comms.cc b/selfdrive/pandad/panda_comms.cc index 59908f0cde23d7..8a20f397d31d32 100644 --- a/selfdrive/pandad/panda_comms.cc +++ b/selfdrive/pandad/panda_comms.cc @@ -36,7 +36,7 @@ PandaUsbHandle::PandaUsbHandle(std::string serial) : PandaCommsHandle(serial) { for (size_t i = 0; i < num_devices; ++i) { libusb_device_descriptor desc; libusb_get_device_descriptor(dev_list[i], &desc); - if (desc.idVendor == 0xbbaa && desc.idProduct == 0xddcc) { + if (desc.idVendor == 0x3801 && desc.idProduct == 0xddcc) { int ret = libusb_open(dev_list[i], &dev_handle); if (dev_handle == NULL || ret < 0) { goto fail; } @@ -110,7 +110,7 @@ std::vector PandaUsbHandle::list() { libusb_device *device = dev_list[i]; libusb_device_descriptor desc; libusb_get_device_descriptor(device, &desc); - if (desc.idVendor == 0xbbaa && desc.idProduct == 0xddcc) { + if (desc.idVendor == 0x3801 && desc.idProduct == 0xddcc) { libusb_device_handle *handle = NULL; int ret = libusb_open(device, &handle); if (ret < 0) { goto finish; } diff --git a/selfdrive/pandad/pandad.cc b/selfdrive/pandad/pandad.cc index dd970dd16ce09d..bf2a465d78127a 100644 --- a/selfdrive/pandad/pandad.cc +++ b/selfdrive/pandad/pandad.cc @@ -416,6 +416,7 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control) if (ir_pwr != prev_ir_pwr || sm.frame % 100 == 0 || ir_pwr >= 50.0) { panda->set_ir_pwr(ir_pwr); + Hardware::set_ir_power(ir_pwr); prev_ir_pwr = ir_pwr; } } diff --git a/selfdrive/test/process_replay/migration.py b/selfdrive/test/process_replay/migration.py index 5376f91aee427f..d531b3b7edc807 100644 --- a/selfdrive/test/process_replay/migration.py +++ b/selfdrive/test/process_replay/migration.py @@ -107,7 +107,7 @@ def migrate_longitudinalPlan(msgs): if msg.which() != 'longitudinalPlan': continue new_msg = msg.as_builder() - new_msg.longitudinalPlan.aTarget, new_msg.longitudinalPlan.shouldStop = get_accel_from_plan(CP, msg.longitudinalPlan.speeds, msg.longitudinalPlan.accels) + new_msg.longitudinalPlan.aTarget, new_msg.longitudinalPlan.shouldStop = get_accel_from_plan(msg.longitudinalPlan.speeds, msg.longitudinalPlan.accels) ops.append((index, new_msg.as_reader())) return ops, [], [] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index d4892b51f25e2d..3120a4de3a144b 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -7a1b6253e715cec2a254c3e7b6839d6f2bd06fb1 +1f37082d56a60f20ba9e36b702a23cbdde3caca7 diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index c3c2461790c3ad..25aaa95f0f18fd 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -377,7 +377,7 @@ def test_model_execution_timings(self): ] for (s, instant_max, avg_max) in cfgs: ts = [getattr(m, s).modelExecutionTime for m in self.msgs[s]] - # TODO some tinygrad init happens in first iteration + # TODO some init can happen in first iteration ts = ts[1:] 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)}" diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 22bf4760bfbdc8..c851d7a969332e 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -67,14 +67,13 @@ if GetOption('extras'): qt_src.remove("main.cc") # replaced by test_runner qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs) -if GetOption('extras') and arch != "Darwin": +if GetOption('extras'): qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs) # spinner and text window qt_env.Program("_text", ["qt/text.cc"], LIBS=qt_libs) qt_env.Program("_spinner", ["qt/spinner.cc"], LIBS=qt_libs) - # setup and factory resetter qt_env.Program("qt/setup/reset", ["qt/setup/reset.cc"], LIBS=qt_libs) qt_env.Program("qt/setup/setup", ["qt/setup/setup.cc", asset_obj], @@ -83,29 +82,30 @@ if GetOption('extras') and arch != "Darwin": # build updater UI qt_env.Program("qt/setup/updater", ["qt/setup/updater.cc", asset_obj], LIBS=qt_libs) - # build installers - senv = qt_env.Clone() - senv['LINKFLAGS'].append('-Wl,-strip-debug') - - release = "release3" - installers = [ - ("openpilot", release), - ("openpilot_test", f"{release}-staging"), - ("openpilot_nightly", "nightly"), - ("openpilot_internal", "nightly-dev"), - ] - - cont = senv.Command(f"installer/continue_openpilot.o", f"installer/continue_openpilot.sh", - "ld -r -b binary -o $TARGET $SOURCE") - for name, branch in installers: - d = {'BRANCH': f"'\"{branch}\"'"} - if "internal" in name: - d['INTERNAL'] = "1" - - obj = senv.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d) - f = senv.Program(f"installer/installers/installer_{name}", [obj, cont], LIBS=qt_libs) - # keep installers small - assert f[0].get_size() < 370*1e3 + if arch != "Darwin": + # build installers + senv = qt_env.Clone() + senv['LINKFLAGS'].append('-Wl,-strip-debug') + + release = "release3" + installers = [ + ("openpilot", release), + ("openpilot_test", f"{release}-staging"), + ("openpilot_nightly", "nightly"), + ("openpilot_internal", "nightly-dev"), + ] + + cont = senv.Command(f"installer/continue_openpilot.o", f"installer/continue_openpilot.sh", + "ld -r -b binary -o $TARGET $SOURCE") + for name, branch in installers: + d = {'BRANCH': f"'\"{branch}\"'"} + if "internal" in name: + d['INTERNAL'] = "1" + + obj = senv.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d) + f = senv.Program(f"installer/installers/installer_{name}", [obj, cont], LIBS=qt_libs) + # keep installers small + assert f[0].get_size() < 370*1e3 # build watch3 if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): diff --git a/selfdrive/ui/qt/network/wifi_manager.cc b/selfdrive/ui/qt/network/wifi_manager.cc index fd9ee17078c86c..17172106345798 100644 --- a/selfdrive/ui/qt/network/wifi_manager.cc +++ b/selfdrive/ui/qt/network/wifi_manager.cc @@ -203,7 +203,7 @@ void WifiManager::connect(const Network &n, const bool is_hidden, const QString connection["ipv4"]["dns-priority"] = 600; connection["ipv6"]["method"] = "ignore"; - call(NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "AddConnection", QVariant::fromValue(connection)); + asyncCall(NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "AddConnection", QVariant::fromValue(connection)); } void WifiManager::deactivateConnectionBySsid(const QString &ssid) { @@ -330,6 +330,10 @@ void WifiManager::initConnections() { lteConnectionPath = path; } } + + if (!isKnownConnection(tethering_ssid)) { + addTetheringConnection(); + } } std::optional WifiManager::activateWifiConnection(const QString &ssid) { @@ -399,9 +403,13 @@ void WifiManager::updateGsmSettings(bool roaming, QString apn, bool metered) { } if (changes) { - call(lteConnectionPath.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "UpdateUnsaved", QVariant::fromValue(settings)); // update is temporary - deactivateConnection(lteConnectionPath); - activateModemConnection(lteConnectionPath); + QDBusPendingCall pending_call = asyncCall(lteConnectionPath.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "UpdateUnsaved", QVariant::fromValue(settings)); // update is temporary + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending_call); + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher]() { + deactivateConnection(lteConnectionPath); + activateModemConnection(lteConnectionPath); + watcher->deleteLater(); + }); } } } @@ -434,10 +442,7 @@ void WifiManager::addTetheringConnection() { connection["ipv4"]["route-metric"] = 1100; connection["ipv6"]["method"] = "ignore"; - auto path = call(NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "AddConnection", QVariant::fromValue(connection)); - if (!path.path().isEmpty()) { - knownConnections[path] = tethering_ssid; - } + asyncCall(NM_DBUS_PATH_SETTINGS, NM_DBUS_INTERFACE_SETTINGS, "AddConnection", QVariant::fromValue(connection)); } void WifiManager::tetheringActivated(QDBusPendingCallWatcher *call) { @@ -453,10 +458,6 @@ void WifiManager::tetheringActivated(QDBusPendingCallWatcher *call) { void WifiManager::setTetheringEnabled(bool enabled) { if (enabled) { - if (!isKnownConnection(tethering_ssid)) { - addTetheringConnection(); - } - auto pending_call = activateWifiConnection(tethering_ssid); if (pending_call) { @@ -478,9 +479,6 @@ bool WifiManager::isTetheringEnabled() { } QString WifiManager::getTetheringPassword() { - if (!isKnownConnection(tethering_ssid)) { - addTetheringConnection(); - } const QDBusObjectPath &path = getConnectionPath(tethering_ssid); if (!path.path().isEmpty()) { QDBusReply> response = call(path.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "GetSecrets", "802-11-wireless-security"); diff --git a/system/athena/athenad.py b/system/athena/athenad.py index 2d9ad110aadd57..2f455981cce3b2 100755 --- a/system/athena/athenad.py +++ b/system/athena/athenad.py @@ -100,9 +100,9 @@ def from_dict(cls, d: dict) -> UploadItem: upload_queue: Queue[UploadItem] = queue.Queue() low_priority_send_queue: Queue[str] = queue.Queue() log_recv_queue: Queue[str] = queue.Queue() +cancelled_uploads: set[str] = set() cur_upload_items: dict[int, UploadItem | None] = {} -cur_upload_items_lock = threading.Lock() def strip_zst_extension(fn: str) -> str: @@ -130,9 +130,8 @@ def initialize(upload_queue: Queue[UploadItem]) -> None: @staticmethod def cache(upload_queue: Queue[UploadItem]) -> None: try: - with upload_queue.mutex: - items = [asdict(item) for item in upload_queue.queue] - + queue: list[UploadItem | None] = list(upload_queue.queue) + items = [asdict(i) for i in queue if i is not None and (i.id not in cancelled_uploads)] Params().put("AthenadUploadQueue", json.dumps(items)) except Exception: cloudlog.exception("athena.UploadQueueCache.cache.exception") @@ -199,13 +198,11 @@ def retry_upload(tid: int, end_event: threading.Event, increase_count: bool = Tr progress=0, current=False ) - - with cur_upload_items_lock: - upload_queue.put_nowait(item) - cur_upload_items[tid] = None - + upload_queue.put_nowait(item) UploadQueueCache.cache(upload_queue) + cur_upload_items[tid] = None + for _ in range(RETRY_DELAY): time.sleep(1) if end_event.is_set(): @@ -224,8 +221,7 @@ def cb(sm, item, tid, end_event: threading.Event, sz: int, cur: int) -> None: if end_event.is_set(): raise AbortTransferException - with cur_upload_items_lock: - cur_upload_items[tid] = replace(item, progress=cur / sz if sz else 1) + cur_upload_items[tid] = replace(item, progress=cur / sz if sz else 1) def upload_handler(end_event: threading.Event) -> None: @@ -233,10 +229,14 @@ def upload_handler(end_event: threading.Event) -> None: tid = threading.get_ident() while not end_event.is_set(): + cur_upload_items[tid] = None + try: - with cur_upload_items_lock: - cur_upload_items[tid] = None - cur_upload_items[tid] = item = replace(upload_queue.get(timeout=1), current=True) + cur_upload_items[tid] = item = replace(upload_queue.get(timeout=1), current=True) + + if item.id in cancelled_uploads: + cancelled_uploads.remove(item.id) + continue # Remove item if too old age = datetime.now() - datetime.fromtimestamp(item.created_at / 1000) @@ -415,10 +415,8 @@ def uploadFilesToUrls(files_data: list[UploadFileDict]) -> UploadFilesToUrlRespo @dispatcher.add_method def listUploadQueue() -> list[UploadItemDict]: - with cur_upload_items_lock, upload_queue.mutex: - items = list(upload_queue.queue) + [item for item in cur_upload_items.values() if item is not None] - - return [asdict(item) for item in items] + items = list(upload_queue.queue) + list(cur_upload_items.values()) + return [asdict(i) for i in items if (i is not None) and (i.id not in cancelled_uploads)] @dispatcher.add_method @@ -426,14 +424,13 @@ def cancelUpload(upload_id: str | list[str]) -> dict[str, int | str]: if not isinstance(upload_id, list): upload_id = [upload_id] - with upload_queue.mutex: - remaining_items = [item for item in upload_queue.queue if item.id not in upload_id] - if len(remaining_items) == len(upload_queue.queue): - return {"success": 0, "error": "not found"} + uploading_ids = {item.id for item in list(upload_queue.queue)} + cancelled_ids = uploading_ids.intersection(upload_id) + if len(cancelled_ids) == 0: + return {"success": 0, "error": "not found"} - upload_queue.queue.clear() - upload_queue.queue.extend(remaining_items) - return {"success": 1} + cancelled_uploads.update(cancelled_ids) + return {"success": 1} @dispatcher.add_method def setRouteViewed(route: str) -> dict[str, int | str]: diff --git a/system/athena/tests/test_athenad.py b/system/athena/tests/test_athenad.py index cee37064b9cfad..a6bfc689306533 100644 --- a/system/athena/tests/test_athenad.py +++ b/system/athena/tests/test_athenad.py @@ -78,6 +78,7 @@ def setup_method(self): athenad.upload_queue = queue.Queue() athenad.cur_upload_items.clear() + athenad.cancelled_uploads.clear() for i in os.listdir(Paths.log_root()): p = os.path.join(Paths.log_root(), i) @@ -281,10 +282,13 @@ def test_cancel_upload(self): athenad.upload_queue.put_nowait(item) dispatcher["cancelUpload"](item.id) + assert item.id in athenad.cancelled_uploads + self._wait_for_upload() time.sleep(0.1) assert athenad.upload_queue.qsize() == 0 + assert len(athenad.cancelled_uploads) == 0 @with_upload_handler def test_cancel_expiry(self): @@ -327,7 +331,7 @@ def test_list_upload_queue(self): assert items[0] == asdict(item) assert not items[0]['current'] - dispatcher["cancelUpload"](item.id) + athenad.cancelled_uploads.add(item.id) items = dispatcher["listUploadQueue"]() assert len(items) == 0 @@ -339,7 +343,7 @@ def test_upload_queue_persistence(self): athenad.upload_queue.put_nowait(item2) # Ensure canceled items are not persisted - dispatcher["cancelUpload"](item2.id) + athenad.cancelled_uploads.add(item2.id) # serialize item athenad.UploadQueueCache.cache(athenad.upload_queue) diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index b0193cf5dfcf67..366feae0b2e339 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -89,12 +89,14 @@ void CameraBuf::init(cl_device_id device_id, cl_context context, SpectraCamera * vipc_server->create_buffers_with_sizes(stream_type, VIPC_BUFFER_COUNT, out_img_width, out_img_height, nv12_size, cam->stride, cam->uv_offset); LOGD("created %d YUV vipc buffers with size %dx%d", VIPC_BUFFER_COUNT, cam->stride, cam->y_height); - imgproc = new ImgProc(device_id, context, this, sensor, cam->cc.camera_num, cam->stride, cam->uv_offset); + if (is_raw) imgproc = new ImgProc(device_id, context, this, sensor, cam->cc.camera_num, cam->stride, cam->uv_offset); } CameraBuf::~CameraBuf() { - for (int i = 0; i < frame_buf_count; i++) { - camera_bufs_raw[i].free(); + if (camera_bufs_raw != nullptr) { + for (int i = 0; i < frame_buf_count; i++) { + camera_bufs_raw[i].free(); + } } if (imgproc) delete imgproc; } diff --git a/system/camerad/cameras/process_raw.cl b/system/camerad/cameras/process_raw.cl index 6f6612fab0328a..ff6060d855d07c 100644 --- a/system/camerad/cameras/process_raw.cl +++ b/system/camerad/cameras/process_raw.cl @@ -19,6 +19,17 @@ #endif float get_vignetting_s(float r) { +#if defined(VIGNETTE_PROFILE_4DT6MM) + if (r < 100000) { + return 1.0f + 0.0000013f*r; + } else if (r < 250000) { + return 1.02f + 0.0000011f*r; + } else if (r < 400000) { + return 0.92f + 0.0000015f*r; + } else { + return 0.44f + 0.0000027f*r; + } +#elif defined(VIGNETTE_PROFILE_8DT0MM) if (r < 62500) { return (1.0f + 0.0000008f*r); } else if (r < 490000) { @@ -28,6 +39,9 @@ float get_vignetting_s(float r) { } else { return (0.53503625f + 0.0000000000022f*r*r); } +#else + return 1.0f; +#endif } int4 parse_12bit(uchar8 pvs) { @@ -65,7 +79,7 @@ __kernel void process_raw(const __global uchar * in, __global uchar * out, int e #if VIGNETTING int gx = (gid_x*2 - RGB_WIDTH/2); int gy = (gid_y*2 - RGB_HEIGHT/2); - const float vignette_factor = get_vignetting_s((gx*gx + gy*gy) / VIGNETTE_RSZ); + const float vignette_factor = get_vignetting_s(gx*gx + gy*gy); #else const float vignette_factor = 1.0; #endif diff --git a/system/camerad/cameras/spectra.cc b/system/camerad/cameras/spectra.cc index 83b331cf4a8aac..3f416839012fc7 100644 --- a/system/camerad/cameras/spectra.cc +++ b/system/camerad/cameras/spectra.cc @@ -196,9 +196,9 @@ void SpectraMaster::init() { assert(isp_fd >= 0); LOGD("opened isp"); - //icp_fd = open_v4l_by_name_and_index("cam-icp"); - //assert(icp_fd >= 0); - //LOGD("opened icp"); + icp_fd = open_v4l_by_name_and_index("cam-icp"); + assert(icp_fd >= 0); + LOGD("opened icp"); // query ISP for MMU handles LOG("-- Query for MMU handles"); @@ -215,7 +215,6 @@ void SpectraMaster::init() { cdm_iommu = isp_query_cap_cmd.cdm_iommu.non_secure; // query ICP for MMU handles - /* struct cam_icp_query_cap_cmd icp_query_cap_cmd = {0}; query_cap_cmd.caps_handle = (uint64_t)&icp_query_cap_cmd; query_cap_cmd.size = sizeof(icp_query_cap_cmd); @@ -223,7 +222,6 @@ void SpectraMaster::init() { assert(ret == 0); LOGD("using ICP MMU handle: %x", icp_query_cap_cmd.dev_iommu_handle.non_secure); icp_device_iommu = icp_query_cap_cmd.dev_iommu_handle.non_secure; - */ // subscribe LOG("-- Subscribing"); @@ -712,13 +710,13 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) { } sync_objs[i] = sync_create.sync_obj; - /* - ret = do_cam_control(m->cam_sync_fd, CAM_SYNC_CREATE, &sync_create, sizeof(sync_create)); - if (ret != 0) { - LOGE("failed to create fence: %d %d", ret, sync_create.sync_obj); + if (icp_dev_handle > 0) { + ret = do_cam_control(m->cam_sync_fd, CAM_SYNC_CREATE, &sync_create, sizeof(sync_create)); + if (ret != 0) { + LOGE("failed to create fence: %d %d", ret, sync_create.sync_obj); + } + sync_objs_bps_out[i] = sync_create.sync_obj; } - sync_objs_bps_out[i] = sync_create.sync_obj; - */ // schedule request with camera request manager struct cam_req_mgr_sched_request req_mgr_sched_request = {0}; @@ -746,8 +744,10 @@ void SpectraCamera::camera_map_bufs() { mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE; mem_mgr_map_cmd.mmu_hdls[0] = m->device_iommu; mem_mgr_map_cmd.num_hdl = 1; - //mem_mgr_map_cmd.mmu_hdls[1] = m->icp_device_iommu; - //mem_mgr_map_cmd.num_hdl = 2; + if (icp_dev_handle > 0) { + mem_mgr_map_cmd.num_hdl = 2; + mem_mgr_map_cmd.mmu_hdls[1] = m->icp_device_iommu; + } if (is_raw) { // RAW bayer images @@ -899,8 +899,6 @@ void SpectraCamera::configISP() { } void SpectraCamera::configICP() { - if (!enabled) return; - /* Configures both the ICP and BPS. */ @@ -1048,6 +1046,10 @@ void SpectraCamera::camera_close() { // release devices LOGD("-- Release devices"); + if (icp_dev_handle > 0) { + ret = device_control(m->icp_fd, CAM_RELEASE_DEV, session_handle, icp_dev_handle); + LOGD("release icp: %d", ret); + } ret = device_control(m->isp_fd, CAM_RELEASE_DEV, session_handle, isp_dev_handle); LOGD("release isp: %d", ret); ret = device_control(csiphy_fd, CAM_RELEASE_DEV, session_handle, csiphy_dev_handle); diff --git a/system/camerad/cameras/spectra.h b/system/camerad/cameras/spectra.h index 476722b664a8fb..689fcb9cc38f2b 100644 --- a/system/camerad/cameras/spectra.h +++ b/system/camerad/cameras/spectra.h @@ -22,8 +22,9 @@ const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py // CSLDeviceType/CSLPacketOpcodesIFE from camx // cam_packet_header.op_code = (device << 24) | (opcode); -#define CSLDeviceTypeImageSensor (0x1 << 24) -#define CSLDeviceTypeIFE (0xF << 24) +#define CSLDeviceTypeImageSensor (0x01 << 24) +#define CSLDeviceTypeIFE (0x0F << 24) +#define CSLDeviceTypeBPS (0x10 << 24) #define OpcodesIFEInitialConfig 0x0 #define OpcodesIFEUpdate 0x1 diff --git a/system/camerad/sensors/ar0231_cl.h b/system/camerad/sensors/ar0231_cl.h index 8e96bbce5b6aad..c79242543b27f2 100644 --- a/system/camerad/sensors/ar0231_cl.h +++ b/system/camerad/sensors/ar0231_cl.h @@ -1,9 +1,10 @@ #if SENSOR_ID == 1 +#define VIGNETTE_PROFILE_8DT0MM + #define BIT_DEPTH 12 #define PV_MAX 4096 #define BLACK_LVL 168 -#define VIGNETTE_RSZ 1.0f float4 normalize_pv(int4 parsed, float vignette_factor) { float4 pv = (convert_float4(parsed) - BLACK_LVL) / (PV_MAX - BLACK_LVL); @@ -30,4 +31,4 @@ float3 apply_gamma(float3 rgb, int expo_time) { ((rk * (rgb-mp) * (gamma_k*mp+gamma_b) * (1+1/(rk*mp)) / (1-rk*(rgb-mp))) + gamma_k*mp + gamma_b); } -#endif \ No newline at end of file +#endif diff --git a/system/camerad/sensors/os04c10_cl.h b/system/camerad/sensors/os04c10_cl.h index 3da3fab8dfe146..3b5cf88839dc51 100644 --- a/system/camerad/sensors/os04c10_cl.h +++ b/system/camerad/sensors/os04c10_cl.h @@ -1,13 +1,13 @@ #if SENSOR_ID == 3 #define BGGR +#define VIGNETTE_PROFILE_4DT6MM #define BIT_DEPTH 12 #define PV_MAX10 1023 #define PV_MAX12 4095 #define PV_MAX16 65536 // gamma curve is calibrated to 16bit #define BLACK_LVL 48 -#define VIGNETTE_RSZ 2.2545f float combine_dual_pvs(float lv, float sv, int expo_time) { float svc = fmax(sv * expo_time, (float)(64 * (PV_MAX10 - BLACK_LVL))); diff --git a/system/camerad/sensors/ox03c10_cl.h b/system/camerad/sensors/ox03c10_cl.h index f1fbd16ccbd008..c8cec7cf8a1477 100644 --- a/system/camerad/sensors/ox03c10_cl.h +++ b/system/camerad/sensors/ox03c10_cl.h @@ -1,8 +1,9 @@ #if SENSOR_ID == 2 +#define VIGNETTE_PROFILE_8DT0MM + #define BIT_DEPTH 12 #define BLACK_LVL 64 -#define VIGNETTE_RSZ 1.0f float ox_lut_func(int x) { if (x < 512) { diff --git a/system/camerad/test/debug.sh b/system/camerad/test/debug.sh index 44ff0ffa89f984..8bd8d9d4f05c56 100755 --- a/system/camerad/test/debug.sh +++ b/system/camerad/test/debug.sh @@ -10,7 +10,7 @@ echo 0 | sudo tee /sys/module/cam_debug_util/parameters/debug_mdl sudo dmesg -C scons -u -j8 --minimal . export DEBUG_FRAMES=1 -#export DISABLE_ROAD=1 DISABLE_WIDE_ROAD=1 -export DISABLE_DRIVER=1 -#export LOGPRINT=debug +export DISABLE_ROAD=1 DISABLE_WIDE_ROAD=1 +#export DISABLE_DRIVER=1 +export LOGPRINT=debug ./camerad diff --git a/system/camerad/test/icp_debug.sh b/system/camerad/test/icp_debug.sh new file mode 100755 index 00000000000000..ebeef9bf8f2d7c --- /dev/null +++ b/system/camerad/test/icp_debug.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -e + +cd /sys/kernel/debug/tracing +echo "" > trace +echo 1 > tracing_on +#echo Y > /sys/kernel/debug/camera_icp/a5_debug_q +echo 0x1 > /sys/kernel/debug/camera_icp/a5_debug_type +echo 1 > /sys/kernel/debug/tracing/events/camera/enable +echo 0xffffffff > /sys/kernel/debug/camera_icp/a5_debug_lvl +echo 1 > /sys/kernel/debug/tracing/events/camera/cam_icp_fw_dbg/enable + +cat /sys/kernel/debug/tracing/trace_pipe diff --git a/system/hardware/base.h b/system/hardware/base.h index ca24633a182a91..732f0f99e0acd0 100644 --- a/system/hardware/base.h +++ b/system/hardware/base.h @@ -28,6 +28,7 @@ class HardwareNone { static void reboot() {} static void poweroff() {} static void set_brightness(int percent) {} + static void set_ir_power(int percentage) {} static void set_display_power(bool on) {} static bool get_ssh_enabled() { return false; } diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py index 48c916b146a078..b6de91818e922e 100755 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -1,7 +1,9 @@ #!/usr/bin/env python3 +import fcntl import os import json import queue +import struct import threading import time from collections import OrderedDict, namedtuple @@ -59,6 +61,40 @@ def set_offroad_alert_if_changed(offroad_alert: str, show_alert: bool, extra_tex prev_offroad_states[offroad_alert] = (show_alert, extra_text) set_offroad_alert(offroad_alert, show_alert, extra_text) +def touch_thread(end_event): + count = 0 + + pm = messaging.PubMaster(["touch"]) + + event_format = "llHHi" + event_size = struct.calcsize(event_format) + event_frame = [] + + with open("/dev/input/by-path/platform-894000.i2c-event", "rb") as event_file: + fcntl.fcntl(event_file, fcntl.F_SETFL, os.O_NONBLOCK) + while not end_event.is_set(): + if (count % int(1. / DT_HW)) == 0: + event = event_file.read(event_size) + if event: + (sec, usec, etype, code, value) = struct.unpack(event_format, event) + if etype != 0 or code != 0 or value != 0: + touch = log.Touch.new_message() + touch.sec = sec + touch.usec = usec + touch.type = etype + touch.code = code + touch.value = value + event_frame.append(touch) + else: # end of frame, push new log + msg = messaging.new_message('touch', len(event_frame), valid=True) + msg.touch = event_frame + pm.send('touch', msg) + event_frame = [] + continue + + count += 1 + time.sleep(DT_HW) + def hw_state_thread(end_event, hw_queue): """Handles non critical hardware state, and sends over queue""" @@ -420,6 +456,9 @@ def main(): threading.Thread(target=hardware_thread, args=(end_event, hw_queue)), ] + if TICI: + threads.append(threading.Thread(target=touch_thread, args=(end_event,))) + for t in threads: t.start() diff --git a/system/hardware/tici/agnos.json b/system/hardware/tici/agnos.json index 430f86bfedf51d..d5002159d730ec 100644 --- a/system/hardware/tici/agnos.json +++ b/system/hardware/tici/agnos.json @@ -1,19 +1,19 @@ [ { "name": "boot", - "url": "https://commadist.azureedge.net/agnosupdate/boot-45e107ad65e6cc9ee95dc139f9ed11d56ef7f5f0657f579498a4a48f0a2f7ea3.img.xz", - "hash": "45e107ad65e6cc9ee95dc139f9ed11d56ef7f5f0657f579498a4a48f0a2f7ea3", - "hash_raw": "45e107ad65e6cc9ee95dc139f9ed11d56ef7f5f0657f579498a4a48f0a2f7ea3", - "size": 16418816, + "url": "https://commadist.azureedge.net/agnosupdate/boot-62d10fad3f057dad70a803c74b584296120ed4216a6b67c83f052f0186f73e50.img.xz", + "hash": "62d10fad3f057dad70a803c74b584296120ed4216a6b67c83f052f0186f73e50", + "hash_raw": "62d10fad3f057dad70a803c74b584296120ed4216a6b67c83f052f0186f73e50", + "size": 16422912, "sparse": false, "full_check": true, "has_ab": true }, { "name": "system", - "url": "https://commadist.azureedge.net/agnosupdate/system-c0d738052c77f97b10bcea111479ddabd3fde2653d50533dd0fa2b17bb7881e9.img.xz", - "hash": "c0d738052c77f97b10bcea111479ddabd3fde2653d50533dd0fa2b17bb7881e9", - "hash_raw": "c0d738052c77f97b10bcea111479ddabd3fde2653d50533dd0fa2b17bb7881e9", + "url": "https://commadist.azureedge.net/agnosupdate/system-70c493b8407ba3e315807042448cd957bcf53e81014440195e3dfd25fd60f53c.img.xz", + "hash": "70c493b8407ba3e315807042448cd957bcf53e81014440195e3dfd25fd60f53c", + "hash_raw": "70c493b8407ba3e315807042448cd957bcf53e81014440195e3dfd25fd60f53c", "size": 4404019200, "sparse": false, "full_check": false, @@ -21,9 +21,9 @@ }, { "name": "xbl", - "url": "https://commadist.azureedge.net/agnosupdate/xbl-bece486a68d9470c165e87955e451339cd86ada6ca2c7fde13c49144624ce030.img.xz", - "hash": "bece486a68d9470c165e87955e451339cd86ada6ca2c7fde13c49144624ce030", - "hash_raw": "bece486a68d9470c165e87955e451339cd86ada6ca2c7fde13c49144624ce030", + "url": "https://commadist.azureedge.net/agnosupdate/xbl-468f1ad6ab55e198647ff9191f91bd2918db9c0a3e27bae5673b4c5575c1254c.img.xz", + "hash": "468f1ad6ab55e198647ff9191f91bd2918db9c0a3e27bae5673b4c5575c1254c", + "hash_raw": "468f1ad6ab55e198647ff9191f91bd2918db9c0a3e27bae5673b4c5575c1254c", "size": 3282256, "sparse": false, "full_check": true, @@ -41,9 +41,9 @@ }, { "name": "xbl_config", - "url": "https://commadist.azureedge.net/agnosupdate/xbl_config-868b6f9aa98871dc50ef191a2d8f432578d1eca84f87d9185f8fb61242c3b66f.img.xz", - "hash": "868b6f9aa98871dc50ef191a2d8f432578d1eca84f87d9185f8fb61242c3b66f", - "hash_raw": "868b6f9aa98871dc50ef191a2d8f432578d1eca84f87d9185f8fb61242c3b66f", + "url": "https://commadist.azureedge.net/agnosupdate/xbl_config-92b675dc2862ed15c732d91d9eb307d7e852e349217db8bee8f8829db543686b.img.xz", + "hash": "92b675dc2862ed15c732d91d9eb307d7e852e349217db8bee8f8829db543686b", + "hash_raw": "92b675dc2862ed15c732d91d9eb307d7e852e349217db8bee8f8829db543686b", "size": 98124, "sparse": false, "full_check": true, @@ -51,9 +51,9 @@ }, { "name": "devcfg", - "url": "https://commadist.azureedge.net/agnosupdate/devcfg-c27dc9ab628015ef265e1204ca736b2838ec179e9ecdd79e2ddb59d984b78df1.img.xz", - "hash": "c27dc9ab628015ef265e1204ca736b2838ec179e9ecdd79e2ddb59d984b78df1", - "hash_raw": "c27dc9ab628015ef265e1204ca736b2838ec179e9ecdd79e2ddb59d984b78df1", + "url": "https://commadist.azureedge.net/agnosupdate/devcfg-225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180.img.xz", + "hash": "225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180", + "hash_raw": "225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180", "size": 40336, "sparse": false, "full_check": true, @@ -61,9 +61,9 @@ }, { "name": "aop", - "url": "https://commadist.azureedge.net/agnosupdate/aop-588bb60f0f8194d2df12f041e320a6dfeafae7209b312be3e4f6fe0744192837.img.xz", - "hash": "588bb60f0f8194d2df12f041e320a6dfeafae7209b312be3e4f6fe0744192837", - "hash_raw": "588bb60f0f8194d2df12f041e320a6dfeafae7209b312be3e4f6fe0744192837", + "url": "https://commadist.azureedge.net/agnosupdate/aop-f0fcf7611d0890a72984f15a516dd37fa532dfcb70d428a8406838cf74ce23d5.img.xz", + "hash": "f0fcf7611d0890a72984f15a516dd37fa532dfcb70d428a8406838cf74ce23d5", + "hash_raw": "f0fcf7611d0890a72984f15a516dd37fa532dfcb70d428a8406838cf74ce23d5", "size": 184364, "sparse": false, "full_check": true, diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index f1d1f1e717ed88..da89bb9002a052 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -4,6 +4,7 @@ #include #include #include +#include // for std::clamp #include "common/params.h" #include "common/util.h" @@ -25,7 +26,13 @@ class HardwareTici : public HardwareNone { } static cereal::InitData::DeviceType get_device_type() { - return (get_name() == "tizi") ? cereal::InitData::DeviceType::TIZI : (get_name() == "mici" ? cereal::InitData::DeviceType::MICI : cereal::InitData::DeviceType::TICI); + static const std::map device_map = { + {"tici", cereal::InitData::DeviceType::TICI}, + {"tizi", cereal::InitData::DeviceType::TIZI}, + {"mici", cereal::InitData::DeviceType::MICI} + }; + auto it = device_map.find(get_name()); + return it != device_map.end() ? it->second : cereal::InitData::DeviceType::UNKNOWN; } static int get_voltage() { return std::atoi(util::read_file("/sys/class/hwmon/hwmon1/in1_input").c_str()); } @@ -68,6 +75,28 @@ class HardwareTici : public HardwareNone { } } + static void set_ir_power(int percent) { + auto device = get_device_type(); + if (device == cereal::InitData::DeviceType::TICI || + device == cereal::InitData::DeviceType::TIZI) { + return; + } + + int value = util::map_val(std::clamp(percent, 0, 100), 0, 100, 0, 255); + + std::ofstream torch_brightness("/sys/class/leds/led:torch_2/brightness"); + if (torch_brightness.is_open()) { + torch_brightness << value << "\n"; + torch_brightness.close(); + } + + std::ofstream switch_brightness("/sys/class/leds/led:switch_2/brightness"); + if (switch_brightness.is_open()) { + switch_brightness << value << "\n"; + switch_brightness.close(); + } + } + static std::map get_init_logs() { std::map ret = { {"/BUILD", util::read_file("/BUILD")}, diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index def8267f4089bd..3409888b9deb1a 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -505,8 +505,8 @@ def configure_modem(self): pass # eSIM prime - if sim_id.startswith('8985235'): - dest = "/etc/NetworkManager/system-connections/esim.nmconnection" + dest = "/etc/NetworkManager/system-connections/esim.nmconnection" + if sim_id.startswith('8985235') and not os.path.exists(dest): with open(Path(__file__).parent/'esim.nmconnection') as f, tempfile.NamedTemporaryFile(mode='w') as tf: dat = f.read() dat = dat.replace("sim-id=", f"sim-id={sim_id}") diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index 8598b2faa20bbb..e1b9845c4c47bd 100644 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -33,7 +33,7 @@ def name(self): PROCS = [ Proc(['camerad'], 1.75, msgs=['roadCameraState', 'wideRoadCameraState', 'driverCameraState']), Proc(['modeld'], 1.12, atol=0.2, msgs=['modelV2']), - Proc(['dmonitoringmodeld'], 0.5, msgs=['driverStateV2']), + Proc(['dmonitoringmodeld'], 0.6, msgs=['driverStateV2']), Proc(['encoderd'], 0.23, msgs=[]), ] diff --git a/system/manager/process_config.py b/system/manager/process_config.py index d26fc19afec890..004180c9b56b56 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -63,17 +63,20 @@ def and_(*fns): procs = [ DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"), - NativeProcess("camerad", "system/camerad", ["./camerad"], driverview), + NativeProcess("camerad", "system/camerad", ["./camerad"], driverview, enabled=not WEBCAM), + PythonProcess("webcamerad", "tools.webcam.camerad", driverview, enabled=WEBCAM), NativeProcess("logcatd", "system/logcatd", ["./logcatd"], only_onroad), NativeProcess("proclogd", "system/proclogd", ["./proclogd"], only_onroad), PythonProcess("logmessaged", "system.logmessaged", always_run), PythonProcess("micd", "system.micd", iscar), PythonProcess("timed", "system.timed", always_run, enabled=not PC), - NativeProcess("dmonitoringmodeld", "selfdrive/modeld", ["./dmonitoringmodeld"], driverview, enabled=(not PC or WEBCAM)), + # TODO Make python process once TG allows opening QCOM from child proc + NativeProcess("dmonitoringmodeld", "selfdrive/modeld", ["./dmonitoringmodeld"], driverview, enabled=(WEBCAM or not PC)), NativeProcess("encoderd", "system/loggerd", ["./encoderd"], only_onroad), NativeProcess("stream_encoderd", "system/loggerd", ["./encoderd", "--stream"], notcar), NativeProcess("loggerd", "system/loggerd", ["./loggerd"], logging), + # TODO Make python process once TG allows opening QCOM from child proc NativeProcess("modeld", "selfdrive/modeld", ["./modeld"], only_onroad), NativeProcess("sensord", "system/sensord", ["./sensord"], only_onroad, enabled=not PC), NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None)), @@ -87,7 +90,7 @@ def and_(*fns): PythonProcess("selfdrived", "selfdrive.selfdrived.selfdrived", 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("dmonitoringd", "selfdrive.monitoring.dmonitoringd", driverview, enabled=(WEBCAM or not PC)), PythonProcess("qcomgpsd", "system.qcomgpsd.qcomgpsd", qcomgps, enabled=TICI), PythonProcess("pandad", "selfdrive.pandad.pandad", always_run), PythonProcess("paramsd", "selfdrive.locationd.paramsd", only_onroad), diff --git a/system/timed.py b/system/timed.py index 3eb84353ad6f2c..de9b0ffb598386 100755 --- a/system/timed.py +++ b/system/timed.py @@ -13,7 +13,7 @@ def set_time(new_time): diff = datetime.datetime.now() - new_time - if diff < datetime.timedelta(seconds=10): + if abs(diff) < datetime.timedelta(seconds=10): cloudlog.debug(f"Time diff too small: {diff}") return diff --git a/tinygrad_repo b/tinygrad_repo index bfd980da7d2c2b..480e5e7a1292bf 160000 --- a/tinygrad_repo +++ b/tinygrad_repo @@ -1 +1 @@ -Subproject commit bfd980da7d2c2bab5b073127442c361922032ba1 +Subproject commit 480e5e7a1292bf2f84e18edffd06a985c4b48e65 diff --git a/tools/CTF.md b/tools/CTF.md index a14a41d55da106..32891cd389a0fc 100644 --- a/tools/CTF.md +++ b/tools/CTF.md @@ -11,7 +11,7 @@ Welcome to the first part of the comma CTF! getting started ```bash -# start the route reply +# start the route replay cd tools/replay ./replay '0c7f0c7f0c7f0c7f|2021-10-13--13-00-00' --dcam --ecam diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 2950a67ff225f1..eb0af5b64a52a5 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -248,6 +248,7 @@ std::tuple BinaryView::getSelection(QModelIndex index) { void BinaryViewModel::refresh() { beginResetModel(); + bit_flip_tracker = {}; items.clear(); if (auto dbc_msg = dbc()->msg(msg_id)) { row_count = dbc_msg->size; @@ -295,7 +296,7 @@ void BinaryViewModel::updateItem(int row, int col, uint8_t val, const QColor &co void BinaryViewModel::updateState() { const auto &last_msg = can->lastMessage(msg_id); const auto &binary = last_msg.dat; - // data size may changed. + // Handle size changes in binary data if (binary.size() > row_count) { beginInsertRows({}, row_count, binary.size() - 1); row_count = binary.size(); @@ -303,26 +304,74 @@ void BinaryViewModel::updateState() { endInsertRows(); } - const double max_f = 255.0; - const double factor = 0.25; - const double scaler = max_f / log2(1.0 + factor); - for (int i = 0; i < binary.size(); ++i) { + auto &bit_flips = heatmap_live_mode ? last_msg.bit_flip_counts : getBitFlipChanges(binary.size()); + // Find the maximum bit flip count across the message + uint32_t max_bit_flip_count = 1; // Default to 1 to avoid division by zero + for (const auto &row : bit_flips) { + for (uint32_t count : row) { + max_bit_flip_count = std::max(max_bit_flip_count, count); + } + } + + const double max_alpha = 255.0; + const double min_alpha_with_signal = 25.0; // Base alpha for small flip counts + const double min_alpha_no_signal = 10.0; // Base alpha for small flip counts for no signal bits + const double log_factor = 1.0 + 0.2; // Factor for logarithmic scaling + const double log_scaler = max_alpha / log2(log_factor * max_bit_flip_count); + + for (size_t i = 0; i < binary.size(); ++i) { for (int j = 0; j < 8; ++j) { auto &item = items[i * column_count + j]; - int val = ((binary[i] >> (7 - j)) & 1) != 0 ? 1 : 0; - // Bit update frequency based highlighting - double offset = !item.sigs.empty() ? 50 : 0; - auto n = last_msg.last_changes[i].bit_change_counts[j]; - double min_f = n == 0 ? offset : offset + 25; - double alpha = std::clamp(offset + log2(1.0 + factor * (double)n / (double)last_msg.count) * scaler, min_f, max_f); + int bit_val = (binary[i] >> (7 - j)) & 1; + + double alpha = item.sigs.empty() ? 0 : min_alpha_with_signal; + uint32_t flip_count = bit_flips[i][j]; + if (flip_count > 0) { + double normalized_alpha = log2(1.0 + flip_count * log_factor) * log_scaler; + double min_alpha = item.sigs.empty() ? min_alpha_no_signal : min_alpha_with_signal; + alpha = std::clamp(normalized_alpha, min_alpha, max_alpha); + } + auto color = item.bg_color; color.setAlpha(alpha); - updateItem(i, j, val, color); + updateItem(i, j, bit_val, color); } updateItem(i, 8, binary[i], last_msg.colors[i]); } } +const std::vector> &BinaryViewModel::getBitFlipChanges(size_t msg_size) { + // Return cached results if time range and data are unchanged + auto time_range = can->timeRange(); + if (bit_flip_tracker.time_range == time_range && !bit_flip_tracker.flip_counts.empty()) + return bit_flip_tracker.flip_counts; + + bit_flip_tracker.time_range = time_range; + bit_flip_tracker.flip_counts.assign(msg_size, std::array{}); + + // Iterate over events within the specified time range and calculate bit flips + auto [first, last] = can->eventsInRange(msg_id, time_range); + if (std::distance(first, last) <= 1) return bit_flip_tracker.flip_counts; + + std::vector prev_values((*first)->dat, (*first)->dat + (*first)->size); + for (auto it = std::next(first); it != last; ++it) { + const CanEvent *event = *it; + int size = std::min(msg_size, event->size); + for (int i = 0; i < size; ++i) { + const uint8_t diff = event->dat[i] ^ prev_values[i]; + if (!diff) continue; + + auto &bit_flips = bit_flip_tracker.flip_counts[i]; + for (int bit = 0; bit < 8; ++bit) { + if (diff & (1u << bit)) ++bit_flips[7 - bit]; + } + prev_values[i] = event->dat[i]; + } + } + + return bit_flip_tracker.flip_counts; +} + QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical) { switch (role) { @@ -388,7 +437,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->fillRect(option.rect, item->bg_color); } auto color_role = item->sigs.contains(bin_view->hovered_sig) ? QPalette::BrightText : QPalette::Text; - painter->setPen(option.palette.color(color_role)); + painter->setPen(option.palette.color(bin_view->is_message_active ? QPalette::Normal : QPalette::Disabled, color_role)); } if (item->sigs.size() > 1) { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 584910dc8304a7..920deb0018effb 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -39,6 +39,12 @@ class BinaryViewModel : public QAbstractTableModel { Qt::ItemFlags flags(const QModelIndex &index) const override { return (index.column() == column_count - 1) ? Qt::ItemIsEnabled : Qt::ItemIsEnabled | Qt::ItemIsSelectable; } + const std::vector> &getBitFlipChanges(size_t msg_size); + + struct BitFlipTracker { + std::optional> time_range; + std::vector> flip_counts; + } bit_flip_tracker; struct Item { QColor bg_color = QColor(102, 86, 169, 255); @@ -49,7 +55,7 @@ class BinaryViewModel : public QAbstractTableModel { bool valid = false; }; std::vector items; - + bool heatmap_live_mode = true; MessageId msg_id; int row_count = 0; const int column_count = 9; @@ -63,8 +69,13 @@ class BinaryView : public QTableView { void setMessage(const MessageId &message_id); void highlight(const cabana::Signal *sig); QSet getOverlappingSignals() const; - inline void updateState() { model->updateState(); } + void updateState() { model->updateState(); } + void paintEvent(QPaintEvent *event) override { + is_message_active = can->isMessageActive(model->msg_id); + QTableView::paintEvent(event); + } QSize minimumSizeHint() const override; + void setHeatmapLiveMode(bool live) { model->heatmap_live_mode = live; updateState(); } signals: void signalClicked(const cabana::Signal *sig); @@ -86,6 +97,7 @@ class BinaryView : public QTableView { QModelIndex anchor_index; BinaryViewModel *model; BinaryItemDelegate *delegate; + bool is_message_active = false; const cabana::Signal *resize_sig = nullptr; const cabana::Signal *hovered_sig = nullptr; friend class BinaryItemDelegate; diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index 6c13252e80753b..3588c5edc6450e 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -842,6 +842,8 @@ void ChartView::setSeriesType(SeriesType type) { } updateSeriesPoints(); updateTitle(); + + menu->actions()[(int)type]->setChecked(true); } } diff --git a/tools/cabana/chart/chartswidget.cc b/tools/cabana/chart/chartswidget.cc index e2f0d4d0c9b0c9..08840f46633f10 100644 --- a/tools/cabana/chart/chartswidget.cc +++ b/tools/cabana/chart/chartswidget.cc @@ -23,7 +23,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { main_layout->setSpacing(0); // toolbar - QToolBar *toolbar = new QToolBar(tr("Charts"), this); + toolbar = new QToolBar(tr("Charts"), this); int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize); toolbar->setIconSize({icon_size, icon_size}); @@ -34,6 +34,21 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { toolbar->addWidget(title_label = new QLabel()); title_label->setContentsMargins(0, 0, style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing), 0); + auto chart_type_action = toolbar->addAction(""); + QMenu *chart_type_menu = new QMenu(this); + auto types = std::array{tr("Line"), tr("Step"), tr("Scatter")}; + for (int i = 0; i < types.size(); ++i) { + QString type_text = types[i]; + chart_type_menu->addAction(type_text, this, [=]() { + settings.chart_series_type = i; + chart_type_action->setText("Type: " + type_text); + settingChanged(); + }); + } + chart_type_action->setText("Type: " + types[settings.chart_series_type]); + chart_type_action->setMenu(chart_type_menu); + qobject_cast(toolbar->widgetForAction(chart_type_action))->setPopupMode(QToolButton::InstantPopup); + QMenu *menu = new QMenu(this); for (int i = 0; i < MAX_COLUMN_COUNT; ++i) { menu->addAction(tr("%1").arg(i + 1), [=]() { setColumnCount(i + 1); }); @@ -42,13 +57,13 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { columns_action->setMenu(menu); qobject_cast(toolbar->widgetForAction(columns_action))->setPopupMode(QToolButton::InstantPopup); - QLabel *stretch_label = new QLabel(this); - stretch_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - toolbar->addWidget(stretch_label); + QWidget *spacer = new QWidget(this); + spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + toolbar->addWidget(spacer); range_lb_action = toolbar->addWidget(range_lb = new QLabel(this)); range_slider = new LogSlider(1000, Qt::Horizontal, this); - range_slider->setMaximumWidth(200); + range_slider->setFixedWidth(150 * qApp->devicePixelRatio()); range_slider->setToolTip(tr("Set the chart range")); range_slider->setRange(1, settings.max_cached_minutes * 60); range_slider->setSingleStep(1); @@ -121,10 +136,12 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { setIsDocked(true); newTab(); qApp->installEventFilter(this); - setWhatsThis(tr(R"( - Chart view
- + Chart View
+ Click: Click to seek to a corresponding time.
+ Drag: Zoom into the chart.
+ Shift + Drag: Scrub through the chart to view values.
+ Right Mouse: Open the context menu.
)")); } @@ -176,6 +193,7 @@ QRect ChartsWidget::chartVisibleRect(ChartView *chart) { } void ChartsWidget::showValueTip(double sec) { + emit showTip(sec); if (sec < 0 && !value_tip_visible_) return; value_tip_visible_ = sec >= 0; @@ -219,7 +237,7 @@ void ChartsWidget::setIsDocked(bool docked) { void ChartsWidget::updateToolBar() { title_label->setText(tr("Charts: %1").arg(charts.size())); - columns_action->setText(tr("Column: %1").arg(column_count)); + columns_action->setText(tr("Columns: %1").arg(column_count)); range_lb->setText(utils::formatSeconds(max_chart_range)); bool is_zoomed = can->timeRange().has_value(); @@ -241,7 +259,9 @@ void ChartsWidget::settingChanged() { c->setTheme(theme); } } - range_slider->setRange(1, settings.max_cached_minutes * 60); + if (range_slider->maximum() != settings.max_cached_minutes * 60) { + range_slider->setRange(1, settings.max_cached_minutes * 60); + } for (auto c : charts) { c->setFixedHeight(settings.chart_height); c->setSeriesType((SeriesType)settings.chart_series_type); @@ -380,7 +400,7 @@ void ChartsWidget::doAutoScroll() { } QSize ChartsWidget::minimumSizeHint() const { - return QSize(CHART_MIN_WIDTH, QWidget::minimumSizeHint().height()); + return QSize(CHART_MIN_WIDTH * 1.5 * qApp->devicePixelRatio(), QWidget::minimumSizeHint().height()); } void ChartsWidget::newChart() { @@ -529,20 +549,14 @@ void ChartsContainer::dropEvent(QDropEvent *event) { void ChartsContainer::paintEvent(QPaintEvent *ev) { if (!drop_indictor_pos.isNull() && !childAt(drop_indictor_pos)) { - QRect r; + QRect r = geometry(); + r.setHeight(CHART_SPACING); if (auto insert_after = getDropAfter(drop_indictor_pos)) { - QRect area = insert_after->geometry(); - r = QRect(area.left(), area.bottom() + 1, area.width(), CHART_SPACING); - } else { - r = geometry(); - r.setHeight(CHART_SPACING); + r.moveTop(insert_after->geometry().bottom()); } QPainter p(this); - p.setPen(QPen(palette().highlight(), 2)); - p.drawLine(r.topLeft() + QPoint(1, 0), r.bottomLeft() + QPoint(1, 0)); - p.drawLine(r.topLeft() + QPoint(0, r.height() / 2), r.topRight() + QPoint(0, r.height() / 2)); - p.drawLine(r.topRight(), r.bottomRight()); + p.fillRect(r, palette().highlight()); } } diff --git a/tools/cabana/chart/chartswidget.h b/tools/cabana/chart/chartswidget.h index bfdaaaa95496b3..46e7f546b02e37 100644 --- a/tools/cabana/chart/chartswidget.h +++ b/tools/cabana/chart/chartswidget.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ public slots: signals: void toggleChartsDocking(); void seriesChanged(); + void showTip(double seconds); private: QSize minimumSizeHint() const override; @@ -88,6 +90,7 @@ public slots: bool is_docked = true; ToolButton *dock_btn; + QToolBar *toolbar; QAction *undo_zoom_action; QAction *redo_zoom_action; QAction *reset_zoom_action; diff --git a/tools/cabana/chart/sparkline.cc b/tools/cabana/chart/sparkline.cc index 094fe96182777c..09f86a095a6c42 100644 --- a/tools/cabana/chart/sparkline.cc +++ b/tools/cabana/chart/sparkline.cc @@ -5,15 +5,9 @@ #include void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, double last_msg_ts, int range, QSize size) { - const auto &msgs = can->events(msg_id); - - auto range_start = can->toMonoTime(last_msg_ts - range); - auto range_end = can->toMonoTime(last_msg_ts); - auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), range_start, CompareCanEvent()); - auto last = std::upper_bound(first, msgs.cend(), range_end, CompareCanEvent()); - points.clear(); double value = 0; + auto [first, last] = can->eventsInRange(msg_id, std::make_pair(last_msg_ts -range, last_msg_ts)); for (auto it = first; it != last; ++it) { if (sig->getValue((*it)->dat, (*it)->size, &value)) { points.emplace_back(((*it)->mono_time - (*first)->mono_time) / 1e9, value); diff --git a/tools/cabana/dbc/dbc.h b/tools/cabana/dbc/dbc.h index da44319b5c3ab3..d2b25bc5f2f633 100644 --- a/tools/cabana/dbc/dbc.h +++ b/tools/cabana/dbc/dbc.h @@ -8,16 +8,16 @@ #include #include - const QString UNTITLED = "untitled"; const QString DEFAULT_NODE_NAME = "XXX"; +constexpr int CAN_MAX_DATA_BYTES = 64; struct MessageId { uint8_t source = 0; uint32_t address = 0; QString toString() const { - return QString("%1:%2").arg(source).arg(address, 1, 16); + return QString("%1:%2").arg(source).arg(QString::number(address, 16).toUpper()); } bool operator==(const MessageId &other) const { diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 7befadb7227169..2e213988bc7896 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -2,7 +2,8 @@ #include #include -#include +#include +#include #include "tools/cabana/commands.h" #include "tools/cabana/mainwin.h" @@ -20,19 +21,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tabbar->setContextMenuPolicy(Qt::CustomContextMenu); main_layout->addWidget(tabbar); - // message title - QHBoxLayout *title_layout = new QHBoxLayout(); - title_layout->setContentsMargins(3, 6, 3, 0); - auto spacer = new QSpacerItem(0, 1); - title_layout->addItem(spacer); - title_layout->addWidget(name_label = new ElidedLabel(this), 1); - name_label->setStyleSheet("QLabel{font-weight:bold;}"); - name_label->setAlignment(Qt::AlignCenter); - auto edit_btn = new ToolButton("pencil", tr("Edit Message")); - title_layout->addWidget(edit_btn); - title_layout->addWidget(remove_btn = new ToolButton("x-lg", tr("Remove Message"))); - spacer->changeSize(edit_btn->sizeHint().width() * 2 + 9, 1); - main_layout->addLayout(title_layout); + createToolBar(); // warning warning_widget = new QWidget(this); @@ -58,8 +47,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tab_widget->addTab(history_log = new LogsWidget(this), utils::icon("stopwatch"), "&Logs"); main_layout->addWidget(tab_widget); - QObject::connect(edit_btn, &QToolButton::clicked, this, &DetailWidget::editMsg); - QObject::connect(remove_btn, &QToolButton::clicked, this, &DetailWidget::removeMsg); QObject::connect(binary_view, &BinaryView::signalHovered, signal_view, &SignalView::signalHovered); QObject::connect(binary_view, &BinaryView::signalClicked, [this](const cabana::Signal *s) { signal_view->selectSignal(s, true); }); QObject::connect(binary_view, &BinaryView::editSignal, signal_view->model, &SignalModel::saveSignal); @@ -80,6 +67,41 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QObject::connect(charts, &ChartsWidget::seriesChanged, signal_view, &SignalView::updateChartState); } +void DetailWidget::createToolBar() { + QToolBar *toolbar = new QToolBar(this); + int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize); + toolbar->setIconSize({icon_size, icon_size}); + toolbar->addWidget(name_label = new ElidedLabel(this)); + name_label->setStyleSheet("QLabel{font-weight:bold;}"); + + QWidget *spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + toolbar->addWidget(spacer); + +// Heatmap label and radio buttons + toolbar->addWidget(new QLabel(tr("Heatmap:"), this)); + auto *heatmap_live = new QRadioButton(tr("Live"), this); + auto *heatmap_all = new QRadioButton(tr("All"), this); + heatmap_live->setChecked(true); + + toolbar->addWidget(heatmap_live); + toolbar->addWidget(heatmap_all); + + // Edit and remove buttons + toolbar->addSeparator(); + toolbar->addAction(utils::icon("pencil"), tr("Edit Message"), this, &DetailWidget::editMsg); + action_remove_msg = toolbar->addAction(utils::icon("x-lg"), tr("Remove Message"), this, &DetailWidget::removeMsg); + + layout()->addWidget(toolbar); + + connect(heatmap_live, &QAbstractButton::toggled, this, [this](bool on) { binary_view->setHeatmapLiveMode(on); }); + connect(can, &AbstractStream::timeRangeChanged, this, [=](const std::optional> &range) { + auto text = range ? QString("%1 - %2").arg(range->first, 0, 'f', 3).arg(range->second, 0, 'f', 3) : "All"; + heatmap_all->setText(text); + (range ? heatmap_all : heatmap_live)->setChecked(true); + }); +} + void DetailWidget::showTabBarContextMenu(const QPoint &pt) { int index = tabbar->tabAt(pt); if (index >= 0) { @@ -131,14 +153,11 @@ void DetailWidget::refresh() { for (auto s : binary_view->getOverlappingSignals()) { warnings.push_back(tr("%1 has overlapping bits.").arg(s->name)); } - } else { - warnings.push_back(tr("Drag-Select in binary view to create new signal.")); } - QString msg_name = msg ? QString("%1 (%2)").arg(msg->name, msg->transmitter) : msgName(msg_id); name_label->setText(msg_name); name_label->setToolTip(msg_name); - remove_btn->setEnabled(msg != nullptr); + action_remove_msg->setEnabled(msg != nullptr); if (!warnings.isEmpty()) { warning_label->setText(warnings.join('\n')); @@ -184,8 +203,7 @@ EditMessageDialog::EditMessageDialog(const MessageId &msg_id, const QString &tit name_edit->setValidator(new NameValidator(name_edit)); form_layout->addRow(tr("Size"), size_spin = new QSpinBox(this)); - // TODO: limit the maximum? - size_spin->setMinimum(1); + size_spin->setRange(1, CAN_MAX_DATA_BYTES); size_spin->setValue(size); form_layout->addRow(tr("Node"), node = new QLineEdit(this)); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 15e1ee5f2f954b..47304fbdc50cf4 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -36,6 +36,7 @@ class DetailWidget : public QWidget { void refresh(); private: + void createToolBar(); void showTabBarContextMenu(const QPoint &pt); void editMsg(); void removeMsg(); @@ -47,7 +48,7 @@ class DetailWidget : public QWidget { QWidget *warning_widget; TabBar *tabbar; QTabWidget *tab_widget; - QToolButton *remove_btn; + QAction *action_remove_msg; LogsWidget *history_log; BinaryView *binary_view; SignalView *signal_view; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index d3f868cd47fdb1..8361befb53aa08 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -191,6 +191,7 @@ void MainWindow::createDockWidgets() { video_splitter->handle(1)->setEnabled(!can->liveStreaming()); video_dock->setWidget(video_splitter); QObject::connect(charts_widget, &ChartsWidget::toggleChartsDocking, this, &MainWindow::toggleChartsDocking); + QObject::connect(charts_widget, &ChartsWidget::showTip, video_widget, &VideoWidget::showThumbnail); } void MainWindow::createStatusBar() { diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index ecb739a733cb5e..ed9aeaf3114f0a 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -13,21 +13,6 @@ #include "tools/cabana/commands.h" -static bool isMessageActive(const MessageId &id) { - if (id.source == INVALID_SOURCE) { - return false; - } - // Check if the message is active based on time difference and frequency - const auto &m = can->lastMessage(id); - float delta = can->currentSec() - m.ts; - - if (m.freq < std::numeric_limits::epsilon()) { - return delta < 1.5; - } - - return delta < (5.0 / m.freq) + (1.0 / settings.fps); -} - MessagesWidget::MessagesWidget(QWidget *parent) : menu(new QMenu(this)), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); @@ -207,7 +192,7 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { switch (index.column()) { case Column::NAME: return item.name; case Column::SOURCE: return item.id.source != INVALID_SOURCE ? QString::number(item.id.source) : NA; - case Column::ADDRESS: return QString::number(item.id.address, 16); + case Column::ADDRESS: return toHexString(item.id.address); case Column::NODE: return item.node; case Column::FREQ: return item.id.source != INVALID_SOURCE ? getFreq(can->lastMessage(item.id).freq) : NA; case Column::COUNT: return item.id.source != INVALID_SOURCE ? QString::number(can->lastMessage(item.id).count) : NA; @@ -300,7 +285,7 @@ bool MessageListModel::match(const MessageListModel::Item &item) { match = parseRange(txt, item.id.source); break; case Column::ADDRESS: - match = QString::number(item.id.address, 16).contains(txt, Qt::CaseInsensitive); + match = toHexString(item.id.address).contains(txt, Qt::CaseInsensitive); match = match || parseRange(txt, item.id.address, 16); break; case Column::NODE: @@ -335,7 +320,7 @@ bool MessageListModel::filterAndSort() { std::vector items; items.reserve(all_messages.size()); for (const auto &id : all_messages) { - if (show_inactive_messages || isMessageActive(id)) { + if (show_inactive_messages || can->isMessageActive(id)) { auto msg = dbc()->msg(id); Item item = {.id = id, .name = msg ? msg->name : UNTITLED, @@ -378,7 +363,7 @@ void MessageListModel::sort(int column, Qt::SortOrder order) { void MessageView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { const auto &item = ((MessageListModel*)model())->items_[index.row()]; - if (!isMessageActive(item.id)) { + if (!can->isMessageActive(item.id)) { QStyleOptionViewItem custom_option = option; custom_option.palette.setBrush(QPalette::Text, custom_option.palette.color(QPalette::Disabled, QPalette::Text)); auto color = QApplication::palette().color(QPalette::HighlightedText); diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 523cbf3be70c09..cccc9b6d9ab643 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -89,10 +89,6 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { groupbox = new QGroupBox("Chart"); form_layout = new QFormLayout(groupbox); - form_layout->addRow(tr("Default Series Type"), chart_series_type = new QComboBox(this)); - chart_series_type->addItems({tr("Line"), tr("Step Line"), tr("Scatter")}); - chart_series_type->setCurrentIndex(settings.chart_series_type); - form_layout->addRow(tr("Chart Height"), chart_height = new QSpinBox(this)); chart_height->setRange(100, 500); chart_height->setSingleStep(10); @@ -132,7 +128,6 @@ void SettingsDlg::save() { } settings.fps = fps->value(); settings.max_cached_minutes = cached_minutes->value(); - settings.chart_series_type = chart_series_type->currentIndex(); settings.chart_height = chart_height->value(); settings.log_livestream = log_livestream->isChecked(); settings.log_path = log_path->text(); diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 130b76d5023144..9fe70c3ee80057 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -382,7 +382,7 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie } else if (item->type == SignalModel::Item::Size) { QSpinBox *spin = new QSpinBox(parent); spin->setFrame(false); - spin->setRange(1, 64); + spin->setRange(1, CAN_MAX_DATA_BYTES); return spin; } else if (item->type == SignalModel::Item::SignalType) { QComboBox *c = new QComboBox(parent); diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 7abeafea94e3ba..2278104c269171 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -39,7 +39,7 @@ void AbstractStream::updateMasks() { const int size = std::min(mask.size(), m.last_changes.size()); for (int i = 0; i < size; ++i) { for (int j = 0; j < 8; ++j) { - if (((mask[i] >> (7 - j)) & 1) != 0) m.last_changes[i].bit_change_counts[j] = 0; + if (((mask[i] >> (7 - j)) & 1) != 0) m.bit_flip_counts[i][j] = 0; } } } @@ -59,9 +59,9 @@ size_t AbstractStream::suppressHighlighted() { if (dt < 2.0) { last_change.suppressed = true; } - last_change.bit_change_counts.fill(0); cnt += last_change.suppressed; } + for (auto &flip_counts : m.bit_flip_counts) flip_counts.fill(0); } return cnt; } @@ -127,8 +127,22 @@ const CanData &AbstractStream::lastMessage(const MessageId &id) const { return it != last_msgs.end() ? it->second : empty_data; } +bool AbstractStream::isMessageActive(const MessageId &id) const { + if (id.source == INVALID_SOURCE) { + return false; + } + // Check if the message is active based on time difference and frequency + const auto &m = lastMessage(id); + float delta = currentSec() - m.ts; + + if (m.freq < std::numeric_limits::epsilon()) { + return delta < 1.5; + } + + return delta < (5.0 / m.freq) + (1.0 / settings.fps); +} + void AbstractStream::updateLastMsgsTo(double sec) { - std::lock_guard lk(mutex_); current_sec_ = sec; uint64_t last_ts = toMonoTime(sec); std::unordered_map msgs; @@ -160,10 +174,17 @@ void AbstractStream::updateLastMsgsTo(double sec) { std::any_of(messages_.cbegin(), messages_.cend(), [this](const auto &m) { return !last_msgs.count(m.first); }); last_msgs = messages_; - mutex_.unlock(); - emit msgsReceived(nullptr, id_changed); - resumeStream(); + + std::lock_guard lk(mutex_); + seek_finished_ = true; + seek_finished_cv_.notify_one(); +} + +void AbstractStream::waitForSeekFinshed() { + std::unique_lock lock(mutex_); + seek_finished_cv_.wait(lock, [this]() { return seek_finished_; }); + seek_finished_ = false; } const CanEvent *AbstractStream::newEvent(uint64_t mono_time, const cereal::CanData::Reader &c) { @@ -200,6 +221,15 @@ void AbstractStream::mergeEvents(const std::vector &events) { } } +std::pair AbstractStream::eventsInRange(const MessageId &id, std::optional> time_range) const { + const auto &events = can->events(id); + if (!time_range) return {events.begin(), events.end()}; + + auto first = std::lower_bound(events.begin(), events.end(), can->toMonoTime(time_range->first), CompareCanEvent()); + auto last = std::upper_bound(events.begin(), events.end(), can->toMonoTime(time_range->second), CompareCanEvent()); + return {first, last}; +} + namespace { enum Color { GREYISH_BLUE, CYAN, RED}; @@ -219,15 +249,7 @@ inline QColor blend(const QColor &a, const QColor &b) { // Calculate the frequency from the past one minute data double calc_freq(const MessageId &msg_id, double current_sec) { - const auto &events = can->events(msg_id); - if (events.empty()) return 0.0; - - auto current_mono_time = can->toMonoTime(current_sec); - auto start_mono_time = can->toMonoTime(current_sec - 59); - - auto first = std::lower_bound(events.begin(), events.end(), start_mono_time, CompareCanEvent()); - auto last = std::upper_bound(first, events.end(), current_mono_time, CompareCanEvent()); - + auto [first, last] = can->eventsInRange(msg_id, std::make_pair(current_sec - 59, current_sec)); int count = std::distance(first, last); if (count <= 1) return 0.0; @@ -248,9 +270,10 @@ void CanData::compute(const MessageId &msg_id, const uint8_t *can_data, const in } if (dat.size() != size) { - dat.resize(size); + dat.assign(can_data, can_data + size); colors.assign(size, QColor(0, 0, 0, 0)); last_changes.resize(size); + bit_flip_counts.resize(size); std::for_each(last_changes.begin(), last_changes.end(), [current_sec](auto &c) { c.ts = current_sec; }); } else { constexpr int periodic_threshold = 10; @@ -282,10 +305,11 @@ void CanData::compute(const MessageId &msg_id, const uint8_t *can_data, const in } // Track bit level changes + auto &row_bit_flips = bit_flip_counts[i]; const uint8_t diff = (cur ^ last); for (int bit = 0; bit < 8; bit++) { if (diff & (1u << bit)) { - ++last_change.bit_change_counts[7 - bit]; + ++row_bit_flips[7 - bit]; } } diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 5ecf086c959ea7..f35b19d34f7045 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -33,9 +34,9 @@ struct CanData { int delta = 0; int same_delta_counter = 0; bool suppressed = false; - std::array bit_change_counts; }; std::vector last_changes; + std::vector> bit_flip_counts; double last_freq_update_ts = 0; }; @@ -53,6 +54,7 @@ struct CompareCanEvent { }; typedef std::unordered_map> MessageEventsMap; +using CanEventIter = std::vector::const_iterator; class AbstractStream : public QObject { Q_OBJECT @@ -81,10 +83,12 @@ class AbstractStream : public QObject { inline double toSeconds(uint64_t mono_time) const { return std::max(0.0, (mono_time - beginMonoTime()) / 1e9); } inline const std::unordered_map &lastMessages() const { return last_msgs; } + bool isMessageActive(const MessageId &id) const; inline const MessageEventsMap &eventsMap() const { return events_; } inline const std::vector &allEvents() const { return all_events_; } const CanData &lastMessage(const MessageId &id) const; const std::vector &events(const MessageId &id) const; + std::pair eventsInRange(const MessageId &id, std::optional> time_range) const; size_t suppressHighlighted(); void clearSuppressed(); @@ -108,7 +112,7 @@ class AbstractStream : public QObject { void mergeEvents(const std::vector &events); const CanEvent *newEvent(uint64_t mono_time, const cereal::CanData::Reader &c); void updateEvent(const MessageId &id, double sec, const uint8_t *data, uint8_t size); - virtual void resumeStream() {} + void waitForSeekFinshed(); std::vector all_events_; double current_sec_ = 0; std::optional> time_range_; @@ -124,6 +128,8 @@ class AbstractStream : public QObject { // Members accessed in multiple threads. (mutex protected) std::mutex mutex_; + std::condition_variable seek_finished_cv_; + bool seek_finished_ = false; std::set new_msgs_; std::unordered_map messages_; std::unordered_map> masks_; diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index bfe5ca74da1580..ebe478ded77d1d 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -53,9 +53,12 @@ bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint // Forward replay callbacks to corresponding Qt signals. replay->onSeeking = [this](double sec) { emit seeking(sec); }; - replay->onSeekedTo = [this](double sec) { emit seekedTo(sec); }; + replay->onSeekedTo = [this](double sec) { + emit seekedTo(sec); + waitForSeekFinshed(); + }; replay->onQLogLoaded = [this](std::shared_ptr qlog) { emit qLogLoaded(qlog); }; - replay->onSegmentsMerged = [this]() { QMetaObject::invokeMethod(this, &ReplayStream::mergeSegments, Qt::QueuedConnection); }; + replay->onSegmentsMerged = [this]() { QMetaObject::invokeMethod(this, &ReplayStream::mergeSegments, Qt::BlockingQueuedConnection); }; bool success = replay->load(); if (!success) { diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 2d7f3351935d9c..df1f2526a5e328 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -32,7 +32,6 @@ class ReplayStream : public AbstractStream { inline float getSpeed() const { return replay->getSpeed(); } inline Replay *getReplay() const { return replay.get(); } inline bool isPaused() const override { return replay->isPaused(); } - void resumeStream() override { return replay->resumeStream(); } void pause(bool pause) override; signals: diff --git a/tools/cabana/tools/findsignal.cc b/tools/cabana/tools/findsignal.cc index 8e1749ba8e4a54..ec56fcaac08884 100644 --- a/tools/cabana/tools/findsignal.cc +++ b/tools/cabana/tools/findsignal.cc @@ -225,7 +225,7 @@ void FindSignalDlg::setInitialSignals() { model->initial_signals.clear(); for (const auto &[id, m] : can->lastMessages()) { - if (buses.isEmpty() || buses.contains(id.source) && (addresses.isEmpty() || addresses.contains(id.address))) { + if ((buses.isEmpty() || buses.contains(id.source)) && (addresses.isEmpty() || addresses.contains(id.address))) { const auto &events = can->events(id); auto e = std::lower_bound(events.cbegin(), events.cend(), first_time, CompareCanEvent()); if (e != events.cend()) { diff --git a/tools/cabana/utils/util.h b/tools/cabana/utils/util.h index 0ebd7e41f84681..1aad3103db3e6e 100644 --- a/tools/cabana/utils/util.h +++ b/tools/cabana/utils/util.h @@ -163,3 +163,4 @@ public slots: int num_decimals(double num); QString signalToolTip(const cabana::Signal *sig); +inline QString toHexString(int value) { return QString("0x%1").arg(QString::number(value, 16).toUpper(), 2, '0'); } diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 0b2beb1dd6d333..e792f80a418d81 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -31,9 +31,12 @@ static Replay *getReplay() { VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { setFrameStyle(QFrame::StyledPanel | QFrame::Plain); auto main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); + main_layout->setSpacing(0); if (!can->liveStreaming()) main_layout->addWidget(createCameraWidget()); - main_layout->addLayout(createPlaybackController()); + + createPlaybackController(); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState); @@ -65,15 +68,19 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { timeline_colors[(int)TimelineType::AlertCritical].name())); } -QHBoxLayout *VideoWidget::createPlaybackController() { - QHBoxLayout *layout = new QHBoxLayout(); - layout->addWidget(seek_backward_btn = new ToolButton("rewind", tr("Seek backward"))); - layout->addWidget(play_btn = new ToolButton("play", tr("Play"))); - layout->addWidget(seek_forward_btn = new ToolButton("fast-forward", tr("Seek forward"))); +void VideoWidget::createPlaybackController() { + QToolBar *toolbar = new QToolBar(this); + layout()->addWidget(toolbar); + + int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize); + toolbar->setIconSize({icon_size, icon_size}); + + toolbar->addAction(utils::icon("rewind"), tr("Seek backward"), []() { can->seekTo(can->currentSec() - 1); }); + play_toggle_action = toolbar->addAction(utils::icon("play"), tr("Play"), []() { can->pause(!can->isPaused()); }); + toolbar->addAction(utils::icon("fast-forward"), tr("Seek forward"), []() { can->seekTo(can->currentSec() + 1); }); if (can->liveStreaming()) { - layout->addWidget(skip_to_end_btn = new ToolButton("skip-end", tr("Skip to the end"), this)); - QObject::connect(skip_to_end_btn, &QToolButton::clicked, [this]() { + skip_to_end_action = toolbar->addAction(utils::icon("skip-end"), tr("Skip to the end"), this, [this]() { // set speed to 1.0 speed_btn->menu()->actions()[7]->setChecked(true); can->pause(false); @@ -81,53 +88,48 @@ QHBoxLayout *VideoWidget::createPlaybackController() { }); } - layout->addWidget(time_btn = new QToolButton); - time_btn->setToolTip(settings.absolute_time ? tr("Elapsed time") : tr("Absolute time")); - time_btn->setAutoRaise(true); - layout->addStretch(0); + time_display_action = toolbar->addAction("", this, [this]() { + settings.absolute_time = !settings.absolute_time; + time_display_action->setToolTip(settings.absolute_time ? tr("Elapsed time") : tr("Absolute time")); + updateState(); + }); + + QWidget *spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + toolbar->addWidget(spacer); if (!can->liveStreaming()) { - layout->addWidget(loop_btn = new ToolButton("repeat", tr("Loop playback"))); - QObject::connect(loop_btn, &QToolButton::clicked, this, &VideoWidget::loopPlaybackClicked); + toolbar->addAction(utils::icon("repeat"), tr("Loop playback"), this, &VideoWidget::loopPlaybackClicked); } - // speed selector - layout->addWidget(speed_btn = new QToolButton(this)); - speed_btn->setAutoRaise(true); + createSpeedDropdown(toolbar); +} + +void VideoWidget::createSpeedDropdown(QToolBar *toolbar) { + toolbar->addWidget(speed_btn = new QToolButton(this)); speed_btn->setMenu(new QMenu(speed_btn)); speed_btn->setPopupMode(QToolButton::InstantPopup); QActionGroup *speed_group = new QActionGroup(this); speed_group->setExclusive(true); - int max_width = 0; - QFont font = speed_btn->font(); - font.setBold(true); - speed_btn->setFont(font); - QFontMetrics fm(font); for (float speed : {0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 0.8, 1., 2., 3., 5.}) { - QString name = QString("%1x").arg(speed); - max_width = std::max(max_width, fm.width(name) + fm.horizontalAdvance(QLatin1Char(' ')) * 2); - - QAction *act = new QAction(name, speed_group); - act->setCheckable(true); - QObject::connect(act, &QAction::toggled, [this, speed]() { + auto act = speed_btn->menu()->addAction(QString("%1x").arg(speed), this, [this, speed]() { can->setSpeed(speed); speed_btn->setText(QString("%1x ").arg(speed)); }); - speed_btn->menu()->addAction(act); - if (speed == 1.0)act->setChecked(true); + + speed_group->addAction(act); + act->setCheckable(true); + if (speed == 1.0) { + act->setChecked(true); + act->trigger(); + } } - speed_btn->setMinimumWidth(max_width + style()->pixelMetric(QStyle::PM_MenuButtonIndicator)); - QObject::connect(play_btn, &QToolButton::clicked, []() { can->pause(!can->isPaused()); }); - QObject::connect(seek_backward_btn, &QToolButton::clicked, []() { can->seekTo(can->currentSec() - 1); }); - QObject::connect(seek_forward_btn, &QToolButton::clicked, []() { can->seekTo(can->currentSec() + 1); }); - QObject::connect(time_btn, &QToolButton::clicked, [this]() { - settings.absolute_time = !settings.absolute_time; - time_btn->setToolTip(settings.absolute_time ? tr("Elapsed time") : tr("Absolute time")); - updateState(); - }); - return layout; + QFont font = speed_btn->font(); + font.setBold(true); + speed_btn->setFont(font); + speed_btn->setMinimumWidth(speed_btn->fontMetrics().width("0.05x ") + style()->pixelMetric(QStyle::PM_MenuButtonIndicator)); } QWidget *VideoWidget::createCameraWidget() { @@ -150,7 +152,6 @@ QWidget *VideoWidget::createCameraWidget() { QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->currentSecond()); }); QObject::connect(can, &AbstractStream::paused, cam_widget, [c = cam_widget]() { c->showPausedOverlay(); }); - QObject::connect(can, &AbstractStream::resume, cam_widget, [c = cam_widget]() { c->update(); }); QObject::connect(can, &AbstractStream::eventsMerged, this, [this]() { slider->update(); }); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(cam_widget, &CameraWidget::vipcAvailableStreamsUpdated, this, &VideoWidget::vipcAvailableStreamsUpdated); @@ -158,7 +159,7 @@ QWidget *VideoWidget::createCameraWidget() { if (index != -1) cam_widget->setStreamType((VisionStreamType)camera_tab->tabData(index).toInt()); }); QObject::connect(static_cast(can), &ReplayStream::qLogLoaded, cam_widget, &StreamCameraView::parseQLog, Qt::QueuedConnection); - slider->installEventFilter(cam_widget); + slider->installEventFilter(this); return w; } @@ -180,13 +181,13 @@ void VideoWidget::vipcAvailableStreamsUpdated(std::set streams void VideoWidget::loopPlaybackClicked() { bool is_looping = getReplay()->loop(); getReplay()->setLoop(!is_looping); - loop_btn->setIcon(!is_looping ? "repeat" : "repeat-1"); + qobject_cast(sender())->setIcon(utils::icon(!is_looping ? "repeat" : "repeat-1")); } void VideoWidget::timeRangeChanged() { const auto time_range = can->timeRange(); if (can->liveStreaming()) { - skip_to_end_btn->setEnabled(!time_range.has_value()); + skip_to_end_action->setEnabled(!time_range.has_value()); return; } time_range ? slider->setTimeRange(time_range->first, time_range->second) @@ -208,28 +209,50 @@ void VideoWidget::updateState() { if (camera_tab->count() == 0) { // No streams available cam_widget->update(); // Manually refresh to show alert events } - time_btn->setText(QString("%1 / %2").arg(formatTime(can->currentSec(), true), + time_display_action->setText(QString("%1 / %2").arg(formatTime(can->currentSec(), true), formatTime(slider->maximum() / slider->factor))); } else { - time_btn->setText(formatTime(can->currentSec(), true)); + time_display_action->setText(formatTime(can->currentSec(), true)); } } void VideoWidget::updatePlayBtnState() { - play_btn->setIcon(can->isPaused() ? "play" : "pause"); - play_btn->setToolTip(can->isPaused() ? tr("Play") : tr("Pause")); + play_toggle_action->setIcon(utils::icon(can->isPaused() ? "play" : "pause")); + play_toggle_action->setToolTip(can->isPaused() ? tr("Play") : tr("Pause")); } -// Slider +void VideoWidget::showThumbnail(double seconds) { + if (can->liveStreaming()) return; + + cam_widget->thumbnail_dispaly_time = seconds; + slider->thumbnail_dispaly_time = seconds; + cam_widget->update(); + slider->update(); +} + +bool VideoWidget::eventFilter(QObject *obj, QEvent *event) { + if (event->type() == QEvent::MouseMove) { + auto [min_sec, max_sec] = can->timeRange().value_or(std::make_pair(can->minSeconds(), can->maxSeconds())); + showThumbnail(min_sec + static_cast(event)->pos().x() * (max_sec - min_sec) / slider->width()); + } else if (event->type() == QEvent::Leave) { + showThumbnail(-1); + } + return false; +} +// Slider Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { setMouseTracking(true); } void Slider::paintEvent(QPaintEvent *ev) { QPainter p(this); - QRect r = rect().adjusted(0, 4, 0, -4); + + QStyleOptionSlider opt; + initStyleOption(&opt); + QRect r = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); p.fillRect(r, timeline_colors[(int)TimelineType::None]); + double min = minimum() / factor; double max = maximum() / factor; @@ -254,13 +277,19 @@ void Slider::paintEvent(QPaintEvent *ev) { } } - QStyleOptionSlider opt; - opt.initFrom(this); opt.minimum = minimum(); opt.maximum = maximum(); opt.subControls = QStyle::SC_SliderHandle; opt.sliderPosition = value(); style()->drawComplexControl(QStyle::CC_Slider, &opt, &p); + + if (thumbnail_dispaly_time >= 0) { + int left = (thumbnail_dispaly_time - min) * width() / (max - min) - 1; + QRect rc(left, rect().top() + 1, 2, rect().height() - 2); + p.setBrush(palette().highlight()); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rc, 1.5, 1.5); + } } void Slider::mousePressEvent(QMouseEvent *e) { @@ -272,7 +301,6 @@ void Slider::mousePressEvent(QMouseEvent *e) { } // StreamCameraView - StreamCameraView::StreamCameraView(std::string stream_name, VisionStreamType stream_type, QWidget *parent) : CameraWidget(stream_name, stream_type, parent) { fade_animation = new QPropertyAnimation(this, "overlayOpacity"); @@ -294,6 +322,7 @@ void StreamCameraView::parseQLog(std::shared_ptr qlog) { QPixmap generated_thumb = generateThumbnail(thumb, can->toSeconds(thumb_data.getTimestampEof())); std::lock_guard lock(mutex); thumbnails[thumb_data.getTimestampEof()] = generated_thumb; + big_thumbnails[thumb_data.getTimestampEof()] = thumb; } } }); @@ -304,12 +333,15 @@ void StreamCameraView::paintGL() { CameraWidget::paintGL(); QPainter p(this); - if (auto alert = getReplay()->findAlertAtTime(can->currentSec())) { - drawAlert(p, rect(), *alert); + bool scrubbing = false; + if (thumbnail_dispaly_time >= 0) { + scrubbing = can->isPaused(); + scrubbing ? drawScrubThumbnail(p) : drawThumbnail(p); } - if (thumbnail_pt_) { - drawThumbnail(p); + if (auto alert = getReplay()->findAlertAtTime(scrubbing ? thumbnail_dispaly_time : can->currentSec())) { + drawAlert(p, rect(), *alert); } + if (can->isPaused()) { p.setPen(QColor(200, 200, 200, static_cast(255 * fade_animation->currentValue().toFloat()))); p.setFont(QFont(font().family(), 16, QFont::Bold)); @@ -329,25 +361,37 @@ QPixmap StreamCameraView::generateThumbnail(QPixmap thumb, double seconds) { return scaled; } -void StreamCameraView::drawThumbnail(QPainter &p) { - int pos = std::clamp(thumbnail_pt_->x(), 0, width()); - auto [min_sec, max_sec] = can->timeRange().value_or(std::make_pair(can->minSeconds(), can->maxSeconds())); - double seconds = min_sec + pos * (max_sec - min_sec) / width(); +void StreamCameraView::drawScrubThumbnail(QPainter &p) { + p.fillRect(rect(), Qt::black); + auto it = big_thumbnails.lowerBound(can->toMonoTime(thumbnail_dispaly_time)); + if (it != big_thumbnails.end()) { + QPixmap scaled_thumb = it.value().scaled(rect().size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + QRect thumb_rect(rect().center() - scaled_thumb.rect().center(), scaled_thumb.size()); + p.drawPixmap(thumb_rect.topLeft(), scaled_thumb); + drawTime(p, thumb_rect, thumbnail_dispaly_time); + } +} - auto it = thumbnails.lowerBound(can->toMonoTime(seconds)); +void StreamCameraView::drawThumbnail(QPainter &p) { + auto it = thumbnails.lowerBound(can->toMonoTime(thumbnail_dispaly_time)); if (it != thumbnails.end()) { const QPixmap &thumb = it.value(); + auto [min_sec, max_sec] = can->timeRange().value_or(std::make_pair(can->minSeconds(), can->maxSeconds())); + int pos = (thumbnail_dispaly_time - min_sec) * width() / (max_sec - min_sec); int x = std::clamp(pos - thumb.width() / 2, THUMBNAIL_MARGIN, width() - thumb.width() - THUMBNAIL_MARGIN + 1); int y = height() - thumb.height() - THUMBNAIL_MARGIN; p.drawPixmap(x, y, thumb); - p.setPen(QPen(palette().color(QPalette::BrightText), 2)); - p.setFont(QFont(font().family(), 10)); - p.drawText(x, y, thumb.width(), thumb.height() - THUMBNAIL_MARGIN, - Qt::AlignHCenter | Qt::AlignBottom, QString::number(seconds, 'f', 3)); + drawTime(p, QRect{x, y, thumb.width(), thumb.height()}, thumbnail_dispaly_time); } } +void StreamCameraView::drawTime(QPainter &p, const QRect &rect, double seconds) { + p.setPen(palette().color(QPalette::BrightText)); + p.setFont(QFont(font().family(), 10)); + p.drawText(rect.adjusted(0, 0, 0, -THUMBNAIL_MARGIN), Qt::AlignHCenter | Qt::AlignBottom, QString::number(seconds, 'f', 3)); +} + void StreamCameraView::drawAlert(QPainter &p, const QRect &rect, const Timeline::Entry &alert) { p.setPen(QPen(palette().color(QPalette::BrightText), 2)); QColor color = timeline_colors[int(alert.type)]; @@ -360,14 +404,3 @@ void StreamCameraView::drawAlert(QPainter &p, const QRect &rect, const Timeline: p.fillRect(text_rect.left(), r.top(), text_rect.width(), r.height(), color); p.drawText(text_rect, Qt::AlignTop | Qt::AlignHCenter | Qt::TextWordWrap, text); } - -bool StreamCameraView::eventFilter(QObject *, QEvent *event) { - if (event->type() == QEvent::MouseMove) { - thumbnail_pt_ = static_cast(event)->pos(); - update(); - } else if (event->type() == QEvent::Leave) { - thumbnail_pt_ = std::nullopt; - update(); - } - return false; -} diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 78503365e5b80b..1d87a5cfa0fc3b 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -1,15 +1,14 @@ #pragma once #include -#include #include #include #include -#include #include #include #include +#include #include #include "selfdrive/ui/qt/widgets/cameraview.h" @@ -28,6 +27,7 @@ class Slider : public QSlider { void mousePressEvent(QMouseEvent *e) override; void paintEvent(QPaintEvent *ev) override; const double factor = 1000.0; + double thumbnail_dispaly_time = -1; }; class StreamCameraView : public CameraWidget { @@ -43,11 +43,14 @@ class StreamCameraView : public CameraWidget { QPixmap generateThumbnail(QPixmap thumbnail, double seconds); void drawAlert(QPainter &p, const QRect &rect, const Timeline::Entry &alert); void drawThumbnail(QPainter &p); - bool eventFilter(QObject *obj, QEvent *event) override; + void drawScrubThumbnail(QPainter &p); + void drawTime(QPainter &p, const QRect &rect, double seconds); QPropertyAnimation *fade_animation; + QMap big_thumbnails; QMap thumbnails; - std::optional thumbnail_pt_; + double thumbnail_dispaly_time = -1; + friend class VideoWidget; }; class VideoWidget : public QFrame { @@ -55,25 +58,25 @@ class VideoWidget : public QFrame { public: VideoWidget(QWidget *parnet = nullptr); + void showThumbnail(double seconds); protected: + bool eventFilter(QObject *obj, QEvent *event) override; QString formatTime(double sec, bool include_milliseconds = false); void timeRangeChanged(); void updateState(); void updatePlayBtnState(); QWidget *createCameraWidget(); - QHBoxLayout *createPlaybackController(); + void createPlaybackController(); + void createSpeedDropdown(QToolBar *toolbar); void loopPlaybackClicked(); void vipcAvailableStreamsUpdated(std::set streams); StreamCameraView *cam_widget; - QToolButton *time_btn = nullptr; - ToolButton *seek_backward_btn = nullptr; - ToolButton *play_btn = nullptr; - ToolButton *seek_forward_btn = nullptr; - ToolButton *loop_btn = nullptr; + QAction *time_display_action = nullptr; + QAction *play_toggle_action = nullptr; QToolButton *speed_btn = nullptr; - ToolButton *skip_to_end_btn = nullptr; + QAction *skip_to_end_action = nullptr; Slider *slider = nullptr; QTabBar *camera_tab = nullptr; }; diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh index bb41587c5bac8b..f224f01f953da5 100755 --- a/tools/install_ubuntu_dependencies.sh +++ b/tools/install_ubuntu_dependencies.sh @@ -23,7 +23,6 @@ function install_ubuntu_common_requirements() { $SUDO apt-get install -y --no-install-recommends \ ca-certificates \ clang \ - cppcheck \ build-essential \ gcc-arm-none-eabi \ liblzma-dev \ diff --git a/tools/lib/filereader.py b/tools/lib/filereader.py index 6773d5a5995a84..8206ad22286d7e 100644 --- a/tools/lib/filereader.py +++ b/tools/lib/filereader.py @@ -5,15 +5,12 @@ from openpilot.tools.lib.url_file import URLFile DATA_ENDPOINT = os.getenv("DATA_ENDPOINT", "http://data-raw.comma.internal/") -LOCAL_IPS = ["10.", "192.168.", *[f"172.{i}" for i in range(16, 32)]] def internal_source_available(url=DATA_ENDPOINT): try: hostname = urlparse(url).hostname port = urlparse(url).port or 80 - if not socket.gethostbyname(hostname).startswith(LOCAL_IPS): - return False with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s: s.settimeout(0.5) s.connect((hostname, port)) diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index 062de6aabf788b..c626ec4561d125 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -5,6 +5,9 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" ROOT="$(cd $DIR/../ && pwd)" ARCH=$(uname -m) +# homebrew update is slow +export HOMEBREW_NO_AUTO_UPDATE=1 + if [[ $SHELL == "/bin/zsh" ]]; then RC_FILE="$HOME/.zshrc" elif [[ $SHELL == "/bin/bash" ]]; then @@ -28,7 +31,6 @@ if [[ $(command -v brew) == "" ]]; then fi brew bundle --file=- <<-EOS -brew "cppcheck" brew "git-lfs" brew "zlib" brew "capnp" diff --git a/tools/op.sh b/tools/op.sh index 4d352af5d1e1a4..f0f1308d445d24 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -155,7 +155,7 @@ function op_check_python() { LB=$(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9,]' | cut -d ',' -f1) UB=$(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9,]' | cut -d ',' -f2) VERSION=$(echo $INSTALLED_PYTHON_VERSION | grep -o '[0-9]\+\.[0-9]\+' | tr -d -c '[0-9]') - if [[ $VERSION -ge LB && $VERSION -le UB ]]; then + if [[ $VERSION -ge LB && $VERSION -lt UB ]]; then echo -e " ↳ [${GREEN}✔${NC}] $INSTALLED_PYTHON_VERSION detected." else echo -e " ↳ [${RED}✗${NC}] You need a python version satisfying $(echo $REQUIRED_PYTHON_VERSION | cut -d '=' -f2-) to continue!" @@ -328,7 +328,8 @@ function op_switch() { BRANCH="$1" git fetch "$REMOTE" "$BRANCH" - git checkout -f --recurse-submodules --track "$REMOTE"/"$BRANCH" + git checkout -f FETCH_HEAD + git checkout -B "$BRANCH" --track "$REMOTE"/"$BRANCH" git reset --hard "${REMOTE}/${BRANCH}" git clean -df git submodule update --init --recursive diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 2bd3614530abae..a940b6d04e81a8 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -106,31 +106,27 @@ void Replay::seekTo(double seconds, bool relative) { rInfo("Seeking to %d s, segment %d", (int)target_time, target_segment); notifyEvent(onSeeking, target_time); - double seeked_to_sec = -1; interruptStream([&]() { - current_segment_ = target_segment; + current_segment_.store(target_segment); cur_mono_time_ = route_start_ts_ + target_time * 1e9; - seeking_to_ = target_time; - - if (event_data_->isSegmentLoaded(target_segment)) { - seeked_to_sec = *seeking_to_; - seeking_to_.reset(); - } + seeking_to_.store(target_time, std::memory_order_relaxed); return false; }); - checkSeekProgress(seeked_to_sec); seg_mgr_->setCurrentSegment(target_segment); + checkSeekProgress(); } -void Replay::checkSeekProgress(double seeked_to_sec) { - if (seeked_to_sec >= 0) { - if (onSeekedTo) { - onSeekedTo(seeked_to_sec); - } else { - interruptStream([]() { return true; }); - } +void Replay::checkSeekProgress() { + if (!seg_mgr_->getEventData()->isSegmentLoaded(current_segment_.load())) return; + + double seek_to = seeking_to_.exchange(-1.0, std::memory_order_acquire); + if (seek_to >= 0 && onSeekedTo) { + onSeekedTo(seek_to); } + + // Resume the interrupted stream + interruptStream([]() { return true; }); } void Replay::seekToFlag(FindFlag flag) { @@ -152,29 +148,19 @@ void Replay::pause(bool pause) { void Replay::handleSegmentMerge() { if (exit_) return; - double seeked_to_sec = -1; - interruptStream([&]() { - event_data_ = seg_mgr_->getEventData(); - notifyEvent(onSegmentsMerged); - - bool segment_loaded = event_data_->isSegmentLoaded(current_segment_); - if (seeking_to_ && segment_loaded) { - seeked_to_sec = *seeking_to_; - seeking_to_.reset(); - return false; - } - return segment_loaded; - }); - - checkSeekProgress(seeked_to_sec); - if (!stream_thread_.joinable() && !event_data_->events.empty()) { - startStream(); + auto event_data = seg_mgr_->getEventData(); + if (!stream_thread_.joinable() && !event_data->segments.empty()) { + startStream(event_data->segments.begin()->second); } + notifyEvent(onSegmentsMerged); + + // Interrupt the stream to handle segment merge + interruptStream([]() { return false; }); + checkSeekProgress(); } -void Replay::startStream() { - const auto &cur_segment = event_data_->segments.begin()->second; - const auto &events = cur_segment->log->events; +void Replay::startStream(const std::shared_ptr segment) { + const auto &events = segment->log->events; route_start_ts_ = events.front().mono_time; cur_mono_time_ += route_start_ts_ - 1; @@ -212,7 +198,7 @@ void Replay::startStream() { if (!hasFlag(REPLAY_FLAG_NO_VIPC)) { std::pair camera_size[MAX_CAMERAS] = {}; for (auto type : ALL_CAMERAS) { - if (auto &fr = cur_segment->frames[type]) { + if (auto &fr = segment->frames[type]) { camera_size[type] = {fr->width, fr->height}; } } @@ -271,6 +257,7 @@ void Replay::streamThread() { stream_cv_.wait(lk, [this]() { return exit_ || (events_ready_ && !interrupt_requested_); }); if (exit_) break; + event_data_ = seg_mgr_->getEventData(); const auto &events = event_data_->events; auto first = std::upper_bound(events.cbegin(), events.cend(), Event(cur_which, cur_mono_time_, {})); if (first == events.cend()) { @@ -308,11 +295,11 @@ std::vector::const_iterator Replay::publishEvents(std::vector::con for (; !interrupt_requested_ && first != last; ++first) { const Event &evt = *first; - int segment = toSeconds(evt.mono_time) / 60; - if (current_segment_ != segment) { - current_segment_ = segment; - seg_mgr_->setCurrentSegment(current_segment_); + int segment = toSeconds(evt.mono_time) / 60; + if (current_segment_.load(std::memory_order_relaxed) != segment) { + current_segment_.store(segment, std::memory_order_relaxed); + seg_mgr_->setCurrentSegment(segment); } // Skip events if socket is not present diff --git a/tools/replay/replay.h b/tools/replay/replay.h index d549eaefc4dd76..8525a532a1766c 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -55,9 +55,8 @@ class Replay { inline const std::string &carFingerprint() const { return car_fingerprint_; } inline const std::shared_ptr> getTimeline() const { return timeline_.getEntries(); } inline const std::optional findAlertAtTime(double sec) const { return timeline_.findAlertAtTime(sec); } - const std::shared_ptr getEventData() const { return event_data_; } + const std::shared_ptr getEventData() const { return seg_mgr_->getEventData(); } void installEventFilter(std::function filter) { event_filter_ = filter; } - void resumeStream() { interruptStream([]() { return true; }); } // Event callback functions std::function onSegmentsMerged = nullptr; @@ -68,7 +67,7 @@ class Replay { private: void setupServices(const std::vector &allow, const std::vector &block); void setupSegmentManager(bool has_filters); - void startStream(); + void startStream(const std::shared_ptr segment); void streamThread(); void handleSegmentMerge(); void interruptStream(const std::function& update_fn); @@ -76,7 +75,7 @@ class Replay { std::vector::const_iterator last); void publishMessage(const Event *e); void publishFrame(const Event *e); - void checkSeekProgress(double seeked_to_sec); + void checkSeekProgress(); std::unique_ptr seg_mgr_; Timeline timeline_; @@ -86,8 +85,8 @@ class Replay { std::mutex stream_lock_; bool user_paused_ = false; std::condition_variable stream_cv_; - int current_segment_ = 0; - std::optional seeking_to_; + std::atomic current_segment_ = 0; + std::atomic seeking_to_ = -1.0; std::atomic exit_ = false; std::atomic interrupt_requested_ = false; bool events_ready_ = false; diff --git a/tools/replay/seg_mgr.cc b/tools/replay/seg_mgr.cc index 954b25e8744f88..8a00d426b1a804 100644 --- a/tools/replay/seg_mgr.cc +++ b/tools/replay/seg_mgr.cc @@ -105,7 +105,7 @@ bool SegmentManager::mergeSegments(const SegmentMap::iterator &begin, const Segm merged_event_data->segments[n] = segments_.at(n); } - event_data_ = merged_event_data; + std::atomic_store(&event_data_, std::move(merged_event_data)); merged_segments_ = segments_to_merge; return true; diff --git a/tools/replay/seg_mgr.h b/tools/replay/seg_mgr.h index efb3d7f0eadacf..40bdcd51f06d1d 100644 --- a/tools/replay/seg_mgr.h +++ b/tools/replay/seg_mgr.h @@ -21,14 +21,14 @@ class SegmentManager { }; SegmentManager(const std::string &route_name, uint32_t flags, const std::string &data_dir = "") - : flags_(flags), route_(route_name, data_dir) {}; + : flags_(flags), route_(route_name, data_dir), event_data_(std::make_shared()) {} ~SegmentManager(); bool load(); void setCurrentSegment(int seg_num); void setCallback(const std::function &callback) { onSegmentMergedCallback_ = callback; } void setFilters(const std::vector &filters) { filters_ = filters; } - const std::shared_ptr getEventData() const { return event_data_; } + const std::shared_ptr getEventData() const { return std::atomic_load(&event_data_); } bool hasSegment(int n) const { return segments_.find(n) != segments_.end(); } Route route_; diff --git a/tools/replay/timeline.cc b/tools/replay/timeline.cc index d836de972b60f0..a4c2ffb700c1a4 100644 --- a/tools/replay/timeline.cc +++ b/tools/replay/timeline.cc @@ -1,7 +1,7 @@ #include "tools/replay/timeline.h" -#include #include +#include #include "cereal/gen/cpp/log.capnp.h" @@ -74,7 +74,7 @@ void Timeline::buildTimeline(const Route &route, uint64_t route_start_ts, bool l // Sort and finalize the timeline entries auto entries = std::make_shared>(staging_entries_); std::sort(entries->begin(), entries->end(), [](auto &a, auto &b) { return a.start_time < b.start_time; }); - timeline_entries_ = entries; + std::atomic_store(&timeline_entries_, std::move(entries)); callback(log); // Notify the callback once the log is processed } diff --git a/tools/replay/timeline.h b/tools/replay/timeline.h index 689a80635f9b0d..74add9e5cc4623 100644 --- a/tools/replay/timeline.h +++ b/tools/replay/timeline.h @@ -27,20 +27,20 @@ class Timeline { std::function)> callback); std::optional find(double cur_ts, FindFlag flag) const; std::optional findAlertAtTime(double target_time) const; - const std::shared_ptr> getEntries() const { return timeline_entries_; } + const std::shared_ptr> getEntries() const { return std::atomic_load(&timeline_entries_); } private: - void buildTimeline(const Route &route, uint64_t route_start_ts, bool local_cache, - std::function)> callback); - void updateEngagementStatus(const cereal::SelfdriveState::Reader &cs, std::optional &idx, double seconds); - void updateAlertStatus(const cereal::SelfdriveState::Reader &cs, std::optional &idx, double seconds); + void buildTimeline(const Route &route, uint64_t route_start_ts, bool local_cache, + std::function)> callback); + void updateEngagementStatus(const cereal::SelfdriveState::Reader &cs, std::optional &idx, double seconds); + void updateAlertStatus(const cereal::SelfdriveState::Reader &cs, std::optional &idx, double seconds); - std::thread thread_; - std::atomic should_exit_ = false; + std::thread thread_; + std::atomic should_exit_ = false; - // Temporarily holds entries before they are sorted and finalized - std::vector staging_entries_; + // Temporarily holds entries before they are sorted and finalized + std::vector staging_entries_; - // Final sorted timeline entries - std::shared_ptr> timeline_entries_; + // Final sorted timeline entries + std::shared_ptr> timeline_entries_; }; diff --git a/tools/webcam/README.md b/tools/webcam/README.md index c756069bb5d683..f4b46d1f66b23c 100644 --- a/tools/webcam/README.md +++ b/tools/webcam/README.md @@ -1,7 +1,7 @@ # Run openpilot with webcam on PC What's needed: -- Ubuntu 24.04 +- Ubuntu 24.04 ([WSL2 is not supported](https://github.com/commaai/openpilot/issues/34216)) - GPU (recommended) - Two USB webcams, at least 720p and 78 degrees FOV (e.g. Logitech C920/C615) - [Car harness](https://comma.ai/shop/products/comma-car-harness) with black panda to connect to your car @@ -9,29 +9,27 @@ What's needed: That's it! ## Setup openpilot +- Follow [this readme](../README.md) to install and build the requirements +- Install OpenCL Driver ``` -cd ~ -git clone https://github.com/commaai/openpilot.git -``` -- Follow [this readme](https://github.com/commaai/openpilot/tree/master/tools) to install the requirements -- Install [OpenCL Driver](https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532/l_opencl_p_18.1.0.015.tgz) - -## Build openpilot for webcam -``` -cd ~/openpilot -USE_WEBCAM=1 scons -j$(nproc) +sudo apt install pocl-opencl-icd ``` ## Connect the hardware - Connect the road facing camera first, then the driver facing camera -- (default indexes are 1 and 2; can be modified in system/camerad/cameras/camera_webcam.cc) - Connect your computer to panda ## GO ``` -cd ~/openpilot/system/manager -NOSENSOR=1 USE_WEBCAM=1 ./manager.py +USE_WEBCAM=1 system/manager/manager.py ``` - Start the car, then the UI should show the road webcam's view -- Adjust and secure the webcams (you can run tools/webcam/front_mount_helper.py to help mount the driver camera) +- Adjust and secure the webcams. - Finish calibration and engage! + +## Specify Cameras + +Use the `ROAD_CAM`, `DRIVER_CAM`, and optional `WIDE_CAM` environment variables to specify which camera is which (ie. `DRIVER_CAM=2` uses `/dev/video2` for the driver-facing camera): +``` +USE_WEBCAM=1 ROAD_CAM=4 WIDE_CAM=6 system/manager/manager.py +``` diff --git a/tools/webcam/camerad.py b/tools/webcam/camerad.py index 778fefb8344667..a0916ed5ee4ee6 100755 --- a/tools/webcam/camerad.py +++ b/tools/webcam/camerad.py @@ -9,14 +9,14 @@ from openpilot.tools.webcam.camera import Camera from openpilot.common.realtime import Ratekeeper -DUAL_CAM = os.getenv("DUAL_CAMERA") +WIDE_CAM = os.getenv("WIDE_CAM") CameraType = namedtuple("CameraType", ["msg_name", "stream_type", "cam_id"]) CAMERAS = [ - CameraType("roadCameraState", VisionStreamType.VISION_STREAM_ROAD, os.getenv("CAMERA_ROAD_ID", "/dev/video0")), - CameraType("driverCameraState", VisionStreamType.VISION_STREAM_DRIVER, os.getenv("CAMERA_DRIVER_ID", "/dev/video1")), + CameraType("roadCameraState", VisionStreamType.VISION_STREAM_ROAD, os.getenv("ROAD_CAM", "0")), + CameraType("driverCameraState", VisionStreamType.VISION_STREAM_DRIVER, os.getenv("DRIVER_CAM", "2")), ] -if DUAL_CAM: - CAMERAS.append(CameraType("wideRoadCameraState", VisionStreamType.VISION_STREAM_WIDE_ROAD, DUAL_CAM)) +if WIDE_CAM: + CAMERAS.append(CameraType("wideRoadCameraState", VisionStreamType.VISION_STREAM_WIDE_ROAD, WIDE_CAM)) class Camerad: def __init__(self): @@ -25,8 +25,9 @@ def __init__(self): self.cameras = [] for c in CAMERAS: - print(f"opening {c.msg_name} at {c.cam_id}") - cam = Camera(c.msg_name, c.stream_type, c.cam_id) + cam_device = f"/dev/video{c.cam_id}" + print(f"opening {c.msg_name} at {cam_device}") + cam = Camera(c.msg_name, c.stream_type, cam_device) self.cameras.append(cam) self.vipc_server.create_buffers(c.stream_type, 20, cam.W, cam.H) diff --git a/tools/webcam/start_camerad.sh b/tools/webcam/start_camerad.sh deleted file mode 100755 index aefc4c062a00aa..00000000000000 --- a/tools/webcam/start_camerad.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -# export the block below when call manager.py -export BLOCK="${BLOCK},camerad" -export USE_WEBCAM="1" - -# Change camera index according to your setting -export CAMERA_ROAD_ID="/dev/video0" -export CAMERA_DRIVER_ID="/dev/video1" -#export DUAL_CAMERA="/dev/video2" # optional, camera index for wide road camera - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" - -$DIR/camerad.py diff --git a/uv.lock b/uv.lock index 88c18ee8abbda0..96d5c67af902ca 100644 --- a/uv.lock +++ b/uv.lock @@ -1,12 +1,12 @@ version = 1 -requires-python = ">=3.11, <=3.12" +requires-python = ">=3.11, <3.13" resolution-markers = [ "python_full_version < '3.12' and platform_system == 'Darwin'", "python_full_version < '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux'", - "(python_full_version < '3.12' and platform_machine != 'aarch64' and platform_system != 'Darwin') or (python_full_version < '3.12' and platform_system != 'Darwin' and platform_system != 'Linux')", + "(python_full_version < '3.12' and platform_machine != 'aarch64' and platform_system == 'Linux') or (python_full_version < '3.12' and platform_system != 'Darwin' and platform_system != 'Linux')", "python_full_version >= '3.12' and platform_system == 'Darwin'", "python_full_version >= '3.12' and platform_machine == 'aarch64' and platform_system == 'Linux'", - "(python_full_version >= '3.12' and platform_machine != 'aarch64' and platform_system != 'Darwin') or (python_full_version >= '3.12' and platform_system != 'Darwin' and platform_system != 'Linux')", + "(python_full_version >= '3.12' and platform_machine != 'aarch64' and platform_system == 'Linux') or (python_full_version >= '3.12' and platform_system != 'Darwin' and platform_system != 'Linux')", ] [[package]] @@ -105,23 +105,23 @@ wheels = [ [[package]] name = "aiosignal" -version = "1.3.1" +version = "1.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, + { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 }, ] [[package]] name = "attrs" -version = "24.2.0" +version = "24.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } +sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, + { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 }, ] [[package]] @@ -214,11 +214,11 @@ wheels = [ [[package]] name = "certifi" -version = "2024.8.30" +version = "2024.12.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } +sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, + { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, ] [[package]] @@ -501,8 +501,8 @@ name = "ewmhlib" version = "0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "python-xlib", marker = "sys_platform == 'linux'" }, - { name = "typing-extensions" }, + { name = "python-xlib", marker = "platform_system != 'Darwin' and sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "platform_system != 'Darwin'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/2f/3a/46ca34abf0725a754bc44ef474ad34aedcc3ea23b052d97b18b76715a6a9/EWMHlib-0.2-py3-none-any.whl", hash = "sha256:f5b07d8cfd4c7734462ee744c32d490f2f3233fa7ab354240069344208d2f6f5", size = 46657 }, @@ -546,27 +546,27 @@ wheels = [ [[package]] name = "fonttools" -version = "4.55.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/3a/6ab28db8f90c99e6b502436fb642912b590c352d5ba83e0b22b46db209da/fonttools-4.55.2.tar.gz", hash = "sha256:45947e7b3f9673f91df125d375eb57b9a23f2a603f438a1aebf3171bffa7a205", size = 3492954 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/9b/bce708f6293dce086d7e5ecc223da8e57474537a8d7172cd62af5337bb27/fonttools-4.55.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d34525e8141286fa976e14806639d32294bfb38d28bbdb5f6be9f46a1cd695a6", size = 2760153 }, - { url = "https://files.pythonhosted.org/packages/d6/7c/45dc1e5dfa99636acbcd1613914c6892c3c9bd0fe1541070222f29ee72e6/fonttools-4.55.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ecd1c2b1c2ec46bb73685bc5473c72e16ed0930ef79bc2919ccadc43a99fb16", size = 2289801 }, - { url = "https://files.pythonhosted.org/packages/8c/8d/79e099350cb33fbf75903619e2a9933827b67a87f972400645a3eb222db9/fonttools-4.55.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9008438ad59e5a8e403a62fbefef2b2ff377eb3857d90a3f2a5f4d674ff441b2", size = 4866709 }, - { url = "https://files.pythonhosted.org/packages/ff/e3/46a0a2925d71ccf3d804df8a88c93ee645ad9f5d47327b229e4efdb354ed/fonttools-4.55.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:131591ac8d7a47043aaf29581aba755ae151d46e49d2bf49608601efd71e8b4d", size = 4895476 }, - { url = "https://files.pythonhosted.org/packages/40/2e/02607daff1b2e38aec0f321d691bdf835b39c950f90ce3fae1db3eec0871/fonttools-4.55.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4c83381c3e3e3d9caa25527c4300543578341f21aae89e4fbbb4debdda8d82a2", size = 4877249 }, - { url = "https://files.pythonhosted.org/packages/f4/aa/6b3d069968ffb7fa7b3184c6951851fcd79f097f392fecf2b6df9973930d/fonttools-4.55.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:42aca564b575252fd9954ed0d91d97a24de24289a16ce8ff74ed0bdf5ecebf11", size = 5046125 }, - { url = "https://files.pythonhosted.org/packages/4c/dd/fb1f66fbac4c0f7bc3ef206d08b490f9b3dd5eb89879d1f1c1e41ef2937c/fonttools-4.55.2-cp311-cp311-win32.whl", hash = "sha256:c6457f650ebe15baa17fc06e256227f0a47f46f80f27ec5a0b00160de8dc2c13", size = 2162949 }, - { url = "https://files.pythonhosted.org/packages/86/b1/1198970a2b0ebccceae5fc8963e2e9c2a2aae23bd2f5a9be603dc3894f31/fonttools-4.55.2-cp311-cp311-win_amd64.whl", hash = "sha256:5cfa67414d7414442a5635ff634384101c54f53bb7b0e04aa6a61b013fcce194", size = 2209371 }, - { url = "https://files.pythonhosted.org/packages/3c/62/7ac990a52c2bb249e9de6de0036a24eba5a5a8e8446819ab5a5751a0a45e/fonttools-4.55.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:18f082445b8fe5e91c53e6184f4c1c73f3f965c8bcc614c6cd6effd573ce6c1a", size = 2754521 }, - { url = "https://files.pythonhosted.org/packages/4a/bd/a8034bf5d685f825cec0aca6759639277b1d3b0b1d38842b5f30edfb4176/fonttools-4.55.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c0f91adbbd706e8acd1db73e3e510118e62d0ffb651864567dccc5b2339f90", size = 2287092 }, - { url = "https://files.pythonhosted.org/packages/70/ad/edf4f4e0efdda8205893007d30d62da09f92d3f0b0f1a3faf85bd5df9952/fonttools-4.55.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d8ccce035320d63dba0c35f52499322f5531dbe85bba1514c7cea26297e4c54", size = 4782490 }, - { url = "https://files.pythonhosted.org/packages/7a/5f/f757e5860cc4f187fdf8eacf53abc92613cdbc55355e13ba07e2c937d217/fonttools-4.55.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96e126df9615df214ec7f04bebcf60076297fbc10b75c777ce58b702d7708ffb", size = 4854787 }, - { url = "https://files.pythonhosted.org/packages/92/1b/c647b89e5603f9ae9b8f14885dfaf523351eb9d0b5dcbafaf1512d0d4d97/fonttools-4.55.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:508ebb42956a7a931c4092dfa2d9b4ffd4f94cea09b8211199090d2bd082506b", size = 4763330 }, - { url = "https://files.pythonhosted.org/packages/57/09/117e2b5b2d2fcd607b360e241939a652505577c752f9ca15b2fb9e4fc540/fonttools-4.55.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1b9de46ef7b683d50400abf9f1578eaceee271ff51c36bf4b7366f2be29f498", size = 4990999 }, - { url = "https://files.pythonhosted.org/packages/b9/e5/9be5bd4bfb83187fb83f46b9be6676f653c08a430b975e0a3355fd248c37/fonttools-4.55.2-cp312-cp312-win32.whl", hash = "sha256:2df61d9fc15199cc86dad29f64dd686874a3a52dda0c2d8597d21f509f95c332", size = 2151234 }, - { url = "https://files.pythonhosted.org/packages/f3/c5/0eda5db19bd5fe3f6b8dc30ca5be512999b4923268b9b82fd14c211217b5/fonttools-4.55.2-cp312-cp312-win_amd64.whl", hash = "sha256:d337ec087da8216a828574aa0525d869df0a2ac217a2efc1890974ddd1fbc5b9", size = 2198133 }, - { url = "https://files.pythonhosted.org/packages/69/94/c4d8dfe26a971e00e34df99b46e9518425f59918c8993830e904171e21f9/fonttools-4.55.2-py3-none-any.whl", hash = "sha256:8e2d89fbe9b08d96e22c7a81ec04a4e8d8439c31223e2dc6f2f9fc8ff14bdf9f", size = 1100792 }, +version = "4.55.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/61/a300d1574dc381393424047c0396a0e213db212e28361123af9830d71a8d/fonttools-4.55.3.tar.gz", hash = "sha256:3983313c2a04d6cc1fe9251f8fc647754cf49a61dac6cb1e7249ae67afaafc45", size = 3498155 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/18/14be25545600bd100e5b74a3ac39089b7c1cb403dc513b7ca348be3381bf/fonttools-4.55.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c4491699bad88efe95772543cd49870cf756b019ad56294f6498982408ab03e", size = 2771005 }, + { url = "https://files.pythonhosted.org/packages/b2/51/2e1a5d3871cd7c2ae2054b54e92604e7d6abc3fd3656e9583c399648fe1c/fonttools-4.55.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5323a22eabddf4b24f66d26894f1229261021dacd9d29e89f7872dd8c63f0b8b", size = 2300654 }, + { url = "https://files.pythonhosted.org/packages/73/1a/50109bb2703bc6f774b52ea081db21edf2a9fa4b6d7485faadf9d1b997e9/fonttools-4.55.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5480673f599ad410695ca2ddef2dfefe9df779a9a5cda89503881e503c9c7d90", size = 4877541 }, + { url = "https://files.pythonhosted.org/packages/5d/52/c0b9857fa075da1b8806c5dc2d8342918a8cc2065fd14fbddb3303282693/fonttools-4.55.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da9da6d65cd7aa6b0f806556f4985bcbf603bf0c5c590e61b43aa3e5a0f822d0", size = 4906304 }, + { url = "https://files.pythonhosted.org/packages/0b/1b/55f85c7e962d295e456d5209581c919620ee3e877b95cd86245187a5050f/fonttools-4.55.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e894b5bd60d9f473bed7a8f506515549cc194de08064d829464088d23097331b", size = 4888087 }, + { url = "https://files.pythonhosted.org/packages/83/13/6f2809c612ea2ac51391f92468ff861c63473601530fca96458b453212bf/fonttools-4.55.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aee3b57643827e237ff6ec6d28d9ff9766bd8b21e08cd13bff479e13d4b14765", size = 5056958 }, + { url = "https://files.pythonhosted.org/packages/c1/28/d0ea9e872fa4208b9dfca686e1dd9ca22f6c9ef33ecff2f0ebc2dbe7c29b/fonttools-4.55.3-cp311-cp311-win32.whl", hash = "sha256:eb6ca911c4c17eb51853143624d8dc87cdcdf12a711fc38bf5bd21521e79715f", size = 2173939 }, + { url = "https://files.pythonhosted.org/packages/be/36/d74ae1020bc41a1dff3e6f5a99f646563beecb97e386d27abdac3ba07650/fonttools-4.55.3-cp311-cp311-win_amd64.whl", hash = "sha256:6314bf82c54c53c71805318fcf6786d986461622dd926d92a465199ff54b1b72", size = 2220363 }, + { url = "https://files.pythonhosted.org/packages/89/58/fbcf5dff7e3ea844bb00c4d806ca1e339e1f2dce5529633bf4842c0c9a1f/fonttools-4.55.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f9e736f60f4911061235603a6119e72053073a12c6d7904011df2d8fad2c0e35", size = 2765380 }, + { url = "https://files.pythonhosted.org/packages/81/dd/da6e329e51919b4f421c8738f3497e2ab08c168e76aaef7b6d5351862bdf/fonttools-4.55.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a8aa2c5e5b8b3bcb2e4538d929f6589a5c6bdb84fd16e2ed92649fb5454f11c", size = 2297940 }, + { url = "https://files.pythonhosted.org/packages/00/44/f5ee560858425c99ef07e04919e736db09d6416408e5a8d3bbfb4a6623fd/fonttools-4.55.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07f8288aacf0a38d174445fc78377a97fb0b83cfe352a90c9d9c1400571963c7", size = 4793327 }, + { url = "https://files.pythonhosted.org/packages/24/da/0a001926d791c55e29ac3c52964957a20dbc1963615446b568b7432891c3/fonttools-4.55.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8d5e8916c0970fbc0f6f1bece0063363bb5857a7f170121a4493e31c3db3314", size = 4865624 }, + { url = "https://files.pythonhosted.org/packages/3d/d8/1edd8b13a427a9fb6418373437caa586c0caa57f260af8e0548f4d11e340/fonttools-4.55.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae3b6600565b2d80b7c05acb8e24d2b26ac407b27a3f2e078229721ba5698427", size = 4774166 }, + { url = "https://files.pythonhosted.org/packages/9c/ec/ade054097976c3d6debc9032e09a351505a0196aa5493edf021be376f75e/fonttools-4.55.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:54153c49913f45065c8d9e6d0c101396725c5621c8aee744719300f79771d75a", size = 5001832 }, + { url = "https://files.pythonhosted.org/packages/e2/cd/233f0e31ad799bb91fc78099c8b4e5ec43b85a131688519640d6bae46f6a/fonttools-4.55.3-cp312-cp312-win32.whl", hash = "sha256:827e95fdbbd3e51f8b459af5ea10ecb4e30af50221ca103bea68218e9615de07", size = 2162228 }, + { url = "https://files.pythonhosted.org/packages/46/45/a498b5291f6c0d91b2394b1ed7447442a57d1c9b9cf8f439aee3c316a56e/fonttools-4.55.3-cp312-cp312-win_amd64.whl", hash = "sha256:e6e8766eeeb2de759e862004aa11a9ea3d6f6d5ec710551a88b476192b64fd54", size = 2209118 }, + { url = "https://files.pythonhosted.org/packages/99/3b/406d17b1f63e04a82aa621936e6e1c53a8c05458abd66300ac85ea7f9ae9/fonttools-4.55.3-py3-none-any.whl", hash = "sha256:f412604ccbeee81b091b420272841e5ec5ef68967a9790e80bffd0e30b8e2977", size = 1111638 }, ] [[package]] @@ -667,7 +667,7 @@ name = "humanfriendly" version = "10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyreadline3", marker = "sys_platform == 'win32'" }, + { name = "pyreadline3", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702 } wheels = [ @@ -919,7 +919,7 @@ wheels = [ [[package]] name = "matplotlib" -version = "3.9.3" +version = "3.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "contourpy" }, @@ -932,20 +932,20 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/75/9f/562ed484b11ac9f4bb4f9d2d7546954ec106a8c0f06cc755d6f63e519274/matplotlib-3.9.3.tar.gz", hash = "sha256:cd5dbbc8e25cad5f706845c4d100e2c8b34691b412b93717ce38d8ae803bcfa5", size = 36113438 } +sdist = { url = "https://files.pythonhosted.org/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", size = 36686418 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/ac/66ac58c42aad9ac0ed665746a8a36ecbd16a6c908527c305f9504c04fc2c/matplotlib-3.9.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:cf2a60daf6cecff6828bc608df00dbc794380e7234d2411c0ec612811f01969d", size = 7886350 }, - { url = "https://files.pythonhosted.org/packages/db/43/1274be2b1922858c7a43f0d6e00571fe24696788c7b5a8c980127af24a96/matplotlib-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:213d6dc25ce686516208d8a3e91120c6a4fdae4a3e06b8505ced5b716b50cc04", size = 7771966 }, - { url = "https://files.pythonhosted.org/packages/5f/89/f1bcc6b62707df427a5e6a34be59191da81d96e63d3f92cb61e948bcbca7/matplotlib-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c52f48eb75fcc119a4fdb68ba83eb5f71656999420375df7c94cc68e0e14686e", size = 8201827 }, - { url = "https://files.pythonhosted.org/packages/13/53/b178d51478109f7a700edc94757dd07112e9a0c7a158653b99434b74f9fb/matplotlib-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c93796b44fa111049b88a24105e947f03c01966b5c0cc782e2ee3887b790a3", size = 8314794 }, - { url = "https://files.pythonhosted.org/packages/d6/57/d0ef6cef13ed0f55e37472cc458f2f1f8c4fe9aac69f794be7ccd0702d03/matplotlib-3.9.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cd1077b9a09b16d8c3c7075a8add5ffbfe6a69156a57e290c800ed4d435bef1d", size = 9091489 }, - { url = "https://files.pythonhosted.org/packages/33/97/40a1bed11f7817ba553afd2e7662e7364e3bac7ce4040835391eb558c86e/matplotlib-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:c96eeeb8c68b662c7747f91a385688d4b449687d29b691eff7068a4602fe6dc4", size = 7829997 }, - { url = "https://files.pythonhosted.org/packages/74/d5/eb2338d21b2d36511f9417230413fa0c30fc82283b33dc0e3643969f3b50/matplotlib-3.9.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0a361bd5583bf0bcc08841df3c10269617ee2a36b99ac39d455a767da908bbbc", size = 7883049 }, - { url = "https://files.pythonhosted.org/packages/e5/52/3910833a073e7182ab3ae03810ed418f71c7fdcd65e2862cda1c6a14ffc1/matplotlib-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e14485bb1b83eeb3d55b6878f9560240981e7bbc7a8d4e1e8c38b9bd6ec8d2de", size = 7768285 }, - { url = "https://files.pythonhosted.org/packages/92/67/69df4b6636e40e964788b003535561ea3e98e33e46df4d96fa8c34ef99e6/matplotlib-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a8d279f78844aad213c4935c18f8292a9432d51af2d88bca99072c903948045", size = 8192626 }, - { url = "https://files.pythonhosted.org/packages/40/d6/70a196b0cf62e0a5bc64ccab07816ab4f6c98db0414a55280331a481a5bf/matplotlib-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6c12514329ac0d03128cf1dcceb335f4fbf7c11da98bca68dca8dcb983153a9", size = 8305687 }, - { url = "https://files.pythonhosted.org/packages/c3/43/ef6ab78dd2d8eb362c1e5a31f9cec5ece5761e6143a519153d716d85e590/matplotlib-3.9.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6e9de2b390d253a508dd497e9b5579f3a851f208763ed67fdca5dc0c3ea6849c", size = 9087208 }, - { url = "https://files.pythonhosted.org/packages/30/cb/36844affc69490652b5a99296b9fcee530b96621e23d3143a4839f30fb22/matplotlib-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d796272408f8567ff7eaa00eb2856b3a00524490e47ad505b0b4ca6bb8a7411f", size = 7833105 }, + { url = "https://files.pythonhosted.org/packages/0c/f1/e37f6c84d252867d7ddc418fff70fc661cfd363179263b08e52e8b748e30/matplotlib-3.10.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:fd44fc75522f58612ec4a33958a7e5552562b7705b42ef1b4f8c0818e304a363", size = 8171677 }, + { url = "https://files.pythonhosted.org/packages/c7/8b/92e9da1f28310a1f6572b5c55097b0c0ceb5e27486d85fb73b54f5a9b939/matplotlib-3.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c58a9622d5dbeb668f407f35f4e6bfac34bb9ecdcc81680c04d0258169747997", size = 8044945 }, + { url = "https://files.pythonhosted.org/packages/c5/cb/49e83f0fd066937a5bd3bc5c5d63093703f3637b2824df8d856e0558beef/matplotlib-3.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:845d96568ec873be63f25fa80e9e7fae4be854a66a7e2f0c8ccc99e94a8bd4ef", size = 8458269 }, + { url = "https://files.pythonhosted.org/packages/b2/7d/2d873209536b9ee17340754118a2a17988bc18981b5b56e6715ee07373ac/matplotlib-3.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5439f4c5a3e2e8eab18e2f8c3ef929772fd5641876db71f08127eed95ab64683", size = 8599369 }, + { url = "https://files.pythonhosted.org/packages/b8/03/57d6cbbe85c61fe4cbb7c94b54dce443d68c21961830833a1f34d056e5ea/matplotlib-3.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4673ff67a36152c48ddeaf1135e74ce0d4bce1bbf836ae40ed39c29edf7e2765", size = 9405992 }, + { url = "https://files.pythonhosted.org/packages/14/cf/e382598f98be11bf51dd0bc60eca44a517f6793e3dc8b9d53634a144620c/matplotlib-3.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:7e8632baebb058555ac0cde75db885c61f1212e47723d63921879806b40bec6a", size = 8034580 }, + { url = "https://files.pythonhosted.org/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", size = 8172465 }, + { url = "https://files.pythonhosted.org/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", size = 8043300 }, + { url = "https://files.pythonhosted.org/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", size = 8448936 }, + { url = "https://files.pythonhosted.org/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", size = 8594151 }, + { url = "https://files.pythonhosted.org/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", size = 9400347 }, + { url = "https://files.pythonhosted.org/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", size = 8039144 }, ] [[package]] @@ -959,8 +959,8 @@ wheels = [ [[package]] name = "metadrive-simulator" -version = "0.4.2.3" -source = { url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal/metadrive_simulator-0.4.2.3-py3-none-any.whl" } +version = "0.4.2.4" +source = { url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl" } dependencies = [ { name = "filelock", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, { name = "gymnasium", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, @@ -980,7 +980,7 @@ dependencies = [ { name = "yapf", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] wheels = [ - { url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal/metadrive_simulator-0.4.2.3-py3-none-any.whl", hash = "sha256:6242d4e37e6c592d5eb1cadf497637540d3b754b89813a88c50a93c7fc88b02d" }, + { url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl", hash = "sha256:fbf0ea9be67e65cd45d38ff930e3d49f705dd76c9ddbd1e1482e3f87b61efcef" }, ] [package.metadata] @@ -1372,7 +1372,7 @@ requires-dist = [ { name = "libusb1" }, { name = "lru-dict", marker = "extra == 'dev'" }, { name = "matplotlib", marker = "extra == 'dev'" }, - { name = "metadrive-simulator", marker = "platform_machine != 'aarch64' and extra == 'tools'", url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal/metadrive_simulator-0.4.2.3-py3-none-any.whl" }, + { name = "metadrive-simulator", marker = "platform_machine != 'aarch64' and extra == 'tools'", url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl" }, { name = "mkdocs", marker = "extra == 'docs'" }, { name = "mypy", marker = "extra == 'testing'" }, { name = "natsort", marker = "extra == 'docs'" }, @@ -1825,10 +1825,10 @@ name = "pymonctl" version = "0.92" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ewmhlib", marker = "sys_platform == 'linux'" }, - { name = "pyobjc", marker = "sys_platform == 'darwin'" }, - { name = "python-xlib", marker = "sys_platform == 'linux'" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "ewmhlib", marker = "platform_system != 'Darwin' and sys_platform == 'linux'" }, + { name = "pyobjc", marker = "(platform_machine != 'aarch64' and sys_platform == 'darwin') or (platform_system != 'Linux' and sys_platform == 'darwin')" }, + { name = "python-xlib", marker = "platform_system != 'Darwin' and sys_platform == 'linux'" }, + { name = "pywin32", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "typing-extensions" }, ] wheels = [ @@ -1846,159 +1846,159 @@ name = "pyobjc" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-accessibility", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-accounts", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-addressbook" }, - { name = "pyobjc-framework-adservices", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-adsupport", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-applescriptkit" }, - { name = "pyobjc-framework-applescriptobjc", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-applicationservices" }, - { name = "pyobjc-framework-apptrackingtransparency", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-audiovideobridging", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-authenticationservices", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-automaticassessmentconfiguration", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-automator" }, - { name = "pyobjc-framework-avfoundation", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-avkit", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-avrouting", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-backgroundassets", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-browserenginekit", marker = "platform_release >= '23.4'" }, - { name = "pyobjc-framework-businesschat", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-calendarstore", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-callkit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-cfnetwork" }, - { name = "pyobjc-framework-cinematic", marker = "platform_release >= '23.0'" }, - { name = "pyobjc-framework-classkit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-cloudkit", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-collaboration", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-colorsync", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-contacts", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-contactsui", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coreaudiokit" }, - { name = "pyobjc-framework-corebluetooth", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-coredata" }, - { name = "pyobjc-framework-corehaptics", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-corelocation", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-coremedia", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-coremediaio", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-coremidi" }, - { name = "pyobjc-framework-coreml", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-coremotion", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-coreservices" }, - { name = "pyobjc-framework-corespotlight", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-coretext" }, - { name = "pyobjc-framework-corewlan", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-cryptotokenkit", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-datadetection", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-devicecheck", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-dictionaryservices", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-discrecording" }, - { name = "pyobjc-framework-discrecordingui" }, - { name = "pyobjc-framework-diskarbitration" }, - { name = "pyobjc-framework-dvdplayback" }, - { name = "pyobjc-framework-eventkit", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-exceptionhandling" }, - { name = "pyobjc-framework-executionpolicy", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-extensionkit", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-externalaccessory", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-fileprovider", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-fileproviderui", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-findersync", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-fsevents", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-gamecenter", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-gamecontroller", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-gamekit", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-gameplaykit", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-healthkit", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-imagecapturecore", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-inputmethodkit", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-installerplugins" }, - { name = "pyobjc-framework-instantmessage", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-intents", marker = "platform_release >= '16.0'" }, - { name = "pyobjc-framework-intentsui", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-iobluetooth" }, - { name = "pyobjc-framework-iobluetoothui" }, - { name = "pyobjc-framework-iosurface", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-ituneslibrary", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-kernelmanagement", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-latentsemanticmapping" }, - { name = "pyobjc-framework-launchservices" }, - { name = "pyobjc-framework-libdispatch", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-libxpc", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-linkpresentation", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-localauthentication", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-localauthenticationembeddedui", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-mailkit", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-mapkit", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-mediaaccessibility", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-medialibrary", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-mediaplayer", marker = "platform_release >= '16.0'" }, - { name = "pyobjc-framework-mediatoolbox", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-metal", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-metalfx", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-metalkit", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-metalperformanceshaders", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-metalperformanceshadersgraph", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-metrickit", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-mlcompute", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-modelio", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-multipeerconnectivity", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-naturallanguage", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-netfs", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-network", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-networkextension", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-notificationcenter", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-opendirectory", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-osakit" }, - { name = "pyobjc-framework-oslog", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-passkit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-pencilkit", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-phase", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-photos", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-photosui", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-preferencepanes" }, - { name = "pyobjc-framework-pushkit", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-quartz" }, - { name = "pyobjc-framework-quicklookthumbnailing", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-replaykit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-safariservices", marker = "platform_release >= '16.0'" }, - { name = "pyobjc-framework-safetykit", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-scenekit", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-screencapturekit", marker = "platform_release >= '21.4'" }, - { name = "pyobjc-framework-screensaver" }, - { name = "pyobjc-framework-screentime", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-scriptingbridge", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-searchkit" }, - { name = "pyobjc-framework-security" }, - { name = "pyobjc-framework-securityfoundation" }, - { name = "pyobjc-framework-securityinterface" }, - { name = "pyobjc-framework-sensitivecontentanalysis", marker = "platform_release >= '23.0'" }, - { name = "pyobjc-framework-servicemanagement", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-sharedwithyou", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-sharedwithyoucore", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-shazamkit", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-social", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-soundanalysis", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-speech", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-spritekit", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-storekit", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-symbols", marker = "platform_release >= '23.0'" }, - { name = "pyobjc-framework-syncservices" }, - { name = "pyobjc-framework-systemconfiguration" }, - { name = "pyobjc-framework-systemextensions", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-threadnetwork", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-uniformtypeidentifiers", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-usernotifications", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-usernotificationsui", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-videosubscriberaccount", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-videotoolbox", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-virtualization", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-vision", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-webkit" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-accessibility", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-accounts", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-addressbook", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-adservices", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-adsupport", marker = "(platform_machine != 'aarch64' and platform_release >= '18.0') or (platform_release >= '18.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-applescriptkit", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-applescriptobjc", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-applicationservices", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-apptrackingtransparency", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-audiovideobridging", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-authenticationservices", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-automaticassessmentconfiguration", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-automator", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-avfoundation", marker = "(platform_machine != 'aarch64' and platform_release >= '11.0') or (platform_release >= '11.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-avkit", marker = "(platform_machine != 'aarch64' and platform_release >= '13.0') or (platform_release >= '13.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-avrouting", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-backgroundassets", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-browserenginekit", marker = "(platform_machine != 'aarch64' and platform_release >= '23.4') or (platform_release >= '23.4' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-businesschat", marker = "(platform_machine != 'aarch64' and platform_release >= '18.0') or (platform_release >= '18.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-calendarstore", marker = "(platform_machine != 'aarch64' and platform_release >= '9.0') or (platform_release >= '9.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-callkit", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-cfnetwork", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cinematic", marker = "(platform_machine != 'aarch64' and platform_release >= '23.0') or (platform_release >= '23.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-classkit", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-cloudkit", marker = "(platform_machine != 'aarch64' and platform_release >= '14.0') or (platform_release >= '14.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-collaboration", marker = "(platform_machine != 'aarch64' and platform_release >= '9.0') or (platform_release >= '9.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-colorsync", marker = "(platform_machine != 'aarch64' and platform_release >= '17.0') or (platform_release >= '17.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-contacts", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-contactsui", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-coreaudio", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreaudiokit", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-corebluetooth", marker = "(platform_machine != 'aarch64' and platform_release >= '14.0') or (platform_release >= '14.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-coredata", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-corehaptics", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-corelocation", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-coremedia", marker = "(platform_machine != 'aarch64' and platform_release >= '11.0') or (platform_release >= '11.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-coremediaio", marker = "(platform_machine != 'aarch64' and platform_release >= '11.0') or (platform_release >= '11.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-coremidi", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreml", marker = "(platform_machine != 'aarch64' and platform_release >= '17.0') or (platform_release >= '17.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-coremotion", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-coreservices", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-corespotlight", marker = "(platform_machine != 'aarch64' and platform_release >= '17.0') or (platform_release >= '17.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-coretext", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-corewlan", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-cryptotokenkit", marker = "(platform_machine != 'aarch64' and platform_release >= '14.0') or (platform_release >= '14.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-datadetection", marker = "(platform_machine != 'aarch64' and platform_release >= '21.0') or (platform_release >= '21.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-devicecheck", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-dictionaryservices", marker = "(platform_machine != 'aarch64' and platform_release >= '9.0') or (platform_release >= '9.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-discrecording", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-discrecordingui", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-diskarbitration", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-dvdplayback", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-eventkit", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-exceptionhandling", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-executionpolicy", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-extensionkit", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-externalaccessory", marker = "(platform_machine != 'aarch64' and platform_release >= '17.0') or (platform_release >= '17.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-fileprovider", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-fileproviderui", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-findersync", marker = "(platform_machine != 'aarch64' and platform_release >= '14.0') or (platform_release >= '14.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-fsevents", marker = "(platform_machine != 'aarch64' and platform_release >= '9.0') or (platform_release >= '9.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-gamecenter", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-gamecontroller", marker = "(platform_machine != 'aarch64' and platform_release >= '13.0') or (platform_release >= '13.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-gamekit", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-gameplaykit", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-healthkit", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-imagecapturecore", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-inputmethodkit", marker = "(platform_machine != 'aarch64' and platform_release >= '9.0') or (platform_release >= '9.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-installerplugins", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-instantmessage", marker = "(platform_machine != 'aarch64' and platform_release >= '9.0') or (platform_release >= '9.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-intents", marker = "(platform_machine != 'aarch64' and platform_release >= '16.0') or (platform_release >= '16.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-intentsui", marker = "(platform_machine != 'aarch64' and platform_release >= '21.0') or (platform_release >= '21.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-iobluetooth", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-iobluetoothui", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-iosurface", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-ituneslibrary", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-kernelmanagement", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-latentsemanticmapping", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-launchservices", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-libdispatch", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-libxpc", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-linkpresentation", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-localauthentication", marker = "(platform_machine != 'aarch64' and platform_release >= '14.0') or (platform_release >= '14.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-localauthenticationembeddedui", marker = "(platform_machine != 'aarch64' and platform_release >= '21.0') or (platform_release >= '21.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-mailkit", marker = "(platform_machine != 'aarch64' and platform_release >= '21.0') or (platform_release >= '21.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-mapkit", marker = "(platform_machine != 'aarch64' and platform_release >= '13.0') or (platform_release >= '13.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-mediaaccessibility", marker = "(platform_machine != 'aarch64' and platform_release >= '13.0') or (platform_release >= '13.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-medialibrary", marker = "(platform_machine != 'aarch64' and platform_release >= '13.0') or (platform_release >= '13.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-mediaplayer", marker = "(platform_machine != 'aarch64' and platform_release >= '16.0') or (platform_release >= '16.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-mediatoolbox", marker = "(platform_machine != 'aarch64' and platform_release >= '13.0') or (platform_release >= '13.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-metal", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-metalfx", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-metalkit", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-metalperformanceshaders", marker = "(platform_machine != 'aarch64' and platform_release >= '17.0') or (platform_release >= '17.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-metalperformanceshadersgraph", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-metrickit", marker = "(platform_machine != 'aarch64' and platform_release >= '21.0') or (platform_release >= '21.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-mlcompute", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-modelio", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-multipeerconnectivity", marker = "(platform_machine != 'aarch64' and platform_release >= '14.0') or (platform_release >= '14.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-naturallanguage", marker = "(platform_machine != 'aarch64' and platform_release >= '18.0') or (platform_release >= '18.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-netfs", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-network", marker = "(platform_machine != 'aarch64' and platform_release >= '18.0') or (platform_release >= '18.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-networkextension", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-notificationcenter", marker = "(platform_machine != 'aarch64' and platform_release >= '14.0') or (platform_release >= '14.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-opendirectory", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-osakit", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-oslog", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-passkit", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-pencilkit", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-phase", marker = "(platform_machine != 'aarch64' and platform_release >= '21.0') or (platform_release >= '21.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-photos", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-photosui", marker = "(platform_machine != 'aarch64' and platform_release >= '15.0') or (platform_release >= '15.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-preferencepanes", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-pushkit", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quicklookthumbnailing", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-replaykit", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-safariservices", marker = "(platform_machine != 'aarch64' and platform_release >= '16.0') or (platform_release >= '16.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-safetykit", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-scenekit", marker = "(platform_machine != 'aarch64' and platform_release >= '11.0') or (platform_release >= '11.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-screencapturekit", marker = "(platform_machine != 'aarch64' and platform_release >= '21.4') or (platform_release >= '21.4' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-screensaver", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-screentime", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-scriptingbridge", marker = "(platform_machine != 'aarch64' and platform_release >= '9.0') or (platform_release >= '9.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-searchkit", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-security", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-securityfoundation", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-securityinterface", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-sensitivecontentanalysis", marker = "(platform_machine != 'aarch64' and platform_release >= '23.0') or (platform_release >= '23.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-servicemanagement", marker = "(platform_machine != 'aarch64' and platform_release >= '10.0') or (platform_release >= '10.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-sharedwithyou", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-sharedwithyoucore", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-shazamkit", marker = "(platform_machine != 'aarch64' and platform_release >= '21.0') or (platform_release >= '21.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-social", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-soundanalysis", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-speech", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-spritekit", marker = "(platform_machine != 'aarch64' and platform_release >= '13.0') or (platform_release >= '13.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-storekit", marker = "(platform_machine != 'aarch64' and platform_release >= '11.0') or (platform_release >= '11.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-symbols", marker = "(platform_machine != 'aarch64' and platform_release >= '23.0') or (platform_release >= '23.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-syncservices", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-systemconfiguration", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-systemextensions", marker = "(platform_machine != 'aarch64' and platform_release >= '19.0') or (platform_release >= '19.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-threadnetwork", marker = "(platform_machine != 'aarch64' and platform_release >= '22.0') or (platform_release >= '22.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-uniformtypeidentifiers", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-usernotifications", marker = "(platform_machine != 'aarch64' and platform_release >= '18.0') or (platform_release >= '18.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-usernotificationsui", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-videosubscriberaccount", marker = "(platform_machine != 'aarch64' and platform_release >= '18.0') or (platform_release >= '18.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-videotoolbox", marker = "(platform_machine != 'aarch64' and platform_release >= '12.0') or (platform_release >= '12.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-virtualization", marker = "(platform_machine != 'aarch64' and platform_release >= '20.0') or (platform_release >= '20.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-vision", marker = "(platform_machine != 'aarch64' and platform_release >= '17.0') or (platform_release >= '17.0' and platform_system != 'Linux')" }, + { name = "pyobjc-framework-webkit", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c8/89/982c55c5f4fc9ae1f22fb92b4dc003424df1d43da67f305d0a62ee00f6ac/pyobjc-10.3.2.tar.gz", hash = "sha256:1f35f3f8fc48028f2fdca48f55ac72073fe8980b9fa11a94b86ad69f50c9bd75", size = 10976 } wheels = [ @@ -2020,9 +2020,9 @@ name = "pyobjc-framework-accessibility" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3e/08/e87e90c8de6851589bd8c02ca64eac2dbe1cf51b62fd06a3cb2e52cddb91/pyobjc_framework_accessibility-10.3.2.tar.gz", hash = "sha256:2a7f29d7fae54db6e447d746d29f1c720b48b4d41cf3ed927a58949917c2b7ed", size = 29704 } wheels = [ @@ -2037,8 +2037,8 @@ name = "pyobjc-framework-accounts" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/41/99/587ce238d38c7ebe52c3f9ecc7a50b47ce51e6ace833e6b82435558fc086/pyobjc_framework_accounts-10.3.2.tar.gz", hash = "sha256:50460f185206d57755ddf942f216177ff10b3cda48e6969ed88e57aad1f354d6", size = 16498 } wheels = [ @@ -2051,8 +2051,8 @@ name = "pyobjc-framework-addressbook" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/8a/613db5bbbce90439322a8c2a40274af2780f65e9996604e00061690badbf/pyobjc_framework_addressbook-10.3.2.tar.gz", hash = "sha256:d5c9677aa64e8116b31a1d3f39f0bf2d1681f7cb93dbdc21db314c9dd8ac82f7", size = 85044 } wheels = [ @@ -2067,8 +2067,8 @@ name = "pyobjc-framework-adservices" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d2/49/b3fccd144e3357762278c40a669dfa53a6fdf6ced47217156f7112228dfc/pyobjc_framework_adservices-10.3.2.tar.gz", hash = "sha256:217c25adad25365a65ae9bbdd7e110b3b4597bcb78d9a914b00067a2135906df", size = 12169 } wheels = [ @@ -2081,8 +2081,8 @@ name = "pyobjc-framework-adsupport" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/dd/bdeecdde652e82bfe7d75fddc2e70682433d564bafc5fc851c5e2c558443/pyobjc_framework_adsupport-10.3.2.tar.gz", hash = "sha256:71cac2c9a4dd764fefc7b257483338f73d9783038d52028b97446ea83ad37c87", size = 12307 } wheels = [ @@ -2095,8 +2095,8 @@ name = "pyobjc-framework-applescriptkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1a/78/5abe58d1698dfacc0e5ab719aa2cd93879230e45b9387bcc3b0bb91040d3/pyobjc_framework_applescriptkit-10.3.2.tar.gz", hash = "sha256:a4d74fc6b28d1ff7d39b60c9e0c2d5d1baf575ade6e6d1ea06ed077facec47db", size = 12102 } wheels = [ @@ -2109,8 +2109,8 @@ name = "pyobjc-framework-applescriptobjc" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/8b/d720f671b21a07a8d1815c54ce4e8f313f73ea645a82faa8331a2a05d9c2/pyobjc_framework_applescriptobjc-10.3.2.tar.gz", hash = "sha256:6af16cab0fe4e2d50775e67501bcecae1c5acdba7ed560eba38e5f8e3c8ac38c", size = 12166 } wheels = [ @@ -2123,10 +2123,10 @@ name = "pyobjc-framework-applicationservices" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coretext" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coretext", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/78/a0/32cd02c3e5f0f740f86064a078278c180d3058c857b8425a5128866e3931/pyobjc_framework_applicationservices-10.3.2.tar.gz", hash = "sha256:2116c3854ac07c022268eebc7cb40ccba30727df78442e57e0280b5193c8183c", size = 183088 } wheels = [ @@ -2139,8 +2139,8 @@ name = "pyobjc-framework-apptrackingtransparency" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a2/9f/bd8bb6d37c96060ea265d65e2dd9b6bf30801f6ffd922db7635165ac0968/pyobjc_framework_apptrackingtransparency-10.3.2.tar.gz", hash = "sha256:b1a0c19321f103d7f9c146b921d260083bb536a4d28b9d4337ca2ea4f88318a1", size = 12863 } wheels = [ @@ -2153,8 +2153,8 @@ name = "pyobjc-framework-audiovideobridging" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/ea/67984a0d4065cbf6982d4e18581fa2b8a0023c37ee5bf436ccebb6c8f552/pyobjc_framework_audiovideobridging-10.3.2.tar.gz", hash = "sha256:72b1c8a07fb5ab4f988c9172e5ddf44f1fd15214aa5dc2f80852c6152e13b2b8", size = 59579 } wheels = [ @@ -2167,8 +2167,8 @@ name = "pyobjc-framework-authenticationservices" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dd/16/ca8a01b9ff6bb50fd35465b1a31785575096b4aa079ccbc90cbd40cf7db1/pyobjc_framework_authenticationservices-10.3.2.tar.gz", hash = "sha256:ff990cb7bc2ac9599082f162e38e4db3bf7504c71948c09ec5fb625f4c2e05e1", size = 86841 } wheels = [ @@ -2183,8 +2183,8 @@ name = "pyobjc-framework-automaticassessmentconfiguration" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6b/dd/53aeb33bdd6c137af18e487d7f3e023d5dc36eaa049775ffb7a9d21721b2/pyobjc_framework_automaticassessmentconfiguration-10.3.2.tar.gz", hash = "sha256:cbb1313e5ad4162664a92225a9e4a685a92d03a81e81664acbc51857ec415292", size = 22841 } wheels = [ @@ -2199,8 +2199,8 @@ name = "pyobjc-framework-automator" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/32/16/3796b8abb209e8ff41a19064b88f53e48b886bcd004f6b05afc4f23ada70/pyobjc_framework_automator-10.3.2.tar.gz", hash = "sha256:ee7ec981275e5dbdd2e4d83d4d4be3c3efdcaadf0a9917d935328363dd49085f", size = 195443 } wheels = [ @@ -2215,11 +2215,11 @@ name = "pyobjc-framework-avfoundation" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreaudio", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coremedia", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/8d/8a78df7d0ccbf7e8f7a80692f7891895b323334bde2781a6018452c92eb1/pyobjc_framework_avfoundation-10.3.2.tar.gz", hash = "sha256:e4baa1cb8d63c2b366f90341dee54a646004ad02d4b01119c79904cb869e7a6a", size = 695532 } wheels = [ @@ -2234,9 +2234,9 @@ name = "pyobjc-framework-avkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5e/a9/ee16b75e0a509ab19e1a911c09bddef11b3e426cc7c8294006c583529172/pyobjc_framework_avkit-10.3.2.tar.gz", hash = "sha256:b4c63941aafc7f83790ec6039b3384a19ada304c98c889a2d6ad66ad843fb41d", size = 39355 } wheels = [ @@ -2251,8 +2251,8 @@ name = "pyobjc-framework-avrouting" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/09/89/b45d19ddc5c780fa7e6736cb782bc9b01a1c6ec8690326904020339dd39b/pyobjc_framework_avrouting-10.3.2.tar.gz", hash = "sha256:0c36464e80c77e0d44483c68880ea2d239084c378d200f02e0688967c3de4f55", size = 19018 } wheels = [ @@ -2267,8 +2267,8 @@ name = "pyobjc-framework-backgroundassets" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3f/15/38a5d93d6e03abcfe6833df574fd5087c4bfeccb49dff450a771e2221e08/pyobjc_framework_backgroundassets-10.3.2.tar.gz", hash = "sha256:17436f7eb08d407603e2e633272a7d51023d40b6f81dd577ad34b9db16fdcb6d", size = 22162 } wheels = [ @@ -2283,11 +2283,11 @@ name = "pyobjc-framework-browserenginekit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreaudio", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coremedia", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5f/ab/d09654cb647e5c1c751bd9c819d79a31dfe4072cc79eae28e66f58c05688/pyobjc_framework_browserenginekit-10.3.2.tar.gz", hash = "sha256:5c4d50f2358376c36a3d2721b8d5c259f77e9e62f48503030c2312b8b6b58943", size = 21390 } wheels = [ @@ -2302,8 +2302,8 @@ name = "pyobjc-framework-businesschat" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/ea/e2df6cda4ef666165c97e513cd48f9a4bfc92f8f5137a4df6adf77591448/pyobjc_framework_businesschat-10.3.2.tar.gz", hash = "sha256:a598f401d5f391f0c78aa62a58d0a7f9908fa86abffb884138795f36105800ea", size = 12402 } wheels = [ @@ -2316,8 +2316,8 @@ name = "pyobjc-framework-calendarstore" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/26/ef/032c20f2cd77d1e860f757f47b14fad657735d094f8dcd5dbad96b136376/pyobjc_framework_calendarstore-10.3.2.tar.gz", hash = "sha256:0fbc2133045c18228efc11f8442979381f6060fc18f7e8e25b0395b2d6106c29", size = 63247 } wheels = [ @@ -2330,8 +2330,8 @@ name = "pyobjc-framework-callkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/11/69/365d23487489b14a4a9c19de4447b9974bf71c321f487bb8e2cb465b7961/pyobjc_framework_callkit-10.3.2.tar.gz", hash = "sha256:8d67962c8e385d31ee66ad68e9c15760ba2cad709ce0305efa5f142247e5026a", size = 32282 } wheels = [ @@ -2344,8 +2344,8 @@ name = "pyobjc-framework-cfnetwork" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/f7/628d3733d72268e2210b7c66196e53ed1516b814dad6660e179aa8023e6e/pyobjc_framework_cfnetwork-10.3.2.tar.gz", hash = "sha256:1fa3953b3b240a57bc4b3bf72043a3addadf2d9a473aeaf9fdb09df442fdd7e0", size = 67213 } wheels = [ @@ -2360,11 +2360,11 @@ name = "pyobjc-framework-cinematic" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-avfoundation", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coremedia", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-metal", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5e/e0/31644814a4f4d51c379c350de0db093b2e5ff7adf98f3b320f499b37916d/pyobjc_framework_cinematic-10.3.2.tar.gz", hash = "sha256:8a249b79905a13cc6234ca9167734bc30bbf9672a65630a69faae4415ed8a87b", size = 19667 } wheels = [ @@ -2377,8 +2377,8 @@ name = "pyobjc-framework-classkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/15/e2/b3ace38d1aab8e576349a18dc618b7f397ed37a8d68c01b508b134fcdf6e/pyobjc_framework_classkit-10.3.2.tar.gz", hash = "sha256:afc44c16791e27331b73be3269c3c794f3502515ddd916c0b3bfe2fa060854e6", size = 32863 } wheels = [ @@ -2393,11 +2393,11 @@ name = "pyobjc-framework-cloudkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-accounts" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coredata" }, - { name = "pyobjc-framework-corelocation" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-accounts", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coredata", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-corelocation", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8b/70/daa2a428e1d8c39e55e3480c0bc9c8b39f882b544c88cad3a105e217f6ae/pyobjc_framework_cloudkit-10.3.2.tar.gz", hash = "sha256:ba05c8edb7f73ada94f9d2f8fbeae7302e53b56b2abb956012b84ba7faea141d", size = 99236 } wheels = [ @@ -2410,7 +2410,7 @@ name = "pyobjc-framework-cocoa" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/41/4f09a5e9a6769b4dafb293ea597ed693cc0def0e07867ad0a42664f530b6/pyobjc_framework_cocoa-10.3.2.tar.gz", hash = "sha256:673968e5435845bef969bfe374f31a1a6dc660c98608d2b84d5cae6eafa5c39d", size = 4942530 } wheels = [ @@ -2423,8 +2423,8 @@ name = "pyobjc-framework-collaboration" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7b/d8/5f17469cee1fe7c10c971cc425a57cc820dff14cbd2fb35d26e2a4f62d7e/pyobjc_framework_collaboration-10.3.2.tar.gz", hash = "sha256:0d4ee33154ea1d6ac7b9338b2bb1a9bcb5f5e9e3ffc390195643d60576606b74", size = 16157 } wheels = [ @@ -2437,8 +2437,8 @@ name = "pyobjc-framework-colorsync" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/da/a2/3b6a7409e238ea577bb250bd5164be9c235ca1ba9629c21b8f29b70659d0/pyobjc_framework_colorsync-10.3.2.tar.gz", hash = "sha256:d4a8bcb7a3c13b6ac4ac25498e53b738104d49fadc97278f553268fb2ad7f487", size = 32297 } wheels = [ @@ -2451,8 +2451,8 @@ name = "pyobjc-framework-contacts" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d5/94/14eb1abc06a88d1621eeb39784a9a1346f417c8584d37d767875c50bf54f/pyobjc_framework_contacts-10.3.2.tar.gz", hash = "sha256:f912a1bbd3cee3d8af740e02abc083828604265394871c2c166bc9c1de3130ce", size = 68818 } wheels = [ @@ -2467,9 +2467,9 @@ name = "pyobjc-framework-contactsui" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-contacts" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-contacts", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4c/90/014388a37e3a1e2ec9a4d8e4336a6d5bb9e805c1087a3d3f38fc1b655be4/pyobjc_framework_contactsui-10.3.2.tar.gz", hash = "sha256:c004d225f17cbbb5c8b627275cf6a6f91a05aa956ab62d08e0fd3276fae80558", size = 18259 } wheels = [ @@ -2484,8 +2484,8 @@ name = "pyobjc-framework-coreaudio" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1b/54/0fcdab30ac31a594d699d909aa94c841fd94e173774f36e8c19e18536991/pyobjc_framework_coreaudio-10.3.2.tar.gz", hash = "sha256:c53e3247144b4f316cd588dd684a5f4edc6eebf9ca6beba488711b890bf0ff5f", size = 125996 } wheels = [ @@ -2498,9 +2498,9 @@ name = "pyobjc-framework-coreaudiokit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreaudio", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/52/e03a7a497102acb95018e653c4c03c7fdc6a01ee4bcaf403234d7b37c87d/pyobjc_framework_coreaudiokit-10.3.2.tar.gz", hash = "sha256:a41b0ab17d413bae5b6d673e6c97cfec0d80cb423f590cc4cd3970887ad22f49", size = 20079 } wheels = [ @@ -2515,8 +2515,8 @@ name = "pyobjc-framework-corebluetooth" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/13/ca/35d205c3e153e7bc59a417560a45e27a2410439e6f78390f97c1a996c922/pyobjc_framework_corebluetooth-10.3.2.tar.gz", hash = "sha256:c0a077bc3a2466271efa382c1e024630bc43cc6f9ab8f3f97431ad08b1ad52bb", size = 50622 } wheels = [ @@ -2531,8 +2531,8 @@ name = "pyobjc-framework-coredata" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/dc/8b5d84afead6a72d42fd227af7de8dcd5aad3738179737e91cba8bdd529f/pyobjc_framework_coredata-10.3.2.tar.gz", hash = "sha256:e6da6cb3b5ec7bc1ff4fc71bf933e8a0d9ecd1d1c4028b7f2a2a24b1e2089078", size = 230246 } wheels = [ @@ -2547,8 +2547,8 @@ name = "pyobjc-framework-corehaptics" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9c/47/9f1dc2645fe5d25560f6d16c12a91997f66038d798b7926fbd3598bef3af/pyobjc_framework_corehaptics-10.3.2.tar.gz", hash = "sha256:dcd595bfa0b02212377be6426457eef76dd0a343dc73416a81ba001adbb0d2aa", size = 37194 } wheels = [ @@ -2561,8 +2561,8 @@ name = "pyobjc-framework-corelocation" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/25/a6/14450410f233a8e8d3ed1e48702a0b405f402bd3efa77b8bd62c424ca0fc/pyobjc_framework_corelocation-10.3.2.tar.gz", hash = "sha256:3fc543ff9b5a347bece0668e9c4d73cc94bf47624a723fad0d568d360567583f", size = 89656 } wheels = [ @@ -2577,8 +2577,8 @@ name = "pyobjc-framework-coremedia" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/99/01b557daec18114166ae5fb602437477a60325e08dd9cfa5aac9d1c5174c/pyobjc_framework_coremedia-10.3.2.tar.gz", hash = "sha256:cf69753c12cd193df5ff25eb8f6da857c9aa93e73b8e497ddd77a3f48d1b171c", size = 181120 } wheels = [ @@ -2591,8 +2591,8 @@ name = "pyobjc-framework-coremediaio" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1a/ec/f32539575a5a2cf24c2328f49317b07aff2aa993abbaf44777bcd8e271f1/pyobjc_framework_coremediaio-10.3.2.tar.gz", hash = "sha256:a648ff9ecb49c37353f912801f86d3985df74fd27e880d22c4eb3d7bc8a66db2", size = 88994 } wheels = [ @@ -2607,8 +2607,8 @@ name = "pyobjc-framework-coremidi" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/27/8b01da065b8fc166f91dcae96e38ed4c723743e714aba8e8c51f2f26330e/pyobjc_framework_coremidi-10.3.2.tar.gz", hash = "sha256:53f37f70abeaf67d90d03997517cb5085fcb29d41aa809f3c2b0809571f5258f", size = 78823 } wheels = [ @@ -2623,8 +2623,8 @@ name = "pyobjc-framework-coreml" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/7c/476d4459ce4d44d622365f721620f56fff7cebf50ade3560ae452244adaf/pyobjc_framework_coreml-10.3.2.tar.gz", hash = "sha256:f2e6eabe41fa34e964b707ba7a1269d5e049d5a7ac5574f35c4faa0647f385ba", size = 67101 } wheels = [ @@ -2639,8 +2639,8 @@ name = "pyobjc-framework-coremotion" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4e/f8/829dbf6ac3caad858cd68ba6a12f53ee3eeaef15c4107b34bcc0a1886f98/pyobjc_framework_coremotion-10.3.2.tar.gz", hash = "sha256:7bf2b3ae72e665035d57875a1c179fa4bef89021403ee44ddffacea04e9eb70d", size = 54848 } wheels = [ @@ -2653,9 +2653,9 @@ name = "pyobjc-framework-coreservices" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-fsevents" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-fsevents", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0a/d2/2f5c63ad1b4f7c7c45c4da45cbeb3b13328d21794f5cec2b2018e42c177f/pyobjc_framework_coreservices-10.3.2.tar.gz", hash = "sha256:ee3cf8379839efe4300bbd33dca204ebe873e2671160fff856569976d45c68a8", size = 860352 } wheels = [ @@ -2670,8 +2670,8 @@ name = "pyobjc-framework-corespotlight" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/a5/d34b1be8a07cb0940792b964407a8744b4081204200349557a0dba5b93dc/pyobjc_framework_corespotlight-10.3.2.tar.gz", hash = "sha256:0ae1656bc3e8ece5278d690d1155b025271564fcdfe33f5b780a15f4a10c3e03", size = 69762 } wheels = [ @@ -2686,9 +2686,9 @@ name = "pyobjc-framework-coretext" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/24/8e/bb442edfeeada13d2c96796bd36e3dcc0b91ac5c1a6774c21c12b7498770/pyobjc_framework_coretext-10.3.2.tar.gz", hash = "sha256:b1184146c628ba59c21c59eaa8e12256118daf8823deb7fb12013ecdfbc7f578", size = 233780 } wheels = [ @@ -2701,8 +2701,8 @@ name = "pyobjc-framework-corewlan" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c5/4d/132d46a120db80d9bc30ab24f7dae22f67a484eaaef47c0bb7f8ee9ed2ee/pyobjc_framework_corewlan-10.3.2.tar.gz", hash = "sha256:cb166e835e92332d34597c42d54886baf329363559c7bb017f15ce68a685508c", size = 58109 } wheels = [ @@ -2717,8 +2717,8 @@ name = "pyobjc-framework-cryptotokenkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/72/e771d7856e50da7650618fe46452b5fbd3b0bd7e2827356776d467aa2276/pyobjc_framework_cryptotokenkit-10.3.2.tar.gz", hash = "sha256:996a81a96af6928c5157f8a6f2d2bba8fe68c3948119f2d59918e00fc46f48d0", size = 48947 } wheels = [ @@ -2733,8 +2733,8 @@ name = "pyobjc-framework-datadetection" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/1b/ce373fd11d2696f5dc25462d5e1f91afca6ee322d6576fb4a7131e077358/pyobjc_framework_datadetection-10.3.2.tar.gz", hash = "sha256:4e68c6f53042e2dd90a047d6a443227bf481aa9e3cf7aad1b2f164ff1b19dd0f", size = 13002 } wheels = [ @@ -2747,8 +2747,8 @@ name = "pyobjc-framework-devicecheck" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/23/b0/afcc4f467fc26674c01570ee5623a5b1ba904181ba71c710b646880c1fb9/pyobjc_framework_devicecheck-10.3.2.tar.gz", hash = "sha256:028fbec7a0efad0a5952063d9382017f0d860d31d768db2097e71754b93c9922", size = 13455 } wheels = [ @@ -2761,8 +2761,8 @@ name = "pyobjc-framework-dictionaryservices" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreservices", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9b/4f/f4669fc0429415ea3f01b01ffb4a3ed41c91cae4fcdcc453874b7d2c16de/pyobjc_framework_dictionaryservices-10.3.2.tar.gz", hash = "sha256:d74effe983246e2d8ea53aba0ea47cdfe5d3687d110d13e235279c92cb9aeaf5", size = 10430 } wheels = [ @@ -2775,8 +2775,8 @@ name = "pyobjc-framework-discrecording" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2f/e8/546a077194be0e9f8b99dfd62923e7cf29eaaed97ec355533861c00d6813/pyobjc_framework_discrecording-10.3.2.tar.gz", hash = "sha256:996df211530867edbd82dac9b82209da8686f6814c7ee58411131f965f5fea79", size = 101951 } wheels = [ @@ -2791,9 +2791,9 @@ name = "pyobjc-framework-discrecordingui" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-discrecording" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-discrecording", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/cd/c44a59e6b6e893ef6117e3621f6d5faec326a98a6ebcaf70047a9f54a584/pyobjc_framework_discrecordingui-10.3.2.tar.gz", hash = "sha256:9cf1f1256c1c6dd4fc7debaff7e415949b43e86dd77be5ddc644822566cb3423", size = 18521 } wheels = [ @@ -2806,8 +2806,8 @@ name = "pyobjc-framework-diskarbitration" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2d/c3/fbb59379378f679473375d7a3532986c7fc06f192ce0855d0a6e02de8dec/pyobjc_framework_diskarbitration-10.3.2.tar.gz", hash = "sha256:5e3a4a35b209bd9b983ae6248275784f913318d689b368f7ef584c87b7157336", size = 19001 } wheels = [ @@ -2820,8 +2820,8 @@ name = "pyobjc-framework-dvdplayback" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d9/63/52a3b4c53494cd1ad993b9ceba026cd2f226f45f6c634b429e22b43efaf9/pyobjc_framework_dvdplayback-10.3.2.tar.gz", hash = "sha256:1df1a41cd777559edc585bf097e3ed20a898e3a33f6b2627b6d321fc060ff97c", size = 53372 } wheels = [ @@ -2834,8 +2834,8 @@ name = "pyobjc-framework-eventkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/95/34/ae6a87901b93a020dc0b982b5704096fbcfba50840db4666d3a263cd86de/pyobjc_framework_eventkit-10.3.2.tar.gz", hash = "sha256:a31581cde80f03fc40ca8980d160570bcc747fec035311029fb4cddf9b35993a", size = 64364 } wheels = [ @@ -2848,8 +2848,8 @@ name = "pyobjc-framework-exceptionhandling" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/44/9d/161094a7d8f39b943db22e11db8b7874b151550b0645668f7b6a33b6d8f2/pyobjc_framework_exceptionhandling-10.3.2.tar.gz", hash = "sha256:e49e05db37d15816699585ca9a0f5fccf37bec3f32cf3446f7595b7475678b90", size = 17521 } wheels = [ @@ -2862,8 +2862,8 @@ name = "pyobjc-framework-executionpolicy" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/d8/bb30e70540f1f12b748f3c1c69539d750bcdb0493fbafb2ea5a37052c0fd/pyobjc_framework_executionpolicy-10.3.2.tar.gz", hash = "sha256:736b469e395fef859c1b506ab520e22cdd8937d71026901435fa7b2fcf08b8a4", size = 13158 } wheels = [ @@ -2876,8 +2876,8 @@ name = "pyobjc-framework-extensionkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/47/be/25e45cccd58fc61525d1f92684bed8d274a186706f2222144eb6b268c387/pyobjc_framework_extensionkit-10.3.2.tar.gz", hash = "sha256:626ba65aba8ce021c53eb52a3482d1fcb26d54e94d8ffb9b7376d444309e5bb3", size = 18034 } wheels = [ @@ -2892,8 +2892,8 @@ name = "pyobjc-framework-externalaccessory" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/96/6c4dcab9a457bcbd38401e6d081867f46a07e0fcadfc6cbd05d9a9ffac97/pyobjc_framework_externalaccessory-10.3.2.tar.gz", hash = "sha256:abd334e5da791409378fed7e09b0f488a7e55eb5740d279f0c7f85984c74add4", size = 21090 } wheels = [ @@ -2908,8 +2908,8 @@ name = "pyobjc-framework-fileprovider" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5f/14/b7ccfbce5457b5d86d61b0dcf0fb6a56c5421ddc0a6e17b4b16d0402d621/pyobjc_framework_fileprovider-10.3.2.tar.gz", hash = "sha256:b671131fa42d4e58f661362ef32e996de2f9a09a1ca20218983d7334efc39242", size = 63933 } wheels = [ @@ -2922,8 +2922,8 @@ name = "pyobjc-framework-fileproviderui" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-fileprovider" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-fileprovider", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/23/30/e2b049d329cce54157faa5a5f6f4b3ae3cffe39cd600e3df254320ad2611/pyobjc_framework_fileproviderui-10.3.2.tar.gz", hash = "sha256:0a62ebbf3ae3b9f73f4a36c511f3c143d2cdb657030366c04e7bec1ad27066ce", size = 12868 } wheels = [ @@ -2936,8 +2936,8 @@ name = "pyobjc-framework-findersync" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/92/27/d505d5a508bacb971eb4ec4196372f9a9f286ce319bff1d24296feeadd58/pyobjc_framework_findersync-10.3.2.tar.gz", hash = "sha256:a5ab6ac34ea2c9184111b33b5248009f8a86a994c6d813e2bfd00cc20863046e", size = 14563 } wheels = [ @@ -2950,8 +2950,8 @@ name = "pyobjc-framework-fsevents" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/97/70/a37b1b8397bb3e23a8c15c78209f998d0294311a70b81104a5f22cbe9b26/pyobjc_framework_fsevents-10.3.2.tar.gz", hash = "sha256:fb215032d65aa39eb5af1b6481f605e71afa77f881b37ba804af77bf24d2fde3", size = 27720 } wheels = [ @@ -2966,8 +2966,8 @@ name = "pyobjc-framework-gamecenter" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/61/e2/aa9d68a95afae2740b2b5af02bf4cdde11788c6e294cc2fdbcaed86723bb/pyobjc_framework_gamecenter-10.3.2.tar.gz", hash = "sha256:f641026c98c11e0c6d81cea0abdf1b113499e61327da63dc783c94f7ec4c460a", size = 30461 } wheels = [ @@ -2982,8 +2982,8 @@ name = "pyobjc-framework-gamecontroller" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/47/e8/909649206c4781bebe19f20d76287c473418b39ff501c161586ad37e16d2/pyobjc_framework_gamecontroller-10.3.2.tar.gz", hash = "sha256:57225d1a760315bc3f11828780076dc1b12a470b52bde2b7a20f45d6556e5e4a", size = 94410 } wheels = [ @@ -2998,9 +2998,9 @@ name = "pyobjc-framework-gamekit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/ca/a3229141293e5128e5968428d34c5d2071e7eaf111b1d648dddb1b6d10e8/pyobjc_framework_gamekit-10.3.2.tar.gz", hash = "sha256:a1df3c59cdae5693a29d81057853b053871196197b56bce05d98dc84b233e0e4", size = 137941 } wheels = [ @@ -3015,9 +3015,9 @@ name = "pyobjc-framework-gameplaykit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-spritekit" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-spritekit", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/0b/e0f9e58ff69017b9b2bd17ef682672f63013670bb2c01b310fd74c2eb0ba/pyobjc_framework_gameplaykit-10.3.2.tar.gz", hash = "sha256:399a7ab7b47203f4506f98b6c121e6faa5bf7e77c154af6e6e486359f201a818", size = 56131 } wheels = [ @@ -3032,8 +3032,8 @@ name = "pyobjc-framework-healthkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/76/0bec0e66cd86756dfe28be0cd66f2b4a43fac0a83f46a9c067c738018c10/pyobjc_framework_healthkit-10.3.2.tar.gz", hash = "sha256:01a575de6fdeb38e98f8e04c720c5e1edc4e90ed3ef3b36e991dd18f8b37e83a", size = 114164 } wheels = [ @@ -3048,8 +3048,8 @@ name = "pyobjc-framework-imagecapturecore" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/6b/f0fdad6e56b28723a1136ae282ef2252b483d15aeebb8ae8deb1e062e0c8/pyobjc_framework_imagecapturecore-10.3.2.tar.gz", hash = "sha256:ed62f815a124e2a7560356b370ccf36eb422d211fe187ef720eb7651a9a16469", size = 82245 } wheels = [ @@ -3064,8 +3064,8 @@ name = "pyobjc-framework-inputmethodkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/da/de/fca23e845f47ff685b9ce2a67f59d9a78eba1617a3718014810be8326ec8/pyobjc_framework_inputmethodkit-10.3.2.tar.gz", hash = "sha256:e722e6658df548183435013c450191d9157f2f97e7b96b9c1d180eb8da8138ec", size = 24867 } wheels = [ @@ -3080,8 +3080,8 @@ name = "pyobjc-framework-installerplugins" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0c/f4/dda750337702cee8cca7ca36eb8d4b5464f6dbd5210b9a21620f6cf54117/pyobjc_framework_installerplugins-10.3.2.tar.gz", hash = "sha256:f271955cb92531a4f8be254572e92d3837a34dfa3b0dd582fa37673b788eb70c", size = 26832 } wheels = [ @@ -3094,9 +3094,9 @@ name = "pyobjc-framework-instantmessage" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/79/d2d1b92734c3225c67341908e07dea47217260ed1c00456999826731d57e/pyobjc_framework_instantmessage-10.3.2.tar.gz", hash = "sha256:cc32e911c0d7574a48a0b2b1e298e979ea1396ddfac71cc3cef63d5ef8affd9e", size = 33093 } wheels = [ @@ -3109,8 +3109,8 @@ name = "pyobjc-framework-intents" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6b/fb/5e69eb244560faaf7ff992b0ee8645467f16af4377d16a92246d76ae863c/pyobjc_framework_intents-10.3.2.tar.gz", hash = "sha256:24c080176487bb957ea06599e62eaa8f728d690362a2cc6efd1335abb30c1f1c", size = 362250 } wheels = [ @@ -3125,8 +3125,8 @@ name = "pyobjc-framework-intentsui" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-intents" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-intents", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d6/96/460efe35ca330ef828a364ea0b8ba5efd1eedc3f2ec3d029fd955716a99d/pyobjc_framework_intentsui-10.3.2.tar.gz", hash = "sha256:e2192a7d1858b1a510b5acefe44f9ff8df89a2c7b65868366bb15befb76804dc", size = 19163 } wheels = [ @@ -3139,8 +3139,8 @@ name = "pyobjc-framework-iobluetooth" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7e/91/c57034bf6ccfbc7716141dd9e0d863a46e595322257085e1a69f310086ec/pyobjc_framework_iobluetooth-10.3.2.tar.gz", hash = "sha256:aa8e054cec1066513c4c130ff5d08a1ac020b62ae23fab1d94cbf29ca69e3374", size = 226443 } wheels = [ @@ -3155,8 +3155,8 @@ name = "pyobjc-framework-iobluetoothui" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-iobluetooth" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-iobluetooth", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/ab/f171f336c7ed09f8e3ff1f8a74cac297046fa7feade6cc32a2848d99cbd5/pyobjc_framework_iobluetoothui-10.3.2.tar.gz", hash = "sha256:00093d69bf0eded017848908b96055648e61de115a270b9c61c06ab77c612c62", size = 19545 } wheels = [ @@ -3169,8 +3169,8 @@ name = "pyobjc-framework-iosurface" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/97/93/4d67e85a15a23158e52ea7360731f228f151f4472797306944c4592be627/pyobjc_framework_iosurface-10.3.2.tar.gz", hash = "sha256:f308cc99c91ec4f7e3c3472a7a8396d842536881472beeff34f32e85dd0772d7", size = 19661 } wheels = [ @@ -3183,8 +3183,8 @@ name = "pyobjc-framework-ituneslibrary" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/49/7fd55a0b5f9772f73e7aff273b9dab999843559b2bdd4b2683cc90137938/pyobjc_framework_ituneslibrary-10.3.2.tar.gz", hash = "sha256:a8b8fb857ae428677e30c90c24264c69070c9eaae90c58ec40dddc5cac6c2069", size = 40393 } wheels = [ @@ -3197,8 +3197,8 @@ name = "pyobjc-framework-kernelmanagement" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f7/1a/7ecb8bc2bc0bba690bb85279fbee52162f810816e92b54ec60b96efd5ebb/pyobjc_framework_kernelmanagement-10.3.2.tar.gz", hash = "sha256:c4220bc64bddccdbb57c1040c16f6e04d4eccc1c48df86c66e255236698b5b1a", size = 12262 } wheels = [ @@ -3211,8 +3211,8 @@ name = "pyobjc-framework-latentsemanticmapping" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/a4/34ff1d3358ab11d98a81a306d478a8530014af18f125f172de00d150055c/pyobjc_framework_latentsemanticmapping-10.3.2.tar.gz", hash = "sha256:477e25832c19e269c969dd25e3c9a7659b237b80ab130f1e4b7f0b98fda9f0a8", size = 16958 } wheels = [ @@ -3225,8 +3225,8 @@ name = "pyobjc-framework-launchservices" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreservices", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/21/1d36e3d7461b0521270b06717443c4bec4aaac7cddd17b36427608b6adbe/pyobjc_framework_launchservices-10.3.2.tar.gz", hash = "sha256:8aabb555e93702f43d2d6c5f85c9efa5d1f03b1caeec75a8359ab72f84fb6299", size = 20337 } wheels = [ @@ -3239,8 +3239,8 @@ name = "pyobjc-framework-libdispatch" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/12/a908f3f94952c8c9e3d6e6bd425613a79692e7d400557ede047992439edc/pyobjc_framework_libdispatch-10.3.2.tar.gz", hash = "sha256:e9f4311fbf8df602852557a98d2a64f37a9d363acf4d75634120251bbc7b7304", size = 45132 } wheels = [ @@ -3253,8 +3253,8 @@ name = "pyobjc-framework-libxpc" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/fa/0776ec3eef69bb343cd5e3072d87814448fdde98b6a8d1f41ca044b7737c/pyobjc_framework_libxpc-10.3.2.tar.gz", hash = "sha256:c22b7c7de66152643a50b3c10a5899ae44c99b5d6bda7d76c0f7efda0c6ea831", size = 40167 } wheels = [ @@ -3267,9 +3267,9 @@ name = "pyobjc-framework-linkpresentation" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/24/fb62451a1c4846a69a5914e755cab2b35940f631d87c903e32eea4d4a2d1/pyobjc_framework_linkpresentation-10.3.2.tar.gz", hash = "sha256:345761452e2e441fc21c1898a4e14dba26315d2f46a66a876153d46c823f39e6", size = 14524 } wheels = [ @@ -3282,9 +3282,9 @@ name = "pyobjc-framework-localauthentication" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-security", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/90/e0/642b80c3320c654fc57497fe78e423a9c010fe49d6142da807bb774f4365/pyobjc_framework_localauthentication-10.3.2.tar.gz", hash = "sha256:20774489eaa5f5f91f089d801b84e51018e3eaf972e01743997678ad4b65e62c", size = 26544 } wheels = [ @@ -3297,9 +3297,9 @@ name = "pyobjc-framework-localauthenticationembeddedui" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-localauthentication" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-localauthentication", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bb/6b/7e340412752aab504fe1bf51b5bf2063a99dda2f7a28e8f171103be2291c/pyobjc_framework_localauthenticationembeddedui-10.3.2.tar.gz", hash = "sha256:5c4c01c6ccbc042b66d06147f24b6aea8f3f41bfbaefd26f2b441da6a5ee1303", size = 13657 } wheels = [ @@ -3312,8 +3312,8 @@ name = "pyobjc-framework-mailkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/e3/b394d68e0b8db1f9b6b055bc8751433ee09afd3a2d9fe080091bc359fd88/pyobjc_framework_mailkit-10.3.2.tar.gz", hash = "sha256:56bc122e7681ffff1811f596ce665f5d95df7619650710d9385bad9763965406", size = 26357 } wheels = [ @@ -3326,10 +3326,10 @@ name = "pyobjc-framework-mapkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-corelocation" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-corelocation", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/a9/7b736ad9922c96183930db3a526dab59ff9e3eab5cd6c652ffed093ce6cb/pyobjc_framework_mapkit-10.3.2.tar.gz", hash = "sha256:7c3e04c4e6f2c85a489c95a8a69c319b135438d3aa38bd43d16bab1d0934978c", size = 135878 } wheels = [ @@ -3344,8 +3344,8 @@ name = "pyobjc-framework-mediaaccessibility" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d8/ba/1c5df04734fea28cb24b855fe176a80ebcfe55c8541a31c68b45701573be/pyobjc_framework_mediaaccessibility-10.3.2.tar.gz", hash = "sha256:b709ecc94cb2b04e7ab1d4ba5d0654c6fd24fb5c0b977d0a531d258178e409ed", size = 17011 } wheels = [ @@ -3358,9 +3358,9 @@ name = "pyobjc-framework-medialibrary" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/81/98/34bf44d4d2ffe1dbd2641dba92f0ab8f34b172ff07b1e427e15dc7b87fd1/pyobjc_framework_medialibrary-10.3.2.tar.gz", hash = "sha256:b9070f65f93f6b892918021e4655cc1c68ab6757d8554e28bedbc1dceba92276", size = 17990 } wheels = [ @@ -3373,8 +3373,8 @@ name = "pyobjc-framework-mediaplayer" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-avfoundation", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/25/e2/d06d712043f5dfe7db4aa69c5fbc922a8e30c8bf6c18070cd819b362c552/pyobjc_framework_mediaplayer-10.3.2.tar.gz", hash = "sha256:b57558c771ec922381333bf05bf642e1420785806c97b10d660bc6eb0740bab4", size = 77668 } wheels = [ @@ -3387,8 +3387,8 @@ name = "pyobjc-framework-mediatoolbox" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/30/87/73808a57088e6760d0c9b1be893e1f54947f54094330cfa982fff3613bc0/pyobjc_framework_mediatoolbox-10.3.2.tar.gz", hash = "sha256:0545b375b268594c3e0a63973d6efcce0310b39b316bd0b41fe5d60b3fa0e33d", size = 21849 } wheels = [ @@ -3403,8 +3403,8 @@ name = "pyobjc-framework-metal" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ef/12/a7695cab9ee18c2500ada306b283fc80f6628cb5fc396ee19fcc470bf186/pyobjc_framework_metal-10.3.2.tar.gz", hash = "sha256:59246982eab788b955f6d45dfb8c80e8f97bd1b56e1d678c90e91ad4a9376e35", size = 300113 } wheels = [ @@ -3419,8 +3419,8 @@ name = "pyobjc-framework-metalfx" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-metal", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cd/7e/409a363fba2ae9582d64771e64f5465908a08d8632f07d1ca64e7ecdd2dc/pyobjc_framework_metalfx-10.3.2.tar.gz", hash = "sha256:02e83be7f013a416af42605120431b01c4a02fe2c80f898b7e45f90c30300a19", size = 21954 } wheels = [ @@ -3435,9 +3435,9 @@ name = "pyobjc-framework-metalkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-metal", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/f0/73fbc89e07f98e66666f7e7bf95dff809e270fc7e04ad9e89f67840e402c/pyobjc_framework_metalkit-10.3.2.tar.gz", hash = "sha256:309042ce797def3c2b20db41f471e939c9860e810c717a88665e5fdf140a478b", size = 38634 } wheels = [ @@ -3452,8 +3452,8 @@ name = "pyobjc-framework-metalperformanceshaders" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-metal", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/d2/4f38e3c4f673dcf13d2e79e68e2e33382174c36416e423a1da30a9dc0cb9/pyobjc_framework_metalperformanceshaders-10.3.2.tar.gz", hash = "sha256:e224a9ab8fb9218bb4d7acf8dad946631f89ee0b8f800264ed57443e5df0982f", size = 215765 } wheels = [ @@ -3468,8 +3468,8 @@ name = "pyobjc-framework-metalperformanceshadersgraph" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metalperformanceshaders" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-metalperformanceshaders", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/a2/7b0d61e70af9eeae2f428e3d5b8acaf4b5011d6cf07d23e539534510fe4f/pyobjc_framework_metalperformanceshadersgraph-10.3.2.tar.gz", hash = "sha256:d83a4f1343c823674d2dc2730a0f0bd6231ad54409cf467c6bd5fe4a9791c22e", size = 81917 } wheels = [ @@ -3482,8 +3482,8 @@ name = "pyobjc-framework-metrickit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/67/e9/7bb34b031109e3cde9e8b59af4e1b66a59868ec57f40c3c84140ba281704/pyobjc_framework_metrickit-10.3.2.tar.gz", hash = "sha256:5a3b6f9a9db09a6521ab54610fd8f6a8644622ff248992e8608cfbe721efedca", size = 32121 } wheels = [ @@ -3496,8 +3496,8 @@ name = "pyobjc-framework-mlcompute" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6a/83/d1af0d51ce57e96adb86c43507ec7fa6f6d3cb0ac92c4c881e04c88ec149/pyobjc_framework_mlcompute-10.3.2.tar.gz", hash = "sha256:be84c8ff600d2dde5abd9b5d27e4607a14361c6fef404803ad4681f6ecac5569", size = 68700 } wheels = [ @@ -3510,9 +3510,9 @@ name = "pyobjc-framework-modelio" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/44/9c/93d1bf803924372e31547c1faef512c457f11ecb61ae6554d903cb1acf48/pyobjc_framework_modelio-10.3.2.tar.gz", hash = "sha256:ab0b2ed488e7ba4e4d2862cbc8629d309832bdfcdde3b0c32f87dd2d9e7134bf", size = 93453 } wheels = [ @@ -3527,8 +3527,8 @@ name = "pyobjc-framework-multipeerconnectivity" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dd/e9/f511850e84be7d8645e70934da5f80faa7bd688cd244a1dfbc76ef464870/pyobjc_framework_multipeerconnectivity-10.3.2.tar.gz", hash = "sha256:12f04aca1142ef91ac8292f76ab7fcb3c93eefcb1a1333073dd011cad97cab8a", size = 23803 } wheels = [ @@ -3543,8 +3543,8 @@ name = "pyobjc-framework-naturallanguage" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6b/f8/a7a3d00c1eb5bc8c1d7efd24e655e2f5100322d6adf4c5f12d77018bcc9f/pyobjc_framework_naturallanguage-10.3.2.tar.gz", hash = "sha256:a3a81148b24b744ce5c4289074279cfe4947a79ca9de4d88aa1dbdc44182dede", size = 39472 } wheels = [ @@ -3557,8 +3557,8 @@ name = "pyobjc-framework-netfs" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e7/32/c6614fa0255968b8eea59c76da292b6c65f9caf8929d5f524b8155c6e006/pyobjc_framework_netfs-10.3.2.tar.gz", hash = "sha256:931239d3a0171d09b089f229bc58add8098c0d45a37f8f0ef45059ec0d4e69d6", size = 15546 } wheels = [ @@ -3571,8 +3571,8 @@ name = "pyobjc-framework-network" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/52/6a1309a9b5766053ce5b2c7fed21751fc1bd9c8dedaf84d3fc6b2753bc98/pyobjc_framework_network-10.3.2.tar.gz", hash = "sha256:351a0eda913c84e3b7c0ffe0f1d4679b2bc21118ccc0e59fd4943326b23ba4e3", size = 104316 } wheels = [ @@ -3587,8 +3587,8 @@ name = "pyobjc-framework-networkextension" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/91/132fc6782b988b67c6e65d569c5a83c8cf567ef38d6d69016ef7acc902b7/pyobjc_framework_networkextension-10.3.2.tar.gz", hash = "sha256:d79ebd6fa4489e61e95e96e868352c9cef20c48ccb1d90680300c814b659529b", size = 131032 } wheels = [ @@ -3603,8 +3603,8 @@ name = "pyobjc-framework-notificationcenter" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/35/ec/befdaf13ca4a9056a3760fbb95ae581b0484dc2b5749be30326c9ea2a799/pyobjc_framework_notificationcenter-10.3.2.tar.gz", hash = "sha256:d0dc85e4da0f0e139e032279893db4827595f8f11830080e294f63f57e984c1f", size = 21367 } wheels = [ @@ -3619,8 +3619,8 @@ name = "pyobjc-framework-opendirectory" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8f/cf/5e0c2c3b1c29f3869c17149a69d3142b93343161af135c2a822404c8a61a/pyobjc_framework_opendirectory-10.3.2.tar.gz", hash = "sha256:d506f66c888284e50edb766222d9e3311d9a3ec51b561df1994c498233730f62", size = 159962 } wheels = [ @@ -3633,8 +3633,8 @@ name = "pyobjc-framework-osakit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/5a/11674938bd217abdfc5ccbd23ebfc0bd21f003cf2609cf545503efdd9214/pyobjc_framework_osakit-10.3.2.tar.gz", hash = "sha256:2a718d4bf08d1b09d41eca1131604ee87929b991506d56951e992e2112a0b4e7", size = 18610 } wheels = [ @@ -3647,10 +3647,10 @@ name = "pyobjc-framework-oslog" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coremedia", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/92/1b/1a404937e72478a6698ac935b7dc0e754b76459a913c6dd26a042a12ebcd/pyobjc_framework_oslog-10.3.2.tar.gz", hash = "sha256:3f9680b737130579e1317e8bb25d6eb044a1a9569b9dbe33c056654a0d40efbd", size = 22643 } wheels = [ @@ -3665,8 +3665,8 @@ name = "pyobjc-framework-passkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/83/4d/c89c17233d3e3510c7d609384f71fe7b70432f15d16e31ae61deda8c03cc/pyobjc_framework_passkit-10.3.2.tar.gz", hash = "sha256:e85d94062cab45b99dc7123f8de048720730439b66d3b0386eabddb8856aaf12", size = 95237 } wheels = [ @@ -3681,8 +3681,8 @@ name = "pyobjc-framework-pencilkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/48/83/630fc7219b046446705771406d9ae6ec027878478e7d8699892786aaec21/pyobjc_framework_pencilkit-10.3.2.tar.gz", hash = "sha256:2390317a7de5f68fb9594f9eccbe55183ee5f40a7efc59c827c5fc2d4abce508", size = 19159 } wheels = [ @@ -3695,8 +3695,8 @@ name = "pyobjc-framework-phase" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-avfoundation", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/67/ff/088a94515efb4c9be86bc45ce1024a924f71a7a836462a9177da42447c0a/pyobjc_framework_phase-10.3.2.tar.gz", hash = "sha256:87a0f4d2e6b9db186fda3e700cfc52bc15a9d38f53f5cb3335be93c75d7cccf2", size = 44249 } wheels = [ @@ -3709,8 +3709,8 @@ name = "pyobjc-framework-photos" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/29/43357f5a2a57972bd4cdd4bbc5a914cee4e4eb1f9a9ba6b0aaed2f6308e3/pyobjc_framework_photos-10.3.2.tar.gz", hash = "sha256:4aa7180a45ef0b5245a277980c2be32195d6b512d66f8abbfdad480466e06434", size = 74548 } wheels = [ @@ -3725,8 +3725,8 @@ name = "pyobjc-framework-photosui" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6a/78/c30494b5207d1ece728541ec21632317a054a6bfb8aecdac770c79d8ab72/pyobjc_framework_photosui-10.3.2.tar.gz", hash = "sha256:0cafb53b9c6014c524ee230d3278cf224e44c885e1166524db9160f8c928e6ba", size = 39302 } wheels = [ @@ -3741,8 +3741,8 @@ name = "pyobjc-framework-preferencepanes" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/63/d76bc32761d619cadb93fe37054c5f4f7d7e805b68e565170d5412452253/pyobjc_framework_preferencepanes-10.3.2.tar.gz", hash = "sha256:e1cee875450f43700cdfc47d6e9f636b82df31420a0bc29b213670a773225cd6", size = 25669 } wheels = [ @@ -3755,8 +3755,8 @@ name = "pyobjc-framework-pushkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/41/8e9e021c0168e7c8460038bd3f3289232b1b9429c002bc981dbb8bba2a68/pyobjc_framework_pushkit-10.3.2.tar.gz", hash = "sha256:852e8a19424b8a83973f7c3f1ada325871ec2645071abf519712ead972dd0395", size = 19530 } wheels = [ @@ -3771,8 +3771,8 @@ name = "pyobjc-framework-quartz" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/bd/d78c845a6f0640975e837d1d0f04d6bbd95bb88b77dcee22482144ac5ad0/pyobjc_framework_quartz-10.3.2.tar.gz", hash = "sha256:193e7752c93e2d1304f914e3a8c069f4b66de237376c5285ba7c72e9ee0e3b15", size = 3776754 } wheels = [ @@ -3785,9 +3785,9 @@ name = "pyobjc-framework-quicklookthumbnailing" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/12/d8dc4cb3be565df9e245bf8b234a07a74aa7d0966e643e17a3ed2a645bc3/pyobjc_framework_quicklookthumbnailing-10.3.2.tar.gz", hash = "sha256:f6d35495fdad885ae928a074eb9b45d2f426cf161a557510db3fc1f872a76ad1", size = 15877 } wheels = [ @@ -3800,8 +3800,8 @@ name = "pyobjc-framework-replaykit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ef/b1/b8539b171c6a335378928e077d5a8f05e97d43d459c4f1578cd7ed82ac83/pyobjc_framework_replaykit-10.3.2.tar.gz", hash = "sha256:05c15651ad4051037e7647b04e0304b288fa4663ab182d5848958a33a3b6c136", size = 23771 } wheels = [ @@ -3816,8 +3816,8 @@ name = "pyobjc-framework-safariservices" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/af/ae/b9a7063c6ecce49efe37298b0d80a00aeb51c7777898a574d78791181046/pyobjc_framework_safariservices-10.3.2.tar.gz", hash = "sha256:3601d177ac3900c681a1dd77a3dab28341c40705572006f3fe7834c9890bb708", size = 29867 } wheels = [ @@ -3832,9 +3832,9 @@ name = "pyobjc-framework-safetykit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/70/b3/b5fa5d14cc95c52a67b3e676a8badc671057bd3b483dcd2dd37b37bc9c2b/pyobjc_framework_safetykit-10.3.2.tar.gz", hash = "sha256:d6902abba592532ae7c4864d16df9cb88dab2451e9fcecaa48b5e01948dd84fd", size = 19392 } wheels = [ @@ -3849,9 +3849,9 @@ name = "pyobjc-framework-scenekit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dc/60/9140bd2f59c00c05a549cad6f6ef303d1ea12bf39ac70cfd9c244ed775a9/pyobjc_framework_scenekit-10.3.2.tar.gz", hash = "sha256:451b02c3b58f78adeb06239f9e4d2ac8545277056e5945eca3592b04c5f3ed67", size = 155651 } wheels = [ @@ -3866,9 +3866,9 @@ name = "pyobjc-framework-screencapturekit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coremedia", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a5/f6/0f9a509f86d5b876ebdbcf4b96a01a824ecdaf4f3e8ff9516f7e7c13abc9/pyobjc_framework_screencapturekit-10.3.2.tar.gz", hash = "sha256:948d6663243e141acfc4ea1499f4690e5ec51d9cad9db843d5450548a2a7028f", size = 35192 } wheels = [ @@ -3881,8 +3881,8 @@ name = "pyobjc-framework-screensaver" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/7f/b4472750bc0f66b6b43ae462e2bfccc113fa135780ab9b4e43e648f19a51/pyobjc_framework_screensaver-10.3.2.tar.gz", hash = "sha256:2e0bc1406848607931123b87a59235712c40d362247be6c0c0746b26a4bd8e5f", size = 22469 } wheels = [ @@ -3897,8 +3897,8 @@ name = "pyobjc-framework-screentime" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/02/50/6189139ea6736443f8b9f3ff6b776b62070b967965c4292d60e121884fed/pyobjc_framework_screentime-10.3.2.tar.gz", hash = "sha256:1f57188ea57d71204a65e1f342ed34128704bcee3ff7d8566f503d87b779e902", size = 13688 } wheels = [ @@ -3911,8 +3911,8 @@ name = "pyobjc-framework-scriptingbridge" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ed/0c/fff6cf7279cb78e8bd09a9a605d06f6e53a7d7d6b8a5c80f66477010d68b/pyobjc_framework_scriptingbridge-10.3.2.tar.gz", hash = "sha256:07655aff60a238fcf25918bd62fda007aef6076a92c47ea543dd71028e812a8c", size = 21176 } wheels = [ @@ -3927,8 +3927,8 @@ name = "pyobjc-framework-searchkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreservices", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9c/6a/586d7534ef7dd9277297d25ef96e96da5ee701cdaad1d4039c3f9219c1ae/pyobjc_framework_searchkit-10.3.2.tar.gz", hash = "sha256:1acaf21339e6583e901535f82271578b43ec44797b9b1293a3b7692deca3d704", size = 30823 } wheels = [ @@ -3941,8 +3941,8 @@ name = "pyobjc-framework-security" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/08/bbbfa295aef75986d7204ba3d856b26779d9eb2d0efbdcce2ddcb468d9b9/pyobjc_framework_security-10.3.2.tar.gz", hash = "sha256:8e018ad36a5ba4ebf1da45cc3ca2a658906ed1e3f9ffdde8f743c813a233d735", size = 252834 } wheels = [ @@ -3955,9 +3955,9 @@ name = "pyobjc-framework-securityfoundation" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-security", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1c/3f/0b46d29ef0075c27f48288da2daaca83cf3707a922a0fd9051e111045a42/pyobjc_framework_securityfoundation-10.3.2.tar.gz", hash = "sha256:738e8034f7c7a91f37e6e5b0bc94d9d74ad8016c96508994fdc4d76915d76fc4", size = 12907 } wheels = [ @@ -3970,9 +3970,9 @@ name = "pyobjc-framework-securityinterface" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-security", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3c/ea/1dfdf32ab13daa11f99d33ce62cc99076a6162dd4175442675f01711dbd2/pyobjc_framework_securityinterface-10.3.2.tar.gz", hash = "sha256:9d90589f165b2c4fb8c252179f5c0003c8ee6df22d0ead2b8f77e07ff4733dfe", size = 32274 } wheels = [ @@ -3987,9 +3987,9 @@ name = "pyobjc-framework-sensitivecontentanalysis" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2d/c0/b23985c0a71168317a15c3b440cf02b3f546d8248b3d82cb9f13b4fe2b5e/pyobjc_framework_sensitivecontentanalysis-10.3.2.tar.gz", hash = "sha256:561c0b19144648a0dab19da1896cbdfbf484f3cb752e95aa42e27ff7c5da923b", size = 12323 } wheels = [ @@ -4002,8 +4002,8 @@ name = "pyobjc-framework-servicemanagement" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/47/d1/06333ad3eb0fd5f7f2f34d9f3c48f81c1732aa66f7d97c63899c7832fbc3/pyobjc_framework_servicemanagement-10.3.2.tar.gz", hash = "sha256:60415ce7ce789062a1bb066a1e698325cc110fcab94324368f1697cb171387e5", size = 16076 } wheels = [ @@ -4016,8 +4016,8 @@ name = "pyobjc-framework-sharedwithyou" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-sharedwithyoucore" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-sharedwithyoucore", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/21/4b28cac56c3637a942c8ad70490fc48586fbfbc503088594b0110325b116/pyobjc_framework_sharedwithyou-10.3.2.tar.gz", hash = "sha256:2a2717f85b7a8db33ef04dc90dfdfcb9f6891740112bdcd739a7d5ff37185107", size = 28260 } wheels = [ @@ -4032,8 +4032,8 @@ name = "pyobjc-framework-sharedwithyoucore" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6e/8a/62a767e8e37faf7720ef0e9a0743bf6d0b5f0776813ab5a4d0fe7c4d5507/pyobjc_framework_sharedwithyoucore-10.3.2.tar.gz", hash = "sha256:8c877f0e4590da6c687cecabfd15ca5cab3ca82cf70c7d228473e02e0e796225", size = 24687 } wheels = [ @@ -4048,8 +4048,8 @@ name = "pyobjc-framework-shazamkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c2/f3/8626b1f52c3c7665cb8f84966db045877456b9d9c55d9faa686cc773590b/pyobjc_framework_shazamkit-10.3.2.tar.gz", hash = "sha256:6158120a2d25b74a88c1ddc9d5f70df30ad4cd9c19b4f9db95434cc5fbb99f70", size = 23291 } wheels = [ @@ -4062,8 +4062,8 @@ name = "pyobjc-framework-social" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/75/6f/83f92ac162fbb14fef97f100da2ad35ed2ed5bff2cb864e59b34ab5608c8/pyobjc_framework_social-10.3.2.tar.gz", hash = "sha256:8d55fe68ea1dff205c6b10fd57b0ab8e8ff1b0801ae61fd358a1c97b1a88f733", size = 14063 } wheels = [ @@ -4076,8 +4076,8 @@ name = "pyobjc-framework-soundanalysis" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/99/52fead19bfc957466758e76f540c3bced518958f64cc73c6f34b6b21e856/pyobjc_framework_soundanalysis-10.3.2.tar.gz", hash = "sha256:3e5326c40b62238d448da9d52c78b22a659a1ec00eeed4358f58d5dc6758b2aa", size = 15900 } wheels = [ @@ -4090,8 +4090,8 @@ name = "pyobjc-framework-speech" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/3a/c9f92ab6b648b1ea346d2c8aac78e8a82fd56c9e8c1fa0c369c09ce535b7/pyobjc_framework_speech-10.3.2.tar.gz", hash = "sha256:86e825076ce65b5dbdf3ce0b37ab1d251beff3e97773114d3933012d6d771fd8", size = 30314 } wheels = [ @@ -4106,9 +4106,9 @@ name = "pyobjc-framework-spritekit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/11/aefc94b7d2d8a3e43f51bf448d7dea48fca8c637439b2708e203fe16e4c3/pyobjc_framework_spritekit-10.3.2.tar.gz", hash = "sha256:cd28510d2158455ab9f0109655ecbebbdaff98daf3fb6af19e2f472a91496270", size = 95884 } wheels = [ @@ -4121,8 +4121,8 @@ name = "pyobjc-framework-storekit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/24/eb/cf77c88a0a957b142869b184600ca0a43b8a944fd257429e64a9a04b1abe/pyobjc_framework_storekit-10.3.2.tar.gz", hash = "sha256:8112857047363c200708ba4472e644d1d465a134edcd5edd4b0da6ab4bcff143", size = 64015 } wheels = [ @@ -4137,8 +4137,8 @@ name = "pyobjc-framework-symbols" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/bc/80ed504beaeddebaeca4fd1237315987971af99ade2f6e755f4663b8dbeb/pyobjc_framework_symbols-10.3.2.tar.gz", hash = "sha256:b6293ac919513f8f91e2f4d847bca3b67a10e3a9e636bd2a6a05d7d2b43bb3ad", size = 12118 } wheels = [ @@ -4151,9 +4151,9 @@ name = "pyobjc-framework-syncservices" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coredata" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coredata", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ef/49/2a72d27312a7b41f814f0dec33d6b27972a4842e509d2db39200a189ac63/pyobjc_framework_syncservices-10.3.2.tar.gz", hash = "sha256:4ccd394746027b788907af2846dd1ab3505f340f0bf24400191017e5d0e6300e", size = 49889 } wheels = [ @@ -4168,8 +4168,8 @@ name = "pyobjc-framework-systemconfiguration" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/df/28b0da49f01b3f6b0b26d9ae530d4ad5d225e67c812469204552c8bc4c34/pyobjc_framework_systemconfiguration-10.3.2.tar.gz", hash = "sha256:6d98d26da42501abceb9b374ba8e31b01a96af87a77cd578ea1b691f8152bc86", size = 124533 } wheels = [ @@ -4184,8 +4184,8 @@ name = "pyobjc-framework-systemextensions" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d5/45/df446df16f431d2c8c1733f5076b75eb3119ac21371dbe9c900542488099/pyobjc_framework_systemextensions-10.3.2.tar.gz", hash = "sha256:8e513fbc750cce3af0a77fab08c05c9cc2ba0d64116490bd1f7b0f9fe8ba6972", size = 20236 } wheels = [ @@ -4200,8 +4200,8 @@ name = "pyobjc-framework-threadnetwork" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/91/85/821d14d8118329be7106e2d656fd8466ceb20d6d90e4341ac8e7b43dc970/pyobjc_framework_threadnetwork-10.3.2.tar.gz", hash = "sha256:1d8b73000c077da1dafc4c4298acda6df8ec615a4bf94ffc2f9f3ef8c209dc45", size = 12976 } wheels = [ @@ -4214,8 +4214,8 @@ name = "pyobjc-framework-uniformtypeidentifiers" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/40/2b/665cebe17818d7cf6bb5edf38319bcb3dd2915e1eb6c9e65db8c7fb045a0/pyobjc_framework_uniformtypeidentifiers-10.3.2.tar.gz", hash = "sha256:59e8b11d78d89a24f7fb944853b93705ca48febf1ae42be57d16100e38703f69", size = 18820 } wheels = [ @@ -4228,8 +4228,8 @@ name = "pyobjc-framework-usernotifications" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/87/2cf1c42e4686fe407b1043ae6fce7484da9a05d5f930ef4807aeb7f62233/pyobjc_framework_usernotifications-10.3.2.tar.gz", hash = "sha256:84743b40d950959b92bc15265278d4e4de45bf84fc3a45d8636f38476d7201c1", size = 46431 } wheels = [ @@ -4244,9 +4244,9 @@ name = "pyobjc-framework-usernotificationsui" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-usernotifications" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-usernotifications", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/14/c028e54d93df12c4b84376bb1f343bbcf338dea8f21bd724c32de8841efe/pyobjc_framework_usernotificationsui-10.3.2.tar.gz", hash = "sha256:9e21f207dcb4305b2dd80ed5329515867aee0caf8f40157911f8b4c6674e4b60", size = 13611 } wheels = [ @@ -4259,8 +4259,8 @@ name = "pyobjc-framework-videosubscriberaccount" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6d/05/6a25c1ef8189288ae7267cacf444031083840c9bd7fc0f8d9c6e61de34d6/pyobjc_framework_videosubscriberaccount-10.3.2.tar.gz", hash = "sha256:6072e55242c150bfc09417679813966482570fcfd0f0dd740c241ef5589f546a", size = 24126 } wheels = [ @@ -4273,10 +4273,10 @@ name = "pyobjc-framework-videotoolbox" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coremedia", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8c/19/06a028ffdb254cf621795158f7da56c6c0f201d53b40709095a5f60fe55d/pyobjc_framework_videotoolbox-10.3.2.tar.gz", hash = "sha256:8ddfa3d25d53d03d00847f63cfcc7c033aab54d9fc1fdd0d18ff60af17aa2b14", size = 66599 } wheels = [ @@ -4291,8 +4291,8 @@ name = "pyobjc-framework-virtualization" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/5d/df555942df3bcd7df6a6ed0830b5b4a0024f4fda00ee7cefaf61afc19e05/pyobjc_framework_virtualization-10.3.2.tar.gz", hash = "sha256:6b8cd5b69dd5197b96d6b907c9224ea4d05ef3bebad552cfebf331ed98c2d4eb", size = 61977 } wheels = [ @@ -4307,10 +4307,10 @@ name = "pyobjc-framework-vision" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreml" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-coreml", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-quartz", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/f9/f9063b8cdbb2210b51beadffabb7021d55a20b3e9693219c53e98d067c10/pyobjc_framework_vision-10.3.2.tar.gz", hash = "sha256:5cfea4a750657e2c8e7c8b0c26c7aac2578ba09ab8f66ffa0e2ee632410cacf3", size = 108990 } wheels = [ @@ -4325,8 +4325,8 @@ name = "pyobjc-framework-webkit" version = "10.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, + { name = "pyobjc-framework-cocoa", marker = "platform_machine != 'aarch64' or platform_system != 'Linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ef/98/89187c121e130e11ce6c7ed86a2de10cb6d6c8994eb77ab2b81a060d1916/pyobjc_framework_webkit-10.3.2.tar.gz", hash = "sha256:b60d097a87867c252286855158cc35d991e2273f162f40f8e38e95153894bbbf", size = 611469 } wheels = [ @@ -4407,18 +4407,18 @@ wheels = [ [[package]] name = "pyqt5-sip" -version = "12.16.0" +version = "12.16.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/b8/8e2a30fc0e5222e8d86572d5c7c3611fea93ab8d2369927b6e42977c9a42/PyQt5_sip-12.16.0.tar.gz", hash = "sha256:8cfb0345b9438a18ec1dd3952054c2ac1508bd9e306092a96df99329382e3e25", size = 103977 } +sdist = { url = "https://files.pythonhosted.org/packages/3c/cd/f6f957107447bc53e398f6149f55a7f335c434f201e77dcfb8a3c20dc42c/pyqt5_sip-12.16.1.tar.gz", hash = "sha256:8c831f8b619811a32369d72339faa50ae53a963f5fdfa4d71f845c63e9673125", size = 103975 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/9f/a96240fdc5c919bd5065ae7dbc2f8353aa473513ab4847431f531893ab87/PyQt5_sip-12.16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bf825f17a299f8230c7986f2823bea7d3468b0cf1ebde0e6f5ce52270f08635a", size = 122620 }, - { url = "https://files.pythonhosted.org/packages/a0/c0/25ced297d61c838758e1e0486d79e6150d545f6a916259ac66b83f925410/PyQt5_sip-12.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3de8327ca93c1b8df2d3b958b654f2e05aba3e91c1a31a78a9d581e9fe4089c4", size = 276204 }, - { url = "https://files.pythonhosted.org/packages/67/38/825912802ec53ad82a8f5ca787415e15ad4ceab3a42f652e2383deb42b54/PyQt5_sip-12.16.0-cp311-cp311-win32.whl", hash = "sha256:3f4cc0c84cad4ad5da7bec1edc3278a798114819c973da5fb80876f63254637b", size = 49046 }, - { url = "https://files.pythonhosted.org/packages/90/c9/2137950435b4ad24b89e436ef325e4c22ee865539eae35c523aa293218eb/PyQt5_sip-12.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:0a20656422e45d41b5eb5a427d56edc9a3a93bd51143bcbefbba1e1b3e839aab", size = 58996 }, - { url = "https://files.pythonhosted.org/packages/4e/3c/0713c459e95a2a1317d8955189dfd1ef300f70a1f1eeb3b0b65b24dbf8b7/PyQt5_sip-12.16.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:70ebd353ca0da7d7140fcab6718ee802157aa7794171fc80887b9251ebf44e6b", size = 124546 }, - { url = "https://files.pythonhosted.org/packages/f8/bf/b5675329f34182efe52205df26516e842670c57bd24b3d2eb9b97ac9c59e/PyQt5_sip-12.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9ec67e5f55df791c9139dc9c890530f243aac304d60e731846bd9302064dc727", size = 281638 }, - { url = "https://files.pythonhosted.org/packages/be/0f/4e0cd2c07981f51d5f58e68cf25586f7133f170a68ecbbd856f2412f19f6/PyQt5_sip-12.16.0-cp312-cp312-win32.whl", hash = "sha256:7a9260174aa875e24603cb0840fc76ced2f35d90af057ce2f6d79d282cf1bbdc", size = 49430 }, - { url = "https://files.pythonhosted.org/packages/eb/31/8610b8e0f53400dbfd3cfe2f838d725239650e0a27cdf6fc5d5dc1518b8a/PyQt5_sip-12.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:57135e6b1f309b20163aaf15515967bec01ee145c538f87f9f89d8afc8c570f1", size = 57957 }, + { url = "https://files.pythonhosted.org/packages/ea/69/b23bb48eeea59d934587ae5e11d9fce2cfa0536a311c78a177190134a62d/PyQt5_sip-12.16.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09bfdb5f9adea15a542cbe4b89873a6b290c4f1669f66bb5f1a24993ce8bbdd0", size = 122619 }, + { url = "https://files.pythonhosted.org/packages/30/b7/78f68147ce4dfac84d705a9dbbb1c41878a365597fa08918bf2bdfd86809/PyQt5_sip-12.16.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:98b99fcdebbbfc999f4ab10829749151eb371b79201ecd98f20e934c16d0193e", size = 276217 }, + { url = "https://files.pythonhosted.org/packages/3c/01/0387b81f4b0797cb3762e1a2cbbe17086b7c15ba13de37e0f6e94b601a18/PyQt5_sip-12.16.1-cp311-cp311-win32.whl", hash = "sha256:67dbdc1b3be045caebfc75ee87966e23c6bee61d94cb634ddd71b634c9089890", size = 49044 }, + { url = "https://files.pythonhosted.org/packages/9a/96/67914c5e17456365b9d7bc71d6eec2a878340904aa9905ae48554a3f6f18/PyQt5_sip-12.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:8afd633d5f35e4e5205680d310800d10d30fcbfb6bb7b852bfaa31097c1be449", size = 58997 }, + { url = "https://files.pythonhosted.org/packages/7f/3d/8dc6b2ef0132ab1cc534485905b594e6f4176176924e54e35a3f6a0fb164/PyQt5_sip-12.16.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f6724c590de3d556c730ebda8b8f906b38373934472209e94d99357b52b56f5f", size = 124549 }, + { url = "https://files.pythonhosted.org/packages/45/eb/fa72094f2ca861941d38a4df49d0a34bd024972cd458f516ef3c65d128e3/PyQt5_sip-12.16.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:633cba509a98bd626def951bb948d4e736635acbd0b7fabd7be55a3a096a8a0b", size = 281640 }, + { url = "https://files.pythonhosted.org/packages/12/a5/9439567dbf513bfc0fd71a5bb3797fae649338715749e89571ad86b4b3e3/PyQt5_sip-12.16.1-cp312-cp312-win32.whl", hash = "sha256:2b35ff92caa569e540675ffcd79ffbf3e7092cccf7166f89e2a8b388db80aa1c", size = 49428 }, + { url = "https://files.pythonhosted.org/packages/a7/33/d91e003b85ff7ab227d0fff236d48c18ada2f0cd49d5e35cb514867ba609/PyQt5_sip-12.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:a0f83f554727f43dfe92afbf3a8c51e83bb8b78c5f160b635d4359fad681cebe", size = 57957 }, ] [[package]] @@ -4459,7 +4459,7 @@ name = "pytest" version = "8.3.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, @@ -4471,14 +4471,14 @@ wheels = [ [[package]] name = "pytest-asyncio" -version = "0.24.0" +version = "0.25.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 } +sdist = { url = "https://files.pythonhosted.org/packages/94/18/82fcb4ee47d66d99f6cd1efc0b11b2a25029f303c599a5afda7c1bca4254/pytest_asyncio-0.25.0.tar.gz", hash = "sha256:8c0610303c9e0442a5db8604505fc0f545456ba1528824842b37b4a626cbf609", size = 53298 } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 }, + { url = "https://files.pythonhosted.org/packages/88/56/2ee0cab25c11d4e38738a2a98c645a8f002e2ecf7b5ed774c70d53b92bb1/pytest_asyncio-0.25.0-py3-none-any.whl", hash = "sha256:db5432d18eac6b7e28b46dcd9b69921b55c3b1086e85febfe04e70b18d9e81b3", size = 19245 }, ] [[package]] @@ -4544,15 +4544,15 @@ wheels = [ [[package]] name = "pytest-subtests" -version = "0.14.0" +version = "0.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8e/39/8c0a9e34860798b8831945546bf2ee7846a4a2c301d9a4a868dc19b479ef/pytest_subtests-0.14.0.tar.gz", hash = "sha256:8849818a0a515e8052734888cd0f6701291fdbf77552664d9ac772a2f8cc8f0f", size = 17363 } +sdist = { url = "https://files.pythonhosted.org/packages/c0/4c/ba9eab21a2250c2d46c06c0e3cd316850fde9a90da0ac8d0202f074c6817/pytest_subtests-0.14.1.tar.gz", hash = "sha256:350c00adc36c3aff676a66135c81aed9e2182e15f6c3ec8721366918bbbf7580", size = 17632 } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/f7/39bfd95b0367a9ca2a04087ff631592a472d9cb7564cdb3e13a42d9ae6b1/pytest_subtests-0.14.0-py3-none-any.whl", hash = "sha256:7343f2efd90026998d8fe50fe9798cf54c5f00e162584ba4ce8d7658d2c6ed3e", size = 8720 }, + { url = "https://files.pythonhosted.org/packages/a9/b7/7ca948d35642ae72500efda6ba6fa61dcb6683feb596d19c4747c63c0789/pytest_subtests-0.14.1-py3-none-any.whl", hash = "sha256:e92a780d98b43118c28a16044ad9b841727bd7cb6a417073b38fd2d7ccdf052d", size = 8833 }, ] [[package]] @@ -4597,7 +4597,7 @@ name = "python-xlib" version = "0.33" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "platform_system != 'Darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068 } wheels = [ @@ -4648,10 +4648,10 @@ name = "pywinbox" version = "0.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ewmhlib", marker = "sys_platform == 'linux'" }, - { name = "pyobjc", marker = "sys_platform == 'darwin'" }, - { name = "python-xlib", marker = "sys_platform == 'linux'" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "ewmhlib", marker = "platform_system != 'Darwin' and sys_platform == 'linux'" }, + { name = "pyobjc", marker = "(platform_machine != 'aarch64' and sys_platform == 'darwin') or (platform_system != 'Linux' and sys_platform == 'darwin')" }, + { name = "python-xlib", marker = "platform_system != 'Darwin' and sys_platform == 'linux'" }, + { name = "pywin32", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "typing-extensions" }, ] wheels = [ @@ -4663,11 +4663,11 @@ name = "pywinctl" version = "0.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ewmhlib", marker = "sys_platform == 'linux'" }, + { name = "ewmhlib", marker = "platform_system != 'Darwin' and sys_platform == 'linux'" }, { name = "pymonctl" }, - { name = "pyobjc", marker = "sys_platform == 'darwin'" }, - { name = "python-xlib", marker = "sys_platform == 'linux'" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "pyobjc", marker = "(platform_machine != 'aarch64' and sys_platform == 'darwin') or (platform_system != 'Linux' and sys_platform == 'darwin')" }, + { name = "python-xlib", marker = "platform_system != 'Darwin' and sys_platform == 'linux'" }, + { name = "pywin32", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "pywinbox" }, { name = "typing-extensions" }, ] @@ -4831,27 +4831,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.8.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/2b/01245f4f3a727d60bebeacd7ee6d22586c7f62380a2597ddb22c2f45d018/ruff-0.8.2.tar.gz", hash = "sha256:b84f4f414dda8ac7f75075c1fa0b905ac0ff25361f42e6d5da681a465e0f78e5", size = 3349020 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/91/29/366be70216dba1731a00a41f2f030822b0c96c7c4f3b2c0cdce15cbace74/ruff-0.8.2-py3-none-linux_armv6l.whl", hash = "sha256:c49ab4da37e7c457105aadfd2725e24305ff9bc908487a9bf8d548c6dad8bb3d", size = 10530649 }, - { url = "https://files.pythonhosted.org/packages/63/82/a733956540bb388f00df5a3e6a02467b16c0e529132625fe44ce4c5fb9c7/ruff-0.8.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ec016beb69ac16be416c435828be702ee694c0d722505f9c1f35e1b9c0cc1bf5", size = 10274069 }, - { url = "https://files.pythonhosted.org/packages/3d/12/0b3aa14d1d71546c988a28e1b412981c1b80c8a1072e977a2f30c595cc4a/ruff-0.8.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f05cdf8d050b30e2ba55c9b09330b51f9f97d36d4673213679b965d25a785f3c", size = 9909400 }, - { url = "https://files.pythonhosted.org/packages/23/08/f9f08cefb7921784c891c4151cce6ed357ff49e84b84978440cffbc87408/ruff-0.8.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60f578c11feb1d3d257b2fb043ddb47501ab4816e7e221fbb0077f0d5d4e7b6f", size = 10766782 }, - { url = "https://files.pythonhosted.org/packages/e4/71/bf50c321ec179aa420c8ec40adac5ae9cc408d4d37283a485b19a2331ceb/ruff-0.8.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbd5cf9b0ae8f30eebc7b360171bd50f59ab29d39f06a670b3e4501a36ba5897", size = 10286316 }, - { url = "https://files.pythonhosted.org/packages/f2/83/c82688a2a6117539aea0ce63fdf6c08e60fe0202779361223bcd7f40bd74/ruff-0.8.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b402ddee3d777683de60ff76da801fa7e5e8a71038f57ee53e903afbcefdaa58", size = 11338270 }, - { url = "https://files.pythonhosted.org/packages/7f/d7/bc6a45e5a22e627640388e703160afb1d77c572b1d0fda8b4349f334fc66/ruff-0.8.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:705832cd7d85605cb7858d8a13d75993c8f3ef1397b0831289109e953d833d29", size = 12058579 }, - { url = "https://files.pythonhosted.org/packages/da/3b/64150c93946ec851e6f1707ff586bb460ca671581380c919698d6a9267dc/ruff-0.8.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:32096b41aaf7a5cc095fa45b4167b890e4c8d3fd217603f3634c92a541de7248", size = 11615172 }, - { url = "https://files.pythonhosted.org/packages/e4/9e/cf12b697ea83cfe92ec4509ae414dc4c9b38179cc681a497031f0d0d9a8e/ruff-0.8.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e769083da9439508833cfc7c23e351e1809e67f47c50248250ce1ac52c21fb93", size = 12882398 }, - { url = "https://files.pythonhosted.org/packages/a9/27/96d10863accf76a9c97baceac30b0a52d917eb985a8ac058bd4636aeede0/ruff-0.8.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fe716592ae8a376c2673fdfc1f5c0c193a6d0411f90a496863c99cd9e2ae25d", size = 11176094 }, - { url = "https://files.pythonhosted.org/packages/eb/10/cd2fd77d4a4e7f03c29351be0f53278a393186b540b99df68beb5304fddd/ruff-0.8.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:81c148825277e737493242b44c5388a300584d73d5774defa9245aaef55448b0", size = 10771884 }, - { url = "https://files.pythonhosted.org/packages/71/5d/beabb2ff18870fc4add05fa3a69a4cb1b1d2d6f83f3cf3ae5ab0d52f455d/ruff-0.8.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d261d7850c8367704874847d95febc698a950bf061c9475d4a8b7689adc4f7fa", size = 10382535 }, - { url = "https://files.pythonhosted.org/packages/ae/29/6b3fdf3ad3e35b28d87c25a9ff4c8222ad72485ab783936b2b267250d7a7/ruff-0.8.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1ca4e3a87496dc07d2427b7dd7ffa88a1e597c28dad65ae6433ecb9f2e4f022f", size = 10886995 }, - { url = "https://files.pythonhosted.org/packages/e9/dc/859d889b4d9356a1a2cdbc1e4a0dda94052bc5b5300098647e51a58c430b/ruff-0.8.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:729850feed82ef2440aa27946ab39c18cb4a8889c1128a6d589ffa028ddcfc22", size = 11220750 }, - { url = "https://files.pythonhosted.org/packages/0b/08/e8f519f61f1d624264bfd6b8829e4c5f31c3c61193bc3cff1f19dbe7626a/ruff-0.8.2-py3-none-win32.whl", hash = "sha256:ac42caaa0411d6a7d9594363294416e0e48fc1279e1b0e948391695db2b3d5b1", size = 8729396 }, - { url = "https://files.pythonhosted.org/packages/f8/d4/ba1c7ab72aba37a2b71fe48ab95b80546dbad7a7f35ea28cf66fc5cea5f6/ruff-0.8.2-py3-none-win_amd64.whl", hash = "sha256:2aae99ec70abf43372612a838d97bfe77d45146254568d94926e8ed5bbb409ea", size = 9594729 }, - { url = "https://files.pythonhosted.org/packages/23/34/db20e12d3db11b8a2a8874258f0f6d96a9a4d631659d54575840557164c8/ruff-0.8.2-py3-none-win_arm64.whl", hash = "sha256:fb88e2a506b70cfbc2de6fae6681c4f944f7dd5f2fe87233a7233d888bad73e8", size = 9035131 }, +version = "0.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/5e/683c7ef7a696923223e7d95ca06755d6e2acbc5fd8382b2912a28008137c/ruff-0.8.3.tar.gz", hash = "sha256:5e7558304353b84279042fc584a4f4cb8a07ae79b2bf3da1a7551d960b5626d3", size = 3378522 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/c4/bfdbb8b9c419ff3b52479af8581026eeaac3764946fdb463dec043441b7d/ruff-0.8.3-py3-none-linux_armv6l.whl", hash = "sha256:8d5d273ffffff0acd3db5bf626d4b131aa5a5ada1276126231c4174543ce20d6", size = 10535860 }, + { url = "https://files.pythonhosted.org/packages/ef/c5/0aabdc9314b4b6f051168ac45227e2aa8e1c6d82718a547455e40c9c9faa/ruff-0.8.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e4d66a21de39f15c9757d00c50c8cdd20ac84f55684ca56def7891a025d7e939", size = 10346327 }, + { url = "https://files.pythonhosted.org/packages/1a/78/4843a59e7e7b398d6019cf91ab06502fd95397b99b2b858798fbab9151f5/ruff-0.8.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c356e770811858bd20832af696ff6c7e884701115094f427b64b25093d6d932d", size = 9942585 }, + { url = "https://files.pythonhosted.org/packages/91/5a/642ed8f1ba23ffc2dd347697e01eef3c42fad6ac76603be4a8c3a9d6311e/ruff-0.8.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c0a60a825e3e177116c84009d5ebaa90cf40dfab56e1358d1df4e29a9a14b13", size = 10797597 }, + { url = "https://files.pythonhosted.org/packages/30/25/2e654bc7226da09a49730a1a2ea6e89f843b362db80b4b2a7a4f948ac986/ruff-0.8.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fb782f4db39501210ac093c79c3de581d306624575eddd7e4e13747e61ba18", size = 10307244 }, + { url = "https://files.pythonhosted.org/packages/c0/2d/a224d56bcd4383583db53c2b8f410ebf1200866984aa6eb9b5a70f04e71f/ruff-0.8.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f26bc76a133ecb09a38b7868737eded6941b70a6d34ef53a4027e83913b6502", size = 11362439 }, + { url = "https://files.pythonhosted.org/packages/82/01/03e2857f9c371b8767d3e909f06a33bbdac880df17f17f93d6f6951c3381/ruff-0.8.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:01b14b2f72a37390c1b13477c1c02d53184f728be2f3ffc3ace5b44e9e87b90d", size = 12078538 }, + { url = "https://files.pythonhosted.org/packages/af/ae/ff7f97b355da16d748ceec50e1604a8215d3659b36b38025a922e0612e9b/ruff-0.8.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53babd6e63e31f4e96ec95ea0d962298f9f0d9cc5990a1bbb023a6baf2503a82", size = 11616172 }, + { url = "https://files.pythonhosted.org/packages/6a/d0/6156d4d1e53ebd17747049afe801c5d7e3014d9b2f398b9236fe36ba4320/ruff-0.8.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ae441ce4cf925b7f363d33cd6570c51435972d697e3e58928973994e56e1452", size = 12919886 }, + { url = "https://files.pythonhosted.org/packages/4e/84/affcb30bacb94f6036a128ad5de0e29f543d3f67ee42b490b17d68e44b8a/ruff-0.8.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7c65bc0cadce32255e93c57d57ecc2cca23149edd52714c0c5d6fa11ec328cd", size = 11212599 }, + { url = "https://files.pythonhosted.org/packages/60/b9/5694716bdefd8f73df7c0104334156c38fb0f77673d2966a5a1345bab94d/ruff-0.8.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5be450bb18f23f0edc5a4e5585c17a56ba88920d598f04a06bd9fd76d324cb20", size = 10784637 }, + { url = "https://files.pythonhosted.org/packages/24/7e/0e8f835103ac7da81c3663eedf79dec8359e9ae9a3b0d704bae50be59176/ruff-0.8.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8faeae3827eaa77f5721f09b9472a18c749139c891dbc17f45e72d8f2ca1f8fc", size = 10390591 }, + { url = "https://files.pythonhosted.org/packages/27/da/180ec771fc01c004045962ce017ca419a0281f4bfaf867ed0020f555b56e/ruff-0.8.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:db503486e1cf074b9808403991663e4277f5c664d3fe237ee0d994d1305bb060", size = 10894298 }, + { url = "https://files.pythonhosted.org/packages/6d/f8/29f241742ed3954eb2222314b02db29f531a15cab3238d1295e8657c5f18/ruff-0.8.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6567be9fb62fbd7a099209257fef4ad2c3153b60579818b31a23c886ed4147ea", size = 11275965 }, + { url = "https://files.pythonhosted.org/packages/79/e9/5b81dc9afc8a80884405b230b9429efeef76d04caead904bd213f453b973/ruff-0.8.3-py3-none-win32.whl", hash = "sha256:19048f2f878f3ee4583fc6cb23fb636e48c2635e30fb2022b3a1cd293402f964", size = 8807651 }, + { url = "https://files.pythonhosted.org/packages/ea/67/7291461066007617b59a707887b90e319b6a043c79b4d19979f86b7a20e7/ruff-0.8.3-py3-none-win_amd64.whl", hash = "sha256:f7df94f57d7418fa7c3ffb650757e0c2b96cf2501a0b192c18e4fb5571dfada9", size = 9625289 }, + { url = "https://files.pythonhosted.org/packages/03/8f/e4fa95288b81233356d9a9dcaed057e5b0adc6399aa8fd0f6d784041c9c3/ruff-0.8.3-py3-none-win_arm64.whl", hash = "sha256:fe2756edf68ea79707c8d68b78ca9a58ed9af22e430430491ee03e718b5e4936", size = 9078754 }, ] [[package]]