Merge remote-tracking branch 'upstream/master' into zstd-uploader

pull/32736/head
Shane Smiskol 1 year ago
commit 17ea583274
  1. 2
      .github/workflows/docs.yaml
  2. 3
      .github/workflows/selfdrive_tests.yaml
  3. 56
      README.md
  4. 4
      SConstruct
  5. 3
      docs/mkdocs.yml
  6. 10
      pyproject.toml
  7. 2
      selfdrive/car/hyundai/fingerprints.py
  8. 2
      selfdrive/test/test_onroad.py
  9. 34
      system/camerad/cameras/camera_common.cc
  10. 9
      system/camerad/cameras/camera_common.h
  11. 103
      system/camerad/cameras/camera_qcom2.cc
  12. 119
      system/camerad/cameras/camera_qcom2.h
  13. 22
      system/micd.py
  14. 19
      tools/mac_setup.sh
  15. 205
      tools/op.sh
  16. 73
      tools/setup.sh
  17. 5
      tools/ubuntu_setup.sh
  18. 115
      uv.lock

@ -29,7 +29,7 @@ jobs:
- name: Build docs
run: |
# TODO: can we install just the "docs" dependency group without the normal deps?
pip install mkdocs mkdocs-terminal
pip install mkdocs==1.4.3 mkdocs-terminal mkdocs-plugin-commonmark
cd docs
mkdocs build

@ -96,7 +96,7 @@ jobs:
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache
build_mac:
name: build macos
name: build macOS
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
@ -106,7 +106,6 @@ jobs:
- name: Install dependencies
run: ./tools/mac_setup.sh
env:
SKIP_PROMPT: 1
# package install has DeprecationWarnings
PYTHONWARNINGS: default
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV

@ -1,9 +1,32 @@
[![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/8762862/f09e6d29-db2d-4179-80c2-51e8d92bdb5c)](https://comma.ai/shop/comma-3x)
<div align="center" style="text-align: center;">
What is openpilot?
------
<h1>openpilot</h1>
<p>
<b>openpilot is an operating system for robotics.</b>
<br>
Currently, it upgrades the driver assistance system in 275+ supported cars.
</p>
<h3>
<a href="https://docs.comma.ai">Read the docs</a>
<span> · </span>
<a href="https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md">Contribute</a>
<span> · </span>
<a href="https://discord.comma.ai">Community</a>
<span> · </span>
<a href="https://comma.ai/shop">Try it on a comma 3X</a>
</h3>
Quick start: `curl -fsSL openpilot.comma.ai | bash`
[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md).
![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![X Follow](https://img.shields.io/twitter/follow/comma_ai)](https://x.com/comma_ai)
[![Discord](https://img.shields.io/discord/469524606043160576)](https://discord.comma.ai)
</div>
<table>
<tr>
@ -49,18 +72,6 @@ Safety and Testing
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
User Data and comma Account
------
By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
openpilot is open source software: the user is free to disable data collection if they wish to do so.
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
Licensing
------
@ -72,9 +83,14 @@ Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and i
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
NO WARRANTY EXPRESSED OR IMPLIED.**
---
User Data and comma Account
------
<img src="https://d1qb2nb5cznatu.cloudfront.net/startups/i/1061157-bc7e9bf3b246ece7322e6ffe653f6af8-medium_jpg.jpg?buster=1458363130" width="75"></img> <img src="https://cdn-images-1.medium.com/max/1600/1*C87EjxGeMPrkTuVRVWVg4w.png" width="225"></img>
By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)
openpilot is open source software: the user is free to disable data collection if they wish to do so.
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.

@ -169,7 +169,6 @@ if arch != "Darwin":
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
# Enable swaglog include in submodules
cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
ccflags_option = GetOption('ccflags')
@ -205,7 +204,6 @@ env = Environment(
"#third_party/json11",
"#third_party/linux/include",
"#third_party/snpe/include",
"#third_party/qrcode",
"#third_party",
"#cereal",
"#msgq",
@ -314,7 +312,7 @@ try:
except SCons.Errors.UserError:
qt_env.Tool('qt')
qt_env['CPPPATH'] += qt_dirs# + ["#selfdrive/ui/qt/"]
qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"]
qt_flags = [
"-D_REENTRANT",
"-DQT_NO_DEBUG",

@ -5,6 +5,9 @@ site_url: https://docs.comma.ai
strict: true
plugins:
- commonmark
theme:
name: terminal
features:

@ -67,8 +67,9 @@ dependencies = [
[project.optional-dependencies]
docs = [
"Jinja2",
"mkdocs",
"mkdocs==1.4.3", # needed for mkdocs-plugin-commonmark
"mkdocs-terminal",
"mkdocs-plugin-commonmark",
]
testing = [
@ -110,6 +111,7 @@ dev = [
#pprofile = "*"
"pyautogui",
"pyopencl; platform_machine != 'aarch64'", # broken on arm64
"pytools < 2024.1.11; platform_machine != 'aarch64'", # pyopencl use a broken version
"pywinctl",
"pyprof2calltree",
"rerun-sdk",
@ -227,7 +229,7 @@ lint.ignore = [
"UP038", # (x, y) -> x|y for isinstance
]
line-length = 160
target-version="py311"
target-version ="py311"
exclude = [
"body",
"cereal",
@ -239,7 +241,8 @@ exclude = [
"teleoprtc_repo",
"third_party",
]
lint.flake8-implicit-str-concat.allow-multiline=false
lint.flake8-implicit-str-concat.allow-multiline = false
[tool.ruff.lint.flake8-tidy-imports.banned-api]
"selfdrive".msg = "Use openpilot.selfdrive"
"common".msg = "Use openpilot.common"
@ -251,5 +254,6 @@ lint.flake8-implicit-str-concat.allow-multiline=false
[tool.coverage.run]
concurrency = ["multiprocessing", "thread"]
[tool.ruff.format]
quote-style = "preserve"

@ -765,9 +765,11 @@ FW_VERSIONS = {
],
(Ecu.abs, 0x7d1, None): [
b'\xf1\x00JF ESC \x0f 16 \x16\x06\x17 58920-D5080',
b'\xf1\x00JF ESC \t 17 \x16\x06# 58920-D4180',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JFWGN LDWS AT USA LHD 1.00 1.02 95895-D4100 G21',
b'\xf1\x00JFWGN LKAS AT EUR LHD 1.00 1.01 95895-D4100 G20',
],
},
CAR.KIA_OPTIMA_G4_FL: {

@ -56,7 +56,7 @@ PROCS = {
"system.logmessaged": 0.2,
"system.tombstoned": 0,
"logcatd": 0,
"system.micd": 6.0,
"system.micd": 5.0,
"system.timed": 0,
"selfdrive.pandad.pandad": 0,
"system.statsd": 0.4,

@ -244,7 +244,7 @@ static kj::Array<capnp::byte> yuv420_to_jpeg(const CameraBuf *b, int thumbnail_w
return dat;
}
static void publish_thumbnail(PubMaster *pm, const CameraBuf *b) {
void publish_thumbnail(PubMaster *pm, const CameraBuf *b) {
auto thumbnail = yuv420_to_jpeg(b, b->rgb_width / 4, b->rgb_height / 4);
if (thumbnail.size() == 0) return;
@ -284,36 +284,6 @@ float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_sk
return lum_med / 256.0;
}
void *processing_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback) {
const char *thread_name = nullptr;
if (cs == &cameras->road_cam) {
thread_name = "RoadCamera";
} else if (cs == &cameras->driver_cam) {
thread_name = "DriverCamera";
} else {
thread_name = "WideRoadCamera";
}
util::set_thread_name(thread_name);
uint32_t cnt = 0;
while (!do_exit) {
if (!cs->buf.acquire()) continue;
callback(cameras, cs, cnt);
if (cs == &(cameras->road_cam) && cameras->pm && cnt % 100 == 3) {
// this takes 10ms???
publish_thumbnail(cameras->pm, &(cs->buf));
}
++cnt;
}
return NULL;
}
std::thread start_process_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback) {
return std::thread(processing_thread, cameras, cs, callback);
}
void camerad_thread() {
cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT);
#ifdef QCOM2
@ -324,7 +294,7 @@ void camerad_thread() {
#endif
{
MultiCameraState cameras = {};
MultiCameraState cameras;
VisionIpcServer vipc_server("camerad", device_id, context);
cameras_open(&cameras);

@ -2,7 +2,6 @@
#include <fcntl.h>
#include <memory>
#include <thread>
#include "cereal/messaging/messaging.h"
#include "msgq/visionipc/visionipc_server.h"
@ -18,9 +17,6 @@ enum CameraType {
};
// for debugging
const bool env_disable_road = getenv("DISABLE_ROAD") != NULL;
const bool env_disable_wide_road = getenv("DISABLE_WIDE_ROAD") != NULL;
const bool env_disable_driver = getenv("DISABLE_DRIVER") != NULL;
const bool env_debug_frames = getenv("DEBUG_FRAMES") != NULL;
const bool env_log_raw_frames = getenv("LOG_RAW_FRAMES") != NULL;
const bool env_ctrl_exp_from_params = getenv("CTRL_EXP_FROM_PARAMS") != NULL;
@ -72,13 +68,10 @@ public:
void queue(size_t buf_idx);
};
typedef void (*process_thread_cb)(MultiCameraState *s, CameraState *c, int cnt);
void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &frame_data, CameraState *c);
kj::Array<uint8_t> get_raw_frame_image(const CameraBuf *b);
float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_skip);
std::thread start_process_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback);
void publish_thumbnail(PubMaster *pm, const CameraBuf *b);
void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx);
void cameras_open(MultiCameraState *s);
void cameras_run(MultiCameraState *s);

@ -26,6 +26,16 @@ const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py
extern ExitHandler do_exit;
CameraState::CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config)
: multi_cam_state(multi_camera_state),
camera_num(config.camera_num),
stream_type(config.stream_type),
focal_len(config.focal_len),
publish_name(config.publish_name),
init_camera_state(config.init_camera_state),
enabled(config.enabled) {
}
int CameraState::clear_req_queue() {
struct cam_req_mgr_flush_info req_mgr_flush_request = {0};
req_mgr_flush_request.session_hdl = session_handle;
@ -425,48 +435,38 @@ void CameraState::set_exposure_rect() {
}
void CameraState::sensor_set_parameters() {
target_grey_fraction = 0.3;
dc_gain_enabled = false;
dc_gain_weight = ci->dc_gain_min_weight;
gain_idx = ci->analog_gain_rec_idx;
exposure_time = 5;
cur_ev[0] = cur_ev[1] = cur_ev[2] = (1 + dc_gain_weight * (ci->dc_gain_factor-1) / ci->dc_gain_max_weight) * ci->sensor_analog_gains[gain_idx] * exposure_time;
}
void CameraState::camera_map_bufs(MultiCameraState *s) {
void CameraState::camera_map_bufs() {
for (int i = 0; i < FRAME_BUF_COUNT; i++) {
// configure ISP to put the image in place
struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0};
mem_mgr_map_cmd.mmu_hdls[0] = s->device_iommu;
mem_mgr_map_cmd.mmu_hdls[0] = multi_cam_state->device_iommu;
mem_mgr_map_cmd.num_hdl = 1;
mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE;
mem_mgr_map_cmd.fd = buf.camera_bufs[i].fd;
int ret = do_cam_control(s->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret);
buf_handle[i] = mem_mgr_map_cmd.out.buf_handle;
}
enqueue_req_multi(1, FRAME_BUF_COUNT, 0);
}
void CameraState::camera_init(MultiCameraState *s, VisionIpcServer * v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len) {
void CameraState::camera_init(VisionIpcServer * v, cl_device_id device_id, cl_context ctx) {
if (!enabled) return;
LOGD("camera init %d", camera_num);
request_id_last = 0;
skipped = true;
buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, yuv_type);
camera_map_bufs(s);
buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, stream_type);
camera_map_bufs();
fl_pix = focal_len / ci->pixel_size_mm;
set_exposure_rect();
}
void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num_, bool enabled_) {
multi_cam_state = multi_cam_state_;
camera_num = camera_num_;
enabled = enabled_;
void CameraState::camera_open() {
if (!enabled) return;
if (!openSensor()) {
@ -660,9 +660,9 @@ void CameraState::linkDevices() {
}
void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) {
s->driver_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_DRIVER, DRIVER_FL_MM);
s->road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_ROAD, ROAD_FL_MM);
s->wide_road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_WIDE_ROAD, WIDE_FL_MM);
s->driver_cam.camera_init(v, device_id, ctx);
s->road_cam.camera_init(v, device_id, ctx);
s->wide_road_cam.camera_init(v, device_id, ctx);
s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"});
}
@ -706,11 +706,11 @@ void cameras_open(MultiCameraState *s) {
ret = HANDLE_EINTR(ioctl(s->video0_fd, VIDIOC_SUBSCRIBE_EVENT, &sub));
LOGD("req mgr subscribe: %d", ret);
s->driver_cam.camera_open(s, 2, !env_disable_driver);
s->driver_cam.camera_open();
LOGD("driver camera opened");
s->road_cam.camera_open(s, 1, !env_disable_road);
s->road_cam.camera_open();
LOGD("road camera opened");
s->wide_road_cam.camera_open(s, 0, !env_disable_wide_road);
s->wide_road_cam.camera_open();
LOGD("wide road camera opened");
}
@ -943,41 +943,50 @@ void CameraState::set_camera_exposure(float grey_frac) {
sensors_i2c(exp_reg_array.data(), exp_reg_array.size(), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, ci->data_word);
}
static void process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) {
c->set_camera_exposure(set_exposure_target(&c->buf, c->ae_xywh, 2, 4));
void CameraState::run() {
util::set_thread_name(publish_name);
MessageBuilder msg;
auto framed = msg.initEvent().initDriverCameraState();
fill_frame_data(framed, c->buf.cur_frame_data, c);
for (uint32_t cnt = 0; !do_exit; ++cnt) {
// Acquire the buffer; continue if acquisition fails
if (!buf.acquire()) continue;
c->ci->processRegisters(c, framed);
s->pm->send("driverCameraState", msg);
}
MessageBuilder msg;
auto framed = (msg.initEvent().*init_camera_state)();
fill_frame_data(framed, buf.cur_frame_data, this);
void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) {
const CameraBuf *b = &c->buf;
// Log raw frames for road camera
if (env_log_raw_frames && stream_type == VISION_STREAM_ROAD && cnt % 100 == 5) { // no overlap with qlog decimation
framed.setImage(get_raw_frame_image(&buf));
}
// Log frame id for road and wide road cameras
if (stream_type != VISION_STREAM_DRIVER) {
LOGT(buf.cur_frame_data.frame_id, "%s: Image set", publish_name);
}
MessageBuilder msg;
auto framed = c == &s->road_cam ? msg.initEvent().initRoadCameraState() : msg.initEvent().initWideRoadCameraState();
fill_frame_data(framed, b->cur_frame_data, c);
if (env_log_raw_frames && c == &s->road_cam && cnt % 100 == 5) { // no overlap with qlog decimation
framed.setImage(get_raw_frame_image(b));
}
LOGT(c->buf.cur_frame_data.frame_id, "%s: Image set", c == &s->road_cam ? "RoadCamera" : "WideRoadCamera");
// Process camera registers and set camera exposure
ci->processRegisters(this, framed);
set_camera_exposure(set_exposure_target(&buf, ae_xywh, 2, stream_type != VISION_STREAM_DRIVER ? 2 : 4));
c->ci->processRegisters(c, framed);
s->pm->send(c == &s->road_cam ? "roadCameraState" : "wideRoadCameraState", msg);
// Send the message
multi_cam_state->pm->send(publish_name, msg);
if (stream_type == VISION_STREAM_ROAD && cnt % 100 == 3) {
publish_thumbnail(multi_cam_state->pm, &buf); // this takes 10ms???
}
}
}
const int skip = 2;
c->set_camera_exposure(set_exposure_target(b, c->ae_xywh, skip, skip));
MultiCameraState::MultiCameraState()
: driver_cam(this, DRIVER_CAMERA_CONFIG),
road_cam(this, ROAD_CAMERA_CONFIG),
wide_road_cam(this, WIDE_ROAD_CAMERA_CONFIG) {
}
void cameras_run(MultiCameraState *s) {
LOG("-- Starting threads");
std::vector<std::thread> threads;
if (s->driver_cam.enabled) threads.push_back(start_process_thread(s, &s->driver_cam, process_driver_camera));
if (s->road_cam.enabled) threads.push_back(start_process_thread(s, &s->road_cam, process_road_camera));
if (s->wide_road_cam.enabled) threads.push_back(start_process_thread(s, &s->wide_road_cam, process_road_camera));
if (s->driver_cam.enabled) threads.emplace_back(&CameraState::run, &s->driver_cam);
if (s->road_cam.enabled) threads.emplace_back(&CameraState::run, &s->road_cam);
if (s->wide_road_cam.enabled) threads.emplace_back(&CameraState::run, &s->wide_road_cam);
// start devices
LOG("-- Starting devices");

@ -11,67 +11,105 @@
#define FRAME_BUF_COUNT 4
#define ROAD_FL_MM 8.0f
#define WIDE_FL_MM 1.71f
#define DRIVER_FL_MM 1.71f
struct CameraConfig {
int camera_num;
VisionStreamType stream_type;
float focal_len; // millimeters
const char *publish_name;
cereal::FrameData::Builder (cereal::Event::Builder::*init_camera_state)();
bool enabled;
};
const CameraConfig WIDE_ROAD_CAMERA_CONFIG = {
.camera_num = 0,
.stream_type = VISION_STREAM_WIDE_ROAD,
.focal_len = 1.71,
.publish_name = "wideRoadCameraState",
.init_camera_state = &cereal::Event::Builder::initWideRoadCameraState,
.enabled = !getenv("DISABLE_WIDE_ROAD"),
};
const CameraConfig ROAD_CAMERA_CONFIG = {
.camera_num = 1,
.stream_type = VISION_STREAM_ROAD,
.focal_len = 8.0,
.publish_name = "roadCameraState",
.init_camera_state = &cereal::Event::Builder::initRoadCameraState,
.enabled = !getenv("DISABLE_ROAD"),
};
const CameraConfig DRIVER_CAMERA_CONFIG = {
.camera_num = 2,
.stream_type = VISION_STREAM_DRIVER,
.focal_len = 1.71,
.publish_name = "driverCameraState",
.init_camera_state = &cereal::Event::Builder::initDriverCameraState,
.enabled = !getenv("DISABLE_DRIVER"),
};
class CameraState {
public:
MultiCameraState *multi_cam_state;
MultiCameraState *multi_cam_state = nullptr;
std::unique_ptr<const SensorInfo> ci;
bool enabled;
bool enabled = true;
VisionStreamType stream_type;
const char *publish_name = nullptr;
cereal::FrameData::Builder (cereal::Event::Builder::*init_camera_state)() = nullptr;
float focal_len = 0;
std::mutex exp_lock;
int exposure_time;
bool dc_gain_enabled;
int dc_gain_weight;
int gain_idx;
float analog_gain_frac;
int exposure_time = 5;
bool dc_gain_enabled = false;
int dc_gain_weight = 0;
int gain_idx = 0;
float analog_gain_frac = 0;
float cur_ev[3];
float best_ev_score;
int new_exp_g;
int new_exp_t;
float cur_ev[3] = {};
float best_ev_score = 0;
int new_exp_g = 0;
int new_exp_t = 0;
Rect ae_xywh;
float measured_grey_fraction;
float target_grey_fraction;
Rect ae_xywh = {};
float measured_grey_fraction = 0;
float target_grey_fraction = 0.3;
unique_fd sensor_fd;
unique_fd csiphy_fd;
int camera_num;
float fl_pix;
int camera_num = 0;
float fl_pix = 0;
CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config);
void handle_camera_event(void *evdat);
void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain);
void set_camera_exposure(float grey_frac);
void sensors_start();
void camera_open(MultiCameraState *multi_cam_state, int camera_num, bool enabled);
void camera_open();
void set_exposure_rect();
void sensor_set_parameters();
void camera_map_bufs(MultiCameraState *s);
void camera_init(MultiCameraState *s, VisionIpcServer *v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len);
void camera_map_bufs();
void camera_init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx);
void camera_close();
void run();
int32_t session_handle;
int32_t sensor_dev_handle;
int32_t isp_dev_handle;
int32_t csiphy_dev_handle;
int32_t session_handle = -1;
int32_t sensor_dev_handle = -1;
int32_t isp_dev_handle = -1;
int32_t csiphy_dev_handle = -1;
int32_t link_handle;
int32_t link_handle = -1;
int buf0_handle;
int buf_handle[FRAME_BUF_COUNT];
int sync_objs[FRAME_BUF_COUNT];
int request_ids[FRAME_BUF_COUNT];
int request_id_last;
int frame_id_last;
int idx_offset;
bool skipped;
int buf0_handle = 0;
int buf_handle[FRAME_BUF_COUNT] = {};
int sync_objs[FRAME_BUF_COUNT] = {};
int request_ids[FRAME_BUF_COUNT] = {};
int request_id_last = 0;
int frame_id_last = 0;
int idx_offset = 0;
bool skipped = true;
CameraBuf buf;
MemoryManager mm;
@ -95,16 +133,19 @@ private:
Params params;
};
typedef struct MultiCameraState {
class MultiCameraState {
public:
MultiCameraState();
unique_fd video0_fd;
unique_fd cam_sync_fd;
unique_fd isp_fd;
int device_iommu;
int cdm_iommu;
int device_iommu = -1;
int cdm_iommu = -1;
CameraState road_cam;
CameraState wide_road_cam;
CameraState driver_cam;
PubMaster *pm;
} MultiCameraState;
};

@ -1,5 +1,6 @@
#!/usr/bin/env python3
import numpy as np
from functools import cache
from cereal import messaging
from openpilot.common.realtime import Ratekeeper
@ -10,7 +11,16 @@ RATE = 10
FFT_SAMPLES = 4096
REFERENCE_SPL = 2e-5 # newtons/m^2
SAMPLE_RATE = 44100
SAMPLE_BUFFER = 4096 # (approx 100ms)
SAMPLE_BUFFER = 4096 # approx 100ms
@cache
def get_a_weighting_filter():
# Calculate the A-weighting filter
# https://en.wikipedia.org/wiki/A-weighting
freqs = np.fft.fftfreq(FFT_SAMPLES, d=1 / SAMPLE_RATE)
A = 12194 ** 2 * freqs ** 4 / ((freqs ** 2 + 20.6 ** 2) * (freqs ** 2 + 12194 ** 2) * np.sqrt((freqs ** 2 + 107.7 ** 2) * (freqs ** 2 + 737.9 ** 2)))
return A / np.max(A)
def calculate_spl(measurements):
@ -27,16 +37,8 @@ def apply_a_weighting(measurements: np.ndarray) -> np.ndarray:
# Generate a Hanning window of the same length as the audio measurements
measurements_windowed = measurements * np.hanning(len(measurements))
# Calculate the frequency axis for the signal
freqs = np.fft.fftfreq(measurements_windowed.size, d=1 / SAMPLE_RATE)
# Calculate the A-weighting filter
# https://en.wikipedia.org/wiki/A-weighting
A = 12194 ** 2 * freqs ** 4 / ((freqs ** 2 + 20.6 ** 2) * (freqs ** 2 + 12194 ** 2) * np.sqrt((freqs ** 2 + 107.7 ** 2) * (freqs ** 2 + 737.9 ** 2)))
A /= np.max(A) # Normalize the filter
# Apply the A-weighting filter to the signal
return np.abs(np.fft.ifft(np.fft.fft(measurements_windowed) * A))
return np.abs(np.fft.ifft(np.fft.fft(measurements_windowed) * get_a_weighting_filter()))
class Mic:

@ -2,19 +2,12 @@
set -e
if [ -z "$SKIP_PROMPT" ]; then
echo "--------------- macOS support ---------------"
echo "Running openpilot natively on macOS is not officially supported."
echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues."
echo
echo "Check out devcontainers for a seamless experience (see tools/README.md)."
echo "-------------------------------------------------"
echo -n "Are you sure you want to continue? [y/N] "
read -r response
if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
exit 1
fi
fi
echo "--------------- macOS support ---------------"
echo "Running openpilot natively on macOS is still a work-in-progress."
echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues."
echo
echo "Check out devcontainers for a seamless experience (see tools/README.md)."
echo "-------------------------------------------------"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
ROOT="$(cd $DIR/../ && pwd)"

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
RED='\033[0;31m'
GREEN='\033[0;32m'
@ -14,64 +14,66 @@ function op_first_install() {
if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then
RC_FILE="$HOME/.bash_profile"
fi
op_run_command printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE
printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE
echo -e " ↳ [${GREEN}${NC}] op installed successfully. Open a new shell to use it.\n"
)
}
function op_run_command() {
CMD="$@"
echo -e "${BOLD}Running:${NC} $CMD"
if [[ -z "$DRY" ]]; then
eval "$CMD"
fi
}
# be default, assume openpilot dir is in current directory
OPENPILOT_ROOT=$(pwd)
function op_check_openpilot_dir() {
echo "Checking for openpilot directory..."
while [[ "$OPENPILOT_ROOT" != '/' ]];
do
if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then
echo -e " ↳ [${GREEN}${NC}] openpilot found.\n"
return 0
fi
OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)"
done
echo "openpilot directory not found! Make sure that you are inside openpilot"
echo "directory or specify one with the --dir option!"
echo -e " ↳ [${RED}${NC}] openpilot directory not found! Make sure that you are"
echo " inside the openpilot directory or specify one with the"
echo " --dir option!"
return 1
}
function op_run_command() {
CMD="$@"
echo -e "${BOLD}Running:${NC} $CMD"
if [[ -z "$DRY" ]]; then
$CMD
fi
}
function op_check_git() {
(set -e
cd $OPENPILOT_ROOT
echo "Checking for git..."
if ! command -v "git" > /dev/null 2>&1; then
echo -e " ↳ [${RED}${NC}] git not found on your system!"
echo -e " ↳ [${RED}${NC}] git not found on your system!\n"
return 1
else
echo -e " ↳ [${GREEN}${NC}] git found on your system.\n"
echo -e " ↳ [${GREEN}${NC}] git found.\n"
fi
echo "Checking for git lfs files..."
if [[ $(file -b $(git lfs ls-files -n | grep "\.so" | head -n 1)) == "ASCII text" ]]; then
echo -e " ↳ [${RED}${NC}] git lfs files not found! Run git lfs pull"
if [[ $(file -b $OPENPILOT_ROOT/selfdrive/modeld/models/supercombo.onnx) == "ASCII text" ]]; then
echo -e " ↳ [${RED}${NC}] git lfs files not found! Run 'git lfs pull'\n"
return 1
else
echo -e " ↳ [${GREEN}${NC}] git lfs files found on your system.\n"
echo -e " ↳ [${GREEN}${NC}] git lfs files found.\n"
fi
echo "Checking for git submodules..."
if $(git submodule foreach --quiet --recursive 'return 1' 2&> /dev/null); then
echo -e " ↳ [${RED}${NC}] git submodules not found! Run 'git submodule update --init --recursive'"
return 1
else
echo -e " ↳ [${GREEN}${NC}] git submodules found on your system.\n"
fi
for name in body msgq_repo opendbc panda rednose_repo tinygrad_repo; do
if [[ -z $(ls $OPENPILOT_ROOT/$name) ]]; then
echo -e " ↳ [${RED}${NC}] git submodule $name not found! Run 'git submodule update --init --recursive'\n"
return 1
fi
done
echo -e " ↳ [${GREEN}${NC}] git submodules found.\n"
)
}
@ -89,19 +91,19 @@ function op_check_os() {
echo -e " ↳ [${GREEN}${NC}] Ubuntu $VERSION_CODENAME detected.\n"
;;
* )
echo -e " ↳ [${RED}${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!"
echo -e " ↳ [${RED}${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!\n"
return 1
;;
esac
else
echo -e " ↳ [${RED}${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!"
echo -e " ↳ [${RED}${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!\n"
return 1
fi
elif [[ "$OSTYPE" == "darwin"* ]]; then
echo -e " ↳ [${GREEN}${NC}] macos detected.\n"
else
echo -e " ↳ [${RED}${NC}] OS type $OSTYPE not supported!"
echo -e " ↳ [${RED}${NC}] OS type $OSTYPE not supported!\n"
return 1
fi
@ -112,78 +114,109 @@ function op_check_python() {
(set -e
echo "Checking for compatible python version..."
export REQUIRED_PYTHON_VERSION=$(grep "requires-python" pyproject.toml | cut -d= -f3- | tr -d '"' | tr -d ' ')
if ! command -v "python3" > /dev/null 2>&1; then
echo -e " ↳ [${RED}${NC}] python3 not found on your system. You need python version at least $REQUIRED_PYTHON_VERSION to continue!"
REQUIRED_PYTHON_VERSION=$(grep "requires-python" $OPENPILOT_ROOT/pyproject.toml)
INSTALLED_PYTHON_VERSION=$(python3 --version 2> /dev/null || true)
if [[ -z $INSTALLED_PYTHON_VERSION ]]; then
echo -e " ↳ [${RED}${NC}] python3 not found on your system. You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!\n"
return 1
elif [[ $(echo $INSTALLED_PYTHON_VERSION | tr -d -c '[0-9]') -ge $(($(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9]') * 10)) ]]; then
echo -e " ↳ [${GREEN}${NC}] $INSTALLED_PYTHON_VERSION detected.\n"
else
if $(python3 -c "import sys; quit(not sys.version_info >= tuple(map(int, \"$REQUIRED_PYTHON_VERSION\".split('.'))))"); then
echo -e " ↳ [${GREEN}${NC}] $(python3 --version) detected.\n"
else
echo -e " ↳ [${RED}${NC}] You need python version at least $REQUIRED_PYTHON_VERSION to continue!"
return 1
fi
echo -e " ↳ [${RED}${NC}] You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!\n"
return 1
fi
)
}
# this must be run in the same shell as the user calling "op"
function op_venv() {
op_check_openpilot_dir || return 1
op_run_command source $OPENPILOT_ROOT/.venv/bin/activate || (echo -e "\nCan't activate venv. Have you ran 'op install' ?" && return 1)
function op_check_venv() {
echo "Checking for venv..."
if source $OPENPILOT_ROOT/.venv/bin/activate; then
echo -e " ↳ [${GREEN}${NC}] venv detected.\n"
else
echo -e " ↳ [${RED}${NC}] Can't activate venv in $OPENPILOT_ROOT. Assuming global env!\n"
fi
}
function op_check() {
(set -e
function op_before_cmd() {
if [[ ! -z "$NO_VERIFY" ]]; then
return 0
fi
op_check_openpilot_dir
cd $OPENPILOT_ROOT
op_check_git
op_check_os
op_check_venv
op_check_python
)
echo -e "-----------------------------\n"
}
function op_run() {
function op_install() {
(set -e
op_venv
op_check_openpilot_dir
cd $OPENPILOT_ROOT
op_check_os
op_check_python
echo "Installing dependencies..."
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
op_run_command $OPENPILOT_ROOT/tools/ubuntu_setup.sh
elif [[ "$OSTYPE" == "darwin"* ]]; then
op_run_command $OPENPILOT_ROOT/tools/mac_setup.sh
fi
echo -e " ↳ [${GREEN}${NC}] Dependencies installed successfully.\n"
op_run_command $OPENPILOT_ROOT/launch_openpilot.sh
echo "Getting git submodules..."
op_run_command git submodule update --init --recursive
echo -e " ↳ [${GREEN}${NC}] Submodules installed successfully.\n"
echo "Pulling git lfs files..."
op_run_command git lfs pull
echo -e " ↳ [${GREEN}${NC}] Files pulled successfully.\n"
op_check
)
}
function op_install() {
(set -e
function op_venv() {
( set -e
op_check_openpilot_dir
cd $OPENPILOT_ROOT
op_before_cmd
op_check_os
op_check_python
)
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
$OPENPILOT_ROOT/tools/ubuntu_setup.sh
elif [[ "$OSTYPE" == "darwin"* ]]; then
$OPENPILOT_ROOT/tools/mac_setup.sh
if [[ "$?" -eq 0 ]]; then
# this must be run in the same shell as the user calling "op"
op_check_openpilot_dir > /dev/null
op_run_command source $OPENPILOT_ROOT/.venv/bin/activate
fi
}
function op_check() {
(set -e
git submodule update --init --recursive
git lfs pull
op_before_cmd
)
}
function op_build() {
function op_run() {
(set -e
op_venv
cd $OPENPILOT_ROOT
op_before_cmd
op_run_command $OPENPILOT_ROOT/launch_openpilot.sh $@
)
}
function op_build() {
(set -e
op_before_cmd
op_run_command scons $@
)
@ -192,9 +225,7 @@ function op_build() {
function op_juggle() {
(set -e
op_venv
cd $OPENPILOT_ROOT
op_before_cmd
op_run_command $OPENPILOT_ROOT/tools/plotjuggler/juggle.py $@
)
@ -203,9 +234,7 @@ function op_juggle() {
function op_linter() {
(set -e
op_venv
cd $OPENPILOT_ROOT
op_before_cmd
op_run_command pre-commit run --all $@
)
@ -213,14 +242,32 @@ function op_linter() {
function op_replay() {
(set -e
op_check_openpilot_dir
cd $OPENPILOT_ROOT
op_before_cmd
op_run_command $OPENPILOT_ROOT/tools/replay/replay $@
)
}
function op_cabana() {
(set -e
op_before_cmd
op_run_command $OPENPILOT_ROOT/tools/cabana/cabana $@
)
}
function op_sim() {
(set -e
op_before_cmd
op_run_command exec $OPENPILOT_ROOT/tools/sim/run_bridge.py &
op_run_command exec $OPENPILOT_ROOT/tools/sim/launch_openpilot.sh
)
}
function op_default() {
echo "An openpilot helper"
echo ""
@ -242,8 +289,10 @@ function op_default() {
echo -e " ${BOLD}install${NC} Install requirements to use openpilot"
echo -e " ${BOLD}build${NC} Build openpilot"
echo -e " ${BOLD}run${NC} Run openpilot"
echo -e " ${BOLD}sim${NC} Run openpilot in a simulator"
echo -e " ${BOLD}juggle${NC} Run Plotjuggler"
echo -e " ${BOLD}replay${NC} Run replay"
echo -e " ${BOLD}cabana${NC} Run cabana"
echo -e " ${BOLD}linter${NC} Run all the pre-commit checks"
echo -e " ${BOLD}help${NC} Show this message"
echo -e " ${BOLD}--install${NC} Install this tool system wide"
@ -253,6 +302,8 @@ function op_default() {
echo " Specify the openpilot directory you want to use"
echo -e " ${BOLD}--dry${NC}"
echo " Don't actually run anything, just print what would be"
echo -e " ${BOLD}-n, --no-verify${NC}"
echo " Don't run checks before running a command"
echo ""
echo -e "${BOLD}${UNDERLINE}Examples:${NC}"
echo " op --dir /tmp/openpilot check"
@ -271,8 +322,9 @@ function op_default() {
function _op() {
# parse Options
case $1 in
-d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;;
--dry ) shift 1; DRY="1" ;;
-d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;;
--dry ) shift 1; DRY="1" ;;
-n | --no-verify ) shift 1; NO_VERIFY="1" ;;
esac
# parse Commands
@ -283,8 +335,10 @@ function _op() {
build ) shift 1; op_build "$@" ;;
run ) shift 1; op_run "$@" ;;
juggle ) shift 1; op_juggle "$@" ;;
cabana ) shift 1; op_cabana "$@" ;;
linter ) shift 1; op_linter "$@" ;;
replay ) shift 1; op_replay "$@" ;;
sim ) shift 1; op_sim "$@" ;;
--install ) shift 1; op_first_install "$@" ;;
* ) op_default "$@" ;;
esac
@ -309,5 +363,10 @@ unset -f op_default
unset -f op_run_command
unset -f op_linter
unset -f op_replay
unset -f op_cabana
unset -f op_check_venv
unset -f op_before_cmd
unset -f op_sim
unset DRY
unset OPENPILOT_ROOT
unset NO_VERIFY

@ -1,32 +1,59 @@
#!/usr/bin/env bash
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
if [ ! -f launch_openpilot.sh ]; then
if [ ! -d openpilot ]; then
git clone --single-branch --recurse-submodules https://github.com/commaai/openpilot.git
fi
cd openpilot
if [ -z "$OPENPILOT_ROOT" ]; then
# default to current directory for installation
OPENPILOT_ROOT="$(pwd)/openpilot"
fi
if [[ "$OSTYPE" == "darwin"* ]]; then
tools/mac_setup.sh
else
tools/ubuntu_setup.sh
fi
function check_dir() {
echo "Checking for installation directory..."
if [ -d "$OPENPILOT_ROOT" ]; then
echo -e " ↳ [${RED}${NC}] can't install openpilot in $OPENPILOT_ROOT !"
return 1
fi
echo -e " ↳ [${GREEN}${NC}] Successfully chosen $OPENPILOT_ROOT as installation directory\n"
}
function check_git() {
echo "Checking for git..."
if ! command -v "git" > /dev/null 2>&1; then
echo -e " ↳ [${RED}${NC}] git not found on your system, can't continue!"
return 1
else
echo -e " ↳ [${GREEN}${NC}] git found.\n"
fi
}
function git_clone() {
echo "Cloning openpilot..."
if $(git clone --depth=1 https://github.com/commaai/openpilot.git "$OPENPILOT_ROOT"); then
if [[ -f $OPENPILOT_ROOT/launch_openpilot.sh ]]; then
echo -e " ↳ [${GREEN}${NC}] Successfully cloned openpilot.\n"
return 0
fi
fi
echo -e " ↳ [${RED}${NC}] failed to clone openpilot!"
return 1
}
git lfs pull
function install_with_op() {
cd $OPENPILOT_ROOT
$OPENPILOT_ROOT/tools/op.sh --install
$OPENPILOT_ROOT/tools/op.sh install
source .venv/bin/activate
# make op usable right now
alias op="source $OPENPILOT_ROOT/tools/op.sh \"\$@\""
}
echo "Building openpilot"
scons -u -j$(nproc)
check_dir && check_git && git_clone && install_with_op
echo
echo "---- OPENPILOT BUILDING DONE ----"
echo "To push changes to your fork, run the following commands:"
echo "git remote remove origin"
echo "git remote add origin git@github.com:<YOUR_USERNAME>/openpilot.git"
echo "git fetch"
echo "git commit -m \"first commit\""
echo "git push"
unset OPENPILOT_ROOT
unset RED
unset GREEN
unset NC

@ -8,8 +8,3 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
$DIR/install_ubuntu_dependencies.sh
$DIR/install_python_dependencies.sh
echo
echo "---- OPENPILOT SETUP DONE ----"
echo "Open a new shell or configure your active shell env by running:"
echo "source ~/.bashrc"

@ -863,14 +863,14 @@ wheels = [
[[distribution]]
name = "importlib-metadata"
version = "8.0.0"
version = "8.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "zipp" },
]
sdist = { url = "https://files.pythonhosted.org/packages/20/ff/bd28f70283b9cca0cbf0c2a6082acbecd822d1962ae7b2a904861b9965f8/importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812", size = 52667 }
sdist = { url = "https://files.pythonhosted.org/packages/f6/a1/db39a513aa99ab3442010a994eef1cb977a436aded53042e69bee6959f74/importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d", size = 53907 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/ef/38766b2edb096260d9b1b6ad35adaa0bce3b0567abb452b21eb074af88c4/importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f", size = 24769 },
{ url = "https://files.pythonhosted.org/packages/82/47/bb25ec04985d0693da478797c3d8c1092b140f3a53ccb984fbbd38affa5b/importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369", size = 25920 },
]
[[distribution]]
@ -1059,11 +1059,11 @@ wheels = [
[[distribution]]
name = "markdown"
version = "3.6"
version = "3.3.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/22/02/4785861427848cc11e452cc62bb541006a1087cf04a1de83aedd5530b948/Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224", size = 354715 }
sdist = { url = "https://files.pythonhosted.org/packages/d6/58/79df20de6e67a83f0d0bbfe6c19bb82adf68cdf362885257eb01099f930a/Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", size = 324130 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fc/b3/0c0c994fe49cd661084f8d5dc06562af53818cc0abefaca35bdc894577c3/Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f", size = 105381 },
{ url = "https://files.pythonhosted.org/packages/f3/df/ca72f352e15b6f8ce32b74af029f1189abffb906f7c137501ffe69c98a65/Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621", size = 97778 },
]
[[distribution]]
@ -1196,9 +1196,18 @@ dependencies = [
{ name = "yapf" },
]
[[distribution]]
name = "mistletoe"
version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/11/96/ea46a376a7c4cd56955ecdfff0ea68de43996a4e6d1aee4599729453bd11/mistletoe-1.4.0.tar.gz", hash = "sha256:1630f906e5e4bbe66fdeb4d29d277e2ea515d642bb18a9b49b136361a9818c9d", size = 107203 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2a/0f/b5e545f0c7962be90366af3418989b12cf441d9da1e5d89d88f2f3e5cf8f/mistletoe-1.4.0-py3-none-any.whl", hash = "sha256:44a477803861de1237ba22e375c6b617690a31d2902b47279d1f8f7ed498a794", size = 51304 },
]
[[distribution]]
name = "mkdocs"
version = "1.6.0"
version = "1.4.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
@ -1206,32 +1215,29 @@ dependencies = [
{ name = "ghp-import" },
{ name = "jinja2" },
{ name = "markdown" },
{ name = "markupsafe" },
{ name = "mergedeep" },
{ name = "mkdocs-get-deps" },
{ name = "packaging" },
{ name = "pathspec" },
{ name = "pyyaml" },
{ name = "pyyaml-env-tag" },
{ name = "watchdog" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 }
sdist = { url = "https://files.pythonhosted.org/packages/b0/ef/49b4427e5eec761b77a3c3c421d3fd63010e2798b7401dc0fa2b875ef6b5/mkdocs-1.4.3.tar.gz", hash = "sha256:5955093bbd4dd2e9403c5afaf57324ad8b04f16886512a3ee6ef828956481c57", size = 3624951 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b8/c0/930dcf5a3e96b9c8e7ad15502603fc61d495479699e2d2c381e3d37294d1/mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7", size = 3862264 },
{ url = "https://files.pythonhosted.org/packages/42/7a/5ed794942ace9d00bb77a8036c64c999cda6ebaab57e9b8a6ec1aa5fc900/mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd", size = 3654464 },
]
[[distribution]]
name = "mkdocs-get-deps"
version = "0.2.0"
name = "mkdocs-plugin-commonmark"
version = "0.0.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mergedeep" },
{ name = "platformdirs" },
{ name = "pyyaml" },
{ name = "markdown" },
{ name = "mistletoe" },
{ name = "mkdocs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 }
sdist = { url = "https://files.pythonhosted.org/packages/fa/a1/4aaa744deec61d75dbe3c67c18f6e4c1fa7699bc2661b6eff5f891e83023/mkdocs-plugin-commonmark-0.0.4.tar.gz", hash = "sha256:9034507af26646e95188a130782dd07d65c86507fddd3b47ea340c02683e85e7", size = 10805 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 },
{ url = "https://files.pythonhosted.org/packages/f9/4a/4333ef1eb57ff130c7715ba0847dbdae471d153d94507004c92c591cb3c5/mkdocs_plugin_commonmark-0.0.4-py3-none-any.whl", hash = "sha256:70a33394d86a04ec97877ca1b2dff6181de3ec01ef4c7add178fa45b327da535", size = 12532 },
]
[[distribution]]
@ -1585,6 +1591,7 @@ dev = [
{ name = "pyopencl", marker = "platform_machine != 'aarch64'" },
{ name = "pyprof2calltree" },
{ name = "pyqt5", marker = "platform_machine == 'x86_64'" },
{ name = "pytools", marker = "platform_machine != 'aarch64'" },
{ name = "pywinctl" },
{ name = "rerun-sdk" },
{ name = "tabulate" },
@ -1594,6 +1601,7 @@ dev = [
docs = [
{ name = "jinja2" },
{ name = "mkdocs" },
{ name = "mkdocs-plugin-commonmark" },
{ name = "mkdocs-terminal" },
]
testing = [
@ -1705,15 +1713,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/31/13/fe468c8c7400a8eca204e6e160a29bf7dcd45a76e20f1c030f3eaa690d93/parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9", size = 26354 },
]
[[distribution]]
name = "pathspec"
version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 },
]
[[distribution]]
name = "pillow"
version = "10.4.0"
@ -2042,15 +2041,15 @@ wheels = [
[[distribution]]
name = "pymdown-extensions"
version = "10.8.1"
version = "10.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown" },
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/09/11/0a1da270c1011194a6efee7ec1ac07d8b75a9706eed4a80675403f6a9d70/pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940", size = 812097 }
sdist = { url = "https://files.pythonhosted.org/packages/85/71/5f48080bde77b07ca1eba6d7cb5c5598ac6c8f2a399846159b3c8b45e171/pymdown_extensions-10.4.tar.gz", hash = "sha256:bc46f11749ecd4d6b71cf62396104b4a200bad3498cb0f5dad1b8502fe461a35", size = 785151 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c6/d7/e19f9bee2729a8d65b9bf822bb69ac364bf782bac8d761c62b4252769ae0/pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb", size = 250833 },
{ url = "https://files.pythonhosted.org/packages/98/2d/2929de81618c7213176899dd6372d6ec9c8f24337841dd74634fb69864ae/pymdown_extensions-10.4-py3-none-any.whl", hash = "sha256:cfc28d6a09d19448bcbf8eee3ce098c7d17ff99f7bd3069db4819af181212037", size = 240838 },
]
[[distribution]]
@ -4705,7 +4704,7 @@ wheels = [
[[distribution]]
name = "pytest"
version = "8.3.1"
version = "8.3.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
@ -4713,9 +4712,9 @@ dependencies = [
{ name = "packaging" },
{ name = "pluggy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/bc/7f/a6f79e033aa8318b6dfe2173fa6409ee75dafccf409d90884bf921433d88/pytest-8.3.1.tar.gz", hash = "sha256:7e8e5c5abd6e93cb1cc151f23e57adc31fcf8cfd2a3ff2da63e23f732de35db6", size = 1438997 }
sdist = { url = "https://files.pythonhosted.org/packages/b4/8c/9862305bdcd6020bc7b45b1b5e7397a6caf1a33d3025b9a003b39075ffb2/pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce", size = 1439314 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b9/77/ccea391104f576a6e54a54334fc26d29c28aa0ec85714c781fbd2c34ac86/pytest-8.3.1-py3-none-any.whl", hash = "sha256:e9600ccf4f563976e2c99fa02c7624ab938296551f280835ee6516df8bc4ae8c", size = 341628 },
{ url = "https://files.pythonhosted.org/packages/0f/f9/cf155cf32ca7d6fa3601bc4c5dd19086af4b320b706919d48a4c79081cf9/pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", size = 341802 },
]
[[distribution]]
@ -5049,27 +5048,27 @@ wheels = [
[[distribution]]
name = "ruff"
version = "0.5.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8e/1a/5955fa22ab088c1f4d8458b4cbc158c6db72143361e8d46e179c48576aab/ruff-0.5.4.tar.gz", hash = "sha256:2795726d5f71c4f4e70653273d1c23a8182f07dd8e48c12de5d867bfb7557eed", size = 2424702 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/34/2235ecce6794345f42ad334d1b14384c70b202f77509e5678b68a640fe78/ruff-0.5.4-py3-none-linux_armv6l.whl", hash = "sha256:82acef724fc639699b4d3177ed5cc14c2a5aacd92edd578a9e846d5b5ec18ddf", size = 9499774 },
{ url = "https://files.pythonhosted.org/packages/11/23/ffe51028ba274223191d3f96b059108cf7690eb93985a7fdb077c3d1191b/ruff-0.5.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:da62e87637c8838b325e65beee485f71eb36202ce8e3cdbc24b9fcb8b99a37be", size = 8550240 },
{ url = "https://files.pythonhosted.org/packages/28/75/843aa3d10a39ab60fbd63f65c825f647907a9732ac27e24d3f94dd2db618/ruff-0.5.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e98ad088edfe2f3b85a925ee96da652028f093d6b9b56b76fc242d8abb8e2059", size = 8160520 },
{ url = "https://files.pythonhosted.org/packages/19/88/3d0f5244905088cc2fd136fae8ce81f46d145e2449051313c462032d144d/ruff-0.5.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c55efbecc3152d614cfe6c2247a3054cfe358cefbf794f8c79c8575456efe19", size = 9911606 },
{ url = "https://files.pythonhosted.org/packages/1f/ff/6546020836408351e7558dedacc6e5ca7f652f76a9d05ac4882c787d45b1/ruff-0.5.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9b85eaa1f653abd0a70603b8b7008d9e00c9fa1bbd0bf40dad3f0c0bdd06793", size = 9286353 },
{ url = "https://files.pythonhosted.org/packages/b6/bf/51e0c5f12a9bf3c7596cf7f45e1b102f8b49f1da39943e03739890bbf6a4/ruff-0.5.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf497a47751be8c883059c4613ba2f50dd06ec672692de2811f039432875278", size = 10082929 },
{ url = "https://files.pythonhosted.org/packages/b5/0e/a44cb6edb629788de892fc7bb8ac8b47059df94d7ec9c4e52e04bab5be95/ruff-0.5.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:09c14ed6a72af9ccc8d2e313d7acf7037f0faff43cde4b507e66f14e812e37f7", size = 10832586 },
{ url = "https://files.pythonhosted.org/packages/97/ca/e3810f701ae472e5fe3180d56fe6fcc92ea94c7490097a0f731f5602f26f/ruff-0.5.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:628f6b8f97b8bad2490240aa84f3e68f390e13fabc9af5c0d3b96b485921cd60", size = 10421967 },
{ url = "https://files.pythonhosted.org/packages/01/47/a62df6ccd6e5d019271df203ea6564f2022c49f85c0bf6ada708cd7b4a5e/ruff-0.5.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3520a00c0563d7a7a7c324ad7e2cde2355733dafa9592c671fb2e9e3cd8194c1", size = 11371031 },
{ url = "https://files.pythonhosted.org/packages/a1/02/64f24893eea23c447460e6509e9dd0ae18d7a797f67fee1bafed964ebbae/ruff-0.5.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93789f14ca2244fb91ed481456f6d0bb8af1f75a330e133b67d08f06ad85b516", size = 10103164 },
{ url = "https://files.pythonhosted.org/packages/ca/78/683b6c6976fcc33e4a03a0e234e0b9f9b8682f807a661225c829b248de82/ruff-0.5.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:029454e2824eafa25b9df46882f7f7844d36fd8ce51c1b7f6d97e2615a57bbcc", size = 9920056 },
{ url = "https://files.pythonhosted.org/packages/78/3a/6c67c5d670aae2a51a11713aff819d729ed92cb0b1d962b8df27e4657650/ruff-0.5.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9492320eed573a13a0bc09a2957f17aa733fff9ce5bf00e66e6d4a88ec33813f", size = 9361286 },
{ url = "https://files.pythonhosted.org/packages/0d/f5/da3a0e2fd0bcbdb3d2ff579ef9cb3ca2af71b9bee97fa917c9a9e0500b67/ruff-0.5.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6e1f62a92c645e2919b65c02e79d1f61e78a58eddaebca6c23659e7c7cb4ac7", size = 9720829 },
{ url = "https://files.pythonhosted.org/packages/4a/56/5062119a5c9e06d98cd6406bfc1eab7616a7c67494a4d05b6052d99dd147/ruff-0.5.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:768fa9208df2bec4b2ce61dbc7c2ddd6b1be9fb48f1f8d3b78b3332c7d71c1ff", size = 10143530 },
{ url = "https://files.pythonhosted.org/packages/e6/76/16f8f1c8d0cba6c96ab6f292146fc0acb6dd633a989f524d3b3ef1ee8364/ruff-0.5.4-py3-none-win32.whl", hash = "sha256:e1e7393e9c56128e870b233c82ceb42164966f25b30f68acbb24ed69ce9c3a4e", size = 7794271 },
{ url = "https://files.pythonhosted.org/packages/82/35/d6c3c83fb8817328db73c15b1836ccb0c3ce56b72d0d01d98b3a452bec58/ruff-0.5.4-py3-none-win_amd64.whl", hash = "sha256:58b54459221fd3f661a7329f177f091eb35cf7a603f01d9eb3eb11cc348d38c4", size = 8579021 },
{ url = "https://files.pythonhosted.org/packages/3c/ef/3e732c0152280775f728ab99691c718ee9a4ae79bf5af1dd9258f7fe7fef/ruff-0.5.4-py3-none-win_arm64.whl", hash = "sha256:bd53da65f1085fb5b307c38fd3c0829e76acf7b2a912d8d79cadcdb4875c1eb7", size = 8034239 },
version = "0.5.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/95/15/3945cfecfd3de874633d2466327ebb01eabf4f61f962a0dd4bf5ce2dc997/ruff-0.5.5.tar.gz", hash = "sha256:cc5516bdb4858d972fbc31d246bdb390eab8df1a26e2353be2dbc0c2d7f5421a", size = 2434890 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/4d/f9e5e37369b22d74588fe496e82d2aa2fff508f0c05b34c38374194f5a8e/ruff-0.5.5-py3-none-linux_armv6l.whl", hash = "sha256:605d589ec35d1da9213a9d4d7e7a9c761d90bba78fc8790d1c5e65026c1b9eaf", size = 9505926 },
{ url = "https://files.pythonhosted.org/packages/b3/48/ee53a87351dd03472cf1cb8073019a53a7282e4295e7ae62d7f5ae24202a/ruff-0.5.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00817603822a3e42b80f7c3298c8269e09f889ee94640cd1fc7f9329788d7bf8", size = 8585187 },
{ url = "https://files.pythonhosted.org/packages/a2/ec/2c0bd5ec0965672bb2957abf6e44d93c2c7aab2ceb4251ea77eb9234ffd3/ruff-0.5.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:187a60f555e9f865a2ff2c6984b9afeffa7158ba6e1eab56cb830404c942b0f3", size = 8175846 },
{ url = "https://files.pythonhosted.org/packages/8d/d7/e476f96c013d59af08b7b155f2beee03e7595915718573c724a01681bea8/ruff-0.5.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe26fc46fa8c6e0ae3f47ddccfbb136253c831c3289bba044befe68f467bfb16", size = 9948714 },
{ url = "https://files.pythonhosted.org/packages/dd/da/00269f4905b5ceab77f64ec9ed2e8f848ccba68884b66b2423c9f8962878/ruff-0.5.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad25dd9c5faac95c8e9efb13e15803cd8bbf7f4600645a60ffe17c73f60779b", size = 9299822 },
{ url = "https://files.pythonhosted.org/packages/c3/ce/8784906480809b5b43cfbb346bddcc3b9e8716fd73927e4d70fb5260c18e/ruff-0.5.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f70737c157d7edf749bcb952d13854e8f745cec695a01bdc6e29c29c288fc36e", size = 10100197 },
{ url = "https://files.pythonhosted.org/packages/42/a4/4f4796e6b440ed42ec8486e19fe9b9489d94f13c2debf49e68ed58af5d0b/ruff-0.5.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:cfd7de17cef6ab559e9f5ab859f0d3296393bc78f69030967ca4d87a541b97a0", size = 10813891 },
{ url = "https://files.pythonhosted.org/packages/a0/a4/9a0084212e0b2810beadd993f1b36f156438465a4d4193fd5bb2ab833892/ruff-0.5.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09b43e02f76ac0145f86a08e045e2ea452066f7ba064fd6b0cdccb486f7c3e7", size = 10439725 },
{ url = "https://files.pythonhosted.org/packages/8e/f7/4480e739af49f66f04edf2b1dd7ac6fa5e55639491e47267dbfa70d62488/ruff-0.5.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0b856cb19c60cd40198be5d8d4b556228e3dcd545b4f423d1ad812bfdca5884", size = 11358405 },
{ url = "https://files.pythonhosted.org/packages/0e/fd/7a6e01b8098c3375ce694427956a8192c708941051cebd279b988304a753/ruff-0.5.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3687d002f911e8a5faf977e619a034d159a8373514a587249cc00f211c67a091", size = 10130793 },
{ url = "https://files.pythonhosted.org/packages/2f/4a/ba83ca67da7e81a8a191da36f3f6a350243210518c78c2e809fb25cac6c4/ruff-0.5.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ac9dc814e510436e30d0ba535f435a7f3dc97f895f844f5b3f347ec8c228a523", size = 9910666 },
{ url = "https://files.pythonhosted.org/packages/3f/6d/c982a93907559fa5cb62fd68c74b21662a4f088a09ad27f813244c7379c1/ruff-0.5.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:af9bdf6c389b5add40d89b201425b531e0a5cceb3cfdcc69f04d3d531c6be74f", size = 9365153 },
{ url = "https://files.pythonhosted.org/packages/be/a6/b3dbdb4505086d80ab8202c8592ad90a811fc328dc4a5966e065cda12dcc/ruff-0.5.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d40a8533ed545390ef8315b8e25c4bb85739b90bd0f3fe1280a29ae364cc55d8", size = 9736802 },
{ url = "https://files.pythonhosted.org/packages/4d/ba/b850fa0925ce59bc0bce412d18a9633a92126f23153f970437a51be711f0/ruff-0.5.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cab904683bf9e2ecbbe9ff235bfe056f0eba754d0168ad5407832928d579e7ab", size = 10198368 },
{ url = "https://files.pythonhosted.org/packages/56/db/a9162178c90cada13f4c9bed9860947a1c5a79d7ecadd27250c67681dc81/ruff-0.5.5-py3-none-win32.whl", hash = "sha256:696f18463b47a94575db635ebb4c178188645636f05e934fdf361b74edf1bb2d", size = 7798506 },
{ url = "https://files.pythonhosted.org/packages/c9/5b/13288039ea8190c121b70f1a11be2c4830cb3ebb57dc91d91fc5d3c65fc6/ruff-0.5.5-py3-none-win_amd64.whl", hash = "sha256:50f36d77f52d4c9c2f1361ccbfbd09099a1b2ea5d2b2222c586ab08885cf3445", size = 8611739 },
{ url = "https://files.pythonhosted.org/packages/ba/b3/525847f73ab956053b130ec9f5d1ea078d94282b1d5eda90c09b8a81a935/ruff-0.5.5-py3-none-win_arm64.whl", hash = "sha256:3191317d967af701f1b73a31ed5788795936e423b7acce82a2b63e26eb3e89d6", size = 8039120 },
]
[[distribution]]
@ -5124,15 +5123,15 @@ wheels = [
[[distribution]]
name = "sentry-sdk"
version = "2.10.0"
version = "2.11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/34/d8/ec3e43d4ce31e4f4cb6adb7210950362d71ce87a96c89934c4ac94f7110f/sentry_sdk-2.10.0.tar.gz", hash = "sha256:545fcc6e36c335faa6d6cda84669b6e17025f31efbf3b2211ec14efe008b75d1", size = 273996 }
sdist = { url = "https://files.pythonhosted.org/packages/6d/b3/39e4cd04b75a1ada788342d0d30a781cf65b5e43da806d5bf2bad4846ea3/sentry_sdk-2.11.0.tar.gz", hash = "sha256:4ca16e9f5c7c6bc2fb2d5c956219f4926b148e511fffdbbde711dc94f1e0468f", size = 276242 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4f/9e/9298785949269c8930e1fd3707b960da6e1a95a2442b747b8f8cca4578cb/sentry_sdk-2.10.0-py2.py3-none-any.whl", hash = "sha256:87b3d413c87d8e7f816cc9334bff255a83d8b577db2b22042651c30c19c09190", size = 302064 },
{ url = "https://files.pythonhosted.org/packages/bc/3c/a8ab3309d22c1d7142f811882e7d45449696f87c6e4e723b1433b6069b84/sentry_sdk-2.11.0-py2.py3-none-any.whl", hash = "sha256:d964710e2dbe015d9dc4ff0ad16225d68c3b36936b742a6fe0504565b760a3b7", size = 303581 },
]
[[distribution]]

Loading…
Cancel
Save