diff --git a/.github/labeler.yaml b/.github/labeler.yaml
index db1f976da8..861c2efdbd 100644
--- a/.github/labeler.yaml
+++ b/.github/labeler.yaml
@@ -12,7 +12,7 @@ simulation:
ui:
- changed-files:
- - any-glob-to-all-files: 'selfdrive/ui/**'
+ - any-glob-to-all-files: '{selfdrive/ui/**,system/ui/**}'
tools:
- changed-files:
diff --git a/.github/workflows/auto-cache/action.yaml b/.github/workflows/auto-cache/action.yaml
index fadd422b6e..377b1eedcd 100644
--- a/.github/workflows/auto-cache/action.yaml
+++ b/.github/workflows/auto-cache/action.yaml
@@ -12,7 +12,7 @@ inputs:
required: true
save:
description: 'whether to save the cache'
- default: 'false'
+ default: 'true'
required: false
outputs:
cache-hit:
diff --git a/.gitignore b/.gitignore
index 834b463083..40438f5fd0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,10 +47,8 @@ selfdrive/pandad/pandad
cereal/services.h
cereal/gen
cereal/messaging/bridge
-selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json
system/proclogd/proclogd
-selfdrive/ui/translations/alerts_generated.h
selfdrive/ui/translations/tmp
selfdrive/test/longitudinal_maneuvers/out
selfdrive/car/tests/cars_dump
diff --git a/RELEASES.md b/RELEASES.md
index 3ff80ca4dc..5730877f94 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -4,6 +4,7 @@ Version 0.9.9 (2025-05-15)
* New training architecture supervised by MLSIM
* Steering actuator delay is now learned online
* Tesla Model 3 and Y support thanks to lukasloetkolben!
+* Lexus RC 2023 support thanks to nelsonjchen!
* Coming soon
* New Honda models
* Bigger vision model
diff --git a/cereal/log.capnp b/cereal/log.capnp
index 6b5398405c..9ab51e0b77 100644
--- a/cereal/log.capnp
+++ b/cereal/log.capnp
@@ -127,6 +127,7 @@ struct OnroadEvent @0xc4fa6047f024e718 {
espActive @90;
personalityChanged @91;
aeb @92;
+ userFlag @95;
soundsUnavailableDEPRECATED @47;
}
@@ -489,6 +490,7 @@ struct DeviceState @0xa4d8b5af2aa492eb {
# device thermals
cpuTempC @26 :List(Float32);
gpuTempC @27 :List(Float32);
+ dspTempC @49 :Float32;
memoryTempC @28 :Float32;
nvmeTempC @35 :List(Float32);
modemTempC @36 :List(Float32);
diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py
index 8ad956b61b..b03285f80a 100644
--- a/cereal/messaging/__init__.py
+++ b/cereal/messaging/__init__.py
@@ -145,12 +145,16 @@ class SubMaster:
self.updated = {s: False for s in services}
self.recv_time = {s: 0. for s in services}
self.recv_frame = {s: 0 for s in services}
- self.alive = {s: False for s in services}
- self.freq_ok = {s: False for s in services}
self.sock = {}
self.data = {}
- self.valid = {}
- self.logMonoTime = {}
+ self.logMonoTime = {s: 0 for s in services}
+
+ # zero-frequency / on-demand services are always alive and presumed valid; all others must pass checks
+ on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in services}
+ self.static_freq_services = set(s for s in services if not on_demand[s])
+ self.alive = {s: on_demand[s] for s in services}
+ self.freq_ok = {s: on_demand[s] for s in services}
+ self.valid = {s: on_demand[s] for s in services}
self.freq_tracker: Dict[str, FrequencyTracker] = {}
self.poller = Poller()
@@ -177,8 +181,6 @@ class SubMaster:
data = new_message(s, 0) # lists
self.data[s] = getattr(data.as_reader(), s)
- self.logMonoTime[s] = 0
- self.valid[s] = False
self.freq_tracker[s] = FrequencyTracker(SERVICE_LIST[s].frequency, self.update_freq, s == poll)
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
@@ -215,14 +217,10 @@ class SubMaster:
self.logMonoTime[s] = msg.logMonoTime
self.valid[s] = msg.valid
- for s in self.services:
- if SERVICE_LIST[s].frequency > 1e-5 and not self.simulation:
- # alive if delay is within 10x the expected frequency
- self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency)
- self.freq_ok[s] = self.freq_tracker[s].valid
- else:
- self.freq_ok[s] = True
- self.alive[s] = self.seen[s] if self.simulation else True
+ for s in self.static_freq_services:
+ # alive if delay is within 10x the expected frequency; checks relaxed in simulator
+ self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) or (self.seen[s] and self.simulation)
+ self.freq_ok[s] = self.freq_tracker[s].valid or self.simulation
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
return all(self.alive[s] for s in (service_list or self.services) if s not in self.ignore_alive)
diff --git a/cereal/messaging/tests/test_pub_sub_master.py b/cereal/messaging/tests/test_pub_sub_master.py
index e9bc7a85cb..e47e713393 100644
--- a/cereal/messaging/tests/test_pub_sub_master.py
+++ b/cereal/messaging/tests/test_pub_sub_master.py
@@ -6,6 +6,7 @@ import cereal.messaging as messaging
from cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \
random_bytes, random_carstate, assert_carstate, \
zmq_sleep
+from cereal.services import SERVICE_LIST
class TestSubMaster:
@@ -26,7 +27,9 @@ class TestSubMaster:
sm = messaging.SubMaster(socks)
assert sm.frame == -1
assert not any(sm.updated.values())
- assert not any(sm.alive.values())
+ assert not any(sm.seen.values())
+ on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in sm.services}
+ assert all(sm.alive[s] == sm.valid[s] == sm.freq_ok[s] == on_demand[s] for s in sm.services)
assert all(t == 0. for t in sm.recv_time.values())
assert all(f == 0 for f in sm.recv_frame.values())
assert all(t == 0 for t in sm.logMonoTime.values())
@@ -83,6 +86,7 @@ class TestSubMaster:
"cameraOdometry": (20, 10),
"liveCalibration": (4, 4),
"carParams": (None, None),
+ "userFlag": (None, None),
}
for service, (max_freq, min_freq) in checks.items():
diff --git a/common/realtime.py b/common/realtime.py
index 82176a00a6..57926b4c4f 100644
--- a/common/realtime.py
+++ b/common/realtime.py
@@ -1,6 +1,7 @@
"""Utilities for reading real time clocks and keeping soft real time constraints."""
import gc
import os
+import sys
import time
from setproctitle import getproctitle
@@ -28,13 +29,13 @@ class Priority:
def set_core_affinity(cores: list[int]) -> None:
- if not PC:
+ if sys.platform == 'linux' and not PC:
os.sched_setaffinity(0, cores)
def config_realtime_process(cores: int | list[int], priority: int) -> None:
gc.disable()
- if not PC:
+ if sys.platform == 'linux' and not PC:
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(priority))
c = cores if isinstance(cores, list) else [cores, ]
set_core_affinity(c)
diff --git a/docs/CARS.md b/docs/CARS.md
index c22568ce2e..55871eba2f 100644
--- a/docs/CARS.md
+++ b/docs/CARS.md
@@ -4,12 +4,13 @@
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
-# 304 Supported Cars
+# 311 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|
Hardware Needed
|Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
-|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|Parts
- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|26 mph|12 mph|[](##)|[](##)|Parts
- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|Parts
- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[](##)|[](##)|Parts
- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[](##)|[](##)|Parts
- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Acura|RDX 2019-21|All|openpilot available[1](#footnotes)|0 mph|3 mph|[](##)|[](##)|Parts
- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
@@ -32,17 +33,22 @@ A supported vehicle is one that just works when you install a comma device. All
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|Parts
- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Ford|Escape 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Focus 2018[3](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Focus Hybrid 2018[3](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Ford|Kuga Hybrid 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Ford|Kuga Plug-in Hybrid 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Ford|Kuga Hybrid 2024|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Maverick 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Ford|Maverick Hybrid 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
@@ -186,6 +192,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[](##)|[](##)|Parts
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Lexus|RC 2023|All|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
diff --git a/docs/SAFETY.md b/docs/SAFETY.md
index 4b568728a7..18a450a395 100644
--- a/docs/SAFETY.md
+++ b/docs/SAFETY.md
@@ -25,9 +25,9 @@ ensuring two main safety requirements.
by stepping on the brake pedal or by pressing the cancel button.
2. The vehicle must not alter its trajectory too quickly for the driver to safely
react. This means that while the system is engaged, the actuators are constrained
- to operate within reasonable limits[^1].
+ to operate within reasonable limits[^1].
-For additional safety implementation details, refer to [panda safety model](https://github.com/commaai/panda#safety-model). For vehicle specific implementation of the safety concept, refer to [panda/board/safety/](https://github.com/commaai/panda/tree/master/board/safety).
+For additional safety implementation details, refer to [panda safety model](https://github.com/commaai/panda#safety-model). For vehicle specific implementation of the safety concept, refer to [opendbc/safety/safety](https://github.com/commaai/opendbc/tree/master/opendbc/safety/safety).
**Extra note**: comma.ai strongly discourages the use of openpilot forks with safety code either missing or
not fully meeting the above requirements.
diff --git a/docs/assets/three-back.svg b/docs/assets/three-back.svg
new file mode 100644
index 0000000000..4dfeeeb46a
--- /dev/null
+++ b/docs/assets/three-back.svg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8a5245f9458982b608fee67fc689d899ca638a405ff62bf9db5e4978b177ef3e
+size 121394
diff --git a/docs/how-to/connect-to-comma.md b/docs/how-to/connect-to-comma.md
index 469ef81672..cbaccaae6a 100644
--- a/docs/how-to/connect-to-comma.md
+++ b/docs/how-to/connect-to-comma.md
@@ -32,9 +32,13 @@ For doing development work on device, it's recommended to use [SSH agent forward
## ADB
-In order to use ADB on your device, you'll need to enable it in the device's settings.
+In order to use ADB on your device, you'll need to perform the following steps using the image below for reference:
+
+
+* Plug your device into constant power using port 2, letting the device boot up
* Enable ADB in your device's settings
+* Plug in your device to your PC using port 1
* Connect to your device
* `adb shell` over USB
* `adb connect` over WiFi
diff --git a/launch_env.sh b/launch_env.sh
index aff451e541..73a7a89789 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.13"
+ export AGNOS_VERSION="12.1"
fi
export STAGING_ROOT="/data/safe_staging"
diff --git a/opendbc_repo b/opendbc_repo
index 6af5ad8dd5..c856a2c0bd 160000
--- a/opendbc_repo
+++ b/opendbc_repo
@@ -1 +1 @@
-Subproject commit 6af5ad8dd5de3b890d2812cc19b063caae858b31
+Subproject commit c856a2c0bd2b3c75f86a73b051c0c4cc7159559e
diff --git a/pyproject.toml b/pyproject.toml
index 344bf2cfcc..20bfebd938 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -47,6 +47,7 @@ dependencies = [
# logging
"pyzmq",
"sentry-sdk",
+ "xattr", # used in place of 'os.getxattr' for macos compatibility
# athena
"PyJWT",
@@ -170,7 +171,7 @@ quiet-level = 3
# if you've got a short variable name that's getting flagged, add it here
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl"
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
-skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*"
+skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*"
[tool.mypy]
python_version = "3.11"
diff --git a/selfdrive/car/car_specific.py b/selfdrive/car/car_specific.py
index bbecc6e688..dc37519be1 100644
--- a/selfdrive/car/car_specific.py
+++ b/selfdrive/car/car_specific.py
@@ -191,7 +191,7 @@ class CarSpecificEvents:
events.add(EventName.accFaulted)
if CS.steeringPressed:
events.add(EventName.steerOverride)
- if CS.steeringDisengage:
+ if CS.steeringDisengage and not CS_prev.steeringDisengage:
events.add(EventName.steerDisengage)
if CS.brakePressed and CS.standstill:
events.add(EventName.preEnableStandstill)
diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py
index 43c30eb64d..6e13d55b29 100644
--- a/selfdrive/car/tests/test_docs.py
+++ b/selfdrive/car/tests/test_docs.py
@@ -4,7 +4,7 @@ from openpilot.common.basedir import BASEDIR
from opendbc.car.docs import generate_cars_md, get_all_car_docs
from openpilot.selfdrive.debug.dump_car_docs import dump_car_docs
from openpilot.selfdrive.debug.print_docs_diff import print_car_docs_diff
-from openpilot.selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE
+from openpilot.selfdrive.car.docs import CARS_MD_TEMPLATE
class TestCarDocs:
@@ -13,11 +13,7 @@ class TestCarDocs:
cls.all_cars = get_all_car_docs()
def test_generator(self):
- generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE)
- with open(CARS_MD_OUT) as f:
- current_cars_md = f.read()
-
- assert generated_cars_md == current_cars_md, "Run selfdrive/car/docs.py to update the compatibility documentation"
+ generate_cars_md(self.all_cars, CARS_MD_TEMPLATE)
def test_docs_diff(self):
dump_path = os.path.join(BASEDIR, "selfdrive", "car", "tests", "cars_dump")
diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py
index 53f2bb586d..0a4784aca8 100644
--- a/selfdrive/car/tests/test_models.py
+++ b/selfdrive/car/tests/test_models.py
@@ -330,6 +330,7 @@ class TestCarModelBase(unittest.TestCase):
prev_panda_gas = self.safety.get_gas_pressed_prev()
prev_panda_brake = self.safety.get_brake_pressed_prev()
prev_panda_regen_braking = self.safety.get_regen_braking_prev()
+ prev_panda_steering_disengage = self.safety.get_steering_disengage_prev()
prev_panda_vehicle_moving = self.safety.get_vehicle_moving()
prev_panda_vehicle_speed_min = self.safety.get_vehicle_speed_min()
prev_panda_vehicle_speed_max = self.safety.get_vehicle_speed_max()
@@ -357,6 +358,9 @@ class TestCarModelBase(unittest.TestCase):
if self.safety.get_regen_braking_prev() != prev_panda_regen_braking:
self.assertEqual(CS.regenBraking, self.safety.get_regen_braking_prev())
+ if self.safety.get_steering_disengage_prev() != prev_panda_steering_disengage:
+ self.assertEqual(CS.steeringDisengage, self.safety.get_steering_disengage_prev())
+
if self.safety.get_vehicle_moving() != prev_panda_vehicle_moving:
self.assertEqual(not CS.standstill, self.safety.get_vehicle_moving())
@@ -432,6 +436,7 @@ class TestCarModelBase(unittest.TestCase):
brake_pressed = False
checks['brakePressed'] += brake_pressed != self.safety.get_brake_pressed_prev()
checks['regenBraking'] += CS.regenBraking != self.safety.get_regen_braking_prev()
+ checks['steeringDisengage'] += CS.steeringDisengage != self.safety.get_steering_disengage_prev()
if self.CP.pcmCruise:
# On most pcmCruise cars, openpilot's state is always tied to the PCM's cruise state.
diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py
index 25bb190fcd..84d7760dce 100755
--- a/selfdrive/modeld/modeld.py
+++ b/selfdrive/modeld/modeld.py
@@ -26,7 +26,7 @@ from openpilot.common.transformations.camera import DEVICE_CAMERAS
from openpilot.common.transformations.model import get_warp_matrix
from openpilot.system import sentry
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
-from openpilot.selfdrive.controls.lib.drive_helpers import get_accel_from_plan, smooth_value
+from openpilot.selfdrive.controls.lib.drive_helpers import get_accel_from_plan, smooth_value, get_curvature_from_plan
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, Plan
@@ -41,7 +41,7 @@ POLICY_PKL_PATH = Path(__file__).parent / 'models/driving_policy_tinygrad.pkl'
VISION_METADATA_PATH = Path(__file__).parent / 'models/driving_vision_metadata.pkl'
POLICY_METADATA_PATH = Path(__file__).parent / 'models/driving_policy_metadata.pkl'
-LAT_SMOOTH_SECONDS = 0.3
+LAT_SMOOTH_SECONDS = 0.1
LONG_SMOOTH_SECONDS = 0.3
MIN_LAT_CONTROL_SPEED = 0.3
@@ -55,7 +55,11 @@ def get_action_from_model(model_output: dict[str, np.ndarray], prev_action: log.
action_t=long_action_t)
desired_accel = smooth_value(desired_accel, prev_action.desiredAcceleration, LONG_SMOOTH_SECONDS)
- desired_curvature = model_output['desired_curvature'][0, 0]
+ desired_curvature = get_curvature_from_plan(plan[:,Plan.T_FROM_CURRENT_EULER][:,2],
+ plan[:,Plan.ORIENTATION_RATE][:,2],
+ ModelConstants.T_IDXS,
+ v_ego,
+ lat_action_t)
if v_ego > MIN_LAT_CONTROL_SPEED:
desired_curvature = smooth_value(desired_curvature, prev_action.desiredCurvature, LAT_SMOOTH_SECONDS)
else:
diff --git a/selfdrive/modeld/models/driving_vision.onnx b/selfdrive/modeld/models/driving_vision.onnx
index 5e08b78472..0a7b4a803d 100644
--- a/selfdrive/modeld/models/driving_vision.onnx
+++ b/selfdrive/modeld/models/driving_vision.onnx
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f222d2c528f1763828de01bb55e8979b1e4056e1dbb41350f521d2d2bb09d177
+oid sha256:dad289ae367cefcb862ef1d707fb4919d008f0eeaa1ebaf18df58d8de5a7d96e
size 46265585
diff --git a/selfdrive/pandad/pandad.cc b/selfdrive/pandad/pandad.cc
index db7dd387e0..fbf4e206ae 100644
--- a/selfdrive/pandad/pandad.cc
+++ b/selfdrive/pandad/pandad.cc
@@ -456,7 +456,12 @@ void pandad_run(std::vector &pandas) {
for (auto *panda : pandas) {
std::string log = panda->serial_read();
if (!log.empty()) {
- LOGD("%s", log.c_str());
+ if (log.find("Register 0x") != std::string::npos) {
+ // Log register divergent faults as errors
+ LOGE("%s", log.c_str());
+ } else {
+ LOGD("%s", log.c_str());
+ }
}
}
diff --git a/selfdrive/selfdrived/events.py b/selfdrive/selfdrived/events.py
index c187ed474a..6293deb2af 100755
--- a/selfdrive/selfdrived/events.py
+++ b/selfdrive/selfdrived/events.py
@@ -894,7 +894,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# causing the connection to the panda to be lost
EventName.usbError: {
ET.SOFT_DISABLE: soft_disable_alert("USB Error: Reboot Your Device"),
- ET.PERMANENT: NormalPermanentAlert("USB Error: Reboot Your Device", ""),
+ ET.PERMANENT: NormalPermanentAlert("USB Error: Reboot Your Device"),
ET.NO_ENTRY: NoEntryAlert("USB Error: Reboot Your Device"),
},
@@ -982,6 +982,9 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
ET.WARNING: personality_changed_alert,
},
+ EventName.userFlag: {
+ ET.PERMANENT: NormalPermanentAlert("Bookmark Saved", duration=1.5),
+ },
}
diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py
index face7dab29..c888551777 100755
--- a/selfdrive/selfdrived/selfdrived.py
+++ b/selfdrive/selfdrived/selfdrived.py
@@ -77,7 +77,7 @@ class SelfdriveD:
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose', 'liveDelay',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
- 'controlsState', 'carControl', 'driverAssistance', 'alertDebug'] + \
+ 'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userFlag'] + \
self.camera_packets + self.sensor_packets + self.gps_packets,
ignore_alive=ignore, ignore_avg_freq=ignore,
ignore_valid=ignore, frequency=int(1/DT_CTRL))
@@ -159,7 +159,11 @@ class SelfdriveD:
self.events.add(EventName.selfdriveInitializing)
return
- # no more events while in dashcam mode
+ # Check for user flag (bookmark) press
+ if self.sm.updated['userFlag']:
+ self.events.add(EventName.userFlag)
+
+ # Don't add any more events while in dashcam mode
if self.CP.passive:
return
@@ -365,7 +369,7 @@ class SelfdriveD:
if self.sm['modelV2'].frameDropPerc > 20:
self.events.add(EventName.modeldLagging)
- # decrement personality on distance button press
+ # Decrement personality on distance button press
if self.CP.openpilotLongitudinalControl:
if any(not be.pressed and be.type == ButtonType.gapAdjustCruise for be in CS.buttonEvents):
self.personality = (self.personality - 1) % 3
diff --git a/system/athena/athenad.py b/system/athena/athenad.py
index 5813bc90a5..fb546fa40f 100755
--- a/system/athena/athenad.py
+++ b/system/athena/athenad.py
@@ -776,8 +776,11 @@ def ws_manage(ws: WebSocket, end_event: threading.Event) -> None:
# While not sending data, onroad, we can expect to time out in 7 + (7 * 2) = 21s
# offroad, we can expect to time out in 30 + (10 * 3) = 60s
# FIXME: TCP_USER_TIMEOUT is effectively 2x for some reason (32s), so it's mostly unused
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_USER_TIMEOUT, 16000 if onroad else 0)
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 7 if onroad else 30)
+ if sys.platform == 'linux':
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_USER_TIMEOUT, 16000 if onroad else 0)
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 7 if onroad else 30)
+ elif sys.platform == 'darwin':
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPALIVE, 7 if onroad else 30)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 7 if onroad else 10)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 2 if onroad else 3)
diff --git a/system/hardware/base.py b/system/hardware/base.py
index 1e3b94e44e..90b42b2f1f 100644
--- a/system/hardware/base.py
+++ b/system/hardware/base.py
@@ -33,6 +33,7 @@ class ThermalZone:
class ThermalConfig:
cpu: list[ThermalZone] | None = None
gpu: list[ThermalZone] | None = None
+ dsp: ThermalZone | None = None
pmic: list[ThermalZone] | None = None
memory: ThermalZone | None = None
intake: ThermalZone | None = None
diff --git a/system/hardware/tici/agnos.json b/system/hardware/tici/agnos.json
index 1a3cd382a9..a415851a10 100644
--- a/system/hardware/tici/agnos.json
+++ b/system/hardware/tici/agnos.json
@@ -56,29 +56,29 @@
},
{
"name": "boot",
- "url": "https://commadist.azureedge.net/agnosupdate/boot-9b07cc366919890cc88bdd45c8c7e643bf66557caf9ad6a1373accc6dcacd892.img.xz",
- "hash": "9b07cc366919890cc88bdd45c8c7e643bf66557caf9ad6a1373accc6dcacd892",
- "hash_raw": "9b07cc366919890cc88bdd45c8c7e643bf66557caf9ad6a1373accc6dcacd892",
+ "url": "https://commadist.azureedge.net/agnosupdate/boot-3d8e848796924081f5a6b3d745808b1117ae2ec41c03f2d41ee2e75633bd6425.img.xz",
+ "hash": "3d8e848796924081f5a6b3d745808b1117ae2ec41c03f2d41ee2e75633bd6425",
+ "hash_raw": "3d8e848796924081f5a6b3d745808b1117ae2ec41c03f2d41ee2e75633bd6425",
"size": 18479104,
"sparse": false,
"full_check": true,
"has_ab": true,
- "ondevice_hash": "41d31b862fec1b87879b508c405adb9d7b5c0a3324f7350bd904f451605b06cf"
+ "ondevice_hash": "2075104847d1c96a06f07e85efb9f48d0e792d75a059047eae7ba4b463ffeadf"
},
{
"name": "system",
- "url": "https://commadist.azureedge.net/agnosupdate/system-02a6f40cc305faf703ab8f993a49d720043e4df1c0787d60dcf87eedb9f2ffde.img.xz",
- "hash": "c56256a64e6d7e16886e39a4263ffb686ed0f03d3a665c3552f54a39723f8824",
- "hash_raw": "02a6f40cc305faf703ab8f993a49d720043e4df1c0787d60dcf87eedb9f2ffde",
- "size": 4404019200,
+ "url": "https://commadist.azureedge.net/agnosupdate/system-b22bd239c6f9527596fd49b98b7d521a563f99b90953ce021ee36567498e99c7.img.xz",
+ "hash": "cb9bfde1e995b97f728f5d5ad8d7a0f7a01544db5d138ead9b2350f222640939",
+ "hash_raw": "b22bd239c6f9527596fd49b98b7d521a563f99b90953ce021ee36567498e99c7",
+ "size": 5368709120,
"sparse": true,
"full_check": false,
"has_ab": true,
- "ondevice_hash": "ed2e11f52beb8559223bf9fb989fd4ef5d2ce66eeb11ae0053fff8e41903a533",
+ "ondevice_hash": "e92a1f34158c60364c8d47b8ebbb6e59edf8d4865cd5edfeb2355d6f54f617fc",
"alt": {
- "hash": "02a6f40cc305faf703ab8f993a49d720043e4df1c0787d60dcf87eedb9f2ffde",
- "url": "https://commadist.azureedge.net/agnosupdate/system-02a6f40cc305faf703ab8f993a49d720043e4df1c0787d60dcf87eedb9f2ffde.img",
- "size": 4404019200
+ "hash": "b22bd239c6f9527596fd49b98b7d521a563f99b90953ce021ee36567498e99c7",
+ "url": "https://commadist.azureedge.net/agnosupdate/system-b22bd239c6f9527596fd49b98b7d521a563f99b90953ce021ee36567498e99c7.img",
+ "size": 5368709120
}
}
]
\ No newline at end of file
diff --git a/system/hardware/tici/all-partitions.json b/system/hardware/tici/all-partitions.json
index 4e24b229d4..be303b7f90 100644
--- a/system/hardware/tici/all-partitions.json
+++ b/system/hardware/tici/all-partitions.json
@@ -339,62 +339,62 @@
},
{
"name": "boot",
- "url": "https://commadist.azureedge.net/agnosupdate/boot-9b07cc366919890cc88bdd45c8c7e643bf66557caf9ad6a1373accc6dcacd892.img.xz",
- "hash": "9b07cc366919890cc88bdd45c8c7e643bf66557caf9ad6a1373accc6dcacd892",
- "hash_raw": "9b07cc366919890cc88bdd45c8c7e643bf66557caf9ad6a1373accc6dcacd892",
+ "url": "https://commadist.azureedge.net/agnosupdate/boot-3d8e848796924081f5a6b3d745808b1117ae2ec41c03f2d41ee2e75633bd6425.img.xz",
+ "hash": "3d8e848796924081f5a6b3d745808b1117ae2ec41c03f2d41ee2e75633bd6425",
+ "hash_raw": "3d8e848796924081f5a6b3d745808b1117ae2ec41c03f2d41ee2e75633bd6425",
"size": 18479104,
"sparse": false,
"full_check": true,
"has_ab": true,
- "ondevice_hash": "41d31b862fec1b87879b508c405adb9d7b5c0a3324f7350bd904f451605b06cf"
+ "ondevice_hash": "2075104847d1c96a06f07e85efb9f48d0e792d75a059047eae7ba4b463ffeadf"
},
{
"name": "system",
- "url": "https://commadist.azureedge.net/agnosupdate/system-02a6f40cc305faf703ab8f993a49d720043e4df1c0787d60dcf87eedb9f2ffde.img.xz",
- "hash": "c56256a64e6d7e16886e39a4263ffb686ed0f03d3a665c3552f54a39723f8824",
- "hash_raw": "02a6f40cc305faf703ab8f993a49d720043e4df1c0787d60dcf87eedb9f2ffde",
- "size": 4404019200,
+ "url": "https://commadist.azureedge.net/agnosupdate/system-b22bd239c6f9527596fd49b98b7d521a563f99b90953ce021ee36567498e99c7.img.xz",
+ "hash": "cb9bfde1e995b97f728f5d5ad8d7a0f7a01544db5d138ead9b2350f222640939",
+ "hash_raw": "b22bd239c6f9527596fd49b98b7d521a563f99b90953ce021ee36567498e99c7",
+ "size": 5368709120,
"sparse": true,
"full_check": false,
"has_ab": true,
- "ondevice_hash": "ed2e11f52beb8559223bf9fb989fd4ef5d2ce66eeb11ae0053fff8e41903a533",
+ "ondevice_hash": "e92a1f34158c60364c8d47b8ebbb6e59edf8d4865cd5edfeb2355d6f54f617fc",
"alt": {
- "hash": "02a6f40cc305faf703ab8f993a49d720043e4df1c0787d60dcf87eedb9f2ffde",
- "url": "https://commadist.azureedge.net/agnosupdate/system-02a6f40cc305faf703ab8f993a49d720043e4df1c0787d60dcf87eedb9f2ffde.img",
- "size": 4404019200
+ "hash": "b22bd239c6f9527596fd49b98b7d521a563f99b90953ce021ee36567498e99c7",
+ "url": "https://commadist.azureedge.net/agnosupdate/system-b22bd239c6f9527596fd49b98b7d521a563f99b90953ce021ee36567498e99c7.img",
+ "size": 5368709120
}
},
{
"name": "userdata_90",
- "url": "https://commadist.azureedge.net/agnosupdate/userdata_90-175a5d3353daa5e7b7d9939cb51a2f1d7e6312b4708ad654c351da2f1ef4f108.img.xz",
- "hash": "ff01a0ca5a2ea6661f836248043a211cd8d71c3269c139cb574b56855fabc3f4",
- "hash_raw": "175a5d3353daa5e7b7d9939cb51a2f1d7e6312b4708ad654c351da2f1ef4f108",
+ "url": "https://commadist.azureedge.net/agnosupdate/userdata_90-4bb7239f7e82c846e4d2584c0c433f03c582a80950de4094e6c190563d6d84ac.img.xz",
+ "hash": "b18001a2a87caa070fabf6321f8215ac353d6444564e3f86329b4dccc039ce54",
+ "hash_raw": "4bb7239f7e82c846e4d2584c0c433f03c582a80950de4094e6c190563d6d84ac",
"size": 96636764160,
"sparse": true,
"full_check": true,
"has_ab": false,
- "ondevice_hash": "2f3d69e5015a45a18c3553f2edc5706aacd6d84a4b3d5010a3d76a1a3aa910b0"
+ "ondevice_hash": "15ce16f2349d5b4d5fec6ad1e36222b1ae744ed10b8930bc9af75bd244dccb3c"
},
{
"name": "userdata_89",
- "url": "https://commadist.azureedge.net/agnosupdate/userdata_89-61bdaf82d3036af6e45e86adbaab02918b41debd5b58b6708d7987084d514d1b.img.xz",
- "hash": "714970777e02bb53a71640735bdb84b3071ecbc0346b978ce12eb667d75634ec",
- "hash_raw": "61bdaf82d3036af6e45e86adbaab02918b41debd5b58b6708d7987084d514d1b",
+ "url": "https://commadist.azureedge.net/agnosupdate/userdata_89-e36b59bf9ff755b6ca488df2ba1e20da8f7dab6b8843129f3fdcccd7ff2ff7d8.img.xz",
+ "hash": "12682cf54596ab1bd1c2464c4ca85888e4e06b47af5ff7d0432399e9907e2f64",
+ "hash_raw": "e36b59bf9ff755b6ca488df2ba1e20da8f7dab6b8843129f3fdcccd7ff2ff7d8",
"size": 95563022336,
"sparse": true,
"full_check": true,
"has_ab": false,
- "ondevice_hash": "95e6889a808b8d266660990e67e917cf3b63179f23588565af7f2fa54f70ac76"
+ "ondevice_hash": "e4df9dea47ff04967d971263d50c17460ef240457e8d814e7c4f409f7493eb8a"
},
{
"name": "userdata_30",
- "url": "https://commadist.azureedge.net/agnosupdate/userdata_30-a40553d3fd339cb0107f1cc55fd532820f192a7a9a90d05243ad00fcbf804997.img.xz",
- "hash": "33e5ab398620f147b885a9627b2608591bd9e1c9aa481eb705dc86707d706ea2",
- "hash_raw": "a40553d3fd339cb0107f1cc55fd532820f192a7a9a90d05243ad00fcbf804997",
+ "url": "https://commadist.azureedge.net/agnosupdate/userdata_30-fe1d86f5322c675c58b3ae9753a4670abf44a25746bf6ac822aed108bb577282.img.xz",
+ "hash": "fa471703be0f0647617d183312d5209d23407f1628e4ab0934e6ec54b1a6b263",
+ "hash_raw": "fe1d86f5322c675c58b3ae9753a4670abf44a25746bf6ac822aed108bb577282",
"size": 32212254720,
"sparse": true,
"full_check": true,
"has_ab": false,
- "ondevice_hash": "cd6291dea40968123f7af0b831cbfbbd6e515b676f2e427ae47ff358f6ac148e"
+ "ondevice_hash": "0b5b2402c9caa1ed7b832818e66580c974251e735bda91f2f226c41499d5616e"
}
-]
+]
\ No newline at end of file
diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py
index ffa852403f..694d42f4d6 100644
--- a/system/hardware/tici/hardware.py
+++ b/system/hardware/tici/hardware.py
@@ -335,6 +335,7 @@ class Tici(HardwareBase):
return ThermalConfig(cpu=[ThermalZone(f"cpu{i}-silver-usr") for i in range(4)] +
[ThermalZone(f"cpu{i}-gold-usr") for i in range(4)],
gpu=[ThermalZone("gpu0-usr"), ThermalZone("gpu1-usr")],
+ dsp=ThermalZone("compute-hvx-usr"),
memory=ThermalZone("ddr-usr"),
pmic=[ThermalZone("pm8998_tz"), ThermalZone("pm8005_tz")],
intake=intake,
diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py
index 669889a2ae..fd65ecd5cd 100644
--- a/system/hardware/tici/tests/test_power_draw.py
+++ b/system/hardware/tici/tests/test_power_draw.py
@@ -56,10 +56,10 @@ class TestPowerDraw:
def valid_msg_count(self, proc, msg_counts):
msgs_received = sum(msg_counts[msg] for msg in proc.msgs)
msgs_expected = self.get_expected_messages(proc)
- return np.core.numeric.isclose(msgs_expected, msgs_received, rtol=.02, atol=2)
+ return np.isclose(msgs_expected, msgs_received, rtol=.02, atol=2)
def valid_power_draw(self, proc, used):
- return np.core.numeric.isclose(used, proc.power, rtol=proc.rtol, atol=proc.atol)
+ return np.isclose(used, proc.power, rtol=proc.rtol, atol=proc.atol)
def tabulate_msg_counts(self, msgs_and_power):
msg_counts = defaultdict(int)
diff --git a/system/loggerd/loggerd.cc b/system/loggerd/loggerd.cc
index 953ae1df32..2d2d4640ed 100644
--- a/system/loggerd/loggerd.cc
+++ b/system/loggerd/loggerd.cc
@@ -203,7 +203,7 @@ void handle_user_flag(LoggerdState *s) {
// mark route for uploading
Params params;
- std::string routes = Params().get("AthenadRecentlyViewedRoutes");
+ std::string routes = params.get("AthenadRecentlyViewedRoutes");
params.put("AthenadRecentlyViewedRoutes", routes + "," + s->logger.routeName());
prev_segment = s->logger.segment();
diff --git a/system/loggerd/uploader.py b/system/loggerd/uploader.py
index c1bf804880..6e6df6114e 100755
--- a/system/loggerd/uploader.py
+++ b/system/loggerd/uploader.py
@@ -89,7 +89,7 @@ class Uploader:
def list_upload_files(self, metered: bool) -> Iterator[tuple[str, str, str]]:
r = self.params.get("AthenadRecentlyViewedRoutes", encoding="utf8")
- requested_routes = [] if r is None else r.split(",")
+ requested_routes = [] if r is None else [route for route in r.split(",") if route]
for logdir in listdir_by_creation(self.root):
path = os.path.join(self.root, logdir)
diff --git a/system/loggerd/xattr_cache.py b/system/loggerd/xattr_cache.py
index d3220118ac..39bb172059 100644
--- a/system/loggerd/xattr_cache.py
+++ b/system/loggerd/xattr_cache.py
@@ -1,16 +1,17 @@
-import os
import errno
+import xattr
+
_cached_attributes: dict[tuple, bytes | None] = {}
def getxattr(path: str, attr_name: str) -> bytes | None:
key = (path, attr_name)
if key not in _cached_attributes:
try:
- response = os.getxattr(path, attr_name)
+ response = xattr.getxattr(path, attr_name)
except OSError as e:
- # ENODATA means attribute hasn't been set
- if e.errno == errno.ENODATA:
+ # ENODATA (Linux) or ENOATTR (macOS) means attribute hasn't been set
+ if e.errno == errno.ENODATA or (hasattr(errno, 'ENOATTR') and e.errno == errno.ENOATTR):
response = None
else:
raise
@@ -19,4 +20,4 @@ def getxattr(path: str, attr_name: str) -> bytes | None:
def setxattr(path: str, attr_name: str, attr_value: bytes) -> None:
_cached_attributes.pop((path, attr_name), None)
- return os.setxattr(path, attr_name, attr_value)
+ xattr.setxattr(path, attr_name, attr_value)
diff --git a/system/micd.py b/system/micd.py
index af1aa31360..38f3225f55 100755
--- a/system/micd.py
+++ b/system/micd.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import numpy as np
from functools import cache
+import threading
from cereal import messaging
from openpilot.common.realtime import Ratekeeper
@@ -52,12 +53,18 @@ class Mic:
self.sound_pressure_weighted = 0
self.sound_pressure_level_weighted = 0
+ self.lock = threading.Lock()
+
def update(self):
- msg = messaging.new_message('microphone', valid=True)
- msg.microphone.soundPressure = float(self.sound_pressure)
- msg.microphone.soundPressureWeighted = float(self.sound_pressure_weighted)
+ with self.lock:
+ sound_pressure = self.sound_pressure
+ sound_pressure_weighted = self.sound_pressure_weighted
+ sound_pressure_level_weighted = self.sound_pressure_level_weighted
- msg.microphone.soundPressureWeightedDb = float(self.sound_pressure_level_weighted)
+ msg = messaging.new_message('microphone', valid=True)
+ msg.microphone.soundPressure = float(sound_pressure)
+ msg.microphone.soundPressureWeighted = float(sound_pressure_weighted)
+ msg.microphone.soundPressureWeightedDb = float(sound_pressure_level_weighted)
self.pm.send('microphone', msg)
self.rk.keep_time()
@@ -69,17 +76,17 @@ class Mic:
Logged A-weighted equivalents are rough approximations of the human-perceived loudness.
"""
+ with self.lock:
+ self.measurements = np.concatenate((self.measurements, indata[:, 0]))
- self.measurements = np.concatenate((self.measurements, indata[:, 0]))
-
- while self.measurements.size >= FFT_SAMPLES:
- measurements = self.measurements[:FFT_SAMPLES]
+ while self.measurements.size >= FFT_SAMPLES:
+ measurements = self.measurements[:FFT_SAMPLES]
- self.sound_pressure, _ = calculate_spl(measurements)
- measurements_weighted = apply_a_weighting(measurements)
- self.sound_pressure_weighted, self.sound_pressure_level_weighted = calculate_spl(measurements_weighted)
+ self.sound_pressure, _ = calculate_spl(measurements)
+ measurements_weighted = apply_a_weighting(measurements)
+ self.sound_pressure_weighted, self.sound_pressure_level_weighted = calculate_spl(measurements_weighted)
- self.measurements = self.measurements[FFT_SAMPLES:]
+ self.measurements = self.measurements[FFT_SAMPLES:]
@retry(attempts=7, delay=3)
def get_stream(self, sd):
diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py
index a3e209c394..eae5962277 100644
--- a/system/ui/lib/application.py
+++ b/system/ui/lib/application.py
@@ -7,7 +7,7 @@ from openpilot.common.basedir import BASEDIR
from openpilot.common.swaglog import cloudlog
from openpilot.system.hardware import HARDWARE
-DEFAULT_FPS = 30
+DEFAULT_FPS = 60
FPS_LOG_INTERVAL = 5 # Seconds between logging FPS drops
FPS_DROP_THRESHOLD = 0.9 # FPS drop threshold for triggering a warning
FPS_CRITICAL_THRESHOLD = 0.5 # Critical threshold for triggering strict actions
diff --git a/system/ui/lib/scroll_panel.py b/system/ui/lib/scroll_panel.py
index 0dc757ff6f..7dc2fdb917 100644
--- a/system/ui/lib/scroll_panel.py
+++ b/system/ui/lib/scroll_panel.py
@@ -4,6 +4,7 @@ from enum import IntEnum
MOUSE_WHEEL_SCROLL_SPEED = 30
INERTIA_FRICTION = 0.95 # The rate at which the inertia slows down
MIN_VELOCITY = 0.1 # Minimum velocity before stopping the inertia
+DRAG_THRESHOLD = 5 # Pixels of movement to consider it a drag, not a click
class ScrollState(IntEnum):
@@ -16,10 +17,12 @@ class GuiScrollPanel:
def __init__(self, show_vertical_scroll_bar: bool = False):
self._scroll_state: ScrollState = ScrollState.IDLE
self._last_mouse_y: float = 0.0
+ self._start_mouse_y: float = 0.0 # Track the initial mouse position for drag detection
self._offset = rl.Vector2(0, 0)
self._view = rl.Rectangle(0, 0, 0, 0)
self._show_vertical_scroll_bar: bool = show_vertical_scroll_bar
self._velocity_y = 0.0 # Velocity for inertia
+ self._is_dragging = False
def handle_scroll(self, bounds: rl.Rectangle, content: rl.Rectangle) -> rl.Vector2:
mouse_pos = rl.get_mouse_position()
@@ -35,20 +38,27 @@ class GuiScrollPanel:
self._scroll_state = ScrollState.DRAGGING_SCROLLBAR
self._last_mouse_y = mouse_pos.y
+ self._start_mouse_y = mouse_pos.y # Record starting position
self._velocity_y = 0.0 # Reset velocity when drag starts
+ self._is_dragging = False # Reset dragging flag
if self._scroll_state != ScrollState.IDLE:
if rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT):
delta_y = mouse_pos.y - self._last_mouse_y
+ # Check if movement exceeds the drag threshold
+ total_drag = abs(mouse_pos.y - self._start_mouse_y)
+ if total_drag > DRAG_THRESHOLD:
+ self._is_dragging = True
+
if self._scroll_state == ScrollState.DRAGGING_CONTENT:
self._offset.y += delta_y
- else:
+ elif self._scroll_state == ScrollState.DRAGGING_SCROLLBAR:
delta_y = -delta_y
self._last_mouse_y = mouse_pos.y
self._velocity_y = delta_y # Update velocity during drag
- else:
+ elif rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT):
self._scroll_state = ScrollState.IDLE
# Handle mouse wheel scrolling
@@ -73,3 +83,6 @@ class GuiScrollPanel:
self._offset.y = max(min(self._offset.y, 0), -max_scroll_y)
return self._offset
+
+ def is_click_valid(self) -> bool:
+ return self._scroll_state == ScrollState.IDLE and not self._is_dragging and rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT)
diff --git a/system/ui/lib/toggle.py b/system/ui/lib/toggle.py
new file mode 100644
index 0000000000..e72faef11c
--- /dev/null
+++ b/system/ui/lib/toggle.py
@@ -0,0 +1,53 @@
+import pyray as rl
+
+ON_COLOR = rl.GREEN
+OFF_COLOR = rl.Color(0x39, 0x39, 0x39, 255)
+KNOB_COLOR = rl.WHITE
+BG_HEIGHT = 60
+KNOB_HEIGHT = 80
+WIDTH = 160
+
+
+class Toggle:
+ def __init__(self, x, y, initial_state=False):
+ self._state = initial_state
+ self._rect = rl.Rectangle(x, y, WIDTH, KNOB_HEIGHT)
+
+ def handle_input(self):
+ if rl.is_mouse_button_pressed(rl.MOUSE_LEFT_BUTTON):
+ mouse_pos = rl.get_mouse_position()
+ if rl.check_collision_point_rec(mouse_pos, self._rect):
+ self._state = not self._state
+
+ def get_state(self):
+ return self._state
+
+ def render(self):
+ self._draw_background()
+ self._draw_knob()
+
+ def _draw_background(self):
+ bg_rect = rl.Rectangle(
+ self._rect.x + 5,
+ self._rect.y + (KNOB_HEIGHT - BG_HEIGHT) / 2,
+ self._rect.width - 10,
+ BG_HEIGHT,
+ )
+ rl.draw_rectangle_rounded(bg_rect, 1.0, 10, ON_COLOR if self._state else OFF_COLOR)
+
+ def _draw_knob(self):
+ knob_radius = KNOB_HEIGHT / 2
+ knob_x = self._rect.x + knob_radius if not self._state else self._rect.x + self._rect.width - knob_radius
+ knob_y = self._rect.y + knob_radius
+ rl.draw_circle(int(knob_x), int(knob_y), knob_radius, KNOB_COLOR)
+
+
+if __name__ == "__main__":
+ from openpilot.system.ui.lib.application import gui_app
+
+ gui_app.init_window("Text toggle example")
+ toggle = Toggle(100, 100)
+ for _ in gui_app.render():
+ toggle.handle_input()
+ toggle.render()
+
diff --git a/system/ui/lib/wifi_manager.py b/system/ui/lib/wifi_manager.py
new file mode 100644
index 0000000000..29d3231d5f
--- /dev/null
+++ b/system/ui/lib/wifi_manager.py
@@ -0,0 +1,694 @@
+import asyncio
+import concurrent.futures
+import threading
+import time
+import uuid
+from collections.abc import Callable
+from dataclasses import dataclass
+from enum import IntEnum
+from typing import TypeVar
+
+from dbus_next.aio import MessageBus
+from dbus_next import BusType, Variant, Message
+from dbus_next.errors import DBusError
+from dbus_next.constants import MessageType
+from openpilot.common.params import Params
+from openpilot.common.swaglog import cloudlog
+
+T = TypeVar("T")
+
+# NetworkManager constants
+NM = "org.freedesktop.NetworkManager"
+NM_PATH = '/org/freedesktop/NetworkManager'
+NM_IFACE = 'org.freedesktop.NetworkManager'
+NM_SETTINGS_PATH = '/org/freedesktop/NetworkManager/Settings'
+NM_SETTINGS_IFACE = 'org.freedesktop.NetworkManager.Settings'
+NM_CONNECTION_IFACE = 'org.freedesktop.NetworkManager.Settings.Connection'
+NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
+NM_PROPERTIES_IFACE = 'org.freedesktop.DBus.Properties'
+NM_DEVICE_IFACE = "org.freedesktop.NetworkManager.Device"
+
+NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT = 8
+
+TETHERING_IP_ADDRESS = "192.168.43.1"
+DEFAULT_TETHERING_PASSWORD = "12345678"
+
+# NetworkManager device states
+class NMDeviceState(IntEnum):
+ DISCONNECTED = 30
+ PREPARE = 40
+ NEED_AUTH = 60
+ IP_CONFIG = 70
+ ACTIVATED = 100
+
+class SecurityType(IntEnum):
+ OPEN = 0
+ WPA = 1
+ WPA2 = 2
+ WPA3 = 3
+ UNSUPPORTED = 4
+
+@dataclass
+class NetworkInfo:
+ ssid: str
+ strength: int
+ is_connected: bool
+ security_type: SecurityType
+ path: str
+ bssid: str
+ # saved_path: str
+
+
+@dataclass
+class WifiManagerCallbacks:
+ need_auth: Callable[[str], None] | None = None
+ activated: Callable[[], None] | None = None
+ forgotten: Callable[[], None] | None = None
+
+
+class WifiManager:
+ def __init__(self, callbacks):
+ self.callbacks: WifiManagerCallbacks = callbacks
+ self.networks: list[NetworkInfo] = []
+ self.bus: MessageBus = None
+ self.device_path: str = ""
+ self.device_proxy = None
+ self.saved_connections: dict[str, str] = {}
+ self.active_ap_path: str = ""
+ self.scan_task: asyncio.Task | None = None
+ self._tethering_ssid = "weedle-" + Params().get("DongleId", encoding="utf-8")
+ self.running: bool = True
+ self._current_connection_ssid: str | None = None
+
+ async def connect(self) -> None:
+ """Connect to the DBus system bus."""
+ try:
+ self.bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
+ if not await self._find_wifi_device():
+ raise ValueError("No Wi-Fi device found")
+ await self._setup_signals(self.device_path)
+
+ self.active_ap_path = await self.get_active_access_point()
+ await self.add_tethering_connection(self._tethering_ssid, DEFAULT_TETHERING_PASSWORD)
+ self.saved_connections = await self._get_saved_connections()
+ self.scan_task = asyncio.create_task(self._periodic_scan())
+ except DBusError as e:
+ cloudlog.error(f"Failed to connect to DBus: {e}")
+ raise
+ except Exception as e:
+ cloudlog.error(f"Unexpected error during connect: {e}")
+ raise
+
+ async def shutdown(self) -> None:
+ self.running = False
+ if self.scan_task:
+ self.scan_task.cancel()
+ try:
+ await self.scan_task
+ except asyncio.CancelledError:
+ pass
+ if self.bus:
+ await self.bus.disconnect()
+
+ async def request_scan(self) -> None:
+ try:
+ interface = self.device_proxy.get_interface(NM_WIRELESS_IFACE)
+ await interface.call_request_scan({})
+ except DBusError as e:
+ cloudlog.warning(f"Scan request failed: {str(e)}")
+
+ async def get_active_access_point(self):
+ try:
+ props_iface = self.device_proxy.get_interface(NM_PROPERTIES_IFACE)
+ ap_path = await props_iface.call_get(NM_WIRELESS_IFACE, 'ActiveAccessPoint')
+ return ap_path.value
+ except DBusError as e:
+ cloudlog.error(f"Error fetching active access point: {str(e)}")
+ return ''
+
+ async def forget_connection(self, ssid: str) -> bool:
+ path = self.saved_connections.get(ssid)
+ if not path:
+ return False
+
+ try:
+ nm_iface = await self._get_interface(NM, path, NM_CONNECTION_IFACE)
+ await nm_iface.call_delete()
+ if self._current_connection_ssid == ssid:
+ self._current_connection_ssid = None
+
+ if ssid in self.saved_connections:
+ del self.saved_connections[ssid]
+
+ return True
+ except DBusError as e:
+ cloudlog.error(f"Failed to delete connection for SSID: {ssid}. Error: {e}")
+ return False
+
+ async def activate_connection(self, ssid: str) -> bool:
+ connection_path = self.saved_connections.get(ssid)
+ if not connection_path:
+ return False
+ try:
+ nm_iface = await self._get_interface(NM, NM_PATH, NM_IFACE)
+ await nm_iface.call_activate_connection(connection_path, self.device_path, "/")
+ return True
+ except DBusError as e:
+ cloudlog.error(f"Failed to activate connection {ssid}: {str(e)}")
+ return False
+
+ async def connect_to_network(self, ssid: str, password: str = None, bssid: str = None, is_hidden: bool = False) -> None:
+ """Connect to a selected Wi-Fi network."""
+ try:
+ self._current_connection_ssid = ssid
+
+ if ssid in self.saved_connections:
+ # Forget old connection if new password provided
+ if password:
+ await self.forget_connection(ssid)
+ await asyncio.sleep(0.2) # NetworkManager delay
+ else:
+ # Just activate existing connection
+ await self.activate_connection(ssid)
+ return
+
+ connection = {
+ 'connection': {
+ 'type': Variant('s', '802-11-wireless'),
+ 'uuid': Variant('s', str(uuid.uuid4())),
+ 'id': Variant('s', ssid),
+ 'autoconnect-retries': Variant('i', 0),
+ },
+ '802-11-wireless': {
+ 'ssid': Variant('ay', ssid.encode('utf-8')),
+ 'hidden': Variant('b', is_hidden),
+ 'mode': Variant('s', 'infrastructure'),
+ },
+ 'ipv4': {'method': Variant('s', 'auto')},
+ 'ipv6': {'method': Variant('s', 'ignore')},
+ }
+
+ if bssid:
+ connection['802-11-wireless']['bssid'] = Variant('ay', bssid.encode('utf-8'))
+
+ if password:
+ connection['802-11-wireless-security'] = {
+ 'key-mgmt': Variant('s', 'wpa-psk'),
+ 'auth-alg': Variant('s', 'open'),
+ 'psk': Variant('s', password),
+ }
+
+ nm_iface = await self._get_interface(NM, NM_PATH, NM_IFACE)
+ await nm_iface.call_add_and_activate_connection(connection, self.device_path, "/")
+ await self._update_connection_status()
+ except DBusError as e:
+ self._current_connection_ssid = None
+ cloudlog.error(f"Error connecting to network: {e}")
+
+ def is_saved(self, ssid: str) -> bool:
+ return ssid in self.saved_connections
+
+ async def _find_wifi_device(self) -> bool:
+ nm_iface = await self._get_interface(NM, NM_PATH, NM_IFACE)
+ devices = await nm_iface.get_devices()
+
+ for device_path in devices:
+ device = await self.bus.introspect(NM, device_path)
+ device_proxy = self.bus.get_proxy_object(NM, device_path, device)
+ device_interface = device_proxy.get_interface(NM_DEVICE_IFACE)
+ device_type = await device_interface.get_device_type() # type: ignore[attr-defined]
+ if device_type == 2: # Wi-Fi device
+ self.device_path = device_path
+ self.device_proxy = device_proxy
+ return True
+
+ return False
+
+ async def add_tethering_connection(self, ssid: str, password: str = "12345678") -> bool:
+ """Create a WiFi tethering connection."""
+ if len(password) < 8:
+ print("Tethering password must be at least 8 characters")
+ return False
+
+ try:
+ # First, check if a hotspot connection already exists
+ settings_iface = await self._get_interface(NM, NM_SETTINGS_PATH, NM_SETTINGS_IFACE)
+ connection_paths = await settings_iface.call_list_connections()
+
+ # Look for an existing hotspot connection
+ for path in connection_paths:
+ try:
+ settings = await self._get_connection_settings(path)
+ conn_type = settings.get('connection', {}).get('type', Variant('s', '')).value
+ wifi_mode = settings.get('802-11-wireless', {}).get('mode', Variant('s', '')).value
+
+ if conn_type == '802-11-wireless' and wifi_mode == 'ap':
+ # Extract the SSID to check
+ connection_ssid = self._extract_ssid(settings)
+ if connection_ssid == ssid:
+ return True
+ except DBusError:
+ continue
+
+ connection = {
+ 'connection': {
+ 'id': Variant('s', 'Hotspot'),
+ 'uuid': Variant('s', str(uuid.uuid4())),
+ 'type': Variant('s', '802-11-wireless'),
+ 'interface-name': Variant('s', 'wlan0'),
+ 'autoconnect': Variant('b', False),
+ },
+ '802-11-wireless': {
+ 'band': Variant('s', 'bg'),
+ 'mode': Variant('s', 'ap'),
+ 'ssid': Variant('ay', ssid.encode('utf-8')),
+ },
+ '802-11-wireless-security': {
+ 'group': Variant('as', ['ccmp']),
+ 'key-mgmt': Variant('s', 'wpa-psk'),
+ 'pairwise': Variant('as', ['ccmp']),
+ 'proto': Variant('as', ['rsn']),
+ 'psk': Variant('s', password),
+ },
+ 'ipv4': {
+ 'method': Variant('s', 'shared'),
+ 'address-data': Variant('aa{sv}', [{'address': Variant('s', TETHERING_IP_ADDRESS), 'prefix': Variant('u', 24)}]),
+ 'gateway': Variant('s', TETHERING_IP_ADDRESS),
+ 'never-default': Variant('b', True),
+ },
+ 'ipv6': {
+ 'method': Variant('s', 'ignore'),
+ },
+ }
+
+ settings_iface = await self._get_interface(NM, NM_SETTINGS_PATH, NM_SETTINGS_IFACE)
+ new_connection = await settings_iface.call_add_connection(connection)
+ print(f"Added tethering connection with path: {new_connection}")
+ return True
+ except DBusError as e:
+ print(f"Failed to add tethering connection: {e}")
+ return False
+ except Exception as e:
+ print(f"Unexpected error adding tethering connection: {e}")
+ return False
+
+ async def get_tethering_password(self) -> str:
+ """Get the current tethering password."""
+ try:
+ hotspot_path = self.saved_connections.get(self._tethering_ssid)
+ if hotspot_path:
+ conn_iface = await self._get_interface(NM, hotspot_path, NM_CONNECTION_IFACE)
+ secrets = await conn_iface.call_get_secrets('802-11-wireless-security')
+ if secrets and '802-11-wireless-security' in secrets:
+ psk = secrets.get('802-11-wireless-security', {}).get('psk', Variant('s', '')).value
+ return str(psk) if psk is not None else ""
+ return ""
+ except DBusError as e:
+ print(f"Failed to get tethering password: {e}")
+ return ""
+ except Exception as e:
+ print(f"Unexpected error getting tethering password: {e}")
+ return ""
+
+ async def set_tethering_password(self, password: str) -> bool:
+ """Set the tethering password."""
+ if len(password) < 8:
+ cloudlog.error("Tethering password must be at least 8 characters")
+ return False
+
+ try:
+ hotspot_path = self.saved_connections.get(self._tethering_ssid)
+ if not hotspot_path:
+ print("No hotspot connection found")
+ return False
+
+ # Update the connection settings with new password
+ settings = await self._get_connection_settings(hotspot_path)
+ if '802-11-wireless-security' not in settings:
+ settings['802-11-wireless-security'] = {}
+ settings['802-11-wireless-security']['psk'] = Variant('s', password)
+
+ # Apply changes
+ conn_iface = await self._get_interface(NM, hotspot_path, NM_CONNECTION_IFACE)
+ await conn_iface.call_update(settings)
+
+ # Check if connection is active and restart if needed
+ is_active = False
+ nm_iface = await self._get_interface(NM, NM_PATH, NM_IFACE)
+ active_connections = await nm_iface.get_active_connections()
+
+ for conn_path in active_connections:
+ props_iface = await self._get_interface(NM, conn_path, NM_PROPERTIES_IFACE)
+ conn_id_path = await props_iface.call_get('org.freedesktop.NetworkManager.Connection.Active', 'Connection')
+ if conn_id_path.value == hotspot_path:
+ is_active = True
+ await nm_iface.call_deactivate_connection(conn_path)
+ break
+
+ if is_active:
+ await nm_iface.call_activate_connection(hotspot_path, self.device_path, "/")
+
+ print("Tethering password updated successfully")
+ return True
+ except DBusError as e:
+ print(f"Failed to set tethering password: {e}")
+ return False
+ except Exception as e:
+ print(f"Unexpected error setting tethering password: {e}")
+ return False
+
+ async def is_tethering_active(self) -> bool:
+ """Check if tethering is active for the specified SSID."""
+ try:
+ hotspot_path = self.saved_connections.get(self._tethering_ssid)
+ if not hotspot_path:
+ return False
+
+ nm_iface = await self._get_interface(NM, NM_PATH, NM_IFACE)
+ active_connections = await nm_iface.get_active_connections()
+
+ for conn_path in active_connections:
+ props_iface = await self._get_interface(NM, conn_path, NM_PROPERTIES_IFACE)
+ conn_id_path = await props_iface.call_get('org.freedesktop.NetworkManager.Connection.Active', 'Connection')
+
+ if conn_id_path.value == hotspot_path:
+ return True
+
+ return False
+ except Exception:
+ return False
+
+ async def _periodic_scan(self):
+ while self.running:
+ try:
+ await self.request_scan()
+ await self._get_available_networks()
+ await asyncio.sleep(30)
+ except asyncio.CancelledError:
+ break
+ except DBusError as e:
+ cloudlog.error(f"Scan failed: {e}")
+ await asyncio.sleep(5)
+
+ async def _setup_signals(self, device_path: str) -> None:
+ rules = [
+ f"type='signal',interface='{NM_PROPERTIES_IFACE}',member='PropertiesChanged',path='{device_path}'",
+ f"type='signal',interface='{NM_DEVICE_IFACE}',member='StateChanged',path='{device_path}'",
+ f"type='signal',interface='{NM_SETTINGS_IFACE}',member='NewConnection',path='{NM_SETTINGS_PATH}'",
+ f"type='signal',interface='{NM_SETTINGS_IFACE}',member='ConnectionRemoved',path='{NM_SETTINGS_PATH}'",
+ ]
+ for rule in rules:
+ await self._add_match_rule(rule)
+
+ # Set up signal handlers
+ self.device_proxy.get_interface(NM_PROPERTIES_IFACE).on_properties_changed(self._on_properties_changed)
+ self.device_proxy.get_interface(NM_DEVICE_IFACE).on_state_changed(self._on_state_changed)
+
+ settings_iface = await self._get_interface(NM, NM_SETTINGS_PATH, NM_SETTINGS_IFACE)
+ settings_iface.on_new_connection(self._on_new_connection)
+ settings_iface.on_connection_removed(self._on_connection_removed)
+
+ def _on_properties_changed(self, interface: str, changed: dict, invalidated: list):
+ # print("property changed", interface, changed, invalidated)
+ if 'LastScan' in changed:
+ asyncio.create_task(self._get_available_networks())
+ elif interface == NM_WIRELESS_IFACE and "ActiveAccessPoint" in changed:
+ self.active_ap_path = changed["ActiveAccessPoint"].value
+ asyncio.create_task(self._get_available_networks())
+
+ def _on_state_changed(self, new_state: int, old_state: int, reason: int):
+ print(f"State changed: {old_state} -> {new_state}, reason: {reason}")
+ if new_state == NMDeviceState.ACTIVATED:
+ if self.callbacks.activated:
+ self.callbacks.activated()
+ asyncio.create_task(self._update_connection_status())
+ self._current_connection_ssid = None
+ elif new_state in (NMDeviceState.DISCONNECTED, NMDeviceState.NEED_AUTH):
+ for network in self.networks:
+ network.is_connected = False
+ if new_state == NMDeviceState.NEED_AUTH and reason == NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT and self.callbacks.need_auth:
+ if self._current_connection_ssid:
+ self.callbacks.need_auth(self._current_connection_ssid)
+ else:
+ # Try to find the network from active_ap_path
+ for network in self.networks:
+ if network.path == self.active_ap_path:
+ self.callbacks.need_auth(network.ssid)
+ break
+ else:
+ # Couldn't identify the network that needs auth
+ cloudlog.error("Network needs authentication but couldn't identify which one")
+
+ def _on_new_connection(self, path: str) -> None:
+ """Callback for NewConnection signal."""
+ print(f"New connection added: {path}")
+ asyncio.create_task(self._add_saved_connection(path))
+
+ def _on_connection_removed(self, path: str) -> None:
+ """Callback for ConnectionRemoved signal."""
+ print(f"Connection removed: {path}")
+ for ssid, p in list(self.saved_connections.items()):
+ if path == p:
+ del self.saved_connections[ssid]
+ if self.callbacks.forgotten:
+ self.callbacks.forgotten()
+ break
+
+ async def _add_saved_connection(self, path: str) -> None:
+ """Add a new saved connection to the dictionary."""
+ try:
+ settings = await self._get_connection_settings(path)
+ if ssid := self._extract_ssid(settings):
+ self.saved_connections[ssid] = path
+ except DBusError as e:
+ cloudlog.error(f"Failed to add connection {path}: {e}")
+
+ def _extract_ssid(self, settings: dict) -> str | None:
+ """Extract SSID from connection settings."""
+ ssid_variant = settings.get('802-11-wireless', {}).get('ssid', Variant('ay', b'')).value
+ return ''.join(chr(b) for b in ssid_variant) if ssid_variant else None
+
+ async def _update_connection_status(self):
+ self.active_ap_path = await self.get_active_access_point()
+ await self._get_available_networks()
+
+ async def _add_match_rule(self, rule):
+ """Add a match rule on the bus."""
+ reply = await self.bus.call(
+ Message(
+ message_type=MessageType.METHOD_CALL,
+ destination='org.freedesktop.DBus',
+ interface="org.freedesktop.DBus",
+ path='/org/freedesktop/DBus',
+ member='AddMatch',
+ signature='s',
+ body=[rule],
+ )
+ )
+
+ assert reply.message_type == MessageType.METHOD_RETURN
+ return reply
+
+ async def _get_available_networks(self):
+ """Get a list of available networks via NetworkManager."""
+ wifi_iface = self.device_proxy.get_interface(NM_WIRELESS_IFACE)
+ access_points = await wifi_iface.get_access_points()
+ network_dict = {}
+ for ap_path in access_points:
+ try:
+ props_iface = await self._get_interface(NM, ap_path, NM_PROPERTIES_IFACE)
+ properties = await props_iface.call_get_all('org.freedesktop.NetworkManager.AccessPoint')
+ ssid_variant = properties['Ssid'].value
+ ssid = ''.join(chr(byte) for byte in ssid_variant)
+ if not ssid:
+ continue
+
+ bssid = properties.get('HwAddress', Variant('s', '')).value
+ strength = properties['Strength'].value
+ flags = properties['Flags'].value
+ wpa_flags = properties['WpaFlags'].value
+ rsn_flags = properties['RsnFlags'].value
+ existing_network = network_dict.get(ssid)
+ if not existing_network or ((not existing_network.bssid and bssid) or (existing_network.strength < strength)):
+ network_dict[ssid] = NetworkInfo(
+ ssid=ssid,
+ strength=strength,
+ security_type=self._get_security_type(flags, wpa_flags, rsn_flags),
+ path=ap_path,
+ bssid=bssid,
+ is_connected=self.active_ap_path == ap_path,
+ )
+
+ except DBusError as e:
+ cloudlog.error(f"Error fetching networks: {e}")
+ except Exception as e:
+ cloudlog.error({e})
+
+ self.networks = sorted(
+ network_dict.values(),
+ key=lambda network: (
+ not network.is_connected,
+ -network.strength, # Higher signal strength first
+ network.ssid.lower(),
+ ),
+ )
+
+ async def _get_connection_settings(self, path):
+ """Fetch connection settings for a specific connection path."""
+ try:
+ connection_proxy = await self.bus.introspect(NM, path)
+ connection = self.bus.get_proxy_object(NM, path, connection_proxy)
+ settings = connection.get_interface(NM_CONNECTION_IFACE)
+ return await settings.call_get_settings()
+ except DBusError as e:
+ cloudlog.error(f"Failed to get settings for {path}: {str(e)}")
+ return {}
+
+ async def _process_chunk(self, paths_chunk):
+ """Process a chunk of connection paths."""
+ tasks = [self._get_connection_settings(path) for path in paths_chunk]
+ return await asyncio.gather(*tasks, return_exceptions=True)
+
+ async def _get_saved_connections(self) -> dict[str, str]:
+ try:
+ settings_iface = await self._get_interface(NM, NM_SETTINGS_PATH, NM_SETTINGS_IFACE)
+ connection_paths = await settings_iface.call_list_connections()
+ saved_ssids: dict[str, str] = {}
+ batch_size = 20
+ for i in range(0, len(connection_paths), batch_size):
+ chunk = connection_paths[i : i + batch_size]
+ results = await self._process_chunk(chunk)
+ for path, config in zip(chunk, results, strict=True):
+ if isinstance(config, dict) and '802-11-wireless' in config:
+ if ssid := self._extract_ssid(config):
+ saved_ssids[ssid] = path
+ return saved_ssids
+ except DBusError as e:
+ cloudlog.error(f"Error fetching saved connections: {str(e)}")
+ return {}
+
+ async def _get_interface(self, bus_name: str, path: str, name: str):
+ introspection = await self.bus.introspect(bus_name, path)
+ proxy = self.bus.get_proxy_object(bus_name, path, introspection)
+ return proxy.get_interface(name)
+
+ def _get_security_type(self, flags: int, wpa_flags: int, rsn_flags: int) -> SecurityType:
+ """Determine the security type based on flags."""
+ if flags == 0 and not (wpa_flags or rsn_flags):
+ return SecurityType.OPEN
+ if rsn_flags & 0x200: # SAE (WPA3 Personal)
+ return SecurityType.WPA3
+ if rsn_flags: # RSN indicates WPA2 or higher
+ return SecurityType.WPA2
+ if wpa_flags: # WPA flags indicate WPA
+ return SecurityType.WPA
+ return SecurityType.UNSUPPORTED
+
+
+class WifiManagerWrapper:
+ def __init__(self):
+ self._manager: WifiManager | None = None
+ self._callbacks: WifiManagerCallbacks = WifiManagerCallbacks()
+
+ self._thread = threading.Thread(target=self._run, daemon=True)
+ self._loop: asyncio.EventLoop | None = None
+ self._running = False
+
+ def set_callbacks(self, callbacks: WifiManagerCallbacks):
+ self._callbacks = callbacks
+
+ def start(self) -> None:
+ if not self._running:
+ self._thread.start()
+ while self._thread is not None and not self._running:
+ time.sleep(0.1)
+
+ def _run(self):
+ self._loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(self._loop)
+
+ try:
+ self._manager = WifiManager(self._callbacks)
+ self._running = True
+ self._loop.run_forever()
+ except Exception as e:
+ cloudlog.error(f"Error in WifiManagerWrapper thread: {e}")
+ finally:
+ if self._loop.is_running():
+ self._loop.stop()
+ self._running = False
+
+ def shutdown(self) -> None:
+ if self._running:
+ if self._manager is not None:
+ self._run_coroutine(self._manager.shutdown())
+ if self._loop and self._loop.is_running():
+ self._loop.call_soon_threadsafe(self._loop.stop)
+ if self._thread and self._thread.is_alive():
+ self._thread.join(timeout=2.0)
+ self._running = False
+
+ @property
+ def networks(self) -> list[NetworkInfo]:
+ """Get the current list of networks."""
+ return self._run_coroutine_sync(lambda manager: manager.networks.copy(), default=[])
+
+ def is_saved(self, ssid: str) -> bool:
+ """Check if a network is saved."""
+ return self._run_coroutine_sync(lambda manager: manager.is_saved(ssid), default=False)
+
+ def connect(self):
+ """Connect to DBus and start Wi-Fi scanning."""
+ if not self._manager:
+ return
+ self._run_coroutine(self._manager.connect())
+
+ def request_scan(self):
+ """Request a scan for Wi-Fi networks."""
+ if not self._manager:
+ return
+ self._run_coroutine(self._manager.request_scan())
+
+ def forget_connection(self, ssid: str):
+ """Forget a saved Wi-Fi connection."""
+ if not self._manager:
+ return
+ self._run_coroutine(self._manager.forget_connection(ssid))
+
+ def activate_connection(self, ssid: str):
+ """Activate an existing Wi-Fi connection."""
+ if not self._manager:
+ return
+ self._run_coroutine(self._manager.activate_connection(ssid))
+
+ def connect_to_network(self, ssid: str, password: str = None, bssid: str = None, is_hidden: bool = False):
+ """Connect to a Wi-Fi network."""
+ if not self._manager:
+ return
+ self._run_coroutine(self._manager.connect_to_network(ssid, password, bssid, is_hidden))
+
+ def _run_coroutine(self, coro):
+ """Run a coroutine in the async thread."""
+ if not self._running or not self._loop:
+ cloudlog.error("WifiManager thread is not running")
+ return
+ asyncio.run_coroutine_threadsafe(coro, self._loop)
+
+ def _run_coroutine_sync(self, func: Callable[[WifiManager], T], default: T) -> T:
+ """Run a function synchronously in the async thread."""
+ if not self._running or not self._loop or not self._manager:
+ return default
+ future = concurrent.futures.Future[T]()
+
+ def wrapper(manager: WifiManager) -> None:
+ try:
+ future.set_result(func(manager))
+ except Exception as e:
+ future.set_exception(e)
+
+ try:
+ self._loop.call_soon_threadsafe(wrapper, self._manager)
+ return future.result(timeout=1.0)
+ except Exception as e:
+ cloudlog.error(f"WifiManagerWrapper property access failed: {e}")
+ return default
diff --git a/system/ui/lib/window.py b/system/ui/lib/window.py
new file mode 100644
index 0000000000..989a3b0284
--- /dev/null
+++ b/system/ui/lib/window.py
@@ -0,0 +1,58 @@
+import threading
+import time
+import os
+from typing import Generic, Protocol, TypeVar
+from openpilot.common.swaglog import cloudlog
+from openpilot.system.ui.lib.application import gui_app
+
+
+class RendererProtocol(Protocol):
+ def render(self): ...
+
+
+R = TypeVar("R", bound=RendererProtocol)
+
+
+class BaseWindow(Generic[R]):
+ def __init__(self, title: str):
+ self._title = title
+ self._renderer: R | None = None
+ self._stop_event = threading.Event()
+ self._thread = threading.Thread(target=self._run)
+ self._thread.start()
+
+ # wait for the renderer to be initialized
+ while self._renderer is None and self._thread.is_alive():
+ time.sleep(0.01)
+
+ def _create_renderer(self) -> R:
+ raise NotImplementedError()
+
+ def _run(self):
+ if os.getenv("CI") is not None:
+ return
+ gui_app.init_window(self._title)
+ self._renderer = self._create_renderer()
+ try:
+ for _ in gui_app.render():
+ if self._stop_event.is_set():
+ break
+ self._renderer.render()
+ finally:
+ gui_app.close()
+
+ def __enter__(self):
+ return self
+
+ def close(self):
+ if self._thread.is_alive():
+ self._stop_event.set()
+ self._thread.join(timeout=2.0)
+ if self._thread.is_alive():
+ cloudlog.warning(f"Failed to join {self._title} thread")
+
+ def __del__(self):
+ self.close()
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.close()
diff --git a/system/ui/spinner.py b/system/ui/spinner.py
index 5da96c73f9..119bdba3e7 100755
--- a/system/ui/spinner.py
+++ b/system/ui/spinner.py
@@ -6,6 +6,7 @@ import time
from openpilot.common.basedir import BASEDIR
from openpilot.system.ui.lib.application import gui_app
+from openpilot.system.ui.lib.window import BaseWindow
from openpilot.system.ui.text import wrap_text
# Constants
@@ -85,16 +86,12 @@ class SpinnerRenderer:
FONT_SIZE, 0.0, rl.WHITE)
-class Spinner:
+class Spinner(BaseWindow[SpinnerRenderer]):
def __init__(self):
- self._renderer: SpinnerRenderer | None = None
- self._stop_event = threading.Event()
- self._thread = threading.Thread(target=self._run)
- self._thread.start()
+ super().__init__("Spinner")
- # wait for the renderer to be initialized
- while self._renderer is None and self._thread.is_alive():
- time.sleep(0.01)
+ def _create_renderer(self):
+ return SpinnerRenderer()
def update(self, spinner_text: str):
if self._renderer is not None:
@@ -103,35 +100,6 @@ class Spinner:
def update_progress(self, cur: float, total: float):
self.update(str(round(100 * cur / total)))
- def _run(self):
- if os.getenv("CI") is not None:
- return
- gui_app.init_window("Spinner")
- self._renderer = renderer = SpinnerRenderer()
- try:
- for _ in gui_app.render():
- if self._stop_event.is_set():
- break
- renderer.render()
- finally:
- gui_app.close()
-
- def __enter__(self):
- return self
-
- def close(self):
- if self._thread.is_alive():
- self._stop_event.set()
- self._thread.join(timeout=2.0)
- if self._thread.is_alive():
- print("WARNING: failed to join spinner thread")
-
- def __del__(self):
- self.close()
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.close()
-
if __name__ == "__main__":
with Spinner() as s:
diff --git a/system/ui/text.py b/system/ui/text.py
index e57ae45d9a..33e8167c64 100755
--- a/system/ui/text.py
+++ b/system/ui/text.py
@@ -1,13 +1,12 @@
#!/usr/bin/env python3
-import os
import re
-import threading
import time
import pyray as rl
from openpilot.system.hardware import HARDWARE, PC
from openpilot.system.ui.lib.button import gui_button, ButtonStyle
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
from openpilot.system.ui.lib.application import gui_app
+from openpilot.system.ui.lib.window import BaseWindow
MARGIN = 50
SPACING = 40
@@ -74,52 +73,18 @@ class TextWindowRenderer:
return ret
-class TextWindow:
+class TextWindow(BaseWindow[TextWindowRenderer]):
def __init__(self, text: str):
self._text = text
+ super().__init__("Text")
- self._renderer: TextWindowRenderer | None = None
- self._stop_event = threading.Event()
- self._thread = threading.Thread(target=self._run)
- self._thread.start()
-
- # wait for the renderer to be initialized
- while self._renderer is None and self._thread.is_alive():
- time.sleep(0.01)
+ def _create_renderer(self):
+ return TextWindowRenderer(self._text)
def wait_for_exit(self):
while self._thread.is_alive():
time.sleep(0.01)
- def _run(self):
- if os.getenv("CI") is not None:
- return
- gui_app.init_window("Text")
- self._renderer = renderer = TextWindowRenderer(self._text)
- try:
- for _ in gui_app.render():
- if self._stop_event.is_set():
- break
- renderer.render()
- finally:
- gui_app.close()
-
- def __enter__(self):
- return self
-
- def close(self):
- if self._thread.is_alive():
- self._stop_event.set()
- self._thread.join(timeout=2.0)
- if self._thread.is_alive():
- print("WARNING: failed to join text window thread")
-
- def __del__(self):
- self.close()
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.close()
-
if __name__ == "__main__":
with TextWindow(DEMO_TEXT):
diff --git a/system/ui/widgets/keyboard.py b/system/ui/widgets/keyboard.py
index 4d1ad1b2cd..13fdb912b5 100644
--- a/system/ui/widgets/keyboard.py
+++ b/system/ui/widgets/keyboard.py
@@ -44,25 +44,28 @@ keyboard_layouts = {
class Keyboard:
def __init__(self, max_text_size: int = 255):
self._layout = keyboard_layouts["lowercase"]
- self._input_text = ""
self._max_text_size = max_text_size
+ self._string_pointer = rl.ffi.new("char[]", max_text_size)
+ self._input_text = ""
+ self._clear()
@property
- def text(self) -> str:
- return self._input_text
-
- def clear(self):
- self._input_text = ""
+ def text(self):
+ result = rl.ffi.string(self._string_pointer).decode("utf-8")
+ self._clear()
+ return result
def render(self, rect, title, sub_title):
gui_label(rl.Rectangle(rect.x, rect.y, rect.width, 95), title, 90)
gui_label(rl.Rectangle(rect.x, rect.y + 95, rect.width, 60), sub_title, 55, rl.GRAY)
if gui_button(rl.Rectangle(rect.x + rect.width - 300, rect.y, 300, 100), "Cancel"):
- return -1
+ self._clear()
+ return 0
# Text box for input
- rl.gui_text_box(rl.Rectangle(rect.x, rect.y + 160, rect.width, 100), self._input_text, self._max_text_size, True)
-
+ self._sync_string_pointer()
+ rl.gui_text_box(rl.Rectangle(rect.x, rect.y + 160, rect.width, 100), self._string_pointer, self._max_text_size, True)
+ self._input_text = rl.ffi.string(self._string_pointer).decode("utf-8")
h_space, v_space = 15, 15
row_y_start = rect.y + 300 # Starting Y position for the first row
key_height = (rect.height - 300 - 3 * v_space) / 4
@@ -87,7 +90,7 @@ class Keyboard:
else:
self.handle_key_press(key)
- return 0
+ return -1
def handle_key_press(self, key):
if key in (SHIFT_DOWN_KEY, ABC_KEY):
@@ -102,3 +105,14 @@ class Keyboard:
self._input_text = self._input_text[:-1]
elif key != BACKSPACE_KEY and len(self._input_text) < self._max_text_size:
self._input_text += key
+
+ def _clear(self):
+ self._input_text = ''
+ self._string_pointer[0] = b'\0'
+
+ def _sync_string_pointer(self):
+ """Sync the C-string pointer with the internal Python string."""
+ encoded = self._input_text.encode("utf-8")[:self._max_text_size - 1] # Leave room for the null terminator
+ buffer = rl.ffi.buffer(self._string_pointer)
+ buffer[:len(encoded)] = encoded
+ self._string_pointer[len(encoded)] = b'\0' # Null terminator
diff --git a/system/ui/widgets/network.py b/system/ui/widgets/network.py
new file mode 100644
index 0000000000..0e9ad349b6
--- /dev/null
+++ b/system/ui/widgets/network.py
@@ -0,0 +1,177 @@
+from dataclasses import dataclass
+from typing import Literal
+
+import pyray as rl
+from openpilot.system.ui.lib.wifi_manager import NetworkInfo, WifiManagerCallbacks, WifiManagerWrapper
+from openpilot.system.ui.lib.application import gui_app
+from openpilot.system.ui.lib.button import gui_button
+from openpilot.system.ui.lib.label import gui_label
+from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
+from openpilot.system.ui.widgets.keyboard import Keyboard
+from openpilot.system.ui.widgets.confirm_dialog import confirm_dialog
+
+NM_DEVICE_STATE_NEED_AUTH = 60
+ITEM_HEIGHT = 160
+
+
+@dataclass
+class StateIdle:
+ action: Literal["idle"] = "idle"
+
+@dataclass
+class StateConnecting:
+ network: NetworkInfo
+ action: Literal["connecting"] = "connecting"
+
+@dataclass
+class StateNeedsAuth:
+ network: NetworkInfo
+ action: Literal["needs_auth"] = "needs_auth"
+
+@dataclass
+class StateShowForgetConfirm:
+ network: NetworkInfo
+ action: Literal["show_forget_confirm"] = "show_forget_confirm"
+
+@dataclass
+class StateForgetting:
+ network: NetworkInfo
+ action: Literal["forgetting"] = "forgetting"
+
+UIState = StateIdle | StateConnecting | StateNeedsAuth | StateShowForgetConfirm | StateForgetting
+
+
+class WifiManagerUI:
+ def __init__(self, wifi_manager: WifiManagerWrapper):
+ self.state: UIState = StateIdle()
+ self.btn_width = 200
+ self.scroll_panel = GuiScrollPanel()
+ self.keyboard = Keyboard()
+
+ self.wifi_manager = wifi_manager
+ self.wifi_manager.set_callbacks(WifiManagerCallbacks(self._on_need_auth, self._on_activated, self._on_forgotten))
+ self.wifi_manager.start()
+ self.wifi_manager.connect()
+
+ def render(self, rect: rl.Rectangle):
+ if not self.wifi_manager.networks:
+ gui_label(rect, "Scanning Wi-Fi networks...", 72, alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER)
+ return
+
+ match self.state:
+ case StateNeedsAuth(network):
+ result = self.keyboard.render(rect, "Enter password", f"for {network.ssid}")
+ if result == 1:
+ self.connect_to_network(network, self.keyboard.text)
+ elif result == 0:
+ self.state = StateIdle()
+
+ case StateShowForgetConfirm(network):
+ result = confirm_dialog(rect, f'Forget Wi-Fi Network "{network.ssid}"?', "Forget")
+ if result == 1:
+ self.forget_network(network)
+ elif result == 0:
+ self.state = StateIdle()
+
+ case _:
+ self._draw_network_list(rect)
+
+ def _draw_network_list(self, rect: rl.Rectangle):
+ content_rect = rl.Rectangle(rect.x, rect.y, rect.width, len(self.wifi_manager.networks) * ITEM_HEIGHT)
+ offset = self.scroll_panel.handle_scroll(rect, content_rect)
+ clicked = self.scroll_panel.is_click_valid()
+
+ rl.begin_scissor_mode(int(rect.x), int(rect.y), int(rect.width), int(rect.height))
+ for i, network in enumerate(self.wifi_manager.networks):
+ y_offset = rect.y + i * ITEM_HEIGHT + offset.y
+ item_rect = rl.Rectangle(rect.x, y_offset, rect.width, ITEM_HEIGHT)
+ if not rl.check_collision_recs(item_rect, rect):
+ continue
+
+ self._draw_network_item(item_rect, network, clicked)
+ if i < len(self.wifi_manager.networks) - 1:
+ line_y = int(item_rect.y + item_rect.height - 1)
+ rl.draw_line(int(item_rect.x), int(line_y), int(item_rect.x + item_rect.width), line_y, rl.LIGHTGRAY)
+
+ rl.end_scissor_mode()
+
+ def _draw_network_item(self, rect, network: NetworkInfo, clicked: bool):
+ label_rect = rl.Rectangle(rect.x, rect.y, rect.width - self.btn_width * 2, ITEM_HEIGHT)
+ state_rect = rl.Rectangle(rect.x + rect.width - self.btn_width * 2 - 150, rect.y, 300, ITEM_HEIGHT)
+
+ gui_label(label_rect, network.ssid, 55)
+
+ status_text = ""
+ if network.is_connected:
+ status_text = "Connected"
+ match self.state:
+ case StateConnecting(network=connecting):
+ if connecting.ssid == network.ssid:
+ status_text = "CONNECTING..."
+ case StateForgetting(network=forgetting):
+ if forgetting.ssid == network.ssid:
+ status_text = "FORGETTING..."
+ if status_text:
+ rl.gui_label(state_rect, status_text)
+
+ # If the network is saved, show the "Forget" button
+ if self.wifi_manager.is_saved(network.ssid):
+ forget_btn_rect = rl.Rectangle(
+ rect.x + rect.width - self.btn_width,
+ rect.y + (ITEM_HEIGHT - 80) / 2,
+ self.btn_width,
+ 80,
+ )
+ if isinstance(self.state, StateIdle) and gui_button(forget_btn_rect, "Forget") and clicked:
+ self.state = StateShowForgetConfirm(network)
+
+ if isinstance(self.state, StateIdle) and rl.check_collision_point_rec(rl.get_mouse_position(), label_rect) and clicked:
+ if not self.wifi_manager.is_saved(network.ssid):
+ self.state = StateNeedsAuth(network)
+ else:
+ self.connect_to_network(network)
+
+ def connect_to_network(self, network: NetworkInfo, password=''):
+ self.state = StateConnecting(network)
+ if self.wifi_manager.is_saved(network.ssid) and not password:
+ self.wifi_manager.activate_connection(network.ssid)
+ else:
+ self.wifi_manager.connect_to_network(network.ssid, password)
+
+ def forget_network(self, network: NetworkInfo):
+ self.state = StateForgetting(network)
+ self.wifi_manager.forget_connection(network.ssid)
+
+ def _on_need_auth(self, ssid):
+ match self.state:
+ case StateConnecting(ssid):
+ self.state = StateNeedsAuth(ssid)
+ case _:
+ # Find network by SSID
+ network = next((n for n in self.wifi_manager.networks if n.ssid == ssid), None)
+ if network:
+ self.state = StateNeedsAuth(network)
+
+ def _on_activated(self):
+ if isinstance(self.state, StateConnecting):
+ self.state = StateIdle()
+
+ def _on_forgotten(self):
+ if isinstance(self.state, StateForgetting):
+ self.state = StateIdle()
+
+
+def main():
+ gui_app.init_window("Wi-Fi Manager")
+ wifi_manager = WifiManagerWrapper()
+ wifi_ui = WifiManagerUI(wifi_manager)
+
+ for _ in gui_app.render():
+ wifi_ui.render(rl.Rectangle(50, 50, gui_app.width - 100, gui_app.height - 100))
+
+ wifi_manager.shutdown()
+ gui_app.close()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/adb_shell.sh b/tools/adb_shell.sh
deleted file mode 100755
index f757f7d4d0..0000000000
--- a/tools/adb_shell.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env expect
-spawn adb shell
-expect "#"
-send "cd data/openpilot\r"
-send "export TERM=xterm-256color\r"
-send "su comma\r"
-send "clear\r"
-interact
diff --git a/tools/auto_source.py b/tools/auto_source.py
new file mode 100755
index 0000000000..401929a9ad
--- /dev/null
+++ b/tools/auto_source.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+import sys
+from openpilot.tools.lib.logreader import LogReader
+
+
+def main():
+ if len(sys.argv) != 2:
+ print("Usage: python auto_source.py ")
+ sys.exit(1)
+
+ log_path = sys.argv[1]
+ lr = LogReader(log_path, sort_by_time=True)
+ print("\n".join(lr.logreader_identifiers))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/cabana/README.md b/tools/cabana/README.md
index 0b7c5bf3ee..7933098e34 100644
--- a/tools/cabana/README.md
+++ b/tools/cabana/README.md
@@ -12,6 +12,8 @@ Options:
-h, --help Displays help on commandline options.
--help-all Displays help including Qt specific options.
--demo use a demo route instead of providing your own
+ --auto Auto load the route from the best available source (no video):
+ internal, openpilotci, comma_api, car_segments, testing_closet
--qcam load qcamera
--ecam load wide road camera
--msgq read can messages from msgq
diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc
index d140a323e1..97f178b1f3 100644
--- a/tools/cabana/cabana.cc
+++ b/tools/cabana/cabana.cc
@@ -23,6 +23,7 @@ int main(int argc, char *argv[]) {
cmd_parser.addHelpOption();
cmd_parser.addPositionalArgument("route", "the drive to replay. find your drives at connect.comma.ai");
cmd_parser.addOption({"demo", "use a demo route instead of providing your own"});
+ cmd_parser.addOption({"auto", "Auto load the route from the best available source (no video): internal, openpilotci, comma_api, car_segments, testing_closet"});
cmd_parser.addOption({"qcam", "load qcamera"});
cmd_parser.addOption({"ecam", "load wide road camera"});
cmd_parser.addOption({"dcam", "load driver camera"});
@@ -69,7 +70,8 @@ int main(int argc, char *argv[]) {
}
if (!route.isEmpty()) {
auto replay_stream = std::make_unique(&app);
- if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) {
+ bool auto_source = cmd_parser.isSet("auto");
+ if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"), replay_flags, auto_source)) {
return 0;
}
stream = replay_stream.release();
diff --git a/tools/cabana/dbc/dbc.cc b/tools/cabana/dbc/dbc.cc
index ba979f258c..e9c869fce7 100644
--- a/tools/cabana/dbc/dbc.cc
+++ b/tools/cabana/dbc/dbc.cc
@@ -180,25 +180,36 @@ bool cabana::Signal::operator==(const cabana::Signal &other) const {
// helper functions
double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal &sig) {
- int64_t val = 0;
+ const int msb_byte = sig.msb / 8;
+ if (msb_byte >= (int)data_size) return 0;
- int i = sig.msb / 8;
- int bits = sig.size;
- while (i >= 0 && i < data_size && bits > 0) {
- int lsb = (int)(sig.lsb / 8) == i ? sig.lsb : i * 8;
- int msb = (int)(sig.msb / 8) == i ? sig.msb : (i + 1) * 8 - 1;
- int size = msb - lsb + 1;
+ const int lsb_byte = sig.lsb / 8;
+ uint64_t val = 0;
- uint64_t d = (data[i] >> (lsb - (i * 8))) & ((1ULL << size) - 1);
- val |= d << (bits - size);
-
- bits -= size;
- i = sig.is_little_endian ? i - 1 : i + 1;
+ // Fast path: signal fits in a single byte
+ if (msb_byte == lsb_byte) {
+ val = (data[msb_byte] >> (sig.lsb & 7)) & ((1ULL << sig.size) - 1);
+ } else {
+ // Multi-byte case: signal spans across multiple bytes
+ int bits = sig.size;
+ int i = msb_byte;
+ const int step = sig.is_little_endian ? -1 : 1;
+ while (i >= 0 && i < (int)data_size && bits > 0) {
+ const int msb = (i == msb_byte) ? sig.msb & 7 : 7;
+ const int lsb = (i == lsb_byte) ? sig.lsb & 7 : 0;
+ const int nbits = msb - lsb + 1;
+ val = (val << nbits) | ((data[i] >> lsb) & ((1ULL << nbits) - 1));
+ bits -= nbits;
+ i += step;
+ }
}
- if (sig.is_signed) {
- val -= ((val >> (sig.size - 1)) & 0x1) ? (1ULL << sig.size) : 0;
+
+ // Sign extension (if needed)
+ if (sig.is_signed && (val & (1ULL << (sig.size - 1)))) {
+ val |= ~((1ULL << sig.size) - 1);
}
- return val * sig.factor + sig.offset;
+
+ return static_cast(val) * sig.factor + sig.offset;
}
void updateMsbLsb(cabana::Signal &s) {
diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc
index ebe478ded7..b8cf1be299 100644
--- a/tools/cabana/streams/replaystream.cc
+++ b/tools/cabana/streams/replaystream.cc
@@ -7,6 +7,7 @@
#include
#include "common/timing.h"
+#include "common/util.h"
#include "tools/cabana/streams/routes.h"
ReplayStream::ReplayStream(QObject *parent) : AbstractStream(parent) {
@@ -45,9 +46,9 @@ void ReplayStream::mergeSegments() {
}
}
-bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) {
+bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags, bool auto_source) {
replay.reset(new Replay(route.toStdString(), {"can", "roadEncodeIdx", "driverEncodeIdx", "wideRoadEncodeIdx", "carParams"},
- {}, nullptr, replay_flags, data_dir.toStdString()));
+ {}, nullptr, replay_flags, data_dir.toStdString(), auto_source));
replay->setSegmentCacheLimit(settings.max_cached_minutes);
replay->installEventFilter([this](const Event *event) { return eventFilter(event); });
diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h
index df1f2526a5..d429ed1f95 100644
--- a/tools/cabana/streams/replaystream.h
+++ b/tools/cabana/streams/replaystream.h
@@ -18,7 +18,7 @@ class ReplayStream : public AbstractStream {
public:
ReplayStream(QObject *parent);
void start() override { replay->start(); }
- bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE);
+ bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE, bool auto_source = false);
bool eventFilter(const Event *event);
void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); }
bool liveStreaming() const override { return false; }
diff --git a/tools/clip/run.py b/tools/clip/run.py
index 97baa880ea..33c98a0213 100755
--- a/tools/clip/run.py
+++ b/tools/clip/run.py
@@ -16,7 +16,7 @@ from typing import Literal
from cereal.messaging import SubMaster
from openpilot.common.basedir import BASEDIR
from openpilot.common.prefix import OpenpilotPrefix
-from openpilot.tools.lib.route import SegmentRange, get_max_seg_number_cached
+from openpilot.tools.lib.route import Route
DEFAULT_OUTPUT = 'output.mp4'
DEMO_START = 90
@@ -26,7 +26,7 @@ FRAMERATE = 20
PIXEL_DEPTH = '24'
RESOLUTION = '2160x1080'
SECONDS_TO_WARM = 2
-PROC_WAIT_SECONDS = 5
+PROC_WAIT_SECONDS = 30
REPLAY = str(Path(BASEDIR, 'tools/replay/replay').resolve())
UI = str(Path(BASEDIR, 'selfdrive/ui/ui').resolve())
@@ -52,6 +52,29 @@ def check_for_failure(proc: Popen):
raise ChildProcessError(msg)
+def escape_ffmpeg_text(value: str):
+ special_chars = {',': '\\,', ':': '\\:', '=': '\\=', '[': '\\[', ']': '\\]'}
+ value = value.replace('\\', '\\\\\\\\\\\\\\\\')
+ for char, escaped in special_chars.items():
+ value = value.replace(char, escaped)
+ return value
+
+
+def get_meta_text(route: Route):
+ metadata = route.get_metadata()
+ origin_parts = metadata['git_remote'].split('/')
+ origin = origin_parts[3] if len(origin_parts) > 3 else 'unknown'
+ return ', '.join([
+ f"openpilot v{metadata['version']}",
+ f"route: {metadata['fullname']}",
+ f"car: {metadata['platform']}",
+ f"origin: {origin}",
+ f"branch: {metadata['git_branch']}",
+ f"commit: {metadata['git_commit'][:7]}",
+ f"modified: {str(metadata['git_dirty']).lower()}",
+ ])
+
+
def parse_args(parser: ArgumentParser):
args = parser.parse_args()
if args.demo:
@@ -74,20 +97,17 @@ def parse_args(parser: ArgumentParser):
if args.start < SECONDS_TO_WARM:
parser.error(f'start must be greater than {SECONDS_TO_WARM}s to allow the UI time to warm up')
- # if using local files, don't worry about length check right now so we skip the network call
- # TODO: derive segment count from local FS
- if not args.data_dir:
- try:
- num_segs = get_max_seg_number_cached(SegmentRange(args.route))
- except Exception as e:
- parser.error(f'failed to get route length: {e}')
-
- # FIXME: length isn't exactly max segment seconds, simplify to replay exiting at end of data
- length = round(num_segs * 60)
- if args.start >= length:
- parser.error(f'start ({args.start}s) cannot be after end of route ({length}s)')
- if args.end > length:
- parser.error(f'end ({args.end}s) cannot be after end of route ({length}s)')
+ try:
+ args.route = Route(args.route, data_dir=args.data_dir)
+ except Exception as e:
+ parser.error(f'failed to get route: {e}')
+
+ # FIXME: length isn't exactly max segment seconds, simplify to replay exiting at end of data
+ length = round(args.route.max_seg_number * 60)
+ if args.start >= length:
+ parser.error(f'start ({args.start}s) cannot be after end of route ({length}s)')
+ if args.end > length:
+ parser.error(f'end ({args.end}s) cannot be after end of route ({length}s)')
return args
@@ -119,6 +139,12 @@ def validate_route(route: str):
return route
+def validate_title(title: str):
+ if len(title) > 80:
+ raise ArgumentTypeError('title must be no longer than 80 chars')
+ return title
+
+
def wait_for_frames(procs: list[Popen]):
sm = SubMaster(['uiDebug'])
no_frames_drawn = True
@@ -129,20 +155,27 @@ def wait_for_frames(procs: list[Popen]):
check_for_failure(proc)
-def clip(data_dir: str | None, quality: Literal['low', 'high'], prefix: str, route: str, output_filepath: str, start: int, end: int, target_size_mb: int):
- logger.info(f'clipping route {route}, start={start} end={end} quality={quality} target_filesize={target_size_mb}MB')
+def clip(data_dir: str | None, quality: Literal['low', 'high'], prefix: str, route: Route, out: str, start: int, end: int, target_mb: int, title: str | None):
+ logger.info(f'clipping route {route.name.canonical_name}, start={start} end={end} quality={quality} target_filesize={target_mb}MB')
begin_at = max(start - SECONDS_TO_WARM, 0)
duration = end - start
- bit_rate_kbps = int(round(target_size_mb * 8 * 1024 * 1024 / duration / 1000))
+ bit_rate_kbps = int(round(target_mb * 8 * 1024 * 1024 / duration / 1000))
# TODO: evaluate creating fn that inspects /tmp/.X11-unix and creates unused display to avoid possibility of collision
display = f':{randint(99, 999)}'
+ meta_text = get_meta_text(route)
+ overlays = [
+ f"drawtext=text='{escape_ffmpeg_text(meta_text)}':fontfile=Inter.tff:fontcolor=white:fontsize=18:box=1:boxcolor=black@0.33:boxborderw=7:x=(w-text_w)/2:y=5.5:enable='between(t,1,5)'"
+ ]
+ if title:
+ overlays.append(f"drawtext=text='{escape_ffmpeg_text(title)}':fontfile=Inter.tff:fontcolor=white:fontsize=32:box=1:boxcolor=black@0.33:boxborderw=10:x=(w-text_w)/2:y=53")
+
ffmpeg_cmd = [
'ffmpeg', '-y', '-video_size', RESOLUTION, '-framerate', str(FRAMERATE), '-f', 'x11grab', '-draw_mouse', '0',
'-i', display, '-c:v', 'libx264', '-maxrate', f'{bit_rate_kbps}k', '-bufsize', f'{bit_rate_kbps*2}k', '-crf', '23',
- '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-movflags', '+faststart', '-f', 'mp4', '-t', str(duration), output_filepath,
+ '-filter:v', ','.join(overlays), '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-movflags', '+faststart', '-f', 'mp4', '-t', str(duration), out
]
replay_cmd = [REPLAY, '-c', '1', '-s', str(begin_at), '--prefix', prefix]
@@ -150,7 +183,7 @@ def clip(data_dir: str | None, quality: Literal['low', 'high'], prefix: str, rou
replay_cmd.extend(['--data_dir', data_dir])
if quality == 'low':
replay_cmd.append('--qcam')
- replay_cmd.append(route)
+ replay_cmd.append(route.name.canonical_name)
ui_cmd = [UI, '-platform', 'xcb']
xvfb_cmd = ['Xvfb', display, '-terminate', '-screen', '0', f'{RESOLUTION}x{PIXEL_DEPTH}']
@@ -183,7 +216,7 @@ def clip(data_dir: str | None, quality: Literal['low', 'high'], prefix: str, rou
ffmpeg_proc.wait(duration + PROC_WAIT_SECONDS)
for proc in procs:
check_for_failure(proc)
- logger.info(f'recording complete: {Path(output_filepath).resolve()}')
+ logger.info(f'recording complete: {Path(out).resolve()}')
def main():
@@ -199,9 +232,10 @@ def main():
p.add_argument('-p', '--prefix', help='openpilot prefix', default=f'clip_{randint(100, 99999)}')
p.add_argument('-q', '--quality', help='quality of camera (low = qcam, high = hevc)', choices=['low', 'high'], default='high')
p.add_argument('-s', '--start', help='start clipping at seconds', type=int)
+ p.add_argument('-t', '--title', help='overlay this title on the video (e.g. "Chill driving across the Golden Gate Bridge")', type=validate_title)
args = parse_args(p)
try:
- clip(args.data_dir, args.quality, args.prefix, args.route, args.output, args.start, args.end, args.file_size)
+ clip(args.data_dir, args.quality, args.prefix, args.route, args.output, args.start, args.end, args.file_size, args.title)
except KeyboardInterrupt as e:
logger.exception('interrupted by user', exc_info=e)
except Exception as e:
diff --git a/tools/install_ubuntu_dependencies.sh b/tools/install_ubuntu_dependencies.sh
index f33569704a..3d6fd2e7a9 100755
--- a/tools/install_ubuntu_dependencies.sh
+++ b/tools/install_ubuntu_dependencies.sh
@@ -33,6 +33,7 @@ function install_ubuntu_common_requirements() {
git \
git-lfs \
ffmpeg \
+ fonts-inter \
libavformat-dev \
libavcodec-dev \
libavdevice-dev \
diff --git a/tools/lib/route.py b/tools/lib/route.py
index ddb8b0486e..831a1e2ee5 100644
--- a/tools/lib/route.py
+++ b/tools/lib/route.py
@@ -21,6 +21,7 @@ class Route:
def __init__(self, name, data_dir=None):
self._name = RouteName(name)
self.files = None
+ self.metadata = None
if data_dir is not None:
self._segments = self._get_segments_local(data_dir)
else:
@@ -59,6 +60,12 @@ class Route:
qcamera_path_by_seg_num = {s.name.segment_num: s.qcamera_path for s in self._segments}
return [qcamera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number + 1)]
+ def get_metadata(self):
+ if not self.metadata:
+ api = CommaApi(get_token())
+ self.metadata = api.get('v1/route/' + self.name.canonical_name)
+ return self.metadata
+
# TODO: refactor this, it's super repetitive
def _get_segments_remote(self):
api = CommaApi(get_token())
diff --git a/tools/op.sh b/tools/op.sh
index 8a8faaf237..93e774a2ac 100755
--- a/tools/op.sh
+++ b/tools/op.sh
@@ -52,6 +52,7 @@ function op_run_command() {
# be default, assume openpilot dir is in current directory
OPENPILOT_ROOT=$(pwd)
function op_get_openpilot_dir() {
+ # First try traversing up the directory tree
while [[ "$OPENPILOT_ROOT" != '/' ]];
do
if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then
@@ -59,6 +60,14 @@ function op_get_openpilot_dir() {
fi
OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)"
done
+
+ # Fallback to hardcoded directories if not found
+ for dir in "$HOME/openpilot" "/data/openpilot"; do
+ if [[ -f "$dir/launch_openpilot.sh" ]]; then
+ OPENPILOT_ROOT="$dir"
+ return 0
+ fi
+ done
}
function op_install_post_commit() {
@@ -275,7 +284,7 @@ function op_venv() {
function op_adb() {
op_before_cmd
- op_run_command tools/adb_shell.sh
+ op_run_command tools/scripts/adb_ssh.sh
}
function op_check() {
@@ -378,11 +387,6 @@ function op_default() {
echo " op is only a wrapper for existing scripts, tools, and commands."
echo " op will always show you what it will run on your system."
echo ""
- echo " op will try to find your openpilot directory in the following order:"
- echo " 1: use the directory specified with the --dir option"
- echo " 2: use the current working directory"
- echo " 3: go up the file tree non-recursively"
- echo ""
echo -e "${BOLD}${UNDERLINE}Usage:${NC} op [OPTIONS] "
echo ""
echo -e "${BOLD}${UNDERLINE}Commands [System]:${NC}"
diff --git a/tools/replay/README.md b/tools/replay/README.md
index 719f7d2db9..8b4afb0acc 100644
--- a/tools/replay/README.md
+++ b/tools/replay/README.md
@@ -64,6 +64,8 @@ Options:
-s, --start start from
-x playback . between 0.2 - 3
--demo use a demo route instead of providing your own
+ --auto Auto load the route from the best available source (no video):
+ internal, openpilotci, comma_api, car_segments, testing_closet
--data_dir local directory with routes
--prefix set OPENPILOT_PREFIX
--dcam load driver camera
diff --git a/tools/replay/main.cc b/tools/replay/main.cc
index b33b7fa263..38a1da292a 100644
--- a/tools/replay/main.cc
+++ b/tools/replay/main.cc
@@ -19,6 +19,8 @@ Options:
-s, --start Start from
-x, --playback Playback
--demo Use a demo route instead of providing your own
+ --auto Auto load the route from the best available source (no video):
+ internal, openpilotci, comma_api, car_segments, testing_closet
-d, --data_dir Local directory with routes
-p, --prefix Set OPENPILOT_PREFIX
--dcam Load driver camera
@@ -39,6 +41,7 @@ struct ReplayConfig {
std::string data_dir;
std::string prefix;
uint32_t flags = REPLAY_FLAG_NONE;
+ bool auto_source = false;
int start_seconds = 0;
int cache_segments = -1;
float playback_speed = -1;
@@ -52,6 +55,7 @@ bool parseArgs(int argc, char *argv[], ReplayConfig &config) {
{"start", required_argument, nullptr, 's'},
{"playback", required_argument, nullptr, 'x'},
{"demo", no_argument, nullptr, 0},
+ {"auto", no_argument, nullptr, 0},
{"data_dir", required_argument, nullptr, 'd'},
{"prefix", required_argument, nullptr, 'p'},
{"dcam", no_argument, nullptr, 0},
@@ -94,11 +98,9 @@ bool parseArgs(int argc, char *argv[], ReplayConfig &config) {
case 'p': config.prefix = optarg; break;
case 0: {
std::string name = cli_options[option_index].name;
- if (name == "demo") {
- config.route = DEMO_ROUTE;
- } else {
- config.flags |= flag_map.at(name);
- }
+ if (name == "demo") config.route = DEMO_ROUTE;
+ else if (name == "auto") config.auto_source = true;
+ else config.flags |= flag_map.at(name);
break;
}
case 'h': std::cout << helpText; return false;
@@ -136,7 +138,7 @@ int main(int argc, char *argv[]) {
op_prefix = std::make_unique(config.prefix);
}
- Replay replay(config.route, config.allow, config.block, nullptr, config.flags, config.data_dir);
+ Replay replay(config.route, config.allow, config.block, nullptr, config.flags, config.data_dir, config.auto_source);
if (config.cache_segments > 0) {
replay.setSegmentCacheLimit(config.cache_segments);
}
diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc
index 80f586daa6..a8e5cd9d43 100644
--- a/tools/replay/replay.cc
+++ b/tools/replay/replay.cc
@@ -15,8 +15,8 @@ void notifyEvent(Callback &callback, Args &&...args) {
}
Replay::Replay(const std::string &route, std::vector allow, std::vector block,
- SubMaster *sm, uint32_t flags, const std::string &data_dir)
- : sm_(sm), flags_(flags), seg_mgr_(std::make_unique(route, flags, data_dir)) {
+ SubMaster *sm, uint32_t flags, const std::string &data_dir, bool auto_source)
+ : sm_(sm), flags_(flags), seg_mgr_(std::make_unique(route, flags, data_dir, auto_source)) {
std::signal(SIGUSR1, interrupt_sleep_handler);
if (!(flags_ & REPLAY_FLAG_ALL_SERVICES)) {
diff --git a/tools/replay/replay.h b/tools/replay/replay.h
index 6a2c86ff02..5e868d2427 100644
--- a/tools/replay/replay.h
+++ b/tools/replay/replay.h
@@ -29,7 +29,7 @@ enum REPLAY_FLAGS {
class Replay {
public:
Replay(const std::string &route, std::vector allow, std::vector block, SubMaster *sm = nullptr,
- uint32_t flags = REPLAY_FLAG_NONE, const std::string &data_dir = "");
+ uint32_t flags = REPLAY_FLAG_NONE, const std::string &data_dir = "", bool auto_source = false);
~Replay();
bool load();
RouteLoadError lastRouteError() const { return route().lastError(); }
diff --git a/tools/replay/route.cc b/tools/replay/route.cc
index ff5a858e8c..ba00828267 100644
--- a/tools/replay/route.cc
+++ b/tools/replay/route.cc
@@ -10,9 +10,8 @@
#include "tools/replay/replay.h"
#include "tools/replay/util.h"
-Route::Route(const std::string &route, const std::string &data_dir) : data_dir_(data_dir) {
- route_ = parseRoute(route);
-}
+Route::Route(const std::string &route, const std::string &data_dir, bool auto_source)
+ : route_string_(route), data_dir_(data_dir), auto_source_(auto_source) {}
RouteIdentifier Route::parseRoute(const std::string &str) {
RouteIdentifier identifier = {};
@@ -44,27 +43,62 @@ RouteIdentifier Route::parseRoute(const std::string &str) {
}
bool Route::load() {
- err_ = RouteLoadError::None;
+ route_ = parseRoute(route_string_);
if (route_.str.empty() || (data_dir_.empty() && route_.dongle_id.empty())) {
rInfo("invalid route format");
return false;
}
+ // Parse the timestamp from the route identifier (only applicable for old route formats).
struct tm tm_time = {0};
- strptime(route_.timestamp.c_str(), "%Y-%m-%d--%H-%M-%S", &tm_time);
- date_time_ = mktime(&tm_time);
-
- bool ret = data_dir_.empty() ? loadFromServer() : loadFromLocal();
- if (ret) {
- if (route_.begin_segment == -1) route_.begin_segment = segments_.rbegin()->first;
- if (route_.end_segment == -1) route_.end_segment = segments_.rbegin()->first;
- for (auto it = segments_.begin(); it != segments_.end(); /**/) {
- if (it->first < route_.begin_segment || it->first > route_.end_segment) {
- it = segments_.erase(it);
- } else {
- ++it;
+ if (strptime(route_.timestamp.c_str(), "%Y-%m-%d--%H-%M-%S", &tm_time)) {
+ date_time_ = mktime(&tm_time);
+ }
+
+ if (!loadSegments()) {
+ rInfo("Failed to load segments");
+ return false;
+ }
+
+ return true;
+}
+
+bool Route::loadSegments() {
+ if (!auto_source_) {
+ bool ret = data_dir_.empty() ? loadFromServer() : loadFromLocal();
+ if (ret) {
+ // Trim segments
+ if (route_.begin_segment > 0) {
+ segments_.erase(segments_.begin(), segments_.lower_bound(route_.begin_segment));
+ }
+ if (route_.end_segment >= 0) {
+ segments_.erase(segments_.upper_bound(route_.end_segment), segments_.end());
}
}
+ return !segments_.empty();
+ }
+ return loadFromAutoSource();
+}
+
+bool Route::loadFromAutoSource() {
+ auto origin_prefix = getenv("OPENPILOT_PREFIX");
+ if (origin_prefix) {
+ setenv("OPENPILOT_PREFIX", "", 1);
+ }
+ auto cmd = util::string_format("../auto_source.py \"%s\"", route_string_.c_str());
+ auto log_files = split(util::check_output(cmd), '\n');
+ if (origin_prefix) {
+ setenv("OPENPILOT_PREFIX", origin_prefix, 1);
+ }
+
+ const static std::regex rx(R"(\/(\d+)\/)");
+ for (int i = 0; i < log_files.size(); ++i) {
+ int seg_num = i;
+ std::smatch match;
+ if (std::regex_search(log_files[i], match, rx)) {
+ seg_num = std::stoi(match[1]);
+ }
+ addFileToSegment(seg_num, log_files[i]);
}
return !segments_.empty();
}
diff --git a/tools/replay/route.h b/tools/replay/route.h
index 1806be5afa..0375252a19 100644
--- a/tools/replay/route.h
+++ b/tools/replay/route.h
@@ -40,7 +40,7 @@ struct SegmentFile {
class Route {
public:
- Route(const std::string &route, const std::string &data_dir = {});
+ Route(const std::string &route, const std::string &data_dir = {}, bool auto_source = false);
bool load();
RouteLoadError lastError() const { return err_; }
inline const std::string &name() const { return route_.str; }
@@ -52,6 +52,8 @@ public:
static RouteIdentifier parseRoute(const std::string &str);
protected:
+ bool loadSegments();
+ bool loadFromAutoSource();
bool loadFromLocal();
bool loadFromServer(int retries = 3);
bool loadFromJson(const std::string &json);
@@ -59,8 +61,10 @@ protected:
RouteIdentifier route_ = {};
std::string data_dir_;
std::map segments_;
- std::time_t date_time_;
+ std::time_t date_time_ = 0;
RouteLoadError err_ = RouteLoadError::None;
+ bool auto_source_ = false;
+ std::string route_string_;
};
class Segment {
diff --git a/tools/replay/seg_mgr.h b/tools/replay/seg_mgr.h
index 9158e41618..640169749e 100644
--- a/tools/replay/seg_mgr.h
+++ b/tools/replay/seg_mgr.h
@@ -20,8 +20,8 @@ public:
bool isSegmentLoaded(int n) const { return segments.find(n) != segments.end(); }
};
- SegmentManager(const std::string &route_name, uint32_t flags, const std::string &data_dir = "")
- : flags_(flags), route_(route_name, data_dir), event_data_(std::make_shared()) {}
+ SegmentManager(const std::string &route_name, uint32_t flags, const std::string &data_dir = "", bool auto_source = false)
+ : flags_(flags), route_(route_name, data_dir, auto_source), event_data_(std::make_shared()) {}
~SegmentManager();
bool load();
diff --git a/tools/scripts/adb_ssh.sh b/tools/scripts/adb_ssh.sh
new file mode 100755
index 0000000000..43c8e07de6
--- /dev/null
+++ b/tools/scripts/adb_ssh.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+set -e
+
+# this is a little nicer than "adb shell" since
+# "adb shell" doesn't do full terminal emulation
+adb forward tcp:2222 tcp:22
+ssh comma@localhost -p 2222
diff --git a/uv.lock b/uv.lock
index eb43ede212..fbeda4d552 100644
--- a/uv.lock
+++ b/uv.lock
@@ -149,16 +149,16 @@ wheels = [
[[package]]
name = "azure-core"
-version = "1.33.0"
+version = "1.34.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "requests" },
{ name = "six" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/75/aa/7c9db8edd626f1a7d99d09ef7926f6f4fb34d5f9fa00dc394afdfe8e2a80/azure_core-1.33.0.tar.gz", hash = "sha256:f367aa07b5e3005fec2c1e184b882b0b039910733907d001c20fb08ebb8c0eb9", size = 295633, upload-time = "2025-04-03T23:51:02.058Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/c9/29/ff7a519a315e41c85bab92a7478c6acd1cf0b14353139a08caee4c691f77/azure_core-1.34.0.tar.gz", hash = "sha256:bdb544989f246a0ad1c85d72eeb45f2f835afdcbc5b45e43f0dbde7461c81ece", size = 297999, upload-time = "2025-05-01T23:17:27.59Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/07/b7/76b7e144aa53bd206bf1ce34fa75350472c3f69bf30e5c8c18bc9881035d/azure_core-1.33.0-py3-none-any.whl", hash = "sha256:9b5b6d0223a1d38c37500e6971118c1e0f13f54951e6893968b38910bc9cda8f", size = 207071, upload-time = "2025-04-03T23:51:03.806Z" },
+ { url = "https://files.pythonhosted.org/packages/84/9e/5c87b49f65bb16571599bc789857d0ded2f53014d3392bc88a5d1f3ad779/azure_core-1.34.0-py3-none-any.whl", hash = "sha256:0615d3b756beccdb6624d1c0ae97284f38b78fb59a2a9839bf927c66fbbdddd6", size = 207409, upload-time = "2025-05-01T23:17:29.818Z" },
]
[[package]]
@@ -260,37 +260,37 @@ wheels = [
[[package]]
name = "charset-normalizer"
-version = "3.4.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188, upload-time = "2024-12-24T18:12:35.43Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/72/80/41ef5d5a7935d2d3a773e3eaebf0a9350542f2cab4eac59a7a4741fbbbbe/charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", size = 194995, upload-time = "2024-12-24T18:10:12.838Z" },
- { url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471, upload-time = "2024-12-24T18:10:14.101Z" },
- { url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831, upload-time = "2024-12-24T18:10:15.512Z" },
- { url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335, upload-time = "2024-12-24T18:10:18.369Z" },
- { url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862, upload-time = "2024-12-24T18:10:19.743Z" },
- { url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673, upload-time = "2024-12-24T18:10:21.139Z" },
- { url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211, upload-time = "2024-12-24T18:10:22.382Z" },
- { url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039, upload-time = "2024-12-24T18:10:24.802Z" },
- { url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939, upload-time = "2024-12-24T18:10:26.124Z" },
- { url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075, upload-time = "2024-12-24T18:10:30.027Z" },
- { url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340, upload-time = "2024-12-24T18:10:32.679Z" },
- { url = "https://files.pythonhosted.org/packages/b5/b6/9674a4b7d4d99a0d2df9b215da766ee682718f88055751e1e5e753c82db0/charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", size = 95205, upload-time = "2024-12-24T18:10:34.724Z" },
- { url = "https://files.pythonhosted.org/packages/1e/ab/45b180e175de4402dcf7547e4fb617283bae54ce35c27930a6f35b6bef15/charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", size = 102441, upload-time = "2024-12-24T18:10:37.574Z" },
- { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105, upload-time = "2024-12-24T18:10:38.83Z" },
- { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404, upload-time = "2024-12-24T18:10:44.272Z" },
- { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423, upload-time = "2024-12-24T18:10:45.492Z" },
- { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184, upload-time = "2024-12-24T18:10:47.898Z" },
- { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268, upload-time = "2024-12-24T18:10:50.589Z" },
- { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601, upload-time = "2024-12-24T18:10:52.541Z" },
- { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098, upload-time = "2024-12-24T18:10:53.789Z" },
- { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520, upload-time = "2024-12-24T18:10:55.048Z" },
- { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852, upload-time = "2024-12-24T18:10:57.647Z" },
- { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488, upload-time = "2024-12-24T18:10:59.43Z" },
- { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192, upload-time = "2024-12-24T18:11:00.676Z" },
- { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550, upload-time = "2024-12-24T18:11:01.952Z" },
- { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785, upload-time = "2024-12-24T18:11:03.142Z" },
- { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767, upload-time = "2024-12-24T18:12:32.852Z" },
+version = "3.4.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" },
+ { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" },
+ { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" },
+ { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" },
+ { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" },
+ { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" },
+ { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" },
+ { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" },
+ { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" },
+ { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" },
+ { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" },
+ { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" },
+ { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" },
+ { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" },
+ { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" },
]
[[package]]
@@ -503,7 +503,7 @@ version = "0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-xlib", marker = "sys_platform == 'linux'" },
- { name = "typing-extensions" },
+ { name = "typing-extensions", marker = "sys_platform != 'darwin'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/2f/3a/46ca34abf0725a754bc44ef474ad34aedcc3ea23b052d97b18b76715a6a9/EWMHlib-0.2-py3-none-any.whl", hash = "sha256:f5b07d8cfd4c7734462ee744c32d490f2f3233fa7ab354240069344208d2f6f5", size = 46657, upload-time = "2024-04-17T08:15:56.338Z" },
@@ -650,10 +650,10 @@ name = "gymnasium"
version = "1.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "cloudpickle" },
- { name = "farama-notifications" },
- { name = "numpy" },
- { name = "typing-extensions" },
+ { name = "cloudpickle", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "farama-notifications", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "numpy", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "typing-extensions", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/90/69/70cd29e9fc4953d013b15981ee71d4c9ef4d8b2183e6ef2fe89756746dce/gymnasium-1.1.1.tar.gz", hash = "sha256:8bd9ea9bdef32c950a444ff36afc785e1d81051ec32d30435058953c20d2456d", size = 829326, upload-time = "2025-03-06T16:30:36.428Z" }
wheels = [
@@ -964,22 +964,22 @@ name = "metadrive-simulator"
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" },
- { name = "gymnasium" },
- { name = "lxml" },
- { name = "matplotlib" },
- { name = "numpy" },
- { name = "opencv-python-headless" },
- { name = "panda3d" },
- { name = "panda3d-gltf" },
- { name = "pillow" },
- { name = "progressbar" },
- { name = "psutil" },
- { name = "pygments" },
- { name = "requests" },
- { name = "shapely" },
- { name = "tqdm" },
- { name = "yapf" },
+ { name = "filelock", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "gymnasium", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "lxml", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "matplotlib", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "numpy", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "opencv-python-headless", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "panda3d", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "panda3d-gltf", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "pillow", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "progressbar", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "psutil", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "pygments", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "requests", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "shapely", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "tqdm", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "yapf", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
wheels = [
{ 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" },
@@ -1238,7 +1238,7 @@ name = "opencv-python-headless"
version = "4.11.0.86"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "numpy" },
+ { name = "numpy", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929, upload-time = "2025-01-16T13:53:40.22Z" }
wheels = [
@@ -1287,6 +1287,7 @@ dependencies = [
{ name = "sympy" },
{ name = "tqdm" },
{ name = "websocket-client" },
+ { name = "xattr" },
{ name = "zstandard" },
]
@@ -1412,6 +1413,7 @@ requires-dist = [
{ name = "types-requests", marker = "extra == 'dev'" },
{ name = "types-tabulate", marker = "extra == 'dev'" },
{ name = "websocket-client" },
+ { name = "xattr" },
{ name = "zstandard" },
]
provides-extras = ["docs", "testing", "dev", "tools"]
@@ -1448,8 +1450,8 @@ name = "panda3d-gltf"
version = "0.13"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "panda3d" },
- { name = "panda3d-simplepbr" },
+ { name = "panda3d", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "panda3d-simplepbr", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/07/7f/9f18fc3fa843a080acb891af6bcc12262e7bdf1d194a530f7042bebfc81f/panda3d-gltf-0.13.tar.gz", hash = "sha256:d06d373bdd91cf530909b669f43080e599463bbf6d3ef00c3558bad6c6b19675", size = 25573, upload-time = "2021-05-21T05:46:32.738Z" }
wheels = [
@@ -1461,8 +1463,8 @@ name = "panda3d-simplepbr"
version = "0.13.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "panda3d" },
- { name = "typing-extensions" },
+ { name = "panda3d", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "typing-extensions", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0d/be/c4d1ded04c22b357277cf6e6a44c1ab4abb285a700bd1991460460e05b99/panda3d_simplepbr-0.13.1.tar.gz", hash = "sha256:c83766d7c8f47499f365a07fe1dff078fc8b3054c2689bdc8dceabddfe7f1a35", size = 6216055, upload-time = "2025-03-30T16:57:41.087Z" }
wheels = [
@@ -1860,162 +1862,162 @@ name = "pyobjc"
version = "11.0"
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-carbon" },
- { 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-devicediscoveryextension", marker = "platform_release >= '24.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-mediaextension", marker = "platform_release >= '24.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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-accessibility", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-accounts", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-addressbook", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-adservices", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-adsupport", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-applescriptkit", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-applescriptobjc", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-applicationservices", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-apptrackingtransparency", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-audiovideobridging", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-authenticationservices", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-automaticassessmentconfiguration", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-automator", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-avfoundation", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-avkit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-avrouting", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-backgroundassets", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-browserenginekit", marker = "platform_release >= '23.4' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-businesschat", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-calendarstore", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-callkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-carbon", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cfnetwork", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cinematic", marker = "platform_release >= '23.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-classkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cloudkit", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-collaboration", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-colorsync", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-contacts", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-contactsui", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreaudiokit", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-corebluetooth", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-corehaptics", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-corelocation", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremedia", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremediaio", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremidi", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreml", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremotion", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-corespotlight", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coretext", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-corewlan", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cryptotokenkit", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-datadetection", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-devicecheck", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-devicediscoveryextension", marker = "platform_release >= '24.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-dictionaryservices", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-discrecording", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-discrecordingui", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-diskarbitration", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-dvdplayback", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-eventkit", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-exceptionhandling", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-executionpolicy", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-extensionkit", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-externalaccessory", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-fileprovider", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-fileproviderui", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-findersync", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-fsevents", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-gamecenter", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-gamecontroller", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-gamekit", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-gameplaykit", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-healthkit", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-imagecapturecore", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-inputmethodkit", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-installerplugins", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-instantmessage", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-intents", marker = "platform_release >= '16.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-intentsui", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-iobluetooth", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-iobluetoothui", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-iosurface", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-ituneslibrary", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-kernelmanagement", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-latentsemanticmapping", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-launchservices", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-libdispatch", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-libxpc", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-linkpresentation", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-localauthentication", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-localauthenticationembeddedui", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-mailkit", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-mapkit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-mediaaccessibility", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-mediaextension", marker = "platform_release >= '24.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-medialibrary", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-mediaplayer", marker = "platform_release >= '16.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-mediatoolbox", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metal", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metalfx", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metalkit", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metalperformanceshaders", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metalperformanceshadersgraph", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metrickit", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-mlcompute", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-modelio", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-multipeerconnectivity", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-naturallanguage", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-netfs", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-network", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-networkextension", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-notificationcenter", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-opendirectory", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-osakit", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-oslog", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-passkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-pencilkit", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-phase", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-photos", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-photosui", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-preferencepanes", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-pushkit", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quicklookthumbnailing", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-replaykit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-safariservices", marker = "platform_release >= '16.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-safetykit", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-scenekit", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-screencapturekit", marker = "platform_release >= '21.4' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-screensaver", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-screentime", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-scriptingbridge", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-searchkit", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-securityfoundation", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-securityinterface", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-sensitivecontentanalysis", marker = "platform_release >= '23.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-servicemanagement", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-sharedwithyou", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-sharedwithyoucore", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-shazamkit", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-social", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-soundanalysis", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-speech", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-spritekit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-storekit", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-symbols", marker = "platform_release >= '23.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-syncservices", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-systemconfiguration", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-systemextensions", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-threadnetwork", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-uniformtypeidentifiers", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-usernotifications", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-usernotificationsui", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-videosubscriberaccount", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-videotoolbox", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-virtualization", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-vision", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-webkit", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e1/d6/27b1c9a02f6cb4954984ce1a0239618e52f78c329c7e7450bf1f219b0f0a/pyobjc-11.0.tar.gz", hash = "sha256:a8f7baed65797f67afd46290b02f652c23f4b158ddf960bce0441b78f6803418", size = 11044, upload-time = "2025-01-14T19:02:12.55Z" }
wheels = [
@@ -2037,9 +2039,9 @@ name = "pyobjc-framework-accessibility"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b5/61/7484cc4ad3aa7854cd4c969379a5f044261259d08f7c20b6718493b484f9/pyobjc_framework_accessibility-11.0.tar.gz", hash = "sha256:097450c641fa9ac665199762e77867f2a82775be2f749b8fa69223b828f60656", size = 44597, upload-time = "2025-01-14T19:02:17.596Z" }
wheels = [
@@ -2052,8 +2054,8 @@ name = "pyobjc-framework-accounts"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c2/fa/b64f3f02e0a8b189dc07c391546e2dbe30ef1b3515d1427cdab743545b90/pyobjc_framework_accounts-11.0.tar.gz", hash = "sha256:afc4ae277be1e3e1f90269001c2fd886093a5465e365d7f9a3a0af3e17f06210", size = 17340, upload-time = "2025-01-14T19:02:18.625Z" }
wheels = [
@@ -2066,8 +2068,8 @@ name = "pyobjc-framework-addressbook"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/68/ef/5b5f6b61907ae43509fbf1654e043115d9a64d97efdc28fbb90d06c199f6/pyobjc_framework_addressbook-11.0.tar.gz", hash = "sha256:87073c85bb342eb27faa6eceb7a0e8a4c1e32ad1f2b62bb12dafb5e7b9f15837", size = 97116, upload-time = "2025-01-14T19:02:19.527Z" }
wheels = [
@@ -2080,8 +2082,8 @@ name = "pyobjc-framework-adservices"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/51/7c/0c6e01f83b0c5c7968564a40146f4d07080df278457bdb5a982c8f26a74d/pyobjc_framework_adservices-11.0.tar.gz", hash = "sha256:d2e1a2f395e93e1bbe754ab0d76ce1d64c0d3928472634437e0382eafc6765cd", size = 12732, upload-time = "2025-01-14T19:02:20.559Z" }
wheels = [
@@ -2094,8 +2096,8 @@ name = "pyobjc-framework-adsupport"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0c/07/b8b5f741d1e2cad97100444b255e6ecaca3668e7414039981799aa330035/pyobjc_framework_adsupport-11.0.tar.gz", hash = "sha256:20eb8a683d34fb7a6efeceaf964a24b88c3434875c44f66db5e1b609e678043a", size = 12819, upload-time = "2025-01-14T19:02:23.032Z" }
wheels = [
@@ -2108,8 +2110,8 @@ name = "pyobjc-framework-applescriptkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/14/c3/d7f9a33de7ab8e3950350e0862214e66f27ed6bff1a491bc391c377ab83e/pyobjc_framework_applescriptkit-11.0.tar.gz", hash = "sha256:4bafac4a036f0fb8ba01488b8e91d3ac861ce6e61154ffbd0b26f82b99779b50", size = 12638, upload-time = "2025-01-14T19:02:25.1Z" }
wheels = [
@@ -2122,8 +2124,8 @@ name = "pyobjc-framework-applescriptobjc"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fb/9f/bb4fdbcea418f8472d7a67d4d2e4a15fca11fed04648db5208b0fce84807/pyobjc_framework_applescriptobjc-11.0.tar.gz", hash = "sha256:baff9988b6e886aed0e76441358417707de9088be5733f22055fed7904ca1001", size = 12675, upload-time = "2025-01-14T19:02:25.947Z" }
wheels = [
@@ -2136,10 +2138,10 @@ name = "pyobjc-framework-applicationservices"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coretext", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ba/fb/4e42573b0d3baa3fa18ec53614cf979f951313f1451e8f2e17df9429da1f/pyobjc_framework_applicationservices-11.0.tar.gz", hash = "sha256:d6ea18dfc7d5626a3ecf4ac72d510405c0d3a648ca38cae8db841acdebecf4d2", size = 224334, upload-time = "2025-01-14T19:02:26.828Z" }
wheels = [
@@ -2152,8 +2154,8 @@ name = "pyobjc-framework-apptrackingtransparency"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/36/40/c1c48ed49b5e55c7a635aa1e7ca41ffa1c5547e26243f26489c4768cd730/pyobjc_framework_apptrackingtransparency-11.0.tar.gz", hash = "sha256:cd5c834b5b19c21ad6c317ba5d29f30a8d0ae5d14e7cf557da22abc0850f1e91", size = 13385, upload-time = "2025-01-14T19:02:29.226Z" }
wheels = [
@@ -2166,8 +2168,8 @@ name = "pyobjc-framework-audiovideobridging"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/89/5f/0bd5beded0415b53f443da804410eda6a53e1bc64f8779ed9a592719da8c/pyobjc_framework_audiovideobridging-11.0.tar.gz", hash = "sha256:dbc45b06418dd780c365956fdfd69d007436b5ee54c51e671196562eb8290ba6", size = 72418, upload-time = "2025-01-14T19:02:30.083Z" }
wheels = [
@@ -2180,8 +2182,8 @@ name = "pyobjc-framework-authenticationservices"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/31/0f/2de0d941e9c9b2eb1ce8b22eb31adc7227badfe1e53f615431d3a7fdcd48/pyobjc_framework_authenticationservices-11.0.tar.gz", hash = "sha256:6a060ce651df142e8923d1383449bc6f2c7f5eb0b517152dac609bde3901064e", size = 140036, upload-time = "2025-01-14T19:02:31.115Z" }
wheels = [
@@ -2194,8 +2196,8 @@ name = "pyobjc-framework-automaticassessmentconfiguration"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/09/d5/5febfee260b88e426c7e799cc95990818feeaa9f740fb9dd516559c96520/pyobjc_framework_automaticassessmentconfiguration-11.0.tar.gz", hash = "sha256:5d3691af2b94e44ca594b6791556e15a9f0a3f9432df51cb891f5f859a65e467", size = 24420, upload-time = "2025-01-14T19:02:32.101Z" }
wheels = [
@@ -2208,8 +2210,8 @@ name = "pyobjc-framework-automator"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/25/1b/1ba4eb296c3915f2e367e45470cb310a9c78b4dd65a37bd522f458f245aa/pyobjc_framework_automator-11.0.tar.gz", hash = "sha256:412d330f8c6f30066cad15e1bdecdc865510bbce469cc7d9477384c4e9f2550f", size = 200905, upload-time = "2025-01-14T19:02:33.039Z" }
wheels = [
@@ -2222,11 +2224,11 @@ name = "pyobjc-framework-avfoundation"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/76/06/018ad0e2a38dbdbc5c126d7ce37488c4d581d4e2a2b9ef678162bb36d5f6/pyobjc_framework_avfoundation-11.0.tar.gz", hash = "sha256:269a592bdaf8a16948d8935f0cf7c8cb9a53e7ea609a963ada0e55f749ddb530", size = 871064, upload-time = "2025-01-14T19:02:35.757Z" }
wheels = [
@@ -2239,9 +2241,9 @@ name = "pyobjc-framework-avkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/de/79/5b2fcb94b051da32a24b54bb0d90b1d01b190e1402b6303747de47fb17ac/pyobjc_framework_avkit-11.0.tar.gz", hash = "sha256:5fa40919320277b820df3e4c6e84cba91ef7221a28f4eb5374e3dbd80d1e521a", size = 46311, upload-time = "2025-01-14T19:02:37.018Z" }
wheels = [
@@ -2254,8 +2256,8 @@ name = "pyobjc-framework-avrouting"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d5/80/63680dc7788bc3573a20fc5421dfcf606970a0cd3b2457829d9b66603ae0/pyobjc_framework_avrouting-11.0.tar.gz", hash = "sha256:54ec9ea0b5adb5149b554e23c07c6b4f4bdb2892ca2ed7b3e88a5de936313025", size = 20561, upload-time = "2025-01-14T19:02:38.157Z" }
wheels = [
@@ -2268,8 +2270,8 @@ name = "pyobjc-framework-backgroundassets"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a3/17/83b873069b0c0763365de88648ad4a2472e9e96fcac39fa534f3633552e8/pyobjc_framework_backgroundassets-11.0.tar.gz", hash = "sha256:9488c3f86bf427898a88b7100e77200c08a487a35c75c1b5735bd69c57ba38cb", size = 23658, upload-time = "2025-01-14T19:02:42.665Z" }
wheels = [
@@ -2282,11 +2284,11 @@ name = "pyobjc-framework-browserenginekit"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9f/2e/df3d2f7e53132d398c2922d331dd1d2aa352997a1a4a1390e59db51c1d13/pyobjc_framework_browserenginekit-11.0.tar.gz", hash = "sha256:51971527f5103c0e09a4ef438c352ebb037fcad8971f8420a781c72ee421f758", size = 31352, upload-time = "2025-01-14T19:02:45.499Z" }
wheels = [
@@ -2299,8 +2301,8 @@ name = "pyobjc-framework-businesschat"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5a/f2/4541989f2c9c5fc3cdfc94ebf31fc6619554b6c22dafdbb57f866a392bc1/pyobjc_framework_businesschat-11.0.tar.gz", hash = "sha256:20fe1c8c848ef3c2e132172d9a007a8aa65b08875a9ca5c27afbfc4396b16dbb", size = 12953, upload-time = "2025-01-14T19:02:46.378Z" }
wheels = [
@@ -2313,8 +2315,8 @@ name = "pyobjc-framework-calendarstore"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9f/d3/722c1b16c7d9bdd5c408735c15193e8396f2d22ab6410b0af4569f39c46e/pyobjc_framework_calendarstore-11.0.tar.gz", hash = "sha256:40173f729df56b70ec14f9680962a248c3ce7b4babb46e8b0d760a13975ef174", size = 68475, upload-time = "2025-01-14T19:02:48.544Z" }
wheels = [
@@ -2327,8 +2329,8 @@ name = "pyobjc-framework-callkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e4/0a/9d39ebac92006960b8059f664d8eb7b9cdb8763fe4e8102b2d24b853004f/pyobjc_framework_callkit-11.0.tar.gz", hash = "sha256:52e44a05d0357558e1479977ed2bcb325fabc8d337f641f0249178b5b491fc59", size = 39720, upload-time = "2025-01-14T19:02:50.697Z" }
wheels = [
@@ -2341,8 +2343,8 @@ name = "pyobjc-framework-carbon"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/22/15/51964f36a8ae1002b16d213d2e5ba11cc861bdd9369f1e3f116350d788c5/pyobjc_framework_carbon-11.0.tar.gz", hash = "sha256:476f690f0b34aa9e4cb3923e61481aefdcf33e38ec6087b530a94871eee2b914", size = 37538, upload-time = "2025-01-14T19:02:51.62Z" }
wheels = [
@@ -2355,8 +2357,8 @@ name = "pyobjc-framework-cfnetwork"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4f/36/7cebdfb621c7d46eeab3173256bc2e1cba1bbbbe6c0ac8aeb9a4fe2a4627/pyobjc_framework_cfnetwork-11.0.tar.gz", hash = "sha256:eb742fc6a42b248886ff09c3cf247d56e65236864bbea4264e70af8377948d96", size = 78532, upload-time = "2025-01-14T19:02:52.777Z" }
wheels = [
@@ -2369,11 +2371,11 @@ name = "pyobjc-framework-cinematic"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/33/ef/b5857d567cd6e0366f61c381ebea52383b98d1ac03341f39e779a085812a/pyobjc_framework_cinematic-11.0.tar.gz", hash = "sha256:94a2de8bf3f38bd190311b6bf98d1e2cea7888840b3ce3aa92e464c0216a5cdb", size = 25740, upload-time = "2025-01-14T19:02:54.95Z" }
wheels = [
@@ -2386,8 +2388,8 @@ name = "pyobjc-framework-classkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f5/81/126075eaf5ccf254ddb4cfd99d92a266c30803c5b4572ea3a920fd85e850/pyobjc_framework_classkit-11.0.tar.gz", hash = "sha256:dc5b3856612cafdc7071fbebc252b8908dbf2433e0e5ddb15a0bcd1ee282d27c", size = 39301, upload-time = "2025-01-14T19:02:55.779Z" }
wheels = [
@@ -2400,11 +2402,11 @@ name = "pyobjc-framework-cloudkit"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-accounts", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-corelocation", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/89/6c/b0709fed7fc5a1e81de311b9273bb7ba3820a636f8ba880e90510bb6d460/pyobjc_framework_cloudkit-11.0.tar.gz", hash = "sha256:e3f6bf2c3358dd394174b1e69fcec6859951fcd15f6433c6fa3082e3b7e2656d", size = 123034, upload-time = "2025-01-14T19:02:56.769Z" }
wheels = [
@@ -2417,7 +2419,7 @@ name = "pyobjc-framework-cocoa"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c5/32/53809096ad5fc3e7a2c5ddea642590a5f2cb5b81d0ad6ea67fdb2263d9f9/pyobjc_framework_cocoa-11.0.tar.gz", hash = "sha256:00346a8cb81ad7b017b32ff7bf596000f9faa905807b1bd234644ebd47f692c5", size = 6173848, upload-time = "2025-01-14T19:03:00.125Z" }
wheels = [
@@ -2430,8 +2432,8 @@ name = "pyobjc-framework-collaboration"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6b/ee/1f6893eb882af5ecc6a6f4182b2ec85df777c4bc6b9a20a6b42c23abff3f/pyobjc_framework_collaboration-11.0.tar.gz", hash = "sha256:9f53929dd6d5b1a5511494432bf83807041c6f8b9ab6cf6ff184eee0b6f8226f", size = 17084, upload-time = "2025-01-14T19:03:01.98Z" }
wheels = [
@@ -2444,8 +2446,8 @@ name = "pyobjc-framework-colorsync"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9a/24/397a80cd2313cc9e1b73b9acb1de66b740bbece4fe87ed4ea158de8fcef8/pyobjc_framework_colorsync-11.0.tar.gz", hash = "sha256:4f531f6075d9cc4b9d426620a1b04d3aaeb56b5ff178d0a6b0e93d068a5db0d2", size = 39249, upload-time = "2025-01-14T19:03:02.887Z" }
wheels = [
@@ -2458,8 +2460,8 @@ name = "pyobjc-framework-contacts"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f5/a2/89053853b28c1f2f2e69092d3e81b7c26073bc8396fc87772b3b1bfb9d57/pyobjc_framework_contacts-11.0.tar.gz", hash = "sha256:fc215baa9f66dbf9ffa1cb8170d102a3546cfd708b2b42de4e9d43645aec03d9", size = 84253, upload-time = "2025-01-14T19:03:03.743Z" }
wheels = [
@@ -2472,9 +2474,9 @@ name = "pyobjc-framework-contactsui"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-contacts" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-contacts", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3f/67/122b16fd7f2da7f0f48c1d7fcaf0f1951253ddd5489d909a1b5fb80f3925/pyobjc_framework_contactsui-11.0.tar.gz", hash = "sha256:d0f2a4afea807fbe4db1518c4f81f0dc9aa1817fe7cb16115308fc00375a70db", size = 19486, upload-time = "2025-01-14T19:03:04.72Z" }
wheels = [
@@ -2487,8 +2489,8 @@ name = "pyobjc-framework-coreaudio"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/31/e6/3b7a8af3defec012d6cacf277fd8d5c3e254ceace63a05447dc1119f3a7e/pyobjc_framework_coreaudio-11.0.tar.gz", hash = "sha256:38b6b531381119be6998cf704d04c9ea475aaa33f6dd460e0584351475acd0ae", size = 140507, upload-time = "2025-01-14T19:03:05.612Z" }
wheels = [
@@ -2501,9 +2503,9 @@ name = "pyobjc-framework-coreaudiokit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-coreaudio" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ef/1a/604cac8d992b6e66adbb98edb1f65820116f5d74d8decd6d43898ae2929d/pyobjc_framework_coreaudiokit-11.0.tar.gz", hash = "sha256:1a4c3de4a02b0dfa7410c012c7f0939edd2e127d439fb934aeafc68450615f1d", size = 21450, upload-time = "2025-01-14T19:03:06.681Z" }
wheels = [
@@ -2516,8 +2518,8 @@ name = "pyobjc-framework-corebluetooth"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/93/74/66a62a36da9db5924ee15de6fe1eb544930609b307b3bfbc021b5cf43781/pyobjc_framework_corebluetooth-11.0.tar.gz", hash = "sha256:1dcb7c039c2efa7c72dc14cdda80e677240b49fa38999941a77ee02ca142998d", size = 59797, upload-time = "2025-01-14T19:03:07.584Z" }
wheels = [
@@ -2530,8 +2532,8 @@ name = "pyobjc-framework-coredata"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/84/22/6787205b91cb6d526b6b472ebaa5baff275200774050a55b4b25d2bd957a/pyobjc_framework_coredata-11.0.tar.gz", hash = "sha256:b11acb51ff31cfb69a53f4e127996bf194bcac770e8fa67cb5ba3fb16a496058", size = 260029, upload-time = "2025-01-14T19:03:08.609Z" }
wheels = [
@@ -2544,8 +2546,8 @@ name = "pyobjc-framework-corehaptics"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2a/b8/66481497362171e7ad42fc8fcc0272c04b95a707c5c1e7e8f8a8bfe58917/pyobjc_framework_corehaptics-11.0.tar.gz", hash = "sha256:1949b56ac0bd4219eb04c466cdd0f7f93d6826ed92ee61f01a4b5e98139ee039", size = 42956, upload-time = "2025-01-14T19:03:09.753Z" }
wheels = [
@@ -2558,8 +2560,8 @@ name = "pyobjc-framework-corelocation"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0a/2d/b21ca49a34db49390420a9d7d05fd9eb89850dbec0a555c9ee408f52609c/pyobjc_framework_corelocation-11.0.tar.gz", hash = "sha256:05055c3b567f7f8f796845da43fb755d84d630909b927a39f25cf706ef52687d", size = 103955, upload-time = "2025-01-14T19:03:10.707Z" }
wheels = [
@@ -2572,8 +2574,8 @@ name = "pyobjc-framework-coremedia"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/02/60/7c7b9f13c94910882de6cc08f48a52cce9739e75cc3b3b6de5c857e6536a/pyobjc_framework_coremedia-11.0.tar.gz", hash = "sha256:a414db97ba30b43c9dd96213459d6efb169f9e92ce1ad7a75516a679b181ddfb", size = 249161, upload-time = "2025-01-14T19:03:12.291Z" }
wheels = [
@@ -2586,8 +2588,8 @@ name = "pyobjc-framework-coremediaio"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a1/59/904af57d302caa4c20d3bfebb9fb9300ccc3c396134460821c9f1e8ab65b/pyobjc_framework_coremediaio-11.0.tar.gz", hash = "sha256:7d652cf1a2a75c78ea6e8dbc7fc8b782bfc0f07eafc84b700598172c82f373d8", size = 107856, upload-time = "2025-01-14T19:03:14.225Z" }
wheels = [
@@ -2600,8 +2602,8 @@ name = "pyobjc-framework-coremidi"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/90/d004cdf4c52b8b16842e15135495de882d743b4f0217946bd8ae1a920173/pyobjc_framework_coremidi-11.0.tar.gz", hash = "sha256:acace4448b3e4802ab5dd75bbf875aae5e1f6c8cab2b2f1d58af20fc8b2a5a7f", size = 107342, upload-time = "2025-01-14T19:03:15.235Z" }
wheels = [
@@ -2614,8 +2616,8 @@ name = "pyobjc-framework-coreml"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2e/64/4f0a990ec0955fe9b88f1fa58303c8471c551996670216527b4ac559ed8f/pyobjc_framework_coreml-11.0.tar.gz", hash = "sha256:143a1f73a0ea0a0ea103f3175cb87a61bbcb98f70f85320ed4c61302b9156d58", size = 81452, upload-time = "2025-01-14T19:03:16.283Z" }
wheels = [
@@ -2628,8 +2630,8 @@ name = "pyobjc-framework-coremotion"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/be/79/5c4ff39a48f0dc0f764d1330b2360e9f31e3a32414e8690e7f20e4574e93/pyobjc_framework_coremotion-11.0.tar.gz", hash = "sha256:d1e7ca418897e35365d07c6fd5b5d625a3c44261b6ce46dcf80787f634ad6fa5", size = 66508, upload-time = "2025-01-14T19:03:17.254Z" }
wheels = [
@@ -2642,9 +2644,9 @@ name = "pyobjc-framework-coreservices"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-fsevents" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-fsevents", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ca/b5/19c096b9938d6e2fdb1b436f21ad989b77dbeb4e59b3db4bd344800fa1e8/pyobjc_framework_coreservices-11.0.tar.gz", hash = "sha256:ac96954f1945a1153bdfef685611665749eaa8016b5af6f34bd56a274952b03a", size = 1244406, upload-time = "2025-01-14T19:03:19.202Z" }
wheels = [
@@ -2657,8 +2659,8 @@ name = "pyobjc-framework-corespotlight"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fc/6a/6707d7ef339b9ad2dd0994d1df42969ee3b231f2d098f3377d40aed60b4f/pyobjc_framework_corespotlight-11.0.tar.gz", hash = "sha256:a96c9b4ba473bc3ee19afa01a9af989458e6a56e9656c2cdea1850d2b13720e6", size = 86130, upload-time = "2025-01-14T19:03:20.457Z" }
wheels = [
@@ -2671,9 +2673,9 @@ name = "pyobjc-framework-coretext"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9d/e8/9b68dc788828e38143a3e834e66346713751cb83d7f0955016323005c1a2/pyobjc_framework_coretext-11.0.tar.gz", hash = "sha256:a68437153e627847e3898754dd3f13ae0cb852246b016a91f9c9cbccb9f91a43", size = 274222, upload-time = "2025-01-14T19:03:21.521Z" }
wheels = [
@@ -2686,8 +2688,8 @@ name = "pyobjc-framework-corewlan"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2e/a9/cda522b270adb75d62bae447b2131da62912b5eda058a07e3a433689116f/pyobjc_framework_corewlan-11.0.tar.gz", hash = "sha256:8803981d64e3eb4fa0ea56657a9b98e4004de5a84d56e32e5444815d8ed6fa6f", size = 65254, upload-time = "2025-01-14T19:03:23.938Z" }
wheels = [
@@ -2700,8 +2702,8 @@ name = "pyobjc-framework-cryptotokenkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b8/72/b871fa5476479e4a22a4a0e971fb4724b0eb94c721365539ad55f4dc3135/pyobjc_framework_cryptotokenkit-11.0.tar.gz", hash = "sha256:a1bbfe9170c35cb427d39167af55aefea651c5c8a45c0de60226dae04b61a6b1", size = 58734, upload-time = "2025-01-14T19:03:24.851Z" }
wheels = [
@@ -2714,8 +2716,8 @@ name = "pyobjc-framework-datadetection"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/33/6b/b896feb16e914dc81b6ed6cdbd0b6e6390eaafc80fff5297ec17eb0bd716/pyobjc_framework_datadetection-11.0.tar.gz", hash = "sha256:9967555151892f8400cffac86e8656f2cb8d7866963fdee255e0747fa1386533", size = 13738, upload-time = "2025-01-14T19:03:27.054Z" }
wheels = [
@@ -2728,8 +2730,8 @@ name = "pyobjc-framework-devicecheck"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/de/f8/237a92dd9ba8a88b7027f78cba83e61b0011bfc2a49351ecaa177233f639/pyobjc_framework_devicecheck-11.0.tar.gz", hash = "sha256:66cff0323dc8eef1b76d60f9c9752684f11e534ebda60ecbf6858a9c73553f64", size = 14198, upload-time = "2025-01-14T19:03:27.918Z" }
wheels = [
@@ -2742,8 +2744,8 @@ name = "pyobjc-framework-devicediscoveryextension"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e1/48/178a1879109128f34334fdae2fe4463c7620f169593bea96704f347d945e/pyobjc_framework_devicediscoveryextension-11.0.tar.gz", hash = "sha256:576dac3f418cfc4f71020a45f06231d14e4b2a8e182ef0020dd9da3cf238d02f", size = 14511, upload-time = "2025-01-14T19:03:32.132Z" }
wheels = [
@@ -2756,8 +2758,8 @@ name = "pyobjc-framework-dictionaryservices"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-coreservices" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d8/cf/2913c7df737eb8519acb7ef6429127e40d6c334415e38cfa18d6481150eb/pyobjc_framework_dictionaryservices-11.0.tar.gz", hash = "sha256:6b5f27c75424860f169e7c7e182fabffdba22854fedb8023de180e8770661dce", size = 10823, upload-time = "2025-01-14T19:03:32.942Z" }
wheels = [
@@ -2770,8 +2772,8 @@ name = "pyobjc-framework-discrecording"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/cc/f36612b67ca1fff7659d7933b563dce61f8c84dad0bf79fab08bb34949ad/pyobjc_framework_discrecording-11.0.tar.gz", hash = "sha256:6bdc533f067d049ea5032f65af70b5cdab68673574ac32dacb46509a9411d256", size = 122426, upload-time = "2025-01-14T19:03:35.589Z" }
wheels = [
@@ -2784,9 +2786,9 @@ name = "pyobjc-framework-discrecordingui"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-discrecording" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-discrecording", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d4/6b/3c120c59a939854dd4b7a162fad47011375c5ba00a12940f7217aea90eeb/pyobjc_framework_discrecordingui-11.0.tar.gz", hash = "sha256:bec8a252fd2022dce6c58b1f3366a7295efb0c7c77817f11f9efcce70527d7a2", size = 19614, upload-time = "2025-01-14T19:03:36.695Z" }
wheels = [
@@ -2799,8 +2801,8 @@ name = "pyobjc-framework-diskarbitration"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/43/fb/5d3ff093144f499904b1e1bce18d010fe2171b9be62b4679d3dda8b3ad19/pyobjc_framework_diskarbitration-11.0.tar.gz", hash = "sha256:1c3e21398b366a1ce96cf68501a2e415f5ccad4b43a3e7cc901e09e896dfb545", size = 20096, upload-time = "2025-01-14T19:03:37.659Z" }
wheels = [
@@ -2813,8 +2815,8 @@ name = "pyobjc-framework-dvdplayback"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c0/89/89ebee4863fd6f173bff9373b5bda4ffa87eba6197337617ab086e23c7d5/pyobjc_framework_dvdplayback-11.0.tar.gz", hash = "sha256:9a005f441afbc34aea301857e166fd650d82762a75d024253e18d1102b21b2f8", size = 64798, upload-time = "2025-01-14T19:03:38.491Z" }
wheels = [
@@ -2827,8 +2829,8 @@ name = "pyobjc-framework-eventkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/54/13/38a98e5cee62e1655d84cfb88cad54fdec4ec272b5fd0c5ac3fc21e33e49/pyobjc_framework_eventkit-11.0.tar.gz", hash = "sha256:3d412203a510b3d62a5eb0987406e0951b13ed39c3351c0ec874afd72496627c", size = 75399, upload-time = "2025-01-14T19:03:39.441Z" }
wheels = [
@@ -2841,8 +2843,8 @@ name = "pyobjc-framework-exceptionhandling"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cc/46/6c2c4805697a0cfb8413eb7bc6901298e7a1febd49bb1ea960274fc33af3/pyobjc_framework_exceptionhandling-11.0.tar.gz", hash = "sha256:b11562c6eeaef5d8d43e9d817cf50feceb02396e5eb6a7f61df2c0cec93d912b", size = 18157, upload-time = "2025-01-14T19:03:40.393Z" }
wheels = [
@@ -2855,8 +2857,8 @@ name = "pyobjc-framework-executionpolicy"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ab/91/2e4cacbdabf01bc1207817edacc814b6bc486df12e857a8d86964d98fef4/pyobjc_framework_executionpolicy-11.0.tar.gz", hash = "sha256:de953a8acae98079015b19e75ec8154a311ac1a70fb6d885e17fab09464c98a9", size = 13753, upload-time = "2025-01-14T19:03:42.353Z" }
wheels = [
@@ -2869,8 +2871,8 @@ name = "pyobjc-framework-extensionkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/22/98/803e3cb000dac227eb0d223802a0aeb052d34a741e572d9584e7d83afca7/pyobjc_framework_extensionkit-11.0.tar.gz", hash = "sha256:82d9e79532e5a0ff0eadf1ccac236c5d3dca344e1090a0f3e88519faa24143c7", size = 19200, upload-time = "2025-01-14T19:03:43.188Z" }
wheels = [
@@ -2883,8 +2885,8 @@ name = "pyobjc-framework-externalaccessory"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/67/b0/ac0a02fe26e66c33fee751a65c1ed06bbd2934db8636e08bb491e8334bad/pyobjc_framework_externalaccessory-11.0.tar.gz", hash = "sha256:39e59331ced75cdcccf23bb5ffe0fa9d67e0c190c1da8887a0e4349b7e27584f", size = 22577, upload-time = "2025-01-14T19:03:44.021Z" }
wheels = [
@@ -2897,8 +2899,8 @@ name = "pyobjc-framework-fileprovider"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/44/fc/b8593d8645b9933e60a885f451d0c12d9c0e1b00e62121d8660d95852dff/pyobjc_framework_fileprovider-11.0.tar.gz", hash = "sha256:dcc3ac3c90117c1b8027ea5f26dad6fe5045f688ce3e60d07ece12ec56e17ab3", size = 78701, upload-time = "2025-01-14T19:03:44.931Z" }
wheels = [
@@ -2911,8 +2913,8 @@ name = "pyobjc-framework-fileproviderui"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-fileprovider" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-fileprovider", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3d/9d/ca4aed36e6188623e9da633634af772f239bee74934322e1c19ae7b79a53/pyobjc_framework_fileproviderui-11.0.tar.gz", hash = "sha256:cf5c7d32b29d344b65217397eea7b1a2913ce52ce923c9e04135a7a298848d04", size = 13419, upload-time = "2025-01-14T19:03:46.016Z" }
wheels = [
@@ -2925,8 +2927,8 @@ name = "pyobjc-framework-findersync"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f6/e3/24df6e24b589073815be13f2943b93feb12afbf558f6e54c4033b57c29ee/pyobjc_framework_findersync-11.0.tar.gz", hash = "sha256:8dab3feff5debd6bc3746a21ded991716723d98713d1ba37cec1c5e2ad78ee63", size = 15295, upload-time = "2025-01-14T19:03:46.91Z" }
wheels = [
@@ -2939,8 +2941,8 @@ name = "pyobjc-framework-fsevents"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/82/37/4c09cc7b8678e2bb5b68ebc62e817eb88c409b1c41bdc1510d7d24a0372d/pyobjc_framework_fsevents-11.0.tar.gz", hash = "sha256:e01dab04704a518e4c3e1f7d8722819a4f228d5082978e11618aa7abba3883fe", size = 29078, upload-time = "2025-01-14T19:03:49.762Z" }
wheels = [
@@ -2953,8 +2955,8 @@ name = "pyobjc-framework-gamecenter"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7f/3b/e66caebc948d9fe3b2671659caab220aff6d5e80ac25442d83331b523d23/pyobjc_framework_gamecenter-11.0.tar.gz", hash = "sha256:18a05500dbcf2cca4a0f05839ec010c76ee08ab65b65020c9538a31feb274483", size = 31459, upload-time = "2025-01-14T19:03:50.766Z" }
wheels = [
@@ -2967,8 +2969,8 @@ name = "pyobjc-framework-gamecontroller"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fa/30/02ca5a4fb911acf3e8018abcbd29631a842aeac02958ae91fab1acb13ad1/pyobjc_framework_gamecontroller-11.0.tar.gz", hash = "sha256:6d62f4493d634eba03a43a14c4d1e4511e1e3a2ca2e9cbefa6ae9278a272c1d0", size = 115318, upload-time = "2025-01-14T19:03:52.264Z" }
wheels = [
@@ -2981,9 +2983,9 @@ name = "pyobjc-framework-gamekit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3f/df/c161460e5736a34f9b59aa0a3f2d6ad1d1cd9a913aa63c89c41a6ba3b6ae/pyobjc_framework_gamekit-11.0.tar.gz", hash = "sha256:29b5464ca78f0de62e6b6d56e80bbeccb96dc13820b6d5b4e835ab1cc127e5b9", size = 164394, upload-time = "2025-01-14T19:03:53.762Z" }
wheels = [
@@ -2996,9 +2998,9 @@ name = "pyobjc-framework-gameplaykit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-spritekit" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-spritekit", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/41/f0/980c4fc3c594d9726b7eb6ae83f73127b22560e1541c7d272d23d17fdf0d/pyobjc_framework_gameplaykit-11.0.tar.gz", hash = "sha256:90eeec464fba992d75a406ccbddb35ed7420a4f5226f19c018982fa3ba7bf431", size = 72837, upload-time = "2025-01-14T19:03:56.127Z" }
wheels = [
@@ -3011,8 +3013,8 @@ name = "pyobjc-framework-healthkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7b/2f/d79d2ec7c23bfc94bfaa7b7c6f6487a8bffdb73263eea6900aab56135889/pyobjc_framework_healthkit-11.0.tar.gz", hash = "sha256:e78ccb05f747ae3e70b5d73522030b7ba01ef2d390155fba7d50c1c614ae241f", size = 201558, upload-time = "2025-01-14T19:03:57.117Z" }
wheels = [
@@ -3025,8 +3027,8 @@ name = "pyobjc-framework-imagecapturecore"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/38/fe/db1fc3ffd784a9010070cd87a05d7fd2542c400395589341fab5970a01e1/pyobjc_framework_imagecapturecore-11.0.tar.gz", hash = "sha256:f5d185d8c8b564f8b4a815381bcdb424b10d203ba5bdf0fc887085e007df6f7a", size = 99935, upload-time = "2025-01-14T19:03:58.548Z" }
wheels = [
@@ -3039,8 +3041,8 @@ name = "pyobjc-framework-inputmethodkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e7/e9/13d007285582e598903264a7d25cc6771a2a52d6c2a96a68fe91db0844fb/pyobjc_framework_inputmethodkit-11.0.tar.gz", hash = "sha256:86cd648bf98c4e777c884b7f69ebcafba84866740430d297645bf388eee6ce52", size = 26684, upload-time = "2025-01-14T19:03:59.525Z" }
wheels = [
@@ -3053,8 +3055,8 @@ name = "pyobjc-framework-installerplugins"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f2/f3/0379655e8ea3566002768d5e7b3ccd72ca845390632a8dabf801348af3a7/pyobjc_framework_installerplugins-11.0.tar.gz", hash = "sha256:88ec84e6999e8b2df874758b09878504a4fbfc8471cf3cd589d57e556f5b916e", size = 27687, upload-time = "2025-01-14T19:04:00.515Z" }
wheels = [
@@ -3067,9 +3069,9 @@ name = "pyobjc-framework-instantmessage"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/08/4d/6810a1f2039ff24d9498858b3ebb46357d4091aa5cec9ff4e41bbcdb25de/pyobjc_framework_instantmessage-11.0.tar.gz", hash = "sha256:ec5c4c70c9b0e61ae82888067246e4f931e700d625b3c42604e54759d4fbf65c", size = 34027, upload-time = "2025-01-14T19:04:01.405Z" }
wheels = [
@@ -3082,8 +3084,8 @@ name = "pyobjc-framework-intents"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/56/88/07e47b0c5c46fe97c23c883ae7a053c2ca6f6fd6afe851d1c2c784644f0f/pyobjc_framework_intents-11.0.tar.gz", hash = "sha256:6405c816dfed8ffa8b3f8b0fae75f61d64787dbae8db1c475bb4450cf8fdf6b5", size = 447921, upload-time = "2025-01-14T19:04:02.487Z" }
wheels = [
@@ -3096,8 +3098,8 @@ name = "pyobjc-framework-intentsui"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-intents" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-intents", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ee/96/3b3b367f70a4d0a60d2c6251e4a1f4bf470945ae939e0ba20e6d56d10c7a/pyobjc_framework_intentsui-11.0.tar.gz", hash = "sha256:4ce04f926c823fbc1fba7d9c5b33d512b514396719e6bc50ef65b82774e42bc5", size = 20774, upload-time = "2025-01-14T19:04:03.648Z" }
wheels = [
@@ -3110,8 +3112,8 @@ name = "pyobjc-framework-iobluetooth"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1e/46/62913f8e5ac307b154b3dd50a7a0b167c9d7ac2a579223e33208c141c387/pyobjc_framework_iobluetooth-11.0.tar.gz", hash = "sha256:869f01f573482da92674abbae4a154143e993b1fe4b2c3523f9e0f9c48b798d4", size = 300463, upload-time = "2025-01-14T19:04:04.582Z" }
wheels = [
@@ -3124,8 +3126,8 @@ name = "pyobjc-framework-iobluetoothui"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-iobluetooth" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-iobluetooth", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/76/55/d194de8cfa63c96970e6c90c35e80ce3fceb42934a85d3728736a0e416ff/pyobjc_framework_iobluetoothui-11.0.tar.gz", hash = "sha256:a583758d3e54149ee2dcf00374685aa99e8ae407e044f7c378acc002f9f27e63", size = 23091, upload-time = "2025-01-14T19:04:05.659Z" }
wheels = [
@@ -3138,8 +3140,8 @@ name = "pyobjc-framework-iosurface"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fb/91/ae9ca9e1a777eb786d9d43649437d01d24386736cffe9bb2f504b57e8db6/pyobjc_framework_iosurface-11.0.tar.gz", hash = "sha256:24da8d1cf9356717b1c7e75a1c61e9a9417b62f051d13423a4a7b0978d3dcda5", size = 20555, upload-time = "2025-01-14T19:04:09.475Z" }
wheels = [
@@ -3152,8 +3154,8 @@ name = "pyobjc-framework-ituneslibrary"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/41/fe/881ab1058d795fe68ccc1e14df0d5e161601dced15d3be84105ecc44bae6/pyobjc_framework_ituneslibrary-11.0.tar.gz", hash = "sha256:2e15dcfbb9d5e95634ddff153de159a28f5879f1a13fdf95504e011773056c6e", size = 47647, upload-time = "2025-01-14T19:04:11.333Z" }
wheels = [
@@ -3166,8 +3168,8 @@ name = "pyobjc-framework-kernelmanagement"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4a/ea/8ef534fce78817fc577f18de2b34e363873f785894f2bbbfc694823f5088/pyobjc_framework_kernelmanagement-11.0.tar.gz", hash = "sha256:812479d5f85eae27aeeaa22f64c20b926b28b5b9b2bf31c8eab9496d3e038028", size = 12794, upload-time = "2025-01-14T19:04:14.204Z" }
wheels = [
@@ -3180,8 +3182,8 @@ name = "pyobjc-framework-latentsemanticmapping"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/42/29/8838eefeb82da95931134b06624364812dedf7e9cc905f36d95d497f2904/pyobjc_framework_latentsemanticmapping-11.0.tar.gz", hash = "sha256:6f578c3e0a171706bdbfcfc2c572a8059bf8039d22c1475df13583749a35cec1", size = 17704, upload-time = "2025-01-14T19:04:14.972Z" }
wheels = [
@@ -3194,8 +3196,8 @@ name = "pyobjc-framework-launchservices"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-coreservices" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/da/59/eb847389224c670c885ae3d008b1ffe3b996bbe094b43e49dfa84f3947a9/pyobjc_framework_launchservices-11.0.tar.gz", hash = "sha256:7c5c8a8cec013e2cb3fa82a167ca2d61505c36a79f75c718f3f913e597f9ffee", size = 20691, upload-time = "2025-01-14T19:04:15.884Z" }
wheels = [
@@ -3208,8 +3210,8 @@ name = "pyobjc-framework-libdispatch"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ab/33/4ec96a9edd37948f09e94635852c2db695141430cc1adc7b25968e1f3a95/pyobjc_framework_libdispatch-11.0.tar.gz", hash = "sha256:d22df11b07b1c3c8e7cfc4ba9e876a95c19f44acd36cf13d40c5cccc1ffda04b", size = 53496, upload-time = "2025-01-14T19:04:16.82Z" }
wheels = [
@@ -3222,8 +3224,8 @@ name = "pyobjc-framework-libxpc"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b9/7e/9fa73ce6925db9cfd8a6b45d97943af8fe59f92251e7fd201b6e4608c172/pyobjc_framework_libxpc-11.0.tar.gz", hash = "sha256:e0c336913ab6a526b036915aa9038de2a5281e696ac2d3db3347b3040519c11d", size = 48627, upload-time = "2025-01-14T19:04:17.728Z" }
wheels = [
@@ -3236,9 +3238,9 @@ name = "pyobjc-framework-linkpresentation"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/95/5c/dac9fe4ad0a4076c863b5ac9925e751fc18c637ae411e4891c4b7558a5b3/pyobjc_framework_linkpresentation-11.0.tar.gz", hash = "sha256:bc4ace4aab4da4a4e4df10517bd478b6d51ebf00b423268ee8d9f356f9e87be9", size = 15231, upload-time = "2025-01-14T19:04:20.763Z" }
wheels = [
@@ -3251,9 +3253,9 @@ name = "pyobjc-framework-localauthentication"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-security" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ec/b1/bea4b5f8adbb69c0b34eddee63e052f35271cc630db43fbef6873352e21f/pyobjc_framework_localauthentication-11.0.tar.gz", hash = "sha256:eb55a3de647894092d6ed3f8f13fdc38e5dbf4850be320ea14dd2ac83176b298", size = 40020, upload-time = "2025-01-14T19:04:22.206Z" }
wheels = [
@@ -3266,9 +3268,9 @@ name = "pyobjc-framework-localauthenticationembeddedui"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-localauthentication" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-localauthentication", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e1/ee/821f2d2e9da4cba3dc47e50c8367c6405e91551fb7d8ec842858d5b1d45d/pyobjc_framework_localauthenticationembeddedui-11.0.tar.gz", hash = "sha256:7e9bf6df77ff12a4e827988d8578c15b4431694b2fcfd5b0dad5d7738757ee6a", size = 14204, upload-time = "2025-01-14T19:04:23.566Z" }
wheels = [
@@ -3281,8 +3283,8 @@ name = "pyobjc-framework-mailkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d8/79/9c9140f726ba14898762ddc19e7142724e0ce5930f08eb20f33f78b05be8/pyobjc_framework_mailkit-11.0.tar.gz", hash = "sha256:d08a2dcc95b5e7955c7c385fe6e018325113d02c007c4178d3fb3c9ab326c163", size = 32274, upload-time = "2025-01-14T19:04:25.086Z" }
wheels = [
@@ -3295,10 +3297,10 @@ name = "pyobjc-framework-mapkit"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-corelocation", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/7e/ef86c6e218a58bb9497ce9754a77f12ffe01c4b3609279727b7d7e44655a/pyobjc_framework_mapkit-11.0.tar.gz", hash = "sha256:cd8a91df4c0b442fcf1b14d735e566a06b21b3f48a2a4afe269fca45bfa49117", size = 165080, upload-time = "2025-01-14T19:04:26.606Z" }
wheels = [
@@ -3311,8 +3313,8 @@ name = "pyobjc-framework-mediaaccessibility"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/81/8e/9fe2cb251ff6107a03bafa07f63b6593df145a2579fffb096023fb21b167/pyobjc_framework_mediaaccessibility-11.0.tar.gz", hash = "sha256:1298cc0128e1c0724e8f8e63a6167ea6809a985922c67399b997f8243de59ab4", size = 18671, upload-time = "2025-01-14T19:04:27.624Z" }
wheels = [
@@ -3325,10 +3327,10 @@ name = "pyobjc-framework-mediaextension"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-avfoundation" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-coremedia" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/18/1f/e31d9431bc71077b09583ea863b3c91b7de9371d0cc17a8be99be8119daa/pyobjc_framework_mediaextension-11.0.tar.gz", hash = "sha256:ecd8a64939e1c16be005690117c21fd406fc04d3036e2adea7600d2a0c53f4ea", size = 57931, upload-time = "2025-01-14T19:04:28.65Z" }
wheels = [
@@ -3341,9 +3343,9 @@ name = "pyobjc-framework-medialibrary"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/a4/8c7d1635994800dc412a5db2c4b43ed499184651efcec0c8da3cf8e2bcc7/pyobjc_framework_medialibrary-11.0.tar.gz", hash = "sha256:692889fab1e479a9c207f0ff23c900dad5f47caf47c05cc995d9bb7c1e56e8b9", size = 18975, upload-time = "2025-01-14T19:04:29.739Z" }
wheels = [
@@ -3356,8 +3358,8 @@ name = "pyobjc-framework-mediaplayer"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-avfoundation" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a2/ce/3d2783f2f96ddf51bebcf6537a4a0f2a8a1fe4e520de218fc1b7c5b219ed/pyobjc_framework_mediaplayer-11.0.tar.gz", hash = "sha256:c61be0ba6c648db6b1d013a52f9afb8901a8d7fbabd983df2175c1b1fbff81e5", size = 94020, upload-time = "2025-01-14T19:04:30.617Z" }
wheels = [
@@ -3370,8 +3372,8 @@ name = "pyobjc-framework-mediatoolbox"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/da/46/cf5f3bde6cad32f10095850ca44f24ba241d18b26379187c412be1260f39/pyobjc_framework_mediatoolbox-11.0.tar.gz", hash = "sha256:de949a44f10b5a15e5a7131ee53b2806b8cb753fd01a955970ec0f475952ba24", size = 23067, upload-time = "2025-01-14T19:04:32.823Z" }
wheels = [
@@ -3384,8 +3386,8 @@ name = "pyobjc-framework-metal"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/77/e0/a6d18a1183410a5d8610ca1ae6c065b8944586441f8669faee7509817246/pyobjc_framework_metal-11.0.tar.gz", hash = "sha256:cad390150aa63502d5cfe242026b55ed39ffaf816342ddf51e44a9aead6c24be", size = 446102, upload-time = "2025-01-14T19:04:34.011Z" }
wheels = [
@@ -3398,8 +3400,8 @@ name = "pyobjc-framework-metalfx"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-metal" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/68/cf/ff9367e4737a12ebd12a17e693ec247028cf065761acc073ebefb2b2393a/pyobjc_framework_metalfx-11.0.tar.gz", hash = "sha256:2ae41991bf7a733c44fcd5b6550cedea3accaaf0f529643975d3da113c9f0caa", size = 26436, upload-time = "2025-01-14T19:04:36.161Z" }
wheels = [
@@ -3412,9 +3414,9 @@ name = "pyobjc-framework-metalkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-metal" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/92/27/fb3c1b10914abf2ae6682837abf76bcd8cb7af2ba613fbc55fb9d055bb95/pyobjc_framework_metalkit-11.0.tar.gz", hash = "sha256:1bbbe35c7c6a481383d32f6eaae59a1cd8084319a65c1aa343d63a257d8b4ddb", size = 44628, upload-time = "2025-01-14T19:04:36.977Z" }
wheels = [
@@ -3427,8 +3429,8 @@ name = "pyobjc-framework-metalperformanceshaders"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-metal" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/14/c2/c08996a8c6cfef09fb9e726cc99b0bf3ad0ffcef66d5c2543e6b35dd4e2e/pyobjc_framework_metalperformanceshaders-11.0.tar.gz", hash = "sha256:41179e3a11e55325153fffd84f48946d47c1dc1944677febd871a127021e056d", size = 301444, upload-time = "2025-01-14T19:04:38.064Z" }
wheels = [
@@ -3441,8 +3443,8 @@ name = "pyobjc-framework-metalperformanceshadersgraph"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-metalperformanceshaders" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-metalperformanceshaders", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b5/b8/353852c76eb437e907ca0acf8a5b5f9255e9b9ee8c0706b69b0c17498f97/pyobjc_framework_metalperformanceshadersgraph-11.0.tar.gz", hash = "sha256:33077ebbbe1aa7787de2552a83534be6c439d7f4272de17915a85fda8fd3b72d", size = 105381, upload-time = "2025-01-14T19:04:39.831Z" }
wheels = [
@@ -3455,8 +3457,8 @@ name = "pyobjc-framework-metrickit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/28/82/605ad654f40ff4480ba9366ad3726da80c98e33b73f122fb91259be1ce81/pyobjc_framework_metrickit-11.0.tar.gz", hash = "sha256:ee3da403863beec181a2d6dc7b7eeb4d07e954b88bbabac58a82523b2f83fdc7", size = 40414, upload-time = "2025-01-14T19:04:41.186Z" }
wheels = [
@@ -3469,8 +3471,8 @@ name = "pyobjc-framework-mlcompute"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c5/c9/22fe4720685724ec1444c8e5cdb41d360b1434d0971fb3e43cf3e9bf51fd/pyobjc_framework_mlcompute-11.0.tar.gz", hash = "sha256:1a1ee9ab43d1824300055ff94b042a26f38f1d18f6f0aa08be1c88278e7284d9", size = 89265, upload-time = "2025-01-14T19:04:43.326Z" }
wheels = [
@@ -3483,9 +3485,9 @@ name = "pyobjc-framework-modelio"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ca/7c/b75b84d41e7854ffe9c9a42846f8105227a5fd0b02b690b4a75018b2caa3/pyobjc_framework_modelio-11.0.tar.gz", hash = "sha256:c875eb6ff7f94d18362a00faaa3016ae0c28140326338d18aa03c0b62f1c6b9d", size = 122652, upload-time = "2025-01-14T19:04:44.263Z" }
wheels = [
@@ -3498,8 +3500,8 @@ name = "pyobjc-framework-multipeerconnectivity"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/14/80/4137cb9751aa3846c4954b3e61f948aae17afeb6851e01194aa50683caef/pyobjc_framework_multipeerconnectivity-11.0.tar.gz", hash = "sha256:8278a3483c0b6b88a8888ca76c46fd85808f9df56d45708cbc4e4182a5565cd3", size = 25534, upload-time = "2025-01-14T19:04:45.211Z" }
wheels = [
@@ -3512,8 +3514,8 @@ name = "pyobjc-framework-naturallanguage"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/62/64/63e97635fa637384bc8c980796573dc7a9e7074a6866aef073b1faf3e11d/pyobjc_framework_naturallanguage-11.0.tar.gz", hash = "sha256:4c9471fa2c48a8fd4899de4406823e66cb0292dbba7b471622017f3647d53fa4", size = 46385, upload-time = "2025-01-14T19:04:46.185Z" }
wheels = [
@@ -3526,8 +3528,8 @@ name = "pyobjc-framework-netfs"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c7/29/eb569870b52c7581104ed2806cae2d425d60b5ab304128cd58155d5b567f/pyobjc_framework_netfs-11.0.tar.gz", hash = "sha256:3de5f627a62addf4aab8a4d2d07213e9b2b6c8adbe6cc4c332ee868075785a6a", size = 16173, upload-time = "2025-01-14T19:04:47.11Z" }
wheels = [
@@ -3540,8 +3542,8 @@ name = "pyobjc-framework-network"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/78/8e/18e55aff83549e041484d2ee94dd91b29cec9de40508e7fe9c4afec110a7/pyobjc_framework_network-11.0.tar.gz", hash = "sha256:d4dcc02773d7d642a385c7f0d951aeb7361277446c912a49230cddab60a65ab8", size = 124160, upload-time = "2025-01-14T19:04:50.191Z" }
wheels = [
@@ -3554,8 +3556,8 @@ name = "pyobjc-framework-networkextension"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/59/90/97dcfac5895b07e891adf634c3a074b68992d132ccfab386c186ac1a598c/pyobjc_framework_networkextension-11.0.tar.gz", hash = "sha256:5ba2254e2c13010b6c4f1e2948047d95eff86bfddfc77716747718fa3a8cb1af", size = 188551, upload-time = "2025-01-14T19:04:51.352Z" }
wheels = [
@@ -3568,8 +3570,8 @@ name = "pyobjc-framework-notificationcenter"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d7/d0/f0a602e01173531a2b639e283a092cf1f307fd873abd2ed590b9c4122337/pyobjc_framework_notificationcenter-11.0.tar.gz", hash = "sha256:f878b318c693d63d6b8bd1c3e2ad4f8097b22872f18f40142e394d84f1ead9f6", size = 22844, upload-time = "2025-01-14T19:04:52.459Z" }
wheels = [
@@ -3582,8 +3584,8 @@ name = "pyobjc-framework-opendirectory"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/55/cf/ba0cf807758acdc6a19e4787fdcda2eb59034aa22c4203d04fd49b276981/pyobjc_framework_opendirectory-11.0.tar.gz", hash = "sha256:0c82594f4f0bcf2318c4641527f9243962d7b03e67d4f3fb111b899a299fc7eb", size = 189165, upload-time = "2025-01-14T19:04:53.42Z" }
wheels = [
@@ -3596,8 +3598,8 @@ name = "pyobjc-framework-osakit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d3/4a/e49680f7f3ab9c0632ed9be76a0a59299e7fd797335690b3da4d117f2d7b/pyobjc_framework_osakit-11.0.tar.gz", hash = "sha256:77ac18e2660133a9eeb01c76ad3df3b4b36fd29005fc36bca00f57cca121aac3", size = 22535, upload-time = "2025-01-14T19:04:54.753Z" }
wheels = [
@@ -3610,10 +3612,10 @@ name = "pyobjc-framework-oslog"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b0/93/0a72353d0212a815bd5e43aec528ce7b28b71d461d26e5fa3882ff96ffa3/pyobjc_framework_oslog-11.0.tar.gz", hash = "sha256:9d29eb7c89a41d7c702dffb6e2e338a2d5219387c8dae22b67754ddf9e2fcb3f", size = 24151, upload-time = "2025-01-14T19:04:55.587Z" }
wheels = [
@@ -3626,8 +3628,8 @@ name = "pyobjc-framework-passkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cb/f8/ebb2bc840f87292a4f60080463ee698ca08516cc958364741dfff2858b33/pyobjc_framework_passkit-11.0.tar.gz", hash = "sha256:2044d9d634dd98b7b624ee09487b27e5f26a7729f6689abba23a4a011febe19c", size = 120495, upload-time = "2025-01-14T19:04:57.689Z" }
wheels = [
@@ -3640,8 +3642,8 @@ name = "pyobjc-framework-pencilkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f4/8d/1e97cd72b776e5e1294cbda84325b364702617dd435d32448dcc0a80bd93/pyobjc_framework_pencilkit-11.0.tar.gz", hash = "sha256:9598c28e83f5b7f091592cc1af2b16f7ae94cf00045d8d14ed2c17cb9e4ffd50", size = 22812, upload-time = "2025-01-14T19:04:58.652Z" }
wheels = [
@@ -3654,8 +3656,8 @@ name = "pyobjc-framework-phase"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-avfoundation" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d2/a2/65182dcb44fceb2173f4134d6cd4325dfd0731225b621aa2027d2a03d043/pyobjc_framework_phase-11.0.tar.gz", hash = "sha256:e06a0f8308ae4f3731f88b3e1239b7bdfdda3eef97023e3ce972e2f386451d80", size = 59214, upload-time = "2025-01-14T19:04:59.461Z" }
wheels = [
@@ -3668,8 +3670,8 @@ name = "pyobjc-framework-photos"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f7/c3/fc755c1f8f411433d7ba2e92f3fe3e7b417e9629675ad6baf94ac8b01e64/pyobjc_framework_photos-11.0.tar.gz", hash = "sha256:cfdfdefb0d560b091425227d5c0e24a40b445b5251ff4d37bd326cd8626b80cd", size = 92122, upload-time = "2025-01-14T19:05:01.804Z" }
wheels = [
@@ -3682,8 +3684,8 @@ name = "pyobjc-framework-photosui"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e4/2c/70ac99fb2b7ba14d220c78cf6401c0c7a47992269f85f699220a6a2cff09/pyobjc_framework_photosui-11.0.tar.gz", hash = "sha256:3c65342e31f6109d8229992b2712b29cab1021475969b55f4f215dd97e2a99db", size = 47898, upload-time = "2025-01-14T19:05:02.737Z" }
wheels = [
@@ -3696,8 +3698,8 @@ name = "pyobjc-framework-preferencepanes"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/35/01/81cc46e0a92d15f2b664b2efdcc8fd310acac570c9f63a99d446e0489784/pyobjc_framework_preferencepanes-11.0.tar.gz", hash = "sha256:ee000c351befeb81f4fa678ada85695ca4af07933b6bd9b1947164e16dd0b3e5", size = 26419, upload-time = "2025-01-14T19:05:03.787Z" }
wheels = [
@@ -3710,8 +3712,8 @@ name = "pyobjc-framework-pushkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/17/ab/7fe55ce5b32c434142be026ec27b1801a2d4694b159b502f9ecd568eebf2/pyobjc_framework_pushkit-11.0.tar.gz", hash = "sha256:df9854ed4065c50022863b3c11c2a21c4279b36c2b5c8f08b834174aacb44e81", size = 20816, upload-time = "2025-01-14T19:05:05.468Z" }
wheels = [
@@ -3724,8 +3726,8 @@ name = "pyobjc-framework-quartz"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a5/ad/f00f3f53387c23bbf4e0bb1410e11978cbf87c82fa6baff0ee86f74c5fb6/pyobjc_framework_quartz-11.0.tar.gz", hash = "sha256:3205bf7795fb9ae34747f701486b3db6dfac71924894d1f372977c4d70c3c619", size = 3952463, upload-time = "2025-01-14T19:05:07.931Z" }
wheels = [
@@ -3738,9 +3740,9 @@ name = "pyobjc-framework-quicklookthumbnailing"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/50/a1/35ca40d2d4ab05acbc9766986d482482d466529003711c7b4e52a8df4935/pyobjc_framework_quicklookthumbnailing-11.0.tar.gz", hash = "sha256:40763284bd0f71e6a55803f5234ad9cd8e8dd3aaaf5e1fd204e6c952b3f3530d", size = 16784, upload-time = "2025-01-14T19:05:09.857Z" }
wheels = [
@@ -3753,8 +3755,8 @@ name = "pyobjc-framework-replaykit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/aa/43/c751c517dbb8ee599a31e59832c01080473c7964b6996ca29906f46c0967/pyobjc_framework_replaykit-11.0.tar.gz", hash = "sha256:e5693589423eb9ad99d63a7395169f97b484a58108321877b0fc27c748344593", size = 25589, upload-time = "2025-01-14T19:05:10.791Z" }
wheels = [
@@ -3767,8 +3769,8 @@ name = "pyobjc-framework-safariservices"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/40/ec/c9a97b1aa713145cc8c522c4146af06b293cfe1a959a03ee91007949533b/pyobjc_framework_safariservices-11.0.tar.gz", hash = "sha256:dba416bd0ed5f4481bc400bf56ce57e982c19feaae94bc4eb75d8bda9af15b7e", size = 34367, upload-time = "2025-01-14T19:05:12.914Z" }
wheels = [
@@ -3781,9 +3783,9 @@ name = "pyobjc-framework-safetykit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4e/30/89bfdbdca93e57b19891ddeff1742b20a2019cdeb2e44902027dce2642e1/pyobjc_framework_safetykit-11.0.tar.gz", hash = "sha256:9ec996a6a8eecada4b9fd1138244bcffea96a37722531f0ec16566049dfd4cdb", size = 20745, upload-time = "2025-01-14T19:05:13.925Z" }
wheels = [
@@ -3796,9 +3798,9 @@ name = "pyobjc-framework-scenekit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/26/3f/a2761585399e752bce8275c9d56990d4b83e57b13d06dd98335891176a89/pyobjc_framework_scenekit-11.0.tar.gz", hash = "sha256:c0f37019f8de2a583f66e6d14dfd4ae23c8d8703e93f61c1c91728a21f62cd26", size = 213647, upload-time = "2025-01-14T19:05:15.129Z" }
wheels = [
@@ -3811,9 +3813,9 @@ name = "pyobjc-framework-screencapturekit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-coremedia" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/77/90/71f10db2f52ea324f82eaccc959442c43d21778cc5b1294c29e1942e635c/pyobjc_framework_screencapturekit-11.0.tar.gz", hash = "sha256:ca2c960e28216e56f33e4ca9b9b1eda12d9c17b719bae727181e8b96f0314c4b", size = 53046, upload-time = "2025-01-14T19:05:16.834Z" }
wheels = [
@@ -3826,8 +3828,8 @@ name = "pyobjc-framework-screensaver"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f6/b6/71c20259a1bfffcb5103be62564006b1bbc21f80180658101e2370683bcb/pyobjc_framework_screensaver-11.0.tar.gz", hash = "sha256:2e4c643624cc0cffeafc535c43faf5f8de8be030307fa8a5bea257845e8af474", size = 23774, upload-time = "2025-01-14T19:05:19.325Z" }
wheels = [
@@ -3840,8 +3842,8 @@ name = "pyobjc-framework-screentime"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/42/a7/ee60ee5b0471a4367eaa1c8a243418874fd48fac5dbdfdd318a653d94aaa/pyobjc_framework_screentime-11.0.tar.gz", hash = "sha256:6dd74dc64be1865346fcff63b8849253697f7ac68d83ee2708019cf3852c1cd7", size = 14398, upload-time = "2025-01-14T19:05:21.547Z" }
wheels = [
@@ -3854,8 +3856,8 @@ name = "pyobjc-framework-scriptingbridge"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4d/f0/592af19047935e44c07ddd1eba4f05aa8eb460ee842f7d5d48501231cd69/pyobjc_framework_scriptingbridge-11.0.tar.gz", hash = "sha256:65e5edd0ea608ae7f01808b963dfa25743315f563705d75c493c2fa7032f88cc", size = 22626, upload-time = "2025-01-14T19:05:22.461Z" }
wheels = [
@@ -3868,8 +3870,8 @@ name = "pyobjc-framework-searchkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-coreservices" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/15/27/9676327cf7d13346d546325b411a5deaa072bd0fbe733c8aae8a9a00c0e0/pyobjc_framework_searchkit-11.0.tar.gz", hash = "sha256:36f3109e74bc5e6fab60c02be804d5ed1c511ad51ea0d597a6c6a9653573ddf5", size = 31182, upload-time = "2025-01-14T19:05:24.667Z" }
wheels = [
@@ -3882,8 +3884,8 @@ name = "pyobjc-framework-security"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c5/75/4b916bff8c650e387077a35916b7a7d331d5ff03bed7275099d96dcc6cd9/pyobjc_framework_security-11.0.tar.gz", hash = "sha256:ac078bb9cc6762d6f0f25f68325dcd7fe77acdd8c364bf4378868493f06a0758", size = 347059, upload-time = "2025-01-14T19:05:26.17Z" }
wheels = [
@@ -3896,9 +3898,9 @@ name = "pyobjc-framework-securityfoundation"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-security" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/84/d6/0d817edb11d2bdb0f536059e913191e587f1984e39397bb3341209d92c21/pyobjc_framework_securityfoundation-11.0.tar.gz", hash = "sha256:5ae906ded5dd40046c013a7e0c1f59416abafb4b72bc947b6cd259749745e637", size = 13526, upload-time = "2025-01-14T19:05:27.275Z" }
wheels = [
@@ -3911,9 +3913,9 @@ name = "pyobjc-framework-securityinterface"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-security" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b1/88/d7c4942650707fe5b1d3b45b42684f58f2cab7d2772ec74ca96ecef575eb/pyobjc_framework_securityinterface-11.0.tar.gz", hash = "sha256:8843a27cf30a8e4dd6e2cb7702a6d65ad4222429f0ccc6c062537af4683b1c08", size = 37118, upload-time = "2025-01-14T19:05:28.569Z" }
wheels = [
@@ -3926,9 +3928,9 @@ name = "pyobjc-framework-sensitivecontentanalysis"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/00/e4/f1e0f150ae6c6ad7dde9b248f34f324f4f8b1c42260dbf62420f80d79ba9/pyobjc_framework_sensitivecontentanalysis-11.0.tar.gz", hash = "sha256:0f09034688f894c0f4409c16adaf857d78714d55472de4aa2ac40fbd7ba233d6", size = 13060, upload-time = "2025-01-14T19:05:29.655Z" }
wheels = [
@@ -3941,8 +3943,8 @@ name = "pyobjc-framework-servicemanagement"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1b/59/8d38b5cdbcfb57ab842e080436dbd04d5a5d2080e99a2ea1e286cfad12a8/pyobjc_framework_servicemanagement-11.0.tar.gz", hash = "sha256:10b1bbcee3de5bb2b9fc3d6763eb682b7a1d9ddd4bd2c882fece62783cb17885", size = 16882, upload-time = "2025-01-14T19:05:30.537Z" }
wheels = [
@@ -3955,8 +3957,8 @@ name = "pyobjc-framework-sharedwithyou"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-sharedwithyoucore" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-sharedwithyoucore", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/20/84/db667061f815537717a6cac891df01a45b65e6feaa2dfa0c9d2e3803a1ef/pyobjc_framework_sharedwithyou-11.0.tar.gz", hash = "sha256:a3a03daac77ad7364ed22109ca90c6cd2dcb7611a96cbdf37d30543ef1579399", size = 33696, upload-time = "2025-01-14T19:05:31.396Z" }
wheels = [
@@ -3969,8 +3971,8 @@ name = "pyobjc-framework-sharedwithyoucore"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/52/2a/86904cd9cc3bf5cdb9101481e17e67358f39f81ffa0f36768097287e34b3/pyobjc_framework_sharedwithyoucore-11.0.tar.gz", hash = "sha256:3932452677df5d67ea27845ab26ccaaa1d1779196bf16b62c5655f13d822c82d", size = 28877, upload-time = "2025-01-14T19:05:32.283Z" }
wheels = [
@@ -3983,8 +3985,8 @@ name = "pyobjc-framework-shazamkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/dd/2a/1f4ad92260860e500cb61119e8e7fe604b0788c32f5b00446b5a56705a2b/pyobjc_framework_shazamkit-11.0.tar.gz", hash = "sha256:cea736cefe90b6bb989d0a8abdc21ef4b3b431b27657abb09d6deb0b2c1bd37a", size = 25172, upload-time = "2025-01-14T19:05:34.497Z" }
wheels = [
@@ -3997,8 +3999,8 @@ name = "pyobjc-framework-social"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6f/56/ed483f85105ef929241ab1a6ed3dbfd0be558bb900e36b274f997db9c869/pyobjc_framework_social-11.0.tar.gz", hash = "sha256:ccedd6eddb6744049467bce19b4ec4f0667ec60552731c02dcbfa8938a3ac798", size = 14806, upload-time = "2025-01-14T19:05:35.394Z" }
wheels = [
@@ -4011,8 +4013,8 @@ name = "pyobjc-framework-soundanalysis"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9a/14/697ca1b76228a96bb459f3cf43234798b05fdf11691202449d98d9d887af/pyobjc_framework_soundanalysis-11.0.tar.gz", hash = "sha256:f541fcd04ec5d7528dd2ae2d873a92a3092e87fb70b8df229c79defb4d807d1a", size = 16789, upload-time = "2025-01-14T19:05:36.576Z" }
wheels = [
@@ -4025,8 +4027,8 @@ name = "pyobjc-framework-speech"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5f/39/e9f0a73243c38d85f8da6a1a2afda73503e2fcc31a72f5479770bceae0c1/pyobjc_framework_speech-11.0.tar.gz", hash = "sha256:92a191c3ecfe7032eea2140ab5dda826a59c7bb84b13a2edb0ebc471a76e6d7b", size = 40620, upload-time = "2025-01-14T19:05:38.391Z" }
wheels = [
@@ -4039,9 +4041,9 @@ name = "pyobjc-framework-spritekit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-quartz" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b7/6e/642e64f5b62a7777c784931c7f018788b5620e307907d416c837fd0c4315/pyobjc_framework_spritekit-11.0.tar.gz", hash = "sha256:aa43927e325d4ac253b7c0ec4df95393b0354bd278ebe9871803419d12d1ef80", size = 129851, upload-time = "2025-01-14T19:05:39.709Z" }
wheels = [
@@ -4054,8 +4056,8 @@ name = "pyobjc-framework-storekit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/69/ca/f4e5a1ff8c98bbbf208639b2bef7bf3b88936bccda1d8ed34aa7d052f589/pyobjc_framework_storekit-11.0.tar.gz", hash = "sha256:ef7e75b28f1fa8b0b6413e64b9d5d78b8ca358fc2477483d2783f688ff8d75e0", size = 75855, upload-time = "2025-01-14T19:05:41.605Z" }
wheels = [
@@ -4068,8 +4070,8 @@ name = "pyobjc-framework-symbols"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/dc/92/a20a3d7af3c99e0ea086e43715675160a04b86c1d069bdaeb3acdb015d92/pyobjc_framework_symbols-11.0.tar.gz", hash = "sha256:e3de7736dfb8107f515cfd23f03e874dd9468e88ab076d01d922a73fefb620fa", size = 13682, upload-time = "2025-01-14T19:05:45.727Z" }
wheels = [
@@ -4082,9 +4084,9 @@ name = "pyobjc-framework-syncservices"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-coredata" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5a/22/642186906f672461bab1d7773b35ef74e432b9789ca2248186b766e9fd3b/pyobjc_framework_syncservices-11.0.tar.gz", hash = "sha256:7867c23895a8289da8d56e962c144c36ed16bd101dc07d05281c55930b142471", size = 57453, upload-time = "2025-01-14T19:05:46.559Z" }
wheels = [
@@ -4097,8 +4099,8 @@ name = "pyobjc-framework-systemconfiguration"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/70/70/ebebf311523f436df2407f35d7ce62482c01e530b77aceb3ca6356dcef43/pyobjc_framework_systemconfiguration-11.0.tar.gz", hash = "sha256:06487f0fdd43c6447b5fd3d7f3f59826178d32bcf74f848c5b3ea597191d471d", size = 142949, upload-time = "2025-01-14T19:05:47.466Z" }
wheels = [
@@ -4111,8 +4113,8 @@ name = "pyobjc-framework-systemextensions"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/62/4b/904d818debf6216b7be009d492d998c819bf2f2791bfb75870a952e32cf9/pyobjc_framework_systemextensions-11.0.tar.gz", hash = "sha256:da293c99b428fb7f18a7a1d311b17177f73a20c7ffa94de3f72d760df924255e", size = 22531, upload-time = "2025-01-14T19:05:48.463Z" }
wheels = [
@@ -4125,8 +4127,8 @@ name = "pyobjc-framework-threadnetwork"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c4/17/fc8fde4eeb6697e0a5ba1a306cd62d3a95b53f3334744cd22b87037d8a14/pyobjc_framework_threadnetwork-11.0.tar.gz", hash = "sha256:f5713579380f6fb89c877796de86cb4e98428d7a9cbfebe566fb827ba23b2d8e", size = 13820, upload-time = "2025-01-14T19:05:49.307Z" }
wheels = [
@@ -4139,8 +4141,8 @@ name = "pyobjc-framework-uniformtypeidentifiers"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/56/4f/fd571c1f87d5ee3d86c4d2008806e9623d2662bbc788d9001b3fff35275f/pyobjc_framework_uniformtypeidentifiers-11.0.tar.gz", hash = "sha256:6ae6927a3ed1f0197a8c472226f11f46ccd5ed398b4449613e1d10346d9ed15d", size = 20860, upload-time = "2025-01-14T19:05:50.073Z" }
wheels = [
@@ -4153,8 +4155,8 @@ name = "pyobjc-framework-usernotifications"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/78/f5/ca3e6a7d940b3aca4323e4f5409b14b5d2eb45432158430c584e3800ce4d/pyobjc_framework_usernotifications-11.0.tar.gz", hash = "sha256:7950a1c6a8297f006c26c3d286705ffc2a07061d6e844f1106290572097b872c", size = 54857, upload-time = "2025-01-14T19:05:52.42Z" }
wheels = [
@@ -4167,9 +4169,9 @@ name = "pyobjc-framework-usernotificationsui"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
- { name = "pyobjc-framework-usernotifications" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-usernotifications", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e9/e8/f0d50cdc678260a628b92e55b5752155f941c2f72b96fe3f2412a28c5d79/pyobjc_framework_usernotificationsui-11.0.tar.gz", hash = "sha256:d0ec597d189b4d228b0b836474aef318652c1c287b33442a1403c49dc59fdb7f", size = 14369, upload-time = "2025-01-14T19:05:54.498Z" }
wheels = [
@@ -4182,8 +4184,8 @@ name = "pyobjc-framework-videosubscriberaccount"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7e/2e/6a7debd84911a9384b4e7a9cc3f308e3461a00a9d74f33b153bdd872f15f/pyobjc_framework_videosubscriberaccount-11.0.tar.gz", hash = "sha256:163b32f361f48b9d20f317461464abd4427b3242693ae011633fc443c7d5449c", size = 29100, upload-time = "2025-01-14T19:05:55.319Z" }
wheels = [
@@ -4196,10 +4198,10 @@ name = "pyobjc-framework-videotoolbox"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ba/2d/c031a132b142fcd20846cc1ac3ba92abaa58ec04164fd36ca978d9374f1c/pyobjc_framework_videotoolbox-11.0.tar.gz", hash = "sha256:a54ed8f8bcbdd2bdea2a296dc02a8a7d42f81e2b6ccbf4d1f10cec5e7a09bec0", size = 81157, upload-time = "2025-01-14T19:05:56.135Z" }
wheels = [
@@ -4212,8 +4214,8 @@ name = "pyobjc-framework-virtualization"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/65/8d/e57e1f2c5ac950dc3da6c977effde4a55b8b70424b1bdb97b5530559f5bc/pyobjc_framework_virtualization-11.0.tar.gz", hash = "sha256:03e1c1fa20950aa7c275e5f11f1257108b6d1c6a7403afb86f4e9d5fae87b73c", size = 78144, upload-time = "2025-01-14T19:05:57.086Z" }
wheels = [
@@ -4226,10 +4228,10 @@ name = "pyobjc-framework-vision"
version = "11.0"
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 = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-coreml", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ef/53/dc2e0562a177af9306efceb84bc21f5cf7470acaa8f28f64e62bf828b7e1/pyobjc_framework_vision-11.0.tar.gz", hash = "sha256:45342e5253c306dbcd056a68bff04ffbfa00e9ac300a02aabf2e81053b771e39", size = 133175, upload-time = "2025-01-14T19:05:58.013Z" }
wheels = [
@@ -4242,8 +4244,8 @@ name = "pyobjc-framework-webkit"
version = "11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pyobjc-core" },
- { name = "pyobjc-framework-cocoa" },
+ { name = "pyobjc-core", marker = "sys_platform == 'darwin'" },
+ { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/79/4f/02a6270acf225c2a34339677e796002c77506238475059ae6e855358a40c/pyobjc_framework_webkit-11.0.tar.gz", hash = "sha256:fa6bedf9873786b3376a74ce2ea9dcd311f2a80f61e33dcbd931cc956aa29644", size = 767210, upload-time = "2025-01-14T19:05:59.3Z" }
wheels = [
@@ -4256,9 +4258,9 @@ name = "pyopencl"
version = "2025.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "numpy" },
- { name = "platformdirs" },
- { name = "pytools" },
+ { name = "numpy", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "platformdirs", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "pytools", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/28/88/0ac460d3e2def08b2ad6345db6a13613815f616bbbd60c6f4bdf774f4c41/pyopencl-2025.1.tar.gz", hash = "sha256:0116736d7f7920f87b8db4b66a03f27b1d930d2e37ddd14518407cc22dd24779", size = 422510, upload-time = "2025-01-22T00:16:58.421Z" }
wheels = [
@@ -4474,7 +4476,7 @@ name = "python-xlib"
version = "0.33"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "six" },
+ { name = "six", marker = "sys_platform != 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068, upload-time = "2022-12-25T18:53:00.824Z" }
wheels = [
@@ -4492,9 +4494,9 @@ name = "pytools"
version = "2024.1.10"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "platformdirs" },
- { name = "siphash24" },
- { name = "typing-extensions" },
+ { name = "platformdirs", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "siphash24", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+ { name = "typing-extensions", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ee/0f/56e109c0307f831b5d598ad73976aaaa84b4d0e98da29a642e797eaa940c/pytools-2024.1.10.tar.gz", hash = "sha256:9af6f4b045212c49be32bb31fe19606c478ee4b09631886d05a32459f4ce0a12", size = 81741, upload-time = "2024-07-17T18:47:38.287Z" }
wheels = [
@@ -4814,11 +4816,11 @@ wheels = [
[[package]]
name = "setuptools"
-version = "80.1.0"
+version = "80.3.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/aa/b2/bd26ed086b842b68c8fe9aac380ad7e5118cf84fa7abd45bb059a88368a8/setuptools-80.1.0.tar.gz", hash = "sha256:2e308396e1d83de287ada2c2fd6e64286008fe6aca5008e0b6a8cb0e2c86eedd", size = 1354038, upload-time = "2025-04-30T17:41:06.171Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/70/dc/3976b322de9d2e87ed0007cf04cc7553969b6c7b3f48a565d0333748fbcd/setuptools-80.3.1.tar.gz", hash = "sha256:31e2c58dbb67c99c289f51c16d899afedae292b978f8051efaf6262d8212f927", size = 1315082, upload-time = "2025-05-04T18:47:04.397Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/8b/f6/126c9309c8fe93e5d6bb850593cd58d591daf2da45cc78b61e48d8d95879/setuptools-80.1.0-py3-none-any.whl", hash = "sha256:ea0e7655c05b74819f82e76e11a85b31779fee7c4969e82f72bab0664e8317e4", size = 1240689, upload-time = "2025-04-30T17:41:03.789Z" },
+ { url = "https://files.pythonhosted.org/packages/53/7e/5d8af3317ddbf9519b687bd1c39d8737fde07d97f54df65553faca5cffb1/setuptools-80.3.1-py3-none-any.whl", hash = "sha256:ea8e00d7992054c4c592aeb892f6ad51fe1b4d90cc6947cc45c45717c40ec537", size = 1201172, upload-time = "2025-05-04T18:47:02.575Z" },
]
[[package]]
@@ -4826,7 +4828,7 @@ name = "shapely"
version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "numpy" },
+ { name = "numpy", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fb/fe/3b0d2f828ffaceadcdcb51b75b9c62d98e62dd95ce575278de35f24a1c20/shapely-2.1.0.tar.gz", hash = "sha256:2cbe90e86fa8fc3ca8af6ffb00a77b246b918c7cf28677b7c21489b678f6b02e", size = 313617, upload-time = "2025-04-03T09:15:05.725Z" }
wheels = [
@@ -5050,12 +5052,41 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" },
]
+[[package]]
+name = "xattr"
+version = "1.1.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/62/bf/8b98081f9f8fd56d67b9478ff1e0f8c337cde08bcb92f0d592f0a7958983/xattr-1.1.4.tar.gz", hash = "sha256:b7b02ecb2270da5b7e7deaeea8f8b528c17368401c2b9d5f63e91f545b45d372", size = 16729, upload-time = "2025-01-06T19:19:32.557Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/5b/f64ba0f93e6447e1997068959f22ff99e08d77dd88d9edcf97ddcb9e9016/xattr-1.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bb4bbe37ba95542081890dd34fa5347bef4651e276647adaa802d5d0d7d86452", size = 23920, upload-time = "2025-01-06T19:17:48.234Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/54/ad66655f0b1317b0a297aa2d6ed7d6e5d5343495841fad535bee37a56471/xattr-1.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3da489ecef798705f9a39ea8cea4ead0d1eeed55f92c345add89740bd930bab6", size = 18883, upload-time = "2025-01-06T19:17:49.46Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/5d/7d5154570bbcb898e6123c292f697c87c33e12258a1a8b9741539f952681/xattr-1.1.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:798dd0cbe696635a6f74b06fc430818bf9c3b24314e1502eadf67027ab60c9b0", size = 19221, upload-time = "2025-01-06T19:17:51.654Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/b7/135cf3018278051f57bb5dde944cb1ca4f7ad4ec383465a08c6a5c7f7152/xattr-1.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2b6361626efad5eb5a6bf8172c6c67339e09397ee8140ec41258737bea9681", size = 39098, upload-time = "2025-01-06T19:17:53.099Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/62/577e2eb0108158b78cd93ea3782c7a8d464693f1338a5350a1db16f69a89/xattr-1.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7fa20a0c9ce022d19123b1c5b848d00a68b837251835a7929fe041ee81dcd0", size = 36982, upload-time = "2025-01-06T19:17:54.493Z" },
+ { url = "https://files.pythonhosted.org/packages/59/cc/ab3bd7a4bedf445be4b35de4a4627ef2944786724d18eaf28d05c1238c7c/xattr-1.1.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e20eeb08e2c57fc7e71f050b1cfae35cbb46105449853a582bf53fd23c5379e", size = 38891, upload-time = "2025-01-06T19:17:55.853Z" },
+ { url = "https://files.pythonhosted.org/packages/45/e8/2285651d92f1460159753fe6628af259c943fcc5071e48a0540fa11dc34d/xattr-1.1.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:477370e75821bded901487e5e752cffe554d1bd3bd4839b627d4d1ee8c95a093", size = 38362, upload-time = "2025-01-06T19:17:57.078Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/af/7856c0b1970272a53a428bb20dc125f9fd350fb1b40ebca4e54610af1b79/xattr-1.1.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a8682091cd34a9f4a93c8aaea4101aae99f1506e24da00a3cc3dd2eca9566f21", size = 36724, upload-time = "2025-01-06T19:17:58.534Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/34/087e02b32d6288a40b7f6573e97a119016e6c3713d4f4b866bbf56cfb803/xattr-1.1.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2e079b3b1a274ba2121cf0da38bbe5c8d2fb1cc49ecbceb395ce20eb7d69556d", size = 37945, upload-time = "2025-01-06T19:17:59.764Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/2a/d0f9e46de4cec5e4aa45fd939549b977c49dd68202fa844d07cb24ce5f17/xattr-1.1.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ae6579dea05bf9f335a082f711d5924a98da563cac72a2d550f5b940c401c0e9", size = 23917, upload-time = "2025-01-06T19:18:00.868Z" },
+ { url = "https://files.pythonhosted.org/packages/83/e0/a5764257cd9c9eb598f4648a3658d915dd3520ec111ecbd251b685de6546/xattr-1.1.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd6038ec9df2e67af23c212693751481d5f7e858156924f14340376c48ed9ac7", size = 18891, upload-time = "2025-01-06T19:18:02.029Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/83/a81a147987387fd2841a28f767efedb099cf90e23553ead458f2330e47c5/xattr-1.1.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:608b2877526674eb15df4150ef4b70b7b292ae00e65aecaae2f192af224be200", size = 19213, upload-time = "2025-01-06T19:18:03.303Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/52/bf093b4eb9873ffc9e9373dcb38ec8a9b5cd4e6a9f681c4c5cf6bf067a42/xattr-1.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54dad1a6a998c6a23edfd25e99f4d38e9b942d54e518570044edf8c767687ea", size = 39302, upload-time = "2025-01-06T19:18:05.846Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/d8/9d7315ebae76a7f48bc5e1aecc7e592eb43376a0f6cf470a854d895d2093/xattr-1.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0dab6ff72bb2b508f3850c368f8e53bd706585012676e1f71debba3310acde8", size = 37224, upload-time = "2025-01-06T19:18:07.226Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/b2/10eb17bea7e378b2bcd76fc8c2e5158318e2c08e774b13f548f333d7318a/xattr-1.1.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a3c54c6af7cf09432b2c461af257d5f4b1cb2d59eee045f91bacef44421a46d", size = 39145, upload-time = "2025-01-06T19:18:08.403Z" },
+ { url = "https://files.pythonhosted.org/packages/74/fb/95bbc28116b3c19a21acc34ec0a5973e9cc97fe49d3f47a65775af3760a8/xattr-1.1.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e346e05a158d554639fbf7a0db169dc693c2d2260c7acb3239448f1ff4a9d67f", size = 38469, upload-time = "2025-01-06T19:18:09.602Z" },
+ { url = "https://files.pythonhosted.org/packages/af/03/23db582cb271ed47f2d62956e112501d998b5493f892a77104b5795ae2fc/xattr-1.1.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3ff6d9e2103d0d6e5fcd65b85a2005b66ea81c0720a37036445faadc5bbfa424", size = 36797, upload-time = "2025-01-06T19:18:10.709Z" },
+ { url = "https://files.pythonhosted.org/packages/90/c4/b631d0174e097cf8c44d4f70c66545d91dc8ba15bbfa5054dd7da8371461/xattr-1.1.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7a2ee4563c6414dfec0d1ac610f59d39d5220531ae06373eeb1a06ee37cd193f", size = 38128, upload-time = "2025-01-06T19:18:11.884Z" },
+]
+
[[package]]
name = "yapf"
version = "0.43.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "platformdirs" },
+ { name = "platformdirs", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/23/97/b6f296d1e9cc1ec25c7604178b48532fa5901f721bcf1b8d8148b13e5588/yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e", size = 254907, upload-time = "2024-11-14T00:11:41.584Z" }
wheels = [