diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index f5cc0d5003..7fe4263db5 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -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 diff --git a/.github/workflows/jenkins-pr-trigger.yaml b/.github/workflows/jenkins-pr-trigger.yaml new file mode 100644 index 0000000000..db1d524018 --- /dev/null +++ b/.github/workflows/jenkins-pr-trigger.yaml @@ -0,0 +1,45 @@ +name: jenkins scan + +on: + issue_comment: + types: [created, edited] + +jobs: + # TODO: gc old branches in a separate job in this workflow + scan-comments: + runs-on: ubuntu-latest + if: ${{ github.event.issue.pull_request }} + steps: + - name: Check for trigger phrase + id: check_comment + uses: actions/github-script@v7 + with: + script: | + const triggerPhrase = "trigger-jenkins"; + const comment = context.payload.comment.body; + const commenter = context.payload.comment.user.login; + + const { data: permissions } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: commenter + }); + + const hasWriteAccess = permissions.permission === 'write' || permissions.permission === 'admin'; + + return (hasWriteAccess && comment.includes(triggerPhrase)); + result-encoding: json + + - name: Checkout repository + if: steps.check_comment.outputs.result == 'true' + uses: actions/checkout@v4 + with: + ref: refs/pull/${{ github.event.issue.number }}/head + + - name: Push to tmp-jenkins branch + if: steps.check_comment.outputs.result == 'true' + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b tmp-jenkins-${{ github.event.issue.number }} + GIT_LFS_SKIP_PUSH=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }} diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 8968b493cf..a178634321 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -74,8 +74,11 @@ jobs: build: strategy: matrix: - arch: ${{ fromJson('["x86_64"]') }} # TODO: Re-add build test for aarch64 once we switched to ubuntu-2404 - runs-on: ubuntu-latest + arch: ${{ fromJson( + ((github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && '["x86_64", "aarch64"]' || '["x86_64"]' ) }} + runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 with: @@ -84,7 +87,7 @@ jobs: if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' run: | echo "PUSH_IMAGE=true" >> "$GITHUB_ENV" - : # (TODO: Re-add this once we test other archs) echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV" + echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV" $DOCKER_LOGIN - uses: ./.github/workflows/setup-with-retry with: @@ -93,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 @@ -103,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 @@ -118,6 +120,23 @@ jobs: - name: Building openpilot run: . .venv/bin/activate && scons -j$(nproc) + docker_push_multiarch: + name: docker push multiarch tag + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' + needs: [build] + steps: + - uses: actions/checkout@v4 + with: + submodules: false + - name: Setup docker + run: | + $DOCKER_LOGIN + - name: Merge x64 and arm64 tags + run: | + export PUSH_IMAGE=true + scripts/retry.sh selfdrive/test/docker_tag_multiarch.sh base x86_64 aarch64 + static_analysis: name: static analysis runs-on: ${{ ((github.repository == 'commaai/openpilot') && @@ -318,6 +337,7 @@ jobs: }) create_ui_report: + # This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml name: Create UI Report runs-on: ubuntu-latest steps: @@ -335,55 +355,5 @@ jobs: - name: Upload Test Report uses: actions/upload-artifact@v4 with: - name: report-${{ inputs.run_number || '1' }} - path: selfdrive/ui/tests/test_ui/report_${{ inputs.run_number || '1' }} - - name: Get changes to selfdrive/ui - if: ${{ github.event_name == 'pull_request' }} - id: changed-files - uses: tj-actions/changed-files@v44 - with: - files: | - selfdrive/ui/** - - name: Checkout ci-artifacts - if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.any_changed == 'true' }} - uses: actions/checkout@v4 - with: - repository: commaai/ci-artifacts - ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }} - path: ${{ github.workspace }}/ci-artifacts - ref: master - - name: Push Screenshots - if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.any_changed == 'true' }} - working-directory: ${{ github.workspace }}/ci-artifacts - run: | - git checkout -b openpilot/pr-${{ github.event.pull_request.number }} - git config user.name "GitHub Actions Bot" - git config user.email "<>" - sudo mv ${{ github.workspace }}/selfdrive/ui/tests/test_ui/report_1/screenshots/* . - git add . - git commit -m "screenshots for PR #${{ github.event.pull_request.number }}" - git push origin openpilot/pr-${{ github.event.pull_request.number }} --force - - name: Comment Screenshots on PR - if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.any_changed == 'true' }} - uses: thollander/actions-comment-pull-request@v2 - with: - message: | - - ## UI Screenshots - - - - - - - - - - - - - -
- comment_tag: run_id_screenshots - pr_number: ${{ github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + name: report-${{ github.event.number }} + path: selfdrive/ui/tests/test_ui/report_1/screenshots diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index b64963fb60..9085556392 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -73,12 +73,6 @@ jobs: scons-${{ runner.arch }}-ubuntu2004 - name: Building openpilot run: uv run scons -u -j$(nproc) - - name: Saving scons cache - uses: actions/cache/save@v4 - if: github.ref == 'refs/heads/master' - with: - path: /tmp/scons_cache - key: scons-${{ runner.arch }}-ubuntu2004-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }} devcontainer: name: devcontainer diff --git a/.github/workflows/ui_preview.yaml b/.github/workflows/ui_preview.yaml new file mode 100644 index 0000000000..bc19e23778 --- /dev/null +++ b/.github/workflows/ui_preview.yaml @@ -0,0 +1,91 @@ +name: "ui preview" +on: + pull_request_target: + types: [assigned, opened, synchronize, reopened, edited] + branches: + - 'master' + paths: + - 'selfdrive/ui/**' + +env: + UI_JOB_NAME: "Create UI Report" + +jobs: + preview: + if: github.repository == 'commaai/openpilot' + name: preview + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + pull-requests: write + actions: read + steps: + - name: Waiting for ui test to start + run: sleep 30 + + - name: Wait for ui report + uses: lewagon/wait-on-check-action@v1.3.4 + with: + ref: ${{ github.event.pull_request.head.sha }} + check-name: ${{ env.UI_JOB_NAME }} + repo-token: ${{ secrets.GITHUB_TOKEN }} + allowed-conclusions: success + wait-interval: 20 + + - name: Get workflow run ID + id: get_run_id + run: | + echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs | jq -r '.check_runs[] | select(.name == "${{ env.UI_JOB_NAME }}") | .html_url | capture("(?[0-9]+)") | .number')" >> $GITHUB_OUTPUT + + - name: Checkout ci-artifacts + uses: actions/checkout@v4 + with: + repository: commaai/ci-artifacts + ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }} + path: ${{ github.workspace }}/ci-artifacts + ref: master + + - name: Download artifact + id: download-artifact + uses: dawidd6/action-download-artifact@v6 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + run_id: ${{ steps.get_run_id.outputs.run_id }} + search_artifacts: true + name: report-${{ github.event.number }} + path: ${{ github.workspace }}/ci-artifacts + + - name: Push Screenshots + working-directory: ${{ github.workspace }}/ci-artifacts + run: | + git checkout -b openpilot/pr-${{ github.event.number }} + git config user.name "GitHub Actions Bot" + git config user.email "<>" + git add ${{ github.workspace }}/ci-artifacts/* + git commit -m "screenshots for PR #${{ github.event.number }}" + git push origin openpilot/pr-${{ github.event.number }} --force + + - name: Comment Screenshots on PR + uses: thollander/actions-comment-pull-request@v2 + with: + message: | + + ## UI Screenshots + + + + + + + + + + + + + +
+ comment_tag: run_id_screenshots + pr_number: ${{ github.event.number }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ab9ce08c7a..10939f4289 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.2 + rev: v0.5.4 hooks: - id: ruff exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)' diff --git a/README.md b/README.md index db74ee6a1a..8ebc733e63 100644 --- a/README.md +++ b/README.md @@ -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) +
-What is openpilot? ------- +

openpilot

-[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 is an operating system for robotics. +
+ Currently, it upgrades the driver assistance system in 275+ supported cars. +

+ +

+ Read the docs + · + Contribute + · + Community + · + Try it on a comma 3X +

+ +Quick start: `curl -fsSL openpilot.comma.ai | bash` + +![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) + +
@@ -19,7 +42,7 @@ To start using openpilot in a car To use openpilot in a car, you need four things: 1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x). 2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version. -3. **Supported Car:** Ensure that you have one of [the 250+ supported cars](docs/CARS.md). +3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](docs/CARS.md). 4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car. We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play. @@ -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 +------ - +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. diff --git a/SConstruct b/SConstruct index 0c4dbee18e..329ebe3308 100644 --- a/SConstruct +++ b/SConstruct @@ -102,7 +102,6 @@ if arch == "larch64": libpath = [ "/usr/local/lib", - "/usr/lib", "/system/vendor/lib64", f"#third_party/acados/{arch}/lib", ] @@ -170,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') @@ -206,7 +204,6 @@ env = Environment( "#third_party/json11", "#third_party/linux/include", "#third_party/snpe/include", - "#third_party/qrcode", "#third_party", "#cereal", "#msgq", @@ -315,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", diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 45a1503b0c..92cb501b8b 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -5,6 +5,9 @@ site_url: https://docs.comma.ai strict: true +plugins: + - commonmark + theme: name: terminal features: diff --git a/opendbc b/opendbc index 5ba787024f..cff2af8ff8 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 5ba787024f53a00d76c7b253d1f3fee87763c679 +Subproject commit cff2af8ff8690466109f56be62129ebfb85cd5dc diff --git a/panda b/panda index b4e3d5cdd2..f6375848ca 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit b4e3d5cdd2dec2a58807b0d710a5d3561a59529d +Subproject commit f6375848ca393a9483921665b6a2d131d7ec9b20 diff --git a/pyproject.toml b/pyproject.toml index 126e122ab3..afebfe7a7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,22 +52,25 @@ dependencies = [ "websocket_client", # acados deps - "casadi", + "casadi @ https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl ; (python_version == '3.12' and platform_machine == 'aarch64')", # TODO: Go back to pypi casadi when they fix aarch64 for python312 + "casadi; platform_machine != 'aarch64' or python_version != '3.12'", "future-fstrings", # these should be removed "psutil", "pycryptodome", # used in updated/casync, panda, body, and a test - #logreader + # logreader "zstd", ] [project.optional-dependencies] docs = [ "Jinja2", - "mkdocs", + "natsort", + "mkdocs==1.4.3", # needed for mkdocs-plugin-commonmark "mkdocs-terminal", + "mkdocs-plugin-commonmark", ] testing = [ @@ -93,7 +96,6 @@ dev = [ "av", "azure-identity", "azure-storage-blob", - "breathe", "control", "dictdiffer", "flaky", @@ -101,14 +103,11 @@ dev = [ "lru-dict", "matplotlib", "metadrive-simulator@git+https://github.com/commaai/metadrive@opencv_headless ; platform_machine != 'aarch64'", - "mpld3", - "myst-parser", - "natsort", - "opencv-python-headless", "parameterized >=0.8, <0.9", - #pprofile = "*" + #"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", @@ -119,7 +118,6 @@ dev = [ # this is only pinned since 5.15.11 is broken "pyqt5 ==5.15.2; platform_machine == 'x86_64'", # no aarch64 wheels for macOS/linux - ] [project.urls] @@ -226,7 +224,7 @@ lint.ignore = [ "UP038", # (x, y) -> x|y for isinstance ] line-length = 160 -target-version="py311" +target-version ="py311" exclude = [ "body", "cereal", @@ -238,7 +236,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" @@ -250,5 +249,6 @@ lint.flake8-implicit-str-concat.allow-multiline=false [tool.coverage.run] concurrency = ["multiprocessing", "thread"] + [tool.ruff.format] quote-style = "preserve" diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 5528bfd5d5..5198c661d7 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -26,6 +26,7 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x753, None): [ b'04672758AA', + b'04672758AB', b'68226356AF', b'68226356AH', b'68226356AI', @@ -47,6 +48,7 @@ FW_VERSIONS = { b'68352654AE ', b'68366851AH ', b'68366853AE ', + b'68366853AG ', b'68372861AF ', ], (Ecu.transmission, 0x7e1, None): [ @@ -60,6 +62,7 @@ FW_VERSIONS = { b'68277374AD', b'68277374AN', b'68367471AC', + b'68367471AD', b'68380571AB', ], }, @@ -387,6 +390,7 @@ FW_VERSIONS = { b'68294051AI', b'68294052AG', b'68294052AH', + b'68294059AI', b'68294063AG', b'68294063AH', b'68294063AI', @@ -397,6 +401,7 @@ FW_VERSIONS = { b'68434858AC', b'68434859AC', b'68434860AC', + b'68453471AD', b'68453483AC', b'68453483AD', b'68453487AD', @@ -421,11 +426,13 @@ FW_VERSIONS = { b'68527346AE', b'68527361AD', b'68527375AD', + b'68527381AD', b'68527381AE', b'68527382AE', b'68527383AD', b'68527383AE', b'68527387AE', + b'68527397AD', b'68527403AC', b'68527403AD', b'68546047AF', @@ -516,6 +523,7 @@ FW_VERSIONS = { b'05036066AE ', b'05036193AA ', b'05149368AA ', + b'05149374AA ', b'05149591AD ', b'05149591AE ', b'05149592AE ', @@ -546,6 +554,7 @@ FW_VERSIONS = { b'68455145AC ', b'68455145AE ', b'68455146AC ', + b'68460927AA ', b'68467915AC ', b'68467916AC ', b'68467936AC ', @@ -564,6 +573,7 @@ FW_VERSIONS = { b'68539650AF', b'68539651AD', b'68586101AA ', + b'68586102AA ', b'68586105AB ', b'68629919AC ', b'68629922AC ', @@ -602,6 +612,8 @@ FW_VERSIONS = { b'68520867AE', b'68520867AF', b'68520870AC', + b'68520871AC', + b'68528325AE', b'68540431AB', b'68540433AB', b'68551676AA', diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index 4c659f053f..5f959bd68d 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -292,6 +292,7 @@ FW_VERSIONS = { b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102', b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLEC0 4TSHC102', b'\xf1\x00TM MDPS C 1.00 1.02 56310-GA000 4TSHA100', + b'\xf1\x00TM MDPS C 1.00 1.02 56310GA000\x00 4TSHA100', b'\xf1\x00TM MDPS R 1.00 1.05 57700-CL000 4TSHP105', b'\xf1\x00TM MDPS R 1.00 1.06 57700-CL000 4TSHP106', ], @@ -408,6 +409,7 @@ FW_VERSIONS = { b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360', b'\xf1\x00ON ESC \x0b 101\x19\t\x05 58910-S9320', b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360', + b'\xf1\x00ON ESC \x0b 103$\x04\x08 58910-S9360', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00LX2 MDPS C 1,00 1,03 56310-S8020 4LXDC103', @@ -481,11 +483,13 @@ FW_VERSIONS = { }, CAR.GENESIS_G80: { (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00DH__ SCC F-CU- 1.00 1.01 96400-B1110 ', b'\xf1\x00DH__ SCC F-CUP 1.00 1.01 96400-B1120 ', b'\xf1\x00DH__ SCC F-CUP 1.00 1.02 96400-B1120 ', b'\xf1\x00DH__ SCC FHCUP 1.00 1.01 96400-B1110 ', ], (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00DH LKAS AT EUR LHD 1.01 1.01 95895-B1500 161014', b'\xf1\x00DH LKAS AT KOR LHD 1.01 1.01 95895-B1500 161014', b'\xf1\x00DH LKAS AT KOR LHD 1.01 1.02 95895-B1500 170810', b'\xf1\x00DH LKAS AT USA LHD 1.01 1.01 95895-B1500 161014', @@ -761,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: { diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index a4d0ad1707..37c69b54fb 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -1152,6 +1152,7 @@ FW_VERSIONS = { }, CAR.TOYOTA_RAV4_TSS2_2023: { (Ecu.abs, 0x7b0, None): [ + b'\x01F15260R440\x00\x00\x00\x00\x00\x00', b'\x01F15260R450\x00\x00\x00\x00\x00\x00', b'\x01F15260R50000\x00\x00\x00\x00', b'\x01F15260R51000\x00\x00\x00\x00', @@ -1173,6 +1174,7 @@ FW_VERSIONS = { b'\x01896634AE1001\x00\x00\x00\x00', b'\x01896634AF0000\x00\x00\x00\x00', b'\x01896634AJ2000\x00\x00\x00\x00', + b'\x01896634AJ3000\x00\x00\x00\x00', b'\x01896634AL5000\x00\x00\x00\x00', b'\x01896634AL6000\x00\x00\x00\x00', b'\x01896634AL8000\x00\x00\x00\x00', diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 25833da741..588e638c95 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -832,7 +832,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { }, EventName.espActive: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Electronic Stability Control Active"), + ET.SOFT_DISABLE: soft_disable_alert("Electronic Stability Control Active"), ET.NO_ENTRY: NoEntryAlert("Electronic Stability Control Active"), }, diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index e4841c705f..efeb76c4a8 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -22,22 +22,26 @@ def long_control_state_trans(CP, active, long_control_state, v_ego, long_control_state = LongCtrlState.off else: - if long_control_state in (LongCtrlState.off, LongCtrlState.pid): - long_control_state = LongCtrlState.pid - if stopping_condition: + if long_control_state == LongCtrlState.off: + if not starting_condition: long_control_state = LongCtrlState.stopping + else: + if starting_condition and CP.startingState: + long_control_state = LongCtrlState.starting + else: + long_control_state = LongCtrlState.pid + elif long_control_state == LongCtrlState.stopping: if starting_condition and CP.startingState: long_control_state = LongCtrlState.starting elif starting_condition: long_control_state = LongCtrlState.pid - elif long_control_state == LongCtrlState.starting: + elif long_control_state in [LongCtrlState.starting, LongCtrlState.pid]: if stopping_condition: long_control_state = LongCtrlState.stopping elif started_condition: long_control_state = LongCtrlState.pid - return long_control_state class LongControl: diff --git a/selfdrive/controls/tests/test_longcontrol.py b/selfdrive/controls/tests/test_longcontrol.py new file mode 100644 index 0000000000..ab50810d89 --- /dev/null +++ b/selfdrive/controls/tests/test_longcontrol.py @@ -0,0 +1,56 @@ +from cereal import car +from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState, long_control_state_trans + + + + +class TestLongControlStateTransition: + + def test_stay_stopped(self): + CP = car.CarParams.new_message() + active = True + current_state = LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=True, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=True, cruise_standstill=False) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=False, cruise_standstill=True) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.pid + active = False + next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.off + +def test_engage(): + CP = car.CarParams.new_message() + active = True + current_state = LongCtrlState.off + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=True, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=True, cruise_standstill=False) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=False, cruise_standstill=True) + assert next_state == LongCtrlState.stopping + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.pid + +def test_starting(): + CP = car.CarParams.new_message(startingState=True, vEgoStarting=0.5) + active = True + current_state = LongCtrlState.starting + next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.starting + next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0, + should_stop=False, brake_pressed=False, cruise_standstill=False) + assert next_state == LongCtrlState.pid diff --git a/selfdrive/debug/run_process_on_route.py b/selfdrive/debug/run_process_on_route.py index 90db14bc9a..c98763f3c9 100755 --- a/selfdrive/debug/run_process_on_route.py +++ b/selfdrive/debug/run_process_on_route.py @@ -3,8 +3,7 @@ import argparse from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, replay_process -from openpilot.tools.lib.helpers import save_log -from openpilot.tools.lib.logreader import LogReader +from openpilot.tools.lib.logreader import LogReader, save_log if __name__ == "__main__": parser = argparse.ArgumentParser(description="Run process on route and create new logs", diff --git a/selfdrive/modeld/models/commonmodel_pyx.pyx b/selfdrive/modeld/models/commonmodel_pyx.pyx index e292bb0d2d..ecbe644e09 100644 --- a/selfdrive/modeld/models/commonmodel_pyx.pyx +++ b/selfdrive/modeld/models/commonmodel_pyx.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# cython: c_string_encoding=ascii +# cython: c_string_encoding=ascii, language_level=3 import numpy as np cimport numpy as cnp diff --git a/selfdrive/modeld/runners/runmodel_pyx.pyx b/selfdrive/modeld/runners/runmodel_pyx.pyx index e1b201a6a9..12b8ec10ff 100644 --- a/selfdrive/modeld/runners/runmodel_pyx.pyx +++ b/selfdrive/modeld/runners/runmodel_pyx.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# cython: c_string_encoding=ascii +# cython: c_string_encoding=ascii, language_level=3 from libcpp.string cimport string diff --git a/selfdrive/modeld/runners/snpemodel_pyx.pyx b/selfdrive/modeld/runners/snpemodel_pyx.pyx index c3b2b7e9bd..f83b7c8cff 100644 --- a/selfdrive/modeld/runners/snpemodel_pyx.pyx +++ b/selfdrive/modeld/runners/snpemodel_pyx.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# cython: c_string_encoding=ascii +# cython: c_string_encoding=ascii, language_level=3 import os from libcpp cimport bool diff --git a/selfdrive/modeld/runners/thneedmodel_pyx.pyx b/selfdrive/modeld/runners/thneedmodel_pyx.pyx index 53487afa1b..6f8fdd255f 100644 --- a/selfdrive/modeld/runners/thneedmodel_pyx.pyx +++ b/selfdrive/modeld/runners/thneedmodel_pyx.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# cython: c_string_encoding=ascii +# cython: c_string_encoding=ascii, language_level=3 from libcpp cimport bool from libcpp.string cimport string diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index 0e43cad820..a58a58107e 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -10,8 +10,7 @@ from openpilot.tools.lib.openpilotci import BASE_URL, get_url from openpilot.selfdrive.test.process_replay.compare_logs import compare_logs, format_diff from openpilot.selfdrive.test.process_replay.process_replay import get_process_config, replay_process from openpilot.tools.lib.framereader import FrameReader -from openpilot.tools.lib.logreader import LogReader -from openpilot.tools.lib.helpers import save_log +from openpilot.tools.lib.logreader import LogReader, save_log TEST_ROUTE = "2f4452b03ccb98f0|2022-12-03--13-45-30" SEGMENT = 6 diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index bf7a4bfd97..fe33443b49 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -14,8 +14,7 @@ from openpilot.selfdrive.test.process_replay.vision_meta import DRIVER_CAMERA_FR from openpilot.selfdrive.test.update_ci_routes import upload_route from openpilot.tools.lib.route import Route from openpilot.tools.lib.framereader import FrameReader, BaseFrameReader, FrameType -from openpilot.tools.lib.logreader import LogReader, LogIterable -from openpilot.tools.lib.helpers import save_log +from openpilot.tools.lib.logreader import LogReader, LogIterable, save_log class DummyFrameReader(BaseFrameReader): diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 533ab125f9..3bd58dfacb 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -14,8 +14,7 @@ from openpilot.selfdrive.test.process_replay.compare_logs import compare_logs, f from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, PROC_REPLAY_DIR, FAKEDATA, replay_process, \ check_openpilot_enabled, check_most_messages_valid from openpilot.tools.lib.filereader import FileReader -from openpilot.tools.lib.logreader import LogReader -from openpilot.tools.lib.helpers import save_log +from openpilot.tools.lib.logreader import LogReader, save_log source_segments = [ ("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.COMMA_BODY diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index bbb99d13b9..1e4669fb0a 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -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, diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 9046ecc228..c6b4860bf7 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -109,7 +109,7 @@ if GetOption('extras') and arch != "Darwin": obj = senv.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d) f = senv.Program(f"installer/installers/installer_{name}", [obj, cont], LIBS=qt_libs) # keep installers small - assert f[0].get_size() < 350*1e3 + assert f[0].get_size() < 370*1e3 # build watch3 if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): diff --git a/selfdrive/ui/qt/qt_window.cc b/selfdrive/ui/qt/qt_window.cc index f71cea04e9..8d3d7cf72e 100644 --- a/selfdrive/ui/qt/qt_window.cc +++ b/selfdrive/ui/qt/qt_window.cc @@ -18,7 +18,9 @@ void setMainWindow(QWidget *w) { wl_surface *s = reinterpret_cast(native->nativeResourceForWindow("surface", w->windowHandle())); wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270); wl_surface_commit(s); - w->showFullScreen(); + + w->setWindowState(Qt::WindowFullScreen); + w->setVisible(true); // ensure we have a valid eglDisplay, otherwise the ui will silently fail void *egl = native->nativeResourceForWindow("egldisplay", w->windowHandle()); diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index 941b30e2d0..c8093e3029 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -64,7 +64,7 @@ Prevent large data uploads when on a metered connection - Evitar grandes descargas de datos cuando tiene una conexión limitada + Evitar grandes descargas de datos cuando tenga una conexión limitada Hidden Network @@ -72,7 +72,7 @@ CONNECT - CONNECTAR + CONECTAR Enter SSID @@ -117,7 +117,7 @@ DeclinePage You must accept the Terms and Conditions in order to use openpilot. - Debe aceptar los terminos y condiciones para poder utilizar openpilot. + Debe aceptar los términos y condiciones para poder utilizar openpilot. Back @@ -164,11 +164,11 @@ Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Previsualizar la cámara del conductor para garantizar que la monitorización del sistema tenga buena visibilidad (El vehículo tiene que estar apagado) + Previsualizar la cámara del conductor para garantizar que la monitorización del sistema tenga buena visibilidad (el vehículo tiene que estar apagado) Reset Calibration - Reiniciar Calibración + Formatear Calibración RESET @@ -176,11 +176,11 @@ Are you sure you want to reset calibration? - ¿Seguro qué quiere reiniciar la calibración? + ¿Seguro que quiere formatear la calibración? Reset - Reiniciar + Formatear Review Training Guide @@ -196,7 +196,7 @@ Are you sure you want to review the training guide? - ¿Seguro qué quiere revisar la guía de entrenamiento? + ¿Seguro que quiere revisar la guía de entrenamiento? Review @@ -232,11 +232,11 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot requiere que el dispositivo sea montado entre 4° izquierda o derecha y entre 5° arriba o 9° abajo. openpilot está constantemente en calibración, reiniciar es rara vez necesario. + openpilot requiere que el dispositivo sea montado entre 4° grados a la izquierda o derecha y entre 5° grados hacia arriba o 9° grados hacia abajo. openpilot está constantemente en calibración, formatear rara vez es necesario. Your device is pointed %1° %2 and %3° %4. - Su dispositivo está apuntando %1° %2 e %3° %4. + Su dispositivo está apuntando %1° %2 y %3° %4. down @@ -286,7 +286,7 @@ CHILL MODE ON - MODO TRANQUILO + MODO CHILL @@ -298,7 +298,7 @@ Need at least %n character(s)! - ¡Necesita mínimo %n caractere! + ¡Necesita mínimo %n caracter! ¡Necesita mínimo %n caracteres! @@ -314,7 +314,7 @@ MultiOptionDialog Select - Seleccione + Seleccionar Cancel @@ -337,22 +337,22 @@ Wrong password - Contraseña equivocada + Contraseña incorrecta OffroadAlert Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - Temperatura de dispositivo muy alta. Systema enfriando antes de iniciar. Temperatura actual del componente interno: %1 + La temperatura del dispositivo es muy alta. El sistema se está enfriando antes de iniciar. Temperatura actual del componente interno: %1 Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - Inmediatamente conectar al internet para buscar actualizaciones. Si no se conecta al internet, openpilot no iniciara en %1 + Conéctese inmediatamente al internet para buscar actualizaciones. Si no se conecta al internet, openpilot no iniciará en %1 Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. - Conectar al internet para buscar actualizaciones. openpilot no iniciara automáticamente hasta conectarse al internet para buscar actualizaciones. + Conectese al internet para buscar actualizaciones. openpilot no iniciará automáticamente hasta conectarse al internet para buscar actualizaciones. Unable to download updates @@ -362,7 +362,7 @@ Taking camera snapshots. System won't start until finished. - Tomando instantáneas de la cámara. El sistema no se iniciará hasta que finalice. + Tomando capturas de las cámaras. El sistema no se iniciará hasta que finalice. An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. @@ -370,7 +370,7 @@ Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - El dispositivo no pudo registrarse. No se conectará ni cargará en los servidores de comma.ai y no recibe soporte de comma.ai. Si este es un dispositivo oficial, visite https://comma.ai/support. + El dispositivo no pudo registrarse. No se conectará ni subirá datos a los servidores de comma.ai y no recibe soporte de comma.ai. Si este es un dispositivo oficial, visite https://comma.ai/support. NVMe drive not mounted. @@ -378,15 +378,15 @@ Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - Se detectó una unidad NVMe no compatible. El dispositivo puede consumir mucha más energía y sobrecalentarse debido a que NVMe no es compatible. + Se detectó una unidad NVMe incompatible. El dispositivo puede consumir mucha más energía y sobrecalentarse debido a esto. openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - openpilot no pudo identificar su automóvil. Su automóvil no es compatible o no se reconocen sus ECU. Envíe una solicitud de extracción para agregar las versiones de firmware al vehículo adecuado. ¿Necesitas ayuda? Únase a discord.comma.ai. + openpilot no pudo identificar su automóvil. Su automóvil no es compatible o no se reconocen sus ECU. Por favor haga un pull request para agregar las versiones de firmware del vehículo adecuado. ¿Necesita ayuda? Únase a discord.comma.ai. openpilot was unable to identify your car. Check integrity of cables and ensure all connections are secure, particularly that the comma power is fully inserted in the OBD-II port of the vehicle. Need help? Join discord.comma.ai. - openpilot no pudo identificar su automóvil. Verifique la integridad de los cables y asegúrese de que todas las conexiones estén seguras, en particular que comma power esté completamente insertada en el puerto OBD-II del vehículo. ¿Necesitas ayuda? Únase a discord.comma.ai. + openpilot no pudo identificar su automóvil. Verifique la integridad de los cables y asegúrese de que todas las conexiones estén seguras, en particular que el comma power esté completamente insertado en el puerto OBD-II del vehículo. ¿Necesita ayuda? Únase discord.comma.ai. openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. @@ -439,15 +439,15 @@ Go to https://connect.comma.ai on your phone - Ve a https://connect.comma.ai en su telefono + Vaya a https://connect.comma.ai en su teléfono Click "add new device" and scan the QR code on the right - Clic en "agregar nuevo dispositivo" y escanee el código QR a la derecha + Seleccione "agregar nuevo dispositivo" y escanee el código QR a la derecha Bookmark connect.comma.ai to your home screen to use it like an app - Marcar connect.comma.ai como su pantalla de inicio para usarlo como una aplicación + Añada connect.comma.ai a su pantalla de inicio para usarlo como una aplicación @@ -469,7 +469,7 @@ Become a comma prime member at connect.comma.ai - Hazte miembro prime de comma en connect.comma.ai + Hazte miembro de comma prime en connect.comma.ai PRIME FEATURES: @@ -485,11 +485,11 @@ 1 year of drive storage - 1 año de almacenamiento en disco + 1 año de almacenamiento Remote snapshots - Istantánea remota + Capturas remotas @@ -547,25 +547,25 @@ Reset Reset failed. Reboot to try again. - Reset fallido. Reinicie de nuevo. + Formateo fallido. Reinicie para reintentar. Resetting device... This may take up to a minute. - Reiniciando dispositivo... -Esto puede tardar hasta un minuto. + formateando dispositivo... +Esto puede tardar un minuto. Are you sure you want to reset your device? - ¿Seguro que quiere reiniciar su dispositivo? + ¿Seguro que quiere formatear su dispositivo? System Reset - Reiniciar Sistema + Formatear Sistema System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Reinicio del sistema activado. Presione confirmar para borrar todo el contenido y la configuración. Presione cancelar para reanudar el inicio. + Formateo del sistema activado. Presione confirmar para borrar todo el contenido y la configuración. Presione cancelar para reanudar el inicio. Cancel @@ -581,7 +581,7 @@ Esto puede tardar hasta un minuto. Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - No es posible montar una partición de datos. Partición corrompida. Confirme para borrar y reiniciar su dispositivo. + No es posible montar una partición de datos. La partición podría estar corrompida. Confirme para borrar y formatear su dispositivo. @@ -615,19 +615,19 @@ Esto puede tardar hasta un minuto. Ensure the entered URL is valid, and the device’s internet connection is good. - Asegurese de que la URL insertada es válida, y que el dispositivo tiene buena conexión. + Asegúrese de que la URL insertada es válida y que el dispositivo tiene buena conexión. No custom software found at this URL. - No hay software personalizado en esta URL. + No encontramos software personalizado en esta URL. WARNING: Low Voltage - ALERTA: Volage bajo + ALERTA: Voltaje bajo Power your device in a car with a harness or proceed at your own risk. - Encender su dispositivo en el auto con el arnés o proceda bajo su propio riesgo. + Encienda su dispositivo en un auto con el arnés o proceda bajo su propio riesgo. Power off @@ -643,11 +643,11 @@ Esto puede tardar hasta un minuto. Before we get on the road, let’s finish installation and cover some details. - Antes de comenzar, terminemos la instalación y cubramos algunos detalles. + Antes de ponernos en marcha, terminemos la instalación y cubramos algunos detalles. Connect to Wi-Fi - Conectar a la Wi-Fi + Conectarse al Wi-Fi Back @@ -663,7 +663,7 @@ Esto puede tardar hasta un minuto. Choose Software to Install - Elija el software para instalar + Elija el software a instalar openpilot @@ -699,7 +699,7 @@ Esto puede tardar hasta un minuto. Select a language - Seleccione el idioma + Seleccione un idioma @@ -710,7 +710,7 @@ Esto puede tardar hasta un minuto. Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - Empareja tu dispositivo con comma connect (connect.comma.ai) y reclama tu oferta de comma prime. + Empareje su dispositivo con comma connect (connect.comma.ai) y reclame su oferta de comma prime. Pair device @@ -725,11 +725,11 @@ Esto puede tardar hasta un minuto. OFFLINE - SIN LINEA + OFFLINE ONLINE - EN LINEA + EN LÍNEA ERROR @@ -745,7 +745,7 @@ Esto puede tardar hasta un minuto. GOOD - BUENO + BUENA OK @@ -769,7 +769,7 @@ Esto puede tardar hasta un minuto. SEARCH - BUSQUEDA + BÚSQUEDA -- @@ -804,7 +804,7 @@ Esto puede tardar hasta un minuto. SoftwarePanel Updates are only downloaded while the car is off. - Apague el auto para descargar actualizaciones. + Actualizaciones solo se descargan con el auto apagado. Current Version @@ -856,7 +856,7 @@ Esto puede tardar hasta un minuto. failed to check for update - no se pudo buscar actualización + no se pudo buscar actualizaciones DOWNLOAD @@ -883,7 +883,7 @@ Esto puede tardar hasta un minuto. Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - Aviso: Esto otorga acceso SSH a todas las claves públicas en su Github. Nunca inserte un nombre de usuario de Github que no sea suyo. Un empleado de comma nunca le pedirá que añada su nombre de Github. + Aviso: Esto otorga acceso SSH a todas las claves públicas en su Github. Nunca ingrese un nombre de usuario de Github que no sea suyo. Un empleado de comma NUNCA le pedirá que añada un usuario de Github que no sea el suyo. ADD @@ -891,7 +891,7 @@ Esto puede tardar hasta un minuto. Enter your GitHub username - Ingresa tu usuario de GitHub + Ingrese su usuario de GitHub LOADING @@ -903,7 +903,7 @@ Esto puede tardar hasta un minuto. Username '%1' has no keys on GitHub - Nombre de usuario "%1” no tiene claves en GitHub + El usuario "%1” no tiene claves en GitHub Request timed out @@ -911,7 +911,7 @@ Esto puede tardar hasta un minuto. Username '%1' doesn't exist on GitHub - Nombre de usuario '%1' no existe en Github + El usuario '%1' no existe en Github @@ -925,7 +925,7 @@ Esto puede tardar hasta un minuto. TermsPage Terms & Conditions - Terminos & Condiciones + Términos & Condiciones Decline @@ -948,19 +948,19 @@ Esto puede tardar hasta un minuto. Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - Utilice el sistema openpilot para control de crucero adaptativo y asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Cambiar esta configuración solo tendrá efecto con el auto apagado. + Utilice el sistema openpilot para acceder a un autocrucero adaptativo y asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Cambiar esta configuración solo tendrá efecto con el auto apagado. openpilot Longitudinal Control (Alpha) - Control longitudinal de openpilot (Alfa) + Control longitudinal de openpilot (fase experimental) WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - Aviso: el control longitudinal de openpilot está en fase alfa para este automóvil y desactivará el Frenado Automático de Emergencia (AEB). + AVISO: el control longitudinal de openpilot está en fase experimental para este automóvil y desactivará el Frenado Automático de Emergencia (AEB). On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - En este vehículo, openpilot se configura de manera predeterminada con el Control de Crucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal alfa de openpilot. + En este automóvil, openpilot se configura de manera predeterminada con el Autocrucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal de openpilot (aún en fase experimental). Experimental Mode @@ -972,23 +972,23 @@ Esto puede tardar hasta un minuto. When enabled, pressing the accelerator pedal will disengage openpilot. - Cuando esté activado, presionar el acelerador deshabilitará el openpilot. + Cuando esté activado, presionar el acelerador deshabilitará openpilot. Enable Lane Departure Warnings - Activar Aviso de Salida de Carril + Activar Avisos de Salida de Carril Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - Recibir alertas para volver dentro del carril cuando su vehículo se sale fuera del carril sin que esté activado la señal de giro mientras esté conduciendo por encima de 50 km/h (31 mph). + Recibir alertas para volver al carril cuando su vehículo se salga fuera del carril sin que esté activada la señal de giro y esté conduciendo por encima de 50 km/h (31 mph). Always-On Driver Monitoring - Monitoreo del Conductor Siempre Activo + Monitoreo Permanente del Conductor Enable driver monitoring even when openpilot is not engaged. - Habilite el monitoreo del conductor incluso cuando Openpilot no esté activado. + Habilitar el monitoreo del conductor incluso cuando Openpilot no esté activado. Record and Upload Driver Camera @@ -996,7 +996,7 @@ Esto puede tardar hasta un minuto. Upload data from the driver facing camera and help improve the driver monitoring algorithm. - Subir datos de la cámara del conductor para ayudar a mejorar el algoritmo de monitorización del conductor. + Subir datos de la cámara del conductor para ayudar a mejorar el algoritmo de monitoreo del conductor. Use Metric System @@ -1024,19 +1024,19 @@ Esto puede tardar hasta un minuto. Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Se recomienda estándar. En el modo agresivo, openpilot seguirá a los autos líderes más cerca y será más agresivo con el acelerador y el freno. En modo relajado, openpilot se mantendrá más alejado de los coches líderes. En automóviles compatibles, puede recorrer estas personalidades con el botón de distancia del volante. + Se recomienda el modo estándar. En el modo agresivo, openpilot seguirá más cerca a los autos delante suyo y será más agresivo con el acelerador y el freno. En modo relajado, openpilot se mantendrá más alejado de los autos delante suyo. En automóviles compatibles, puede recorrer estas personalidades con el botón de distancia del volante. openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - openpilot por defecto conduce en <b>modo chill</b>. El modo Experimental activa <b>recursos de nível-alfa</b> que no están listos para el modo chill. Los recursos del modo expeimental están listados abajo: + openpilot por defecto conduce en <b>modo chill</b>. El modo Experimental activa <b>funcionalidades en fase experimental</b>, que no están listas para el modo chill. Las funcionalidades del modo expeimental están listados abajo: End-to-End Longitudinal Control - 🌮 Control Longitudinal de Punta a Punta 🌮 + Control Longitudinal de Punta a Punta Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Dajar que el modelo de conducción controle la aceleración y el frenado. openpilot va a conducir como lo haría una persona, incluiyendo parar en los semaforos en rojo y las señales de stop. Dado que el modelo decide la velocidad de conducción, la velocidad de crucero establecida actuará como limitador. Este recurso es de una calidad alfa; errores pueden ocurrir. + Dajar que el modelo de conducción controle la aceleración y el frenado. openpilot conducirá como piensa que lo haría una persona, incluiyendo parar en los semáforos en rojo y las señales de alto. Dado que el modelo decide la velocidad de conducción, la velocidad de crucero establecida solo actuará como el límite superior. Este recurso aún está en fase experimental; deberían esperarse errores. New Driving Visualization @@ -1044,11 +1044,11 @@ Esto puede tardar hasta un minuto. The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. - La visualización de la conducción cambiará a la cámara que enfoca la carretera a velocidades bajas para mostrar mejor los giros. El logo del modo experimental se mostrará en la esquina superior derecha. + La visualización de la conducción cambiará a la cámara que enfoca la carretera a velocidades bajas para mostrar mejor los giros. El logo del modo experimental también se mostrará en la esquina superior derecha. Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - El modo Experimental no está disponible actualmente para este auto, ya que el ACC del auto está siendo usado para el control longitudinal. + El modo Experimental no está disponible actualmente para este auto, ya que el ACC default del auto está siendo usado para el control longitudinal. openpilot longitudinal control may come in a future update. @@ -1056,11 +1056,11 @@ Esto puede tardar hasta un minuto. An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Se puede probar una versión experimental del control longitudinal openpilot, junto con el modo Experimental, en ramas sin liberación. + Se puede probar una versión experimental del control longitudinal openpilot, junto con el modo Experimental, en ramas no liberadas. Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. - Activar el control longitudinal experimental para permitir el modo Experimental. + Activar el control longitudinal (fase experimental) para permitir el modo Experimental. @@ -1071,7 +1071,7 @@ Esto puede tardar hasta un minuto. An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - Es necesario la actualización del sistema operativo. Conecte su dispositivo a Wi-Fi para una actualización rápida. El tamaño de descarga es de aproximadamente 1GB. + Es necesario la actualización del sistema operativo. Conecte su dispositivo al Wi-Fi para una actualización rápida. El tamaño de descarga es de aproximadamente 1GB. Connect to Wi-Fi @@ -1106,7 +1106,7 @@ Esto puede tardar hasta un minuto. Connect to Wi-Fi to upload driving data and help improve openpilot - Conectar a Wi-Fi para subir los datos de conducir para mejorar openpilot + Conectarse al Wi-Fi para subir los datos de conducción y mejorar openpilot Open Settings @@ -1137,7 +1137,7 @@ Esto puede tardar hasta un minuto. Forget Wi-Fi Network "%1"? - Olvidar Red Wi-Fi "%1"? + ¿Olvidar la Red de Wi-Fi "%1"? Forget diff --git a/system/athena/athenad.py b/system/athena/athenad.py index 9769f065f6..b4f9b8b6a7 100755 --- a/system/athena/athenad.py +++ b/system/athena/athenad.py @@ -401,6 +401,7 @@ def uploadFilesToUrls(files_data: list[UploadFileDict]) -> UploadFilesToUrlRespo resp: UploadFilesToUrlResponse = {"enqueued": len(items), "items": items} if failed: + cloudlog.event("athena.uploadFilesToUrls.failed", failed=failed, error=True) resp["failed"] = failed return resp diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 9d82284d9f..542be29d80 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -244,7 +244,7 @@ static kj::Array 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); diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index 555362ab8b..d58f4d3195 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -2,7 +2,6 @@ #include #include -#include #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 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); diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 47ea5ded4d..2729aa264c 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -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,50 +435,50 @@ 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()) { + return; + } + + configISP(); + configCSIPHY(); + linkDevices(); +} + +bool CameraState::openSensor() { sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", camera_num); assert(sensor_fd >= 0); LOGD("opened sensor for %d", camera_num); @@ -493,7 +503,7 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num !init_sensor_lambda(new OS04C10)) { LOGE("** sensor %d FAILED bringup, disabling", camera_num); enabled = false; - return; + return false; } LOGD("-- Probing sensor %d success", camera_num); @@ -512,7 +522,10 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num LOG("-- Configuring sensor"); sensors_i2c(ci->init_reg_array.data(), ci->init_reg_array.size(), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, ci->data_word); + return true; +} +void CameraState::configISP() { // NOTE: to be able to disable road and wide road, we still have to configure the sensor over i2c // If you don't do this, the strobe GPIO is an output (even in reset it seems!) if (!enabled) return; @@ -570,6 +583,13 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num isp_dev_handle = *isp_dev_handle_; LOGD("acquire isp dev"); + // config ISP + alloc_w_mmu_hdl(multi_cam_state->video0_fd, 984480, (uint32_t*)&buf0_handle, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | + CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, multi_cam_state->device_iommu, multi_cam_state->cdm_iommu); + config_isp(0, 0, 1, buf0_handle, 0); +} + +void CameraState::configCSIPHY() { csiphy_fd = open_v4l_by_name_and_index("cam-csiphy-driver", camera_num); assert(csiphy_fd >= 0); LOGD("opened csiphy for %d", camera_num); @@ -580,11 +600,6 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num csiphy_dev_handle = *csiphy_dev_handle_; LOGD("acquire csiphy dev"); - // config ISP - alloc_w_mmu_hdl(multi_cam_state->video0_fd, 984480, (uint32_t*)&buf0_handle, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | - CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, multi_cam_state->device_iommu, multi_cam_state->cdm_iommu); - config_isp(0, 0, 1, buf0_handle, 0); - // config csiphy LOG("-- Config CSI PHY"); { @@ -612,15 +627,16 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num int ret_ = device_config(csiphy_fd, session_handle, csiphy_dev_handle, cam_packet_handle); assert(ret_ == 0); } +} - // link devices +void CameraState::linkDevices() { LOG("-- Link devices"); struct cam_req_mgr_link_info req_mgr_link_info = {0}; req_mgr_link_info.session_hdl = session_handle; req_mgr_link_info.num_devices = 2; req_mgr_link_info.dev_hdls[0] = isp_dev_handle; req_mgr_link_info.dev_hdls[1] = sensor_dev_handle; - ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info)); + int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info)); link_handle = req_mgr_link_info.link_hdl; LOGD("link: %d session: 0x%X isp: 0x%X sensors: 0x%X link: 0x%X", ret, session_handle, isp_dev_handle, sensor_dev_handle, link_handle); @@ -644,9 +660,9 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num } 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"}); } @@ -690,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"); } @@ -927,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); + + // 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); + } + + // 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)); + + // 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??? + } + } } -void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) { - const CameraBuf *b = &c->buf; - - 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"); - - c->ci->processRegisters(c, framed); - s->pm->send(c == &s->road_cam ? "roadCameraState" : "wideRoadCameraState", msg); - - 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 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"); diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 0b15c9c3f0..1b27fb18b8 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -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 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; @@ -86,20 +124,28 @@ public: void sensors_i2c(const struct i2c_random_wr_payload* dat, int len, int op_code, bool data_word); private: + bool openSensor(); + void configISP(); + void configCSIPHY(); + void linkDevices(); + // for debugging 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; +}; diff --git a/system/micd.py b/system/micd.py index 8b738ebe93..af1aa31360 100755 --- a/system/micd.py +++ b/system/micd.py @@ -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: diff --git a/third_party/libyuv/larch64/lib/libyuv.a b/third_party/libyuv/larch64/lib/libyuv.a index fd18814ef1..1c91250231 100644 --- a/third_party/libyuv/larch64/lib/libyuv.a +++ b/third_party/libyuv/larch64/lib/libyuv.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85e765be665eab8ce8b64d6a884148e0ff3905fadcef6c0daa75e4efd84bb5cb -size 499734 +oid sha256:320bef5a75a62dd2731a496040921d5000f1ed237ae70fd7aeb6c010a1534363 +size 462482 diff --git a/tools/install_python_dependencies.sh b/tools/install_python_dependencies.sh index 276de58db7..a90462888f 100755 --- a/tools/install_python_dependencies.sh +++ b/tools/install_python_dependencies.sh @@ -34,7 +34,7 @@ update_uv # TODO: remove --no-cache once this is fixed: https://github.com/astral-sh/uv/issues/4378 echo "installing python packages..." -uv --no-cache sync --all-extras +uv --no-cache sync --frozen --all-extras source .venv/bin/activate echo "PYTHONPATH=${PWD}" > $ROOT/.env diff --git a/tools/latencylogger/latency_logger.py b/tools/latencylogger/latency_logger.py index 8691149e94..f145cc35e4 100755 --- a/tools/latencylogger/latency_logger.py +++ b/tools/latencylogger/latency_logger.py @@ -3,7 +3,6 @@ import argparse import json import matplotlib.patches as mpatches import matplotlib.pyplot as plt -import mpld3 import sys from bisect import bisect_left, bisect_right from collections import defaultdict @@ -174,7 +173,6 @@ def print_timestamps(timestamps, durations, start_times, relative): print(" "+'%-53s%-53s' %(event, str(time*1000))) def graph_timestamps(timestamps, start_times, end_times, relative, offset_services=False, title=""): - # mpld3 doesn't convert properly to D3 font sizes plt.rcParams.update({'font.size': 18}) t0 = find_t0(start_times) @@ -203,15 +201,14 @@ def graph_timestamps(timestamps, start_times, end_times, relative, offset_servic points['labels'].append(event[0]) ax.broken_barh(service_bars, (i-height/2, height), facecolors=(colors), alpha=0.5, offsets=offsets) - scatter = ax.scatter(points['x'], points['y'], marker='d', edgecolor='black') - tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=points['labels']) - mpld3.plugins.connect(fig, tooltip) + ax.scatter(points['x'], points['y'], marker='d', edgecolor='black') + for i, label in enumerate(points['labels']): + ax.annotate(label, (points['x'][i], points['y'][i]), textcoords="offset points", xytext=(0,10), ha='center') plt.title(title) - # Set size relative window size is not trivial: https://github.com/mpld3/mpld3/issues/65 fig.set_size_inches(18, 9) plt.legend(handles=[mpatches.Patch(color=colors[i], label=SERVICES[i]) for i in range(len(SERVICES))]) - return fig + plt.show() def get_timestamps(lr): lr = list(lr) @@ -239,4 +236,4 @@ if __name__ == "__main__": data, _ = get_timestamps(lr) print_timestamps(data['timestamp'], data['duration'], data['start'], args.relative) if args.plot: - mpld3.show(graph_timestamps(data['timestamp'], data['start'], data['end'], args.relative, offset_services=args.offset, title=r)) + graph_timestamps(data['timestamp'], data['start'], data['end'], args.relative, offset_services=args.offset, title=r) diff --git a/tools/lib/helpers.py b/tools/lib/helpers.py index e9b4b85e70..7c34e17cb1 100644 --- a/tools/lib/helpers.py +++ b/tools/lib/helpers.py @@ -1,6 +1,3 @@ -import bz2 - - # regex patterns class RE: DONGLE_ID = r'(?P[a-f0-9]{16})' @@ -18,13 +15,3 @@ class RE: EXPLORER_FILE = fr'^(?P{SEGMENT_NAME})--(?P[a-z]+\.[a-z0-9]+)$' OP_SEGMENT_DIR = fr'^(?P{SEGMENT_NAME})$' - - -def save_log(dest, log_msgs, compress=True): - dat = b"".join(msg.as_builder().to_bytes() for msg in log_msgs) - - if compress: - dat = bz2.compress(dat) - - with open(dest, "wb") as f: - f.write(dat) diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 6ad77bf823..2df1c05256 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -27,6 +27,16 @@ LogIterable = Iterable[LogMessage] RawLogIterable = Iterable[bytes] +def save_log(dest, log_msgs, compress=True): + dat = b"".join(msg.as_builder().to_bytes() for msg in log_msgs) + + if compress: + dat = bz2.compress(dat) + + with open(dest, "wb") as f: + f.write(dat) + + class _LogFileReader: def __init__(self, fn, canonicalize=True, only_union_types=False, sort_by_time=False, dat=None): self.data_version = None @@ -140,6 +150,7 @@ def internal_source(sr: SegmentRange, mode: ReadMode, file_ext: str = "bz2") -> def get_internal_url(sr: SegmentRange, seg, file): return f"cd:/{sr.dongle_id}/{sr.log_id}/{seg}/{file}.{file_ext}" + # TODO: list instead of using static URLs to support routes with multiple file extensions rlog_paths = [get_internal_url(sr, seg, "rlog") for seg in sr.seg_idxs] qlog_paths = [get_internal_url(sr, seg, "qlog") for seg in sr.seg_idxs] diff --git a/tools/lib/route.py b/tools/lib/route.py index 6ff5d19208..ddb8b0486e 100644 --- a/tools/lib/route.py +++ b/tools/lib/route.py @@ -11,7 +11,7 @@ from openpilot.tools.lib.helpers import RE QLOG_FILENAMES = ['qlog', 'qlog.bz2', 'qlog.zst'] QCAMERA_FILENAMES = ['qcamera.ts'] -LOG_FILENAMES = ['rlog', 'rlog.bz2', 'raw_log.bz2'] +LOG_FILENAMES = ['rlog', 'rlog.bz2', 'raw_log.bz2', 'rlog.zst'] CAMERA_FILENAMES = ['fcamera.hevc', 'video.hevc'] DCAMERA_FILENAMES = ['dcamera.hevc'] ECAMERA_FILENAMES = ['ecamera.hevc'] diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index 9823427e65..d19f1cae86 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -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)" diff --git a/tools/op.sh b/tools/op.sh new file mode 100755 index 0000000000..55cc3d60d9 --- /dev/null +++ b/tools/op.sh @@ -0,0 +1,395 @@ +#!/usr/bin/env bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +UNDERLINE='\033[4m' +BOLD='\033[1m' +NC='\033[0m' + +function op_install() { + (set -e + + echo "Installing op system-wide..." + RC_FILE="${HOME}/.$(basename ${SHELL})rc" + if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then + RC_FILE="$HOME/.bash_profile" + fi + 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_get_openpilot_dir() { + while [[ "$OPENPILOT_ROOT" != '/' ]]; + do + if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then + return 0 + fi + OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)" + done +} + +function op_check_openpilot_dir() { + echo "Checking for openpilot directory..." + if [[ -f "$OPENPILOT_ROOT/launch_openpilot.sh" ]]; then + echo -e " ↳ [${GREEN}✔${NC}] openpilot found.\n" + return 0 + fi + + 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_check_git() { + (set -e + + echo "Checking for git..." + if ! command -v "git" > /dev/null 2>&1; then + echo -e " ↳ [${RED}✗${NC}] git not found on your system!" + return 1 + else + echo -e " ↳ [${GREEN}✔${NC}] git found." + fi + + echo "Checking for git lfs files..." + if [[ $(file -b $OPENPILOT_ROOT/selfdrive/modeld/models/supercombo.onnx) == "data" ]]; then + echo -e " ↳ [${GREEN}✔${NC}] git lfs files found." + else + echo -e " ↳ [${RED}✗${NC}] git lfs files not found! Run 'git lfs pull'" + return 1 + fi + + echo "Checking for git submodules..." + 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'" + return 1 + fi + done + echo -e " ↳ [${GREEN}✔${NC}] git submodules found." + + ) +} + +function op_check_os() { + (set -e + + echo "Checking for compatible os version..." + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + + if [ -f "/etc/os-release" ]; then + source /etc/os-release + case "$VERSION_CODENAME" in + "jammy" | "kinetic" | "noble" | "focal") + echo -e " ↳ [${GREEN}✔${NC}] Ubuntu $VERSION_CODENAME detected." + ;; + * ) + echo -e " ↳ [${RED}✗${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!" + return 1 + ;; + esac + else + echo -e " ↳ [${RED}✗${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!" + return 1 + fi + + elif [[ "$OSTYPE" == "darwin"* ]]; then + echo -e " ↳ [${GREEN}✔${NC}] macos detected.\n" + else + echo -e " ↳ [${RED}✗${NC}] OS type $OSTYPE not supported!" + return 1 + fi + + ) +} + +function op_check_python() { + (set -e + + echo "Checking for compatible python version..." + 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!" + 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." + else + echo -e " ↳ [${RED}✗${NC}] You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!" + return 1 + fi + + ) +} + +function op_check_venv() { + echo "Checking for venv..." + if source $OPENPILOT_ROOT/.venv/bin/activate; then + echo -e " ↳ [${GREEN}✔${NC}] venv detected." + else + echo -e " ↳ [${RED}✗${NC}] Can't activate venv in $OPENPILOT_ROOT. Assuming global env!" + fi +} + +function op_before_cmd() { + if [[ ! -z "$NO_VERIFY" ]]; then + return 0 + fi + + op_get_openpilot_dir + cd $OPENPILOT_ROOT + + result="$((op_check_openpilot_dir ) 2>&1)" || (echo -e "$result" && return 1) + result="${result}\n$(( op_check_git ) 2>&1)" || (echo -e "$result" && return 1) + result="${result}\n$(( op_check_os ) 2>&1)" || (echo -e "$result" && return 1) + result="${result}\n$(( op_check_venv ) 2>&1)" || (echo -e "$result" && return 1) + + op_activate_venv + + result="${result}\n$(( op_check_python ) 2>&1)" || (echo -e "$result" && return 1) + + if [[ -z $VERBOSE ]]; then + echo -e "Checking system → [${GREEN}✔${NC}] system is good." + else + echo -e "$result" + fi +} + +function op_setup() { + (set -e + + op_get_openpilot_dir + cd $OPENPILOT_ROOT + + op_check_openpilot_dir + 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" + + 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_activate_venv() { + source $OPENPILOT_ROOT/.venv/bin/activate &> /dev/null || true +} + +function op_venv() { + ( set -e + + op_before_cmd + + ) + + if [[ "$?" -eq 0 ]]; then + # this must be run in the same shell as the user calling "op" + op_get_openpilot_dir + op_run_command source $OPENPILOT_ROOT/.venv/bin/activate + fi +} + +function op_check() { + (set -e + + VERBOSE=1 + op_before_cmd + unset VERBOSE + + ) +} + +function op_build() { + (set -e + + op_before_cmd + op_run_command scons $@ + + ) +} + +function op_juggle() { + (set -e + + op_before_cmd + op_run_command tools/plotjuggler/juggle.py $@ + + ) +} + +function op_lint() { + (set -e + + op_before_cmd + op_run_command pre-commit run --all $@ + + ) +} + +function op_replay() { + (set -e + + op_before_cmd + op_run_command tools/replay/replay $@ + + ) +} + +function op_cabana() { + (set -e + + op_before_cmd + op_run_command tools/cabana/cabana $@ + + ) +} + +function op_sim() { + (set -e + + op_before_cmd + op_run_command exec tools/sim/run_bridge.py & + op_run_command exec tools/sim/launch_openpilot.sh + + ) +} + +function op_default() { + echo "An openpilot helper" + echo "" + echo -e "${BOLD}${UNDERLINE}Description:${NC}" + echo " op is your entry point for all things related to openpilot development." + 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:${NC}" + echo -e " ${BOLD}venv${NC} Activate the Python virtual environment" + echo -e " ${BOLD}check${NC} Check the development environment (git, os, python) to start using openpilot" + echo -e " ${BOLD}setup${NC} Install openpilot dependencies" + echo -e " ${BOLD}build${NC} Build 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}lint${NC} Run all the pre-commit checks" + echo -e " ${BOLD}help${NC} Show this message" + echo -e " ${BOLD}install${NC} Install the 'op' tool system wide" + echo "" + echo -e "${BOLD}${UNDERLINE}Options:${NC}" + echo -e " ${BOLD}-d, --dir${NC}" + 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 run" + echo -e " ${BOLD}-n, --no-verify${NC}" + echo " Skip environment check before running commands" + echo -e " ${BOLD}-v, --verbose${NC}" + echo " Show the result of all checks before running a command" + echo "" + echo -e "${BOLD}${UNDERLINE}Examples:${NC}" + echo " op --dir /tmp/openpilot check" + echo " Run the check command on openpilot located in /tmp/openpilot" + echo "" + echo " op juggle --install" + echo " Install plotjuggler in the openpilot located in your current" + echo " working directory" + echo "" + echo " op --dir /tmp/openpilot build -j4" + echo " Run the build command on openpilot located in /tmp/openpilot" + echo " on 4 cores" +} + + +function _op() { + # parse Options + case $1 in + -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; + --dry ) shift 1; DRY="1" ;; + -n | --no-verify ) shift 1; NO_VERIFY="1" ;; + -v | --verbose ) shift 1; VERBOSE="1" ;; + esac + + # parse Commands + case $1 in + venv ) shift 1; op_venv "$@" ;; + check ) shift 1; op_check "$@" ;; + setup ) shift 1; op_setup "$@" ;; + build ) shift 1; op_build "$@" ;; + juggle ) shift 1; op_juggle "$@" ;; + cabana ) shift 1; op_cabana "$@" ;; + lint ) shift 1; op_lint "$@" ;; + replay ) shift 1; op_replay "$@" ;; + sim ) shift 1; op_sim "$@" ;; + install ) shift 1; op_install "$@" ;; + * ) op_default "$@" ;; + esac +} + +_op $@ + +# remove from env +unset -f _op +unset -f op_check +unset -f op_setup +unset -f op_build +unset -f op_juggle +unset -f op_venv +unset -f op_check_openpilot_dir +unset -f op_check_git +unset -f op_check_python +unset -f op_check_os +unset -f op_install +unset -f op_default +unset -f op_run_command +unset -f op_lint +unset -f op_replay +unset -f op_cabana +unset -f op_check_venv +unset -f op_before_cmd +unset -f op_sim +unset -f op_activate_venv +unset -f op_get_openpilot_dir +unset DRY +unset NC +unset RED +unset GREEN +unset UNDERLINE +unset BOLD +unset OPENPILOT_ROOT +unset NO_VERIFY +unset VERBOSE diff --git a/tools/plotjuggler/juggle.py b/tools/plotjuggler/juggle.py index 1d1612a1cd..22854b368d 100755 --- a/tools/plotjuggler/juggle.py +++ b/tools/plotjuggler/juggle.py @@ -12,8 +12,7 @@ from functools import partial from openpilot.common.basedir import BASEDIR from openpilot.selfdrive.car.fingerprints import MIGRATION -from openpilot.tools.lib.helpers import save_log -from openpilot.tools.lib.logreader import LogReader, ReadMode +from openpilot.tools.lib.logreader import LogReader, ReadMode, save_log juggle_dir = os.path.dirname(os.path.realpath(__file__)) diff --git a/tools/rerun/README.md b/tools/rerun/README.md new file mode 100644 index 0000000000..0fd50e1562 --- /dev/null +++ b/tools/rerun/README.md @@ -0,0 +1,57 @@ +# Rerun +Rerun is a tool to quickly visualize time series data. It supports all openpilot logs , both the `logMessages` and video logs. + +[Instructions](https://rerun.io/docs/reference/viewer/overview) for navigation within the Rerun Viewer. + +## Usage +``` +usage: run.py [-h] [--demo] [--qcam] [--fcam] [--ecam] [--dcam] [--print_services] [--services [SERVICES ...]] [route_or_segment_name] + +A helper to run rerun on openpilot routes + +options: + -h, --help show this help message and exit + --demo Use the demo route instead of providing one (default: False) + --qcam Log decimated driving camera (default: False) + --fcam Log driving camera (default: False) + --ecam Log wide camera (default: False) + --dcam Log driver monitoring camera (default: False) + --print_services List out openpilot services (default: False) + --services [SERVICES ...] Specify openpilot services that will be logged. No service will be logged if not specified. + To log all services include 'all' as one of your services (default: []) + --route [ROUTE] The route or segment name to plot (default: None) +``` + +Examples using route name to observe accelerometer and qcamera: + +`./run.py --services accelerometer --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19"` + +Examples using segment range (more on [SegmentRange](https://github.com/commaai/openpilot/tree/master/tools/lib)): + +`./run.py --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19/2:4"` + +## Cautions: +- You can specify `--services all` to visualize all `logMessage`, but it will draw a lot of memory usage and take a long time to log all messages. Rerun isn't ready for logging big number of data. + +- Logging hevc videos (`--fcam`, `--ecam`, and `--dcam`) are expensive, and it's recommended to use `--qcam` for optimized performance. If possible, limiting your route to a few segments using `SegmentRange` will speed up logging and reduce memory usage + +This example draws 13GB of memory: + +`./run.py --services accelerometer --qcam --route "a2a0ccea32023010/2023-07-27--13-01-19"` + + +## Openpilot services +To list all openpilot services: + +`./run.py --print_services` + +Examples including openpilot services: + +`./run.py --services accelerometer cameraodometry --route "a2a0ccea32023010/2023-07-27--13-01-19/0/q"` + +Examples including all services: + +`./run.py --services all --route "a2a0ccea32023010/2023-07-27--13-01-19/0/q"` + +## Demo +`./run.py --services accelerometer carcontrol caroutput --qcam --demo` diff --git a/tools/rerun/camera_reader.py b/tools/rerun/camera_reader.py new file mode 100644 index 0000000000..325fad18b8 --- /dev/null +++ b/tools/rerun/camera_reader.py @@ -0,0 +1,92 @@ +import tqdm +import subprocess +import multiprocessing +from enum import StrEnum +from functools import partial +from collections import namedtuple + +from openpilot.tools.lib.framereader import ffprobe + +CameraConfig = namedtuple("CameraConfig", ["qcam", "fcam", "ecam", "dcam"]) + +class CameraType(StrEnum): + qcam = "qcamera" + fcam = "fcamera" + ecam = "ecamera" + dcam = "dcamera" + + +def probe_packet_info(camera_path): + args = ["ffprobe", "-v", "quiet", "-show_packets", "-probesize", "10M", camera_path] + dat = subprocess.check_output(args) + dat = dat.decode().split() + return dat + + +class _FrameReader: + def __init__(self, camera_path, segment, h, w, start_time): + self.camera_path = camera_path + self.segment = segment + self.h = h + self.w = w + self.start_time = start_time + + self.ts = self._get_ts() + + def _read_stream_nv12(self): + frame_sz = self.w * self.h * 3 // 2 + proc = subprocess.Popen( + ["ffmpeg", "-v", "quiet", "-i", self.camera_path, "-f", "rawvideo", "-pix_fmt", "nv12", "-"], + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL + ) + try: + while True: + dat = proc.stdout.read(frame_sz) + if len(dat) == 0: + break + yield dat + finally: + proc.kill() + + def _get_ts(self): + dat = probe_packet_info(self.camera_path) + try: + ret = [float(d.split('=')[1]) for d in dat if d.startswith("pts_time=")] + except ValueError: + # pts_times aren't available. Infer timestamps from duration_times + ret = [d for d in dat if d.startswith("duration_time")] + ret = [float(d.split('=')[1])*(i+1)+(self.segment*60)+self.start_time for i, d in enumerate(ret)] + return ret + + def __iter__(self): + for i, frame in enumerate(self._read_stream_nv12()): + yield self.ts[i], frame + + +class CameraReader: + def __init__(self, camera_paths, start_time, seg_idxs): + self.seg_idxs = seg_idxs + self.camera_paths = camera_paths + self.start_time = start_time + + probe = ffprobe(camera_paths[0])["streams"][0] + self.h = probe["height"] + self.w = probe["width"] + + self.__frs = {} + + def _get_fr(self, i): + if i not in self.__frs: + self.__frs[i] = _FrameReader(self.camera_paths[i], segment=i, h=self.h, w=self.w, start_time=self.start_time) + return self.__frs[i] + + def _run_on_segment(self, func, i): + return func(self._get_fr(i)) + + def run_across_segments(self, num_processes, func): + with multiprocessing.Pool(num_processes) as pool: + num_segs = len(self.seg_idxs) + for _ in tqdm.tqdm(pool.imap_unordered(partial(self._run_on_segment, func), self.seg_idxs), total=num_segs): + continue + diff --git a/tools/rerun/run.py b/tools/rerun/run.py index 9975478a73..6d9554038c 100755 --- a/tools/rerun/run.py +++ b/tools/rerun/run.py @@ -6,84 +6,176 @@ import rerun as rr import rerun.blueprint as rrb from functools import partial -from openpilot.tools.lib.logreader import LogReader from cereal.services import SERVICE_LIST +from openpilot.tools.rerun.camera_reader import probe_packet_info, CameraReader, CameraConfig, CameraType +from openpilot.tools.lib.logreader import LogReader +from openpilot.tools.lib.route import Route, SegmentRange NUM_CPUS = multiprocessing.cpu_count() DEMO_ROUTE = "a2a0ccea32023010|2023-07-27--13-01-19" +RR_TIMELINE_NAME = "Timeline" +RR_WIN = "rerun_test" -def log_msg(msg, parent_key=''): - stack = [(msg, parent_key)] - while stack: - current_msg, current_parent_key = stack.pop() - if isinstance(current_msg, list): - for index, item in enumerate(current_msg): - new_key = f"{current_parent_key}/{index}" - if isinstance(item, (int, float)): - rr.log(str(new_key), rr.Scalar(item)) - elif isinstance(item, dict): - stack.append((item, new_key)) - elif isinstance(current_msg, dict): - for key, value in current_msg.items(): - new_key = f"{current_parent_key}/{key}" - if isinstance(value, (int, float)): - rr.log(str(new_key), rr.Scalar(value)) - elif isinstance(value, dict): - stack.append((value, new_key)) - elif isinstance(value, list): - for index, item in enumerate(value): - if isinstance(item, (int, float)): - rr.log(f"{new_key}/{index}", rr.Scalar(item)) - else: - pass # Not a plottable value -def createBlueprint(): - blueprint = None - timeSeriesViews = [] - for topic in sorted(SERVICE_LIST.keys()): - timeSeriesViews.append(rrb.TimeSeriesView(name=topic, origin=f"/{topic}/", visible=False)) - rr.log(topic, rr.SeriesLine(name=topic), timeless=True) - blueprint = rrb.Blueprint(rrb.Grid(rrb.Vertical(*timeSeriesViews,rrb.SelectionPanel(expanded=False),rrb.TimePanel(expanded=False)), - rrb.Spatial2DView(name="thumbnail", origin="/thumbnail"))) - return blueprint +""" +Relevant upstream Rerun issues: +- large time series: https://github.com/rerun-io/rerun/issues/5967 +- loading videos directly: https://github.com/rerun-io/rerun/issues/6532 +""" -def log_thumbnail(thumbnailMsg): - bytesImgData = thumbnailMsg.get('thumbnail') - rr.log("/thumbnail", rr.ImageEncoded(contents=bytesImgData)) +class Rerunner: + def __init__(self, route, segment_range, camera_config, enabled_services): + self.enabled_services = [s.lower() for s in enabled_services] + self.log_all = "all" in self.enabled_services + self.lr = LogReader(route_or_segment_name) -@rr.shutdown_at_exit -def process(blueprint, lr): - rr.init("rerun_test") - rr.connect(default_blueprint=blueprint) + # hevc files don't have start_time. We get it from qcamera.ts + start_time = 0 + dat = probe_packet_info(r.qcamera_paths()[0]) + for d in dat: + if d.startswith("pts_time="): + start_time = float(d.split('=')[1]) + break + + qcam, fcam, ecam, dcam = camera_config + self.camera_readers = {} + if qcam: + self.camera_readers[CameraType.qcam] = CameraReader(route.qcamera_paths(), start_time, segment_range.seg_idxs) + if fcam: + self.camera_readers[CameraType.fcam] = CameraReader(route.camera_paths(), start_time, segment_range.seg_idxs) + if ecam: + self.camera_readers[CameraType.ecam] = CameraReader(route.ecamera_paths(), start_time, segment_range.seg_idxs) + if dcam: + self.camera_readers[CameraType.dcam] = CameraReader(route.dcamera_paths(), start_time, segment_range.seg_idxs) + + def _start_rerun(self): + self.blueprint = self._create_blueprint() + rr.init(RR_WIN, spawn=True) + + def _create_blueprint(self): + blueprint = None + service_views = [] + + log_msg_visible = len(self.enabled_services) <= 3 and not self.log_all + for topic in sorted(SERVICE_LIST.keys()): + if not self.log_all and topic.lower() not in self.enabled_services: + continue + View = rrb.TimeSeriesView if topic != "thumbnail" else rrb.Spatial2DView + service_views.append(View(name=topic, origin=f"/{topic}/", visible=log_msg_visible)) + rr.log(topic, rr.SeriesLine(name=topic), timeless=True) + + blueprint = rrb.Blueprint( + rrb.Horizontal( + rrb.Vertical(*service_views), + rrb.Vertical(*[rrb.Spatial2DView(name=cam_type, origin=cam_type) for cam_type in self.camera_readers.keys()]), + ), + rrb.SelectionPanel(expanded=False), + rrb.TimePanel(expanded=False) + ) + return blueprint + + @staticmethod + def _log_msg(msg, parent_key=''): + stack = [(msg, parent_key)] + while stack: + current_msg, current_parent_key = stack.pop() + if isinstance(current_msg, list): + for index, item in enumerate(current_msg): + new_key = f"{current_parent_key}/{index}" + if isinstance(item, (int, float)): + rr.log(new_key, rr.Scalar(item)) + elif isinstance(item, dict): + stack.append((item, new_key)) + elif isinstance(current_msg, dict): + for key, value in current_msg.items(): + new_key = f"{current_parent_key}/{key}" + if isinstance(value, (int, float)): + rr.log(new_key, rr.Scalar(value)) + elif isinstance(value, dict): + stack.append((value, new_key)) + elif isinstance(value, list): + for index, item in enumerate(value): + if isinstance(item, (int, float)): + rr.log(f"{new_key}/{index}", rr.Scalar(item)) + else: + pass # Not a plottable value + + @staticmethod + @rr.shutdown_at_exit + def _process_log_msgs(blueprint, enabled_services, log_all, lr): + rr.init(RR_WIN) + rr.connect(default_blueprint=blueprint) + + for msg in lr: + rr.set_time_nanos(RR_TIMELINE_NAME, msg.logMonoTime) + msg_type = msg.which() + + if not log_all and msg_type.lower() not in enabled_services: + continue + + if msg_type != "thumbnail": + Rerunner._log_msg(msg.to_dict()[msg.which()], msg.which()) + else: + rr.log("/thumbnail", rr.ImageEncoded(contents=msg.to_dict()[msg.which()].get("thumbnail"))) + + return [] + + @staticmethod + @rr.shutdown_at_exit + def _process_cam_readers(blueprint, cam_type, h, w, fr): + rr.init(RR_WIN) + rr.connect(default_blueprint=blueprint) + + size_hint = (h, w) + for ts, frame in fr: + rr.set_time_nanos(RR_TIMELINE_NAME, int(ts * 1e9)) + rr.log(cam_type, rr.ImageEncoded(contents=frame,format=rr.ImageFormat.NV12(size_hint))) + + def load_data(self): + self._start_rerun() + if len(self.enabled_services) > 0: + self.lr.run_across_segments(NUM_CPUS, partial(self._process_log_msgs, self.blueprint, self.enabled_services, self.log_all)) + for cam_type, cr in self.camera_readers.items(): + cr.run_across_segments(NUM_CPUS, partial(self._process_cam_readers, self.blueprint, cam_type, cr.h, cr.w)) - ret = [] - for msg in lr: - ret.append(msg) - rr.set_time_nanos("TIMELINE", msg.logMonoTime) - if msg.which() != "thumbnail": - log_msg(msg.to_dict()[msg.which()], msg.which()) - else: - log_thumbnail(msg.to_dict()[msg.which()]) - return ret if __name__ == '__main__': parser = argparse.ArgumentParser(description="A helper to run rerun on openpilot routes", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--demo", action="store_true", help="Use the demo route instead of providing one") - parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name to plot") + parser.add_argument("--qcam", action="store_true", help="Log decimated driving camera") + parser.add_argument("--fcam", action="store_true", help="Log driving camera") + parser.add_argument("--ecam", action="store_true", help="Log wide camera") + parser.add_argument("--dcam", action="store_true", help="Log driver monitoring camera") + parser.add_argument("--print_services", action="store_true", help="List out openpilot services") + parser.add_argument("--services", default=[], nargs='*', help="Specify openpilot services that will be logged.\ + No service will be logged if not specified.\ + To log all services include 'all' as one of your services") + parser.add_argument("--route", nargs='?', help="The route or segment name to plot") + args = parser.parse_args() - if len(sys.argv) == 1: + if not args.demo and not args.route: parser.print_help() sys.exit() - args = parser.parse_args() + if args.print_services: + print("\n".join(SERVICE_LIST.keys())) + sys.exit() - blueprint = createBlueprint() - rr.init("rerun_test") - rr.spawn(connect=False) # child processes stream data to Viewer + camera_config = CameraConfig(args.qcam, args.fcam, args.ecam, args.dcam) + + route_or_segment_name = DEMO_ROUTE if args.demo else args.route.strip() + sr = SegmentRange(route_or_segment_name) + r = Route(sr.route_name) + + if len(sr.seg_idxs) > 10: + print("You're requesting more than 10 segments of the route, " + \ + "please be aware that might take a lot of memory") + response = input("Do you wish to continue? (Y/n): ") + if response.strip() != "Y": + sys.exit() + + rerunner = Rerunner(r, sr, camera_config, args.services) + rerunner.load_data() - route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip() - print("Getting route log paths") - lr = LogReader(route_or_segment_name) - lr.run_across_segments(NUM_CPUS, partial(process, blueprint)) diff --git a/tools/setup.sh b/tools/setup.sh index 22d10be80b..9b1ee9c0c1 100755 --- a/tools/setup.sh +++ b/tools/setup.sh @@ -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 +if [ -z "$OPENPILOT_ROOT" ]; then + # default to current directory for installation + OPENPILOT_ROOT="$(pwd)/openpilot" +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 - cd openpilot -fi -if [[ "$OSTYPE" == "darwin"* ]]; then - tools/mac_setup.sh -else - tools/ubuntu_setup.sh -fi + echo -e " ↳ [${GREEN}✔${NC}] Successfully chosen $OPENPILOT_ROOT as installation directory\n" +} -git lfs pull +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 +} -source .venv/bin/activate +function git_clone() { + echo "Cloning openpilot..." + if $(git clone --filter=blob:none 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 "Building openpilot" -scons -u -j$(nproc) + echo -e " ↳ [${RED}✗${NC}] failed to clone openpilot!" + return 1 +} -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:/openpilot.git" -echo "git fetch" -echo "git commit -m \"first commit\"" -echo "git push" +function install_with_op() { + cd $OPENPILOT_ROOT + $OPENPILOT_ROOT/tools/op.sh install + $OPENPILOT_ROOT/tools/op.sh setup + + # make op usable right now + alias op="source $OPENPILOT_ROOT/tools/op.sh \"\$@\"" +} + +check_dir && check_git && git_clone && install_with_op + +unset OPENPILOT_ROOT +unset RED +unset GREEN +unset NC diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 1bdeb50e0d..f425e14cf2 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -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" diff --git a/tools/webcam/camera.py b/tools/webcam/camera.py index d1d61b64d7..ddff46c5d3 100644 --- a/tools/webcam/camera.py +++ b/tools/webcam/camera.py @@ -1,3 +1,4 @@ +# TODO: remove the cv2 dependency, it's only used here import cv2 as cv import numpy as np diff --git a/uv.lock b/uv.lock index 48d53bbda9..866cf921ae 100644 --- a/uv.lock +++ b/uv.lock @@ -96,15 +96,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, ] -[[distribution]] -name = "alabaster" -version = "0.7.16" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511 }, -] - [[distribution]] name = "attrs" version = "23.2.0" @@ -116,22 +107,22 @@ wheels = [ [[distribution]] name = "av" -version = "12.2.0" +version = "12.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/e2/1c5708feb7ceb46c8ab9d2e3fbd451a725f0741d7c5336020d13be527490/av-12.2.0.tar.gz", hash = "sha256:460670325bbd64b7a6774b6bda05985cbe4582d111f81993bfbb08058f8c0484", size = 3828627 } +sdist = { url = "https://files.pythonhosted.org/packages/00/f8/5adeeae0c42a7130933d168b8d84a21c98a32cb9fcf9222e2541ed0d9c7b/av-12.3.0.tar.gz", hash = "sha256:04b1892562aff3277efc79f32bd8f1d0cbb64ed011241cb3e96f9ad471816c22", size = 3833953 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/08/41200974e40a803da6d008cab7a801d187f950d92efa71182680b419a99a/av-12.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f74c9987798d45302b86e94b3bdb6009e9a509c57971b5599aae4353f5b8c5c0", size = 26057398 }, - { url = "https://files.pythonhosted.org/packages/10/94/d4383c50b1a819e0edb43637d6cb03086b1fcc563e9c07fc0eb2840c4e2d/av-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d17e4110efe449842d12bc11166141b5ca08ce821b7529f02ed9dc3b73c9291", size = 20871004 }, - { url = "https://files.pythonhosted.org/packages/b8/eb/82b86e8f763dd104a75478a02228465715984e0fe91ae6c7567093bf75a2/av-12.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a7cc709c0c231f282f1b26a76b42d63100a8bc088522cfd06c500ed4b6c660c", size = 33310123 }, - { url = "https://files.pythonhosted.org/packages/72/b9/bc306aaae0743004ea0f45a779c35ce0896d284e36e715f383eaf04d3a9c/av-12.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:433589001c309d4ab655f0085b47bcab89e5ddeb6472993d9ef92e05eabbbe8e", size = 32783301 }, - { url = "https://files.pythonhosted.org/packages/f2/50/0014d42a7165dc386bef02cae9de3fd5512daafcf0bae56d3cfc1e880df5/av-12.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:505955d5c2c9b7e0034fad7d0b57df6944adda9e42a606c9964ca5693c9b090d", size = 35224812 }, - { url = "https://files.pythonhosted.org/packages/77/fd/a1e1f10666e3aa37caed52804e656f525b978591ab69d20fccc6bb35d115/av-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:a9ca519ae6525a88637b73a1adae87235ac9a141a8d0b0c26a75cd4182c12a9f", size = 26827978 }, - { url = "https://files.pythonhosted.org/packages/26/7e/92107c359b802555f33feef5f60650a433ac084ec5e257134bf26f1ae559/av-12.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f0026b52b9981b15d71f7f09ecd32587d9b99dd350588f8e17ce726662b466c5", size = 26070643 }, - { url = "https://files.pythonhosted.org/packages/9a/9f/7a94c61856e243ecb3aa58ceebbeae5f165862ffb4e8548b497d1d906418/av-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e60a6da4eb5200900b37716dd971676a1dfb8731b53e8f49a3e630b772f5c97", size = 20877075 }, - { url = "https://files.pythonhosted.org/packages/5b/2a/9b02466d6b53581b64c3fb9f6e063e2d83b549bffa7141ba10b0523ad23c/av-12.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d143d10ce726ced812eb0d4834841349027efd082c13d45a42f6914aae402ca6", size = 33536552 }, - { url = "https://files.pythonhosted.org/packages/28/fe/8b7ec1008f42942f0cb0db1f700bc4d1e862018677c32f4d47331202302e/av-12.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbe1ace6ebaae1de41f3b0412367eec42188a381fae83669d4b18e1340648839", size = 33060022 }, - { url = "https://files.pythonhosted.org/packages/ea/aa/2e74958ebb9dde8b33940fedd7ead406bd52760589cd7bcd9c19dbac3163/av-12.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8280def29f209ce294b0aa5045a66c1027b8ba2ba5b82e1f66e8a910ff1c1120", size = 35549894 }, - { url = "https://files.pythonhosted.org/packages/38/cc/437ca48e268120abab9634775d0befecee7ed54327c4df2573f2cf9f9d51/av-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:6740ae90ffd7fe6e7439beab6494c966cd46739943d3046ea01021d4bc2b36e6", size = 26829453 }, + { url = "https://files.pythonhosted.org/packages/5d/20/256fa4fc4ef9bb46fdc4be4662e13a30b0334487c955961f3816d94db04b/av-12.3.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:cc06a806419fddc7102150ffe353c7d96b99b95fd12864280c91c851603fd4cb", size = 24658122 }, + { url = "https://files.pythonhosted.org/packages/5d/45/a9d0475539b4f49deb34f3da558de31cefc6be867d5c0603d575a8485069/av-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e2130ff622a574d3d5d6e88ac335efcdd98c375bb341f87d9fe540830a746f5", size = 19923068 }, + { url = "https://files.pythonhosted.org/packages/af/27/1f2b3e46059c6618fd76ba12a96b49dc8515a426cd477032cd33f80505e8/av-12.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8b9bd99f916ff4d1278654e94658e6ace7ca60f6321f254d09c8cd81d9095b", size = 32555100 }, + { url = "https://files.pythonhosted.org/packages/28/34/759741d397a8bdbb8a359b8b5d49832a444b26c9a7f79c0f88be76a6b979/av-12.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e375d1d89a5c6edfd9f66701fdb6cc9161cc1ff99d15ff0bda21ee1ad38e9e0", size = 31936355 }, + { url = "https://files.pythonhosted.org/packages/b4/6e/77426cb92117c941b0f759908bc83f34f259b11b353acb5de95972b452f7/av-12.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef9066fd8d86548e12d587cbfe7b852159e48ff3c732271c3032668d4bd7c599", size = 34416598 }, + { url = "https://files.pythonhosted.org/packages/ff/d3/4b0fddcd54d0a88ee7e035f239ebb56ce139fac8e02ee0942c43746a66ff/av-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bfaa9864560e43d45d254ed95f70ab1aab24a2fa0cc35ac99eef362f1453bec0", size = 25975217 }, + { url = "https://files.pythonhosted.org/packages/e4/c1/0636bccf5a1a2c935952614b9d34d8d8aae078c9773a60efb5376702f499/av-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5174e995772ebe33561980dca625f830aea8d39a4338728dedb41ae7dc2605af", size = 24669628 }, + { url = "https://files.pythonhosted.org/packages/ef/7d/9126abdafe20fa73d2c19fd108450363253cfea283c350618cc1434f473c/av-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:028d8b40308536f740dace3efd0178eb96825b414897c9594fb74136532901cb", size = 19928928 }, + { url = "https://files.pythonhosted.org/packages/27/75/c1b9e0aa4bd0d8b8311f366b6b38f6c6600d66baddfe2888accc7f76b1f5/av-12.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b030791ecc6185776d832d19ce196f61daf3e17e591a9bb6fd181280e1754138", size = 32793461 }, + { url = "https://files.pythonhosted.org/packages/5a/06/1364c445f8a8ab4870f0f5c4530b496257ae09de7fa01b6108525abea8b9/av-12.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3703a35481fda5798a27bf6208c1ec3b61c18931625771fb3c9fd870539c7d7", size = 32217647 }, + { url = "https://files.pythonhosted.org/packages/27/08/220d5a1ae7e7830d66d041c71e607c1f5df2e3598b12fb406b0d7c2defa7/av-12.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32f3eef56b2df289db6105f9fe2ebc9a8134a8adbd62190daeb8e22c4ff47794", size = 34746451 }, + { url = "https://files.pythonhosted.org/packages/96/67/9f1c444864d4f3e3773100b9ed20e670f80d5575b7a8fd53cca20de9d681/av-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:62d036ee8321d67190887012c3dbcd1ad83248603cc29ea75fbb75835b8d6e6e", size = 25977611 }, ] [[distribution]] @@ -166,7 +157,7 @@ wheels = [ [[distribution]] name = "azure-storage-blob" -version = "12.20.0" +version = "12.21.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -174,31 +165,9 @@ dependencies = [ { name = "isodate" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1b/0f/86cdaec4be486d12fd5bd2c56e835492a58d3bcd4915d24473e889b70f2c/azure-storage-blob-12.20.0.tar.gz", hash = "sha256:eeb91256e41d4b5b9bad6a87fd0a8ade07dd58aa52344e2c8d2746e27a017d3b", size = 551196 } +sdist = { url = "https://files.pythonhosted.org/packages/97/c9/0e1e864eef8071102de2d6b11dfcf8d35410735145b2fbc2e0a5f58d1490/azure-storage-blob-12.21.0.tar.gz", hash = "sha256:b9722725072f5b7373c0f4dd6d78fbae2bb37bffc5c3e01731ab8c750ee8dd7e", size = 557430 } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/19/2be26569e708cb618feecd7316ee0c5475273f7cdb4f9030a862870c74c8/azure_storage_blob-12.20.0-py3-none-any.whl", hash = "sha256:de6b3bf3a90e9341a6bcb96a2ebe981dffff993e9045818f6549afea827a52a9", size = 392162 }, -] - -[[distribution]] -name = "babel" -version = "2.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/d2/9671b93d623300f0aef82cde40e25357f11330bdde91743891b22a555bed/babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413", size = 9390000 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/45/377f7e32a5c93d94cd56542349b34efab5ca3f9e2fd5a68c5e93169aa32d/Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb", size = 9634913 }, -] - -[[distribution]] -name = "breathe" -version = "4.35.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a2/9f/0c6f4ae0608d5edbb1df357c2487edfcbda13e75f4e48a898972592e2e48/breathe-4.35.0.tar.gz", hash = "sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386", size = 83358 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/61/faddc25913de74e60e175bcfd962ec83532653c5895c0a06a83a6b5bbf3d/breathe-4.35.0-py3-none-any.whl", hash = "sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be", size = 92955 }, + { url = "https://files.pythonhosted.org/packages/f4/da/4033cee3855395e84ff73da4b50d3528f9338205299cde89676639387fcc/azure_storage_blob-12.21.0-py3-none-any.whl", hash = "sha256:f9ede187dd5a0ef296b583a7c1861c6938ddd6708d6e70f4203a163c2ab42d43", size = 396449 }, ] [[distribution]] @@ -227,6 +196,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/08/c55e2172f033a44b831ee771bb32fa89c369311c0598a52c03755f29a75e/casadi-3.6.5-cp312-none-win_amd64.whl", hash = "sha256:fe2b64d777e36cc3f101220dd1e219a0e11c3e4ee2b5e708b30fea9a27107e41", size = 43057681 }, ] +[[distribution]] +name = "casadi" +version = "3.6.6" +source = { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl" } +dependencies = [ + { name = "numpy" }, +] +wheels = [ + { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl", hash = "sha256:06a15e0099657b960620a2491e565c7f126030018da80c39f6bd33439160c669" }, +] + [[distribution]] name = "certifi" version = "2024.7.4" @@ -439,36 +419,31 @@ sdist = { url = "https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c [[distribution]] name = "cryptography" -version = "42.0.8" +version = "43.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/93/a7/1498799a2ea06148463a9a2c10ab2f6a921a74fb19e231b27dc412a748e2/cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", size = 671250 } +sdist = { url = "https://files.pythonhosted.org/packages/69/ec/9fb9dcf4f91f0e5e76de597256c43eedefd8423aa59be95c70c4c3db426a/cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e", size = 686873 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/8b/1b929ba8139430e09e140e6939c2b29c18df1f2fc2149e41bdbdcdaf5d1f/cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", size = 5899961 }, - { url = "https://files.pythonhosted.org/packages/fa/5d/31d833daa800e4fab33209843095df7adb4a78ea536929145534cbc15026/cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", size = 3114353 }, - { url = "https://files.pythonhosted.org/packages/5d/32/f6326c70a9f0f258a201d3b2632bca586ea24d214cec3cf36e374040e273/cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", size = 3647773 }, - { url = "https://files.pythonhosted.org/packages/35/66/2d87e9ca95c82c7ee5f2c09716fc4c4242c1ae6647b9bd27e55e920e9f10/cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", size = 3839763 }, - { url = "https://files.pythonhosted.org/packages/c2/de/8083fa2e68d403553a01a9323f4f8b9d7ffed09928ba25635c29fb28c1e7/cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", size = 3632661 }, - { url = "https://files.pythonhosted.org/packages/07/40/d6f6819c62e808ea74639c3c640f7edd636b86cce62cb14943996a15df92/cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", size = 3851536 }, - { url = "https://files.pythonhosted.org/packages/5c/46/de71d48abf2b6d3c808f4fbb0f4dc44a4e72786be23df0541aa2a3f6fd7e/cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", size = 3754209 }, - { url = "https://files.pythonhosted.org/packages/25/c9/86f04e150c5d5d5e4a731a2c1e0e43da84d901f388e3fea3d5de98d689a7/cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", size = 3923551 }, - { url = "https://files.pythonhosted.org/packages/53/c2/903014dafb7271fb148887d4355b2e90319cad6e810663be622b0c933fc9/cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", size = 3739265 }, - { url = "https://files.pythonhosted.org/packages/95/26/82d704d988a193cbdc69ac3b41c687c36eaed1642cce52530ad810c35645/cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", size = 3937371 }, - { url = "https://files.pythonhosted.org/packages/cf/71/4e0d05c9acd638a225f57fb6162aa3d03613c11b76893c23ea4675bb28c5/cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", size = 2438849 }, - { url = "https://files.pythonhosted.org/packages/06/0f/78da3cad74f2ba6c45321dc90394d70420ea846730dc042ef527f5a224b5/cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", size = 2889090 }, - { url = "https://files.pythonhosted.org/packages/60/12/f064af29190cdb1d38fe07f3db6126091639e1dece7ec77c4ff037d49193/cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", size = 5901232 }, - { url = "https://files.pythonhosted.org/packages/43/c2/4a3eef67e009a522711ebd8ac89424c3a7fe591ece7035d964419ad52a1d/cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", size = 3648711 }, - { url = "https://files.pythonhosted.org/packages/49/1c/9f6d13cc8041c05eebff1154e4e71bedd1db8e174fff999054435994187a/cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", size = 3841968 }, - { url = "https://files.pythonhosted.org/packages/5f/f9/c3d4f19b82bdb25a3d857fe96e7e571c981810e47e3f299cc13ac429066a/cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", size = 3633032 }, - { url = "https://files.pythonhosted.org/packages/fa/e2/b7e6e8c261536c489d9cf908769880d94bd5d9a187e166b0dc838d2e6a56/cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", size = 3852478 }, - { url = "https://files.pythonhosted.org/packages/a2/68/e16751f6b859bc120f53fddbf3ebada5c34f0e9689d8af32884d8b2e4b4c/cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e", size = 3754102 }, - { url = "https://files.pythonhosted.org/packages/0f/38/85c74d0ac4c540780e072b1e6f148ecb718418c1062edcb20d22f3ec5bbb/cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", size = 3925042 }, - { url = "https://files.pythonhosted.org/packages/89/f4/a8b982e88eb5350407ebdbf4717b55043271d878705329e107f4783555f2/cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", size = 3738833 }, - { url = "https://files.pythonhosted.org/packages/fd/2b/be327b580645927bb1a1f32d5a175b897a9b956bc085b095e15c40bac9ed/cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", size = 3938751 }, - { url = "https://files.pythonhosted.org/packages/3c/d5/c6a78ffccdbe4516711ebaa9ed2c7eb6ac5dfa3dc920f2c7e920af2418b0/cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", size = 2439281 }, - { url = "https://files.pythonhosted.org/packages/a2/7b/b0d330852dd5953daee6b15f742f15d9f18e9c0154eb4cfcc8718f0436da/cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", size = 2886038 }, + { url = "https://files.pythonhosted.org/packages/d3/46/dcd2eb6840b9452e7fbc52720f3dc54a85eb41e68414733379e8f98e3275/cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74", size = 6239718 }, + { url = "https://files.pythonhosted.org/packages/e8/23/b0713319edff1d8633775b354f8b34a476e4dd5f4cd4b91e488baec3361a/cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895", size = 3808466 }, + { url = "https://files.pythonhosted.org/packages/77/9d/0b98c73cebfd41e4fb0439fe9ce08022e8d059f51caa7afc8934fc1edcd9/cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22", size = 3998060 }, + { url = "https://files.pythonhosted.org/packages/ae/71/e073795d0d1624847f323481f7d84855f699172a632aa37646464b0e1712/cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47", size = 3792596 }, + { url = "https://files.pythonhosted.org/packages/83/25/439a8ddd8058e7f898b7d27c36f94b66c8c8a2d60e1855d725845f4be0bc/cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf", size = 4008355 }, + { url = "https://files.pythonhosted.org/packages/c7/a2/1607f1295eb2c30fcf2c07d7fd0c3772d21dcdb827de2b2730b02df0af51/cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55", size = 3899133 }, + { url = "https://files.pythonhosted.org/packages/5e/64/f41f42ddc9c583737c9df0093affb92c61de7d5b0d299bf644524afe31c1/cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431", size = 4096946 }, + { url = "https://files.pythonhosted.org/packages/cd/cd/d165adcf3e707d6a049d44ade6ca89973549bed0ab3686fa49efdeefea53/cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc", size = 2616826 }, + { url = "https://files.pythonhosted.org/packages/f9/b7/38924229e84c41b0e88d7a5eed8a29d05a44364f85fbb9ddb3984b746fd2/cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778", size = 3078700 }, + { url = "https://files.pythonhosted.org/packages/66/d7/397515233e6a861f921bd0365b162b38e0cc513fcf4f1bdd9cc7bc5a3384/cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66", size = 6242814 }, + { url = "https://files.pythonhosted.org/packages/58/aa/99b2c00a4f54c60d210d6d1759c720ecf28305aa32d6fb1bb1853f415be6/cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5", size = 3809467 }, + { url = "https://files.pythonhosted.org/packages/76/eb/ab783b47b3b9b55371b4361c7ec695144bde1a3343ff2b7a8c1d8fe617bb/cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e", size = 3998617 }, + { url = "https://files.pythonhosted.org/packages/a3/62/62770f34290ebb1b6542bd3f13b3b102875b90aed4804e296f8d2a5ac6d7/cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5", size = 3794003 }, + { url = "https://files.pythonhosted.org/packages/0f/6c/b42660b3075ff543065b2c1c5a3d9bedaadcff8ebce2ee981be2babc2934/cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f", size = 4008774 }, + { url = "https://files.pythonhosted.org/packages/f7/74/028cea86db9315ba3f991e307adabf9f0aa15067011137c38b2fb2aa16eb/cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0", size = 3900098 }, + { url = "https://files.pythonhosted.org/packages/bd/f6/e4387edb55563e2546028ba4c634522fe727693d3cdd9ec0ecacedc75411/cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b", size = 4096867 }, + { url = "https://files.pythonhosted.org/packages/ce/61/55560405e75432bdd9f6cf72fa516cab623b83a3f6d230791bc8fc4afeee/cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf", size = 2616481 }, + { url = "https://files.pythonhosted.org/packages/e6/3d/696e7a0f04555c58a2813d47aaa78cb5ba863c1f453c74a4f45ae772b054/cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709", size = 3081462 }, ] [[distribution]] @@ -532,15 +507,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/a1/8c5287991ddb8d3e4662f71356d9656d91ab3a36618c3dd11b280df0d255/dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50", size = 307696 }, ] -[[distribution]] -name = "docutils" -version = "0.21.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, -] - [[distribution]] name = "ewmhlib" version = "0.2" @@ -832,15 +798,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9c/1f/19ebc343cc71a7ffa78f17018535adc5cbdd87afb31d7c34874680148b32/ifaddr-0.2.0-py3-none-any.whl", hash = "sha256:085e0305cfe6f16ab12d72e2024030f5d52674afad6911bb1eee207177b8a748", size = 12314 }, ] -[[distribution]] -name = "imagesize" -version = "1.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, -] - [[distribution]] name = "import-linter" version = "2.0" @@ -857,14 +814,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]] @@ -1053,23 +1010,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 }, -] - -[[distribution]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, + { url = "https://files.pythonhosted.org/packages/f3/df/ca72f352e15b6f8ce32b74af029f1189abffb906f7c137501ffe69c98a65/Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621", size = 97778 }, ] [[distribution]] @@ -1131,27 +1076,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e3/31/aeab8a3db1fb22a7d04c5215f872b92451baf7f6595ffd59004aeead0b2c/matplotlib-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:44a21d922f78ce40435cb35b43dd7d573cf2a30138d5c4b709d19f00e3907fd7", size = 7974774 }, ] -[[distribution]] -name = "mdit-py-plugins" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/6c/79c52651b22b64dba5c7bbabd7a294cc410bfb2353250dc8ade44d7d8ad8/mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c", size = 42713 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/f7/8a4dcea720a581e69ac8c5a38524baf0e3e2bb5f3819a9ff661464fe7d10/mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a", size = 54794 }, -] - -[[distribution]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, -] - [[distribution]] name = "mergedeep" version = "1.3.4" @@ -1190,9 +1114,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" }, @@ -1200,32 +1133,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]] @@ -1255,19 +1185,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/28/fa/b2ba8229b9381e8f6381c1dcae6f4159a7f72349e414ed19cfbbd1817173/MouseInfo-0.1.3.tar.gz", hash = "sha256:2c62fb8885062b8e520a3cce0a297c657adcc08c60952eb05bc8256ef6f7f6e7", size = 10850 } -[[distribution]] -name = "mpld3" -version = "0.5.10" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "matplotlib" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/90/58/19378f4189a034eb3efc17b133426b8551af1d3b2c70d641a63124579629/mpld3-0.5.10.tar.gz", hash = "sha256:a478eb404fa5212505c59133cf272cd9a94105872e605597720e7f84de38fbc7", size = 1027709 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/6a/e3691bcc47485f38b09853207c928130571821d187cf174eed5418d45e82/mpld3-0.5.10-py3-none-any.whl", hash = "sha256:80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1", size = 202561 }, -] - [[distribution]] name = "mpmath" version = "1.3.0" @@ -1279,17 +1196,16 @@ wheels = [ [[distribution]] name = "msal" -version = "1.29.0" +version = "1.30.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, - { name = "pyjwt" }, - { name = "pyjwt", extra = "crypto" }, + { name = "pyjwt", extra = ["crypto"] }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/d8/438af3c52f48bab135edbd47f24447c4985ec81c122ebf36e027621f6742/msal-1.29.0.tar.gz", hash = "sha256:8f6725f099752553f9b2fe84125e2a5ebe47b49f92eacca33ebedd3a9ebaae25", size = 140817 } +sdist = { url = "https://files.pythonhosted.org/packages/03/ce/45b9af8f43fbbf34d15162e1e39ce34b675c234c56638277cc05562b6dbf/msal-1.30.0.tar.gz", hash = "sha256:b4bf00850092e465157d814efa24a18f788284c9a479491024d62903085ea2fb", size = 142510 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/a7/5b51016902118052a1342e073138a319b758020cd66f3ee79a7e98e56d62/msal-1.29.0-py3-none-any.whl", hash = "sha256:6b301e63f967481f0cc1a3a3bac0cf322b276855bc1b0955468d9deb3f33d511", size = 110860 }, + { url = "https://files.pythonhosted.org/packages/ab/82/8f19334da43b7ef72d995587991a446f140346d76edb96a2c1a2689588e9/msal-1.30.0-py3-none-any.whl", hash = "sha256:423872177410cb61683566dc3932db7a76f661a5d2f6f52f02a047f101e1c1de", size = 111760 }, ] [[distribution]] @@ -1346,25 +1262,25 @@ wheels = [ [[distribution]] name = "mypy" -version = "1.10.1" +version = "1.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/b9/81e4c6dbb1ec1e72503de3ff2c5fe4b7f224e04613b670f8b9004cd8a4dd/mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0", size = 3022304 } +sdist = { url = "https://files.pythonhosted.org/packages/b1/95/a6dbb4fef19402c488b001ff4bd9f1a770e44049ce049b904dcffc65356c/mypy-1.11.0.tar.gz", hash = "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", size = 3078260 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/cf/0645128c6edf70eb9b9687ad42fcb61ea344a7927ed2b78ce2275282fe87/mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a", size = 10740526 }, - { url = "https://files.pythonhosted.org/packages/19/c9/10842953066265e6063c41a85bbee3b877501947c970ea84a1db5f11d32e/mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84", size = 9898375 }, - { url = "https://files.pythonhosted.org/packages/e4/9e/551e897f67c5d67aa1976bc3b4951f297d1daf07250c421bb045b2613350/mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f", size = 12602338 }, - { url = "https://files.pythonhosted.org/packages/2b/a4/55e3635253e5fa7051674dd5a67582f08b0ba8823e1fdbf7241ed5b32d4e/mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b", size = 12680741 }, - { url = "https://files.pythonhosted.org/packages/7a/cc/aa881ad051f99915887db0b5de8facc0e224295be22f92178c8f77fd8359/mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e", size = 9393661 }, - { url = "https://files.pythonhosted.org/packages/5d/86/3c3bdaccc3cbd1372acb15667a2c2cb773523a710a22e2748cbda9a7c1e2/mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7", size = 10864022 }, - { url = "https://files.pythonhosted.org/packages/ec/05/7c87b26b6a769b70f6c0b8a6daef01fc6f3ae566df89a2fa9d04f690b0d3/mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3", size = 9857795 }, - { url = "https://files.pythonhosted.org/packages/ff/b5/cbccba4dca9703c4c467171e7f61ea6a1a75eae991208aa5bc7d49807f91/mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e", size = 12647633 }, - { url = "https://files.pythonhosted.org/packages/02/3c/1f5e57c8cfab4299f7189821ae8bb4896e8e623a04d293fd32e32eb0e617/mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04", size = 12730251 }, - { url = "https://files.pythonhosted.org/packages/f9/20/d33608e8dc3bc0f5966fc1f6c2d16671f0725dcca279beec47c3e19afd9d/mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31", size = 9491734 }, - { url = "https://files.pythonhosted.org/packages/2b/ee/d53a3d4792a09b6cd757978951d6dcf8b10825a8b8522b68e9b5eb53b9a1/mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a", size = 2580108 }, + { url = "https://files.pythonhosted.org/packages/46/69/728aca603433e52b7d2d659678f47562fead09106686a28967d978ef50b8/mypy-1.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb", size = 10872601 }, + { url = "https://files.pythonhosted.org/packages/9a/fd/ba4064c7c0e3c650ef496bf6f41785eaa9091532f0ddffe47186ae24db08/mypy-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1", size = 10034398 }, + { url = "https://files.pythonhosted.org/packages/ab/43/ef3b86ac6899dc211bb1dbef79df589991e0155cc9ac05925b44fc676d86/mypy-1.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3", size = 12418537 }, + { url = "https://files.pythonhosted.org/packages/be/3e/db067303af93fdc532b784b719e887d69d26a13ff52477c65304555c3198/mypy-1.11.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d", size = 12895138 }, + { url = "https://files.pythonhosted.org/packages/4b/56/a1ac65714ee33a35d9f1b6173b8c989c05120cb386dbbe6709ba4cc7a9e4/mypy-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a", size = 9562630 }, + { url = "https://files.pythonhosted.org/packages/ad/f2/656171fddcfc81527f6c1a8c9550896999e7f7da9606aae1ffde2518f0c7/mypy-1.11.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20", size = 11002476 }, + { url = "https://files.pythonhosted.org/packages/70/c9/a906c097dddacbcc52068196db1f3c6ecf636b039dd002baf9ffe6904e99/mypy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba", size = 10001386 }, + { url = "https://files.pythonhosted.org/packages/5d/3a/9cb76b2fca4fb4a3aafa9f6f487c873360f3c6a1b2d05fedaa19ba681f28/mypy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd", size = 12505911 }, + { url = "https://files.pythonhosted.org/packages/08/87/47fe67de644f2eefce265425742e439206653c7d7abf589a9db7adda2c16/mypy-1.11.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d", size = 12952479 }, + { url = "https://files.pythonhosted.org/packages/05/80/aa7b8d066bce6fe07f9b7fab2e557f428e22eff417481ffe065378275402/mypy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2", size = 9662673 }, + { url = "https://files.pythonhosted.org/packages/ce/0e/fc28db5d225623cbbca54d9f4207a3ebf4937d816ba4b61aa3a5ad2af2e7/mypy-1.11.0-py3-none-any.whl", hash = "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", size = 2619149 }, ] [[distribution]] @@ -1376,23 +1292,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, ] -[[distribution]] -name = "myst-parser" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "jinja2" }, - { name = "markdown-it-py" }, - { name = "mdit-py-plugins" }, - { name = "pyyaml" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/49/64/e2f13dac02f599980798c01156393b781aec983b52a6e4057ee58f07c43a/myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87", size = 92392 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/de/21aa8394f16add8f7427f0a1326ccd2b3a2a8a3245c9252bc5ac034c6155/myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1", size = 83163 }, -] - [[distribution]] name = "natsort" version = "8.4.0" @@ -1525,7 +1424,8 @@ source = { editable = "." } dependencies = [ { name = "aiohttp" }, { name = "aiortc" }, - { name = "casadi" }, + { name = "casadi", version = "3.6.5", source = { registry = "https://pypi.org/simple" }, marker = "python_version < '3.12' or python_version > '3.12' or platform_machine != 'aarch64'" }, + { name = "casadi", version = "3.6.6", source = { url = "https://github.com/commaai/casadi/releases/download/nightly-release-3.6.6/casadi-3.6.6-cp312-none-manylinux2014_aarch64.whl" }, marker = "python_version == '3.12' and platform_machine == 'aarch64'" }, { name = "cffi" }, { name = "crcmod" }, { name = "cython" }, @@ -1561,7 +1461,6 @@ dev = [ { name = "av" }, { name = "azure-identity" }, { name = "azure-storage-blob" }, - { name = "breathe" }, { name = "control" }, { name = "dictdiffer" }, { name = "flaky" }, @@ -1570,15 +1469,12 @@ dev = [ { name = "lru-dict" }, { name = "matplotlib" }, { name = "metadrive-simulator", marker = "platform_machine != 'aarch64'" }, - { name = "mpld3" }, - { name = "myst-parser" }, - { name = "natsort" }, - { name = "opencv-python-headless" }, { name = "parameterized" }, { name = "pyautogui" }, { 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" }, @@ -1588,7 +1484,9 @@ dev = [ docs = [ { name = "jinja2" }, { name = "mkdocs" }, + { name = "mkdocs-plugin-commonmark" }, { name = "mkdocs-terminal" }, + { name = "natsort" }, ] testing = [ { name = "coverage" }, @@ -1699,15 +1597,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" @@ -1834,27 +1723,27 @@ wheels = [ [[distribution]] name = "pyarrow" -version = "16.1.0" +version = "17.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1a/f2/67533f116deb6dae7a0ac04681695fe06135912253a115c5ecdc714a32d4/pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315", size = 1080280 } +sdist = { url = "https://files.pythonhosted.org/packages/27/4e/ea6d43f324169f8aec0e57569443a38bab4b398d09769ca64f7b4d467de3/pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28", size = 1112479 } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/17/a12aaddb818b7b73d17f3304afc22bce32ccb26723b507cc9c267aa809f3/pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c", size = 28380406 }, - { url = "https://files.pythonhosted.org/packages/f3/94/4e2a579bbac1adb19e63b054b300f6f7fa04f32f212ce86c18727bdda698/pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c", size = 26040531 }, - { url = "https://files.pythonhosted.org/packages/7e/34/d5b6eb5066553533dd6eb9782d50f353f8c6451ee2e49e0ea54d0e67bc34/pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6", size = 38666685 }, - { url = "https://files.pythonhosted.org/packages/d2/34/4e3c04e7398764e56ef00f8f267f8ebf565808478f5fee850cef4be670c3/pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147", size = 40949577 }, - { url = "https://files.pythonhosted.org/packages/47/62/b446ee0971b00e7437b9c54a8409ae20413235a64c0a301d7cf97070cffa/pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e", size = 38077480 }, - { url = "https://files.pythonhosted.org/packages/fa/15/48a68b30542a0231a75c26d8661bc5c9bbc07b42c5b219e929adba814ba7/pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b", size = 40821141 }, - { url = "https://files.pythonhosted.org/packages/49/4d/62a09116ec357ade462fac4086e0711457a87177bea25ae46b25897d6d7c/pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b", size = 25889334 }, - { url = "https://files.pythonhosted.org/packages/84/bd/d5903125e38c33b74f7b3d57ffffd4ef48145208cfd8742367f12effb59c/pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f", size = 28372822 }, - { url = "https://files.pythonhosted.org/packages/9b/73/560ef6bf05f16305502b8e368c771e8f82d774898b37a3fb231f89c13342/pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a", size = 26004052 }, - { url = "https://files.pythonhosted.org/packages/56/5e/3cd956aceb1c960e8ac6fdc6eea69d642aa2e6ee10e2f10ce7815dbf62a9/pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c", size = 38660648 }, - { url = "https://files.pythonhosted.org/packages/08/4a/668e7fb6bc564e5361097f1f160b2891ca40bcacfe018638e2841073ec3d/pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2", size = 40961053 }, - { url = "https://files.pythonhosted.org/packages/f7/8f/a51a290a855172514b8496c8a74f0e0b98e5e0582d44ae7547cf68dd033b/pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628", size = 38060675 }, - { url = "https://files.pythonhosted.org/packages/25/7b/8da91f8de0b40b760dd748031973b6ac2aa3d4f85c67f45b7e58577ca22e/pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7", size = 40826735 }, - { url = "https://files.pythonhosted.org/packages/fa/2b/a0053f1304586f2976cb2c37ddb0e52cf4114220e805ebba272a1e231ccc/pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444", size = 25838156 }, + { url = "https://files.pythonhosted.org/packages/f9/46/ce89f87c2936f5bb9d879473b9663ce7a4b1f4359acc2f0eb39865eaa1af/pyarrow-17.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1c8856e2ef09eb87ecf937104aacfa0708f22dfeb039c363ec99735190ffb977", size = 29028748 }, + { url = "https://files.pythonhosted.org/packages/8d/8e/ce2e9b2146de422f6638333c01903140e9ada244a2a477918a368306c64c/pyarrow-17.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e19f569567efcbbd42084e87f948778eb371d308e137a0f97afe19bb860ccb3", size = 27190965 }, + { url = "https://files.pythonhosted.org/packages/3b/c8/5675719570eb1acd809481c6d64e2136ffb340bc387f4ca62dce79516cea/pyarrow-17.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b244dc8e08a23b3e352899a006a26ae7b4d0da7bb636872fa8f5884e70acf15", size = 39269081 }, + { url = "https://files.pythonhosted.org/packages/5e/78/3931194f16ab681ebb87ad252e7b8d2c8b23dad49706cadc865dff4a1dd3/pyarrow-17.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b72e87fe3e1db343995562f7fff8aee354b55ee83d13afba65400c178ab2597", size = 39864921 }, + { url = "https://files.pythonhosted.org/packages/d8/81/69b6606093363f55a2a574c018901c40952d4e902e670656d18213c71ad7/pyarrow-17.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dc5c31c37409dfbc5d014047817cb4ccd8c1ea25d19576acf1a001fe07f5b420", size = 38740798 }, + { url = "https://files.pythonhosted.org/packages/4c/21/9ca93b84b92ef927814cb7ba37f0774a484c849d58f0b692b16af8eebcfb/pyarrow-17.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e3343cb1e88bc2ea605986d4b94948716edc7a8d14afd4e2c097232f729758b4", size = 39871877 }, + { url = "https://files.pythonhosted.org/packages/30/d1/63a7c248432c71c7d3ee803e706590a0b81ce1a8d2b2ae49677774b813bb/pyarrow-17.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a27532c38f3de9eb3e90ecab63dfda948a8ca859a66e3a47f5f42d1e403c4d03", size = 25151089 }, + { url = "https://files.pythonhosted.org/packages/d4/62/ce6ac1275a432b4a27c55fe96c58147f111d8ba1ad800a112d31859fae2f/pyarrow-17.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9b8a823cea605221e61f34859dcc03207e52e409ccf6354634143e23af7c8d22", size = 29019418 }, + { url = "https://files.pythonhosted.org/packages/8e/0a/dbd0c134e7a0c30bea439675cc120012337202e5fac7163ba839aa3691d2/pyarrow-17.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1e70de6cb5790a50b01d2b686d54aaf73da01266850b05e3af2a1bc89e16053", size = 27152197 }, + { url = "https://files.pythonhosted.org/packages/cb/05/3f4a16498349db79090767620d6dc23c1ec0c658a668d61d76b87706c65d/pyarrow-17.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0071ce35788c6f9077ff9ecba4858108eebe2ea5a3f7cf2cf55ebc1dbc6ee24a", size = 39263026 }, + { url = "https://files.pythonhosted.org/packages/c2/0c/ea2107236740be8fa0e0d4a293a095c9f43546a2465bb7df34eee9126b09/pyarrow-17.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:757074882f844411fcca735e39aae74248a1531367a7c80799b4266390ae51cc", size = 39880798 }, + { url = "https://files.pythonhosted.org/packages/f6/b0/b9164a8bc495083c10c281cc65064553ec87b7537d6f742a89d5953a2a3e/pyarrow-17.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ba11c4f16976e89146781a83833df7f82077cdab7dc6232c897789343f7891a", size = 38715172 }, + { url = "https://files.pythonhosted.org/packages/f1/c4/9625418a1413005e486c006e56675334929fad864347c5ae7c1b2e7fe639/pyarrow-17.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b0c6ac301093b42d34410b187bba560b17c0330f64907bfa4f7f7f2444b0cf9b", size = 39874508 }, + { url = "https://files.pythonhosted.org/packages/ae/49/baafe2a964f663413be3bd1cf5c45ed98c5e42e804e2328e18f4570027c1/pyarrow-17.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:392bc9feabc647338e6c89267635e111d71edad5fcffba204425a7c8d13610d7", size = 25099235 }, ] [[distribution]] @@ -2036,15 +1925,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]] @@ -4581,14 +4470,14 @@ wheels = [ [[distribution]] name = "pyopenssl" -version = "24.1.0" +version = "24.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/a8/cbeec652549e30103b9e6147ad433405fdd18807ac2d54e6dbb73184d8a1/pyOpenSSL-24.1.0.tar.gz", hash = "sha256:cabed4bfaa5df9f1a16c0ef64a0cb65318b5cd077a7eda7d6970131ca2f41a6f", size = 179671 } +sdist = { url = "https://files.pythonhosted.org/packages/5d/70/ff56a63248562e77c0c8ee4aefc3224258f1856977e0c1472672b62dadb8/pyopenssl-24.2.1.tar.gz", hash = "sha256:4247f0dbe3748d560dcbb2ff3ea01af0f9a1a001ef5f7c4c647956ed8cbf0e95", size = 184323 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/a7/2104f674a5a6845b04c8ff01659becc6b8978ca410b82b94287e0b1e018b/pyOpenSSL-24.1.0-py3-none-any.whl", hash = "sha256:17ed5be5936449c5418d1cd269a1a9e9081bc54c17aed272b45856a3d3dc86ad", size = 56945 }, + { url = "https://files.pythonhosted.org/packages/d9/dd/e0aa7ebef5168c75b772eda64978c597a9129b46be17779054652a7999e4/pyOpenSSL-24.2.1-py3-none-any.whl", hash = "sha256:967d5719b12b243588573f39b0c677637145c7a1ffedcd495a487e58177fbb8d", size = 58390 }, ] [[distribution]] @@ -4699,7 +4588,7 @@ wheels = [ [[distribution]] name = "pytest" -version = "8.2.2" +version = "8.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -4707,21 +4596,21 @@ dependencies = [ { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/58/e993ca5357553c966b9e73cb3475d9c935fe9488746e13ebdf9b80fae508/pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977", size = 1427980 } +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/4e/e7/81ebdd666d3bff6670d27349b5053605d83d55548e6bd5711f3b0ae7dd23/pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", size = 339873 }, + { url = "https://files.pythonhosted.org/packages/0f/f9/cf155cf32ca7d6fa3601bc4c5dd19086af4b320b706919d48a4c79081cf9/pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", size = 341802 }, ] [[distribution]] name = "pytest-asyncio" -version = "0.23.7" +version = "0.23.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/13/d9/1dcac9b3fc6eccf8f1e3a657439c11ffc5cf762edd20f65577f832ba248b/pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268", size = 46296 } +sdist = { url = "https://files.pythonhosted.org/packages/de/b4/0b378b7bf26a8ae161c3890c0b48a91a04106c5713ce81b4b080ea2f4f18/pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3", size = 46920 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/98/947690b1a79af83e584143cb904497caff05bb6016614b38326a81076357/pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b", size = 17585 }, + { url = "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", size = 17663 }, ] [[distribution]] @@ -4788,15 +4677,15 @@ wheels = [ [[distribution]] name = "pytest-subtests" -version = "0.13.0" +version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/be/cebc1b9f6358d174443f46737979e244048a385fe2b0be6fab2b96771dc5/pytest_subtests-0.13.0.tar.gz", hash = "sha256:9e02b9d243c0379b02abf3e0887da122bcb2714b021c3608a37f17ce210adce5", size = 15842 } +sdist = { url = "https://files.pythonhosted.org/packages/67/fe/e691d2f4ce061a475f488cad1ef58431556affea323dde5c764fd7515a70/pytest_subtests-0.13.1.tar.gz", hash = "sha256:989e38f0f1c01bc7c6b2e04db7d9fd859db35d77c2c1a430c831a70cbf3fde2d", size = 15936 } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/19/9fd9ff6e8827983bcfc74a39c4a98ab6b4c32b3f3403b917f352f7b83777/pytest_subtests-0.13.0-py3-none-any.whl", hash = "sha256:5a142064218df37a52299ddb393b1a6b2c1161ca19e71ca60c3a8040eb17e811", size = 8038 }, + { url = "https://files.pythonhosted.org/packages/f5/ac/fc132cb88e8f2042cebcb6ef0ffac40017c514fbadf3931e0b4bcb4bdfb6/pytest_subtests-0.13.1-py3-none-any.whl", hash = "sha256:ab616a22f64cd17c1aee65f18af94dbc30c444f8683de2b30895c3778265e3bd", size = 8038 }, ] [[distribution]] @@ -4856,15 +4745,16 @@ sdist = { url = "https://files.pythonhosted.org/packages/ef/c6/2c5999de3bb153352 [[distribution]] name = "pytools" -version = "2024.1.8" +version = "2024.1.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, { name = "siphash24" }, + { name = "typing-extensions", marker = "python_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/0a/33961bdb345c0621f2883e6c192f05116fe7e4871700eb2100d3e37d152a/pytools-2024.1.8.tar.gz", hash = "sha256:cccc184a10af56dabab3077af82ab0cf7a5b06625313cae0b2f06a3c4b126001", size = 82220 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/0f/56e109c0307f831b5d598ad73976aaaa84b4d0e98da29a642e797eaa940c/pytools-2024.1.10.tar.gz", hash = "sha256:9af6f4b045212c49be32bb31fe19606c478ee4b09631886d05a32459f4ce0a12", size = 81741 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/ea/fa3124d613e07ee93aaf1ec38b846c712a25eda3035af20ae2e7cd5927e5/pytools-2024.1.8-py3-none-any.whl", hash = "sha256:3fe89cf182e97d16842de78f2b08c009030c895c4e1496e96e3679664cf2bd3b", size = 88527 }, + { url = "https://files.pythonhosted.org/packages/66/cf/0a6aaa44b1f9e02b8c0648b5665a82246a93bcc75224c167b4fafa25c093/pytools-2024.1.10-py3-none-any.whl", hash = "sha256:9cabb71038048291400e244e2da441a051d86053339bc484e64e58d8ea263f44", size = 88108 }, ] [[distribution]] @@ -5042,27 +4932,27 @@ wheels = [ [[distribution]] name = "ruff" -version = "0.5.2" +version = "0.5.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/6c/147f04f6a799f659cc810352742994e51441b14c7a5621e285d021261388/ruff-0.5.2.tar.gz", hash = "sha256:2c0df2d2de685433794a14d8d2e240df619b748fbe3367346baa519d8e6f1ca2", size = 2596910 } +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/3b/05/9ec81c397be41596e4329b340780d56bfa9ad1cb95247148bf9859edf575/ruff-0.5.2-py3-none-linux_armv6l.whl", hash = "sha256:7bab8345df60f9368d5f4594bfb8b71157496b44c30ff035d1d01972e764d3be", size = 9482764 }, - { url = "https://files.pythonhosted.org/packages/f3/ea/ebf3ea51ad48abfc6e0bbb762e71b0ffc6220a6fb8735cb09bd5aca7c52e/ruff-0.5.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1aa7acad382ada0189dbe76095cf0a36cd0036779607c397ffdea16517f535b1", size = 8612665 }, - { url = "https://files.pythonhosted.org/packages/0f/52/9e7868770615c16be60549746ad6f48f483320f7ecf5a294f4f051f4e7d4/ruff-0.5.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:aec618d5a0cdba5592c60c2dee7d9c865180627f1a4a691257dea14ac1aa264d", size = 8191223 }, - { url = "https://files.pythonhosted.org/packages/7a/9d/c880e41895b9bc48bf7051c81bcf270d2f6eebdce3c8f02c72fdef582d20/ruff-0.5.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b62adc5ce81780ff04077e88bac0986363e4a3260ad3ef11ae9c14aa0e67ef", size = 9972748 }, - { url = "https://files.pythonhosted.org/packages/0c/0b/17a0730f425f7f630446978b880ac0ad62a7c7e20fb4e21d2ab0a5154887/ruff-0.5.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc42ebf56ede83cb080a50eba35a06e636775649a1ffd03dc986533f878702a3", size = 9289379 }, - { url = "https://files.pythonhosted.org/packages/67/c4/1dcdc4a381aa07509d15dd78ec65e8fedd14c0a70a674ca3bbafa48502ed/ruff-0.5.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c15c6e9f88c67ffa442681365d11df38afb11059fc44238e71a9d9f1fd51de70", size = 10087604 }, - { url = "https://files.pythonhosted.org/packages/a8/fc/2707aa15de9e2485f024535b0fe239013d1be13bb475050f3e21b33109c9/ruff-0.5.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d3de9a5960f72c335ef00763d861fc5005ef0644cb260ba1b5a115a102157251", size = 10875118 }, - { url = "https://files.pythonhosted.org/packages/ef/db/4890a8c350b3fad767c663991052ba5ce42feae05f433fbf73acc3d1e8c3/ruff-0.5.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe5a968ae933e8f7627a7b2fc8893336ac2be0eb0aace762d3421f6e8f7b7f83", size = 10464801 }, - { url = "https://files.pythonhosted.org/packages/d5/30/0018669eb5a0bfd42d4be1d961fa4533bba1926ba83b8cf3e50223ee7d21/ruff-0.5.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04f54a9018f75615ae52f36ea1c5515e356e5d5e214b22609ddb546baef7132", size = 11356413 }, - { url = "https://files.pythonhosted.org/packages/ec/60/e2a9ae058b34128caa5f863f268e1c9bd083793264f4bf7e8e469be651f9/ruff-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed02fb52e3741f0738db5f93e10ae0fb5c71eb33a4f2ba87c9a2fa97462a649", size = 10123340 }, - { url = "https://files.pythonhosted.org/packages/1c/fd/83b9f0107f5d0eea1c4b3a98655d789586d8e2662819df011a7964efa675/ruff-0.5.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3cf8fe659f6362530435d97d738eb413e9f090e7e993f88711b0377fbdc99f60", size = 9940668 }, - { url = "https://files.pythonhosted.org/packages/11/75/2a98e9348bed95e0a121c3e1693c335530ef70280a364cf17f1d2da947cd/ruff-0.5.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:237a37e673e9f3cbfff0d2243e797c4862a44c93d2f52a52021c1a1b0899f846", size = 9380450 }, - { url = "https://files.pythonhosted.org/packages/0e/77/474f883393954f2323febd5cf7c96bfe8c684561f8d22ca843e90d122d73/ruff-0.5.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2a2949ce7c1cbd8317432ada80fe32156df825b2fd611688814c8557824ef060", size = 9718297 }, - { url = "https://files.pythonhosted.org/packages/b2/5a/72b3a1ddefbc7ccb382bcf9668648a6f1fdc4bfcc3d6687f14e6feb40636/ruff-0.5.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:481af57c8e99da92ad168924fd82220266043c8255942a1cb87958b108ac9335", size = 10221735 }, - { url = "https://files.pythonhosted.org/packages/bc/22/7aa3fb2b95dda4d485e5e5f15041679d3170a31b9317b24c6182f4c8faf1/ruff-0.5.2-py3-none-win32.whl", hash = "sha256:f1aea290c56d913e363066d83d3fc26848814a1fed3d72144ff9c930e8c7c718", size = 7786506 }, - { url = "https://files.pythonhosted.org/packages/a8/a0/f28c8380f4eff7451896618ca0cce097e65aef150c60c298a0b5c9f40311/ruff-0.5.2-py3-none-win_amd64.whl", hash = "sha256:8532660b72b5d94d2a0a7a27ae7b9b40053662d00357bb2a6864dd7e38819084", size = 8583643 }, - { url = "https://files.pythonhosted.org/packages/b5/c3/dd06a34c98fc887a8c027e1b17e7ceca479db98b24d3a2d98f8239f0ee71/ruff-0.5.2-py3-none-win_arm64.whl", hash = "sha256:73439805c5cb68f364d826a5c5c4b6c798ded6b7ebaa4011f01ce6c94e4d5583", size = 8012737 }, + { 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]] @@ -5117,24 +5007,24 @@ 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]] name = "setuptools" -version = "70.3.0" +version = "71.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/d8/10a70e86f6c28ae59f101a9de6d77bf70f147180fbf40c3af0f64080adc3/setuptools-70.3.0.tar.gz", hash = "sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5", size = 2333112 } +sdist = { url = "https://files.pythonhosted.org/packages/32/c0/5b8013b5a812701c72e3b1e2b378edaa6514d06bee6704a5ab0d7fa52931/setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936", size = 2422233 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/15/88e46eb9387e905704b69849618e699dc2f54407d8953cc4ec4b8b46528d/setuptools-70.3.0-py3-none-any.whl", hash = "sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc", size = 931070 }, + { url = "https://files.pythonhosted.org/packages/51/a0/ee460cc54e68afcf33190d198299c9579a5eafeadef0016ae8563237ccb6/setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855", size = 2341722 }, ] [[distribution]] @@ -5198,15 +5088,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d6/5b/3ada173f07b4ec9bfa03b779e59ecada48eb7cb1a29f51cfce70edce7f3f/smbus2-0.4.3-py2.py3-none-any.whl", hash = "sha256:a2fc29cfda4081ead2ed61ef2c4fc041d71dd40a8d917e85216f44786fca2d1d", size = 11553 }, ] -[[distribution]] -name = "snowballstemmer" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, -] - [[distribution]] name = "sortedcontainers" version = "2.4.0" @@ -5231,87 +5112,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/09/bfdd393f1bb1b90b4a6849b84972b7059c95e36818cc489922228d58cc63/sounddevice-0.4.7-py3-none-win_amd64.whl", hash = "sha256:0c8b3543da1496f282b66a7bc54b755577ba638b1af06c146d4ac7f39d86b548", size = 200096 }, ] -[[distribution]] -name = "sphinx" -version = "7.4.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alabaster" }, - { name = "babel" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "docutils" }, - { name = "imagesize" }, - { name = "jinja2" }, - { name = "packaging" }, - { name = "pygments" }, - { name = "requests" }, - { name = "snowballstemmer" }, - { name = "sphinxcontrib-applehelp" }, - { name = "sphinxcontrib-devhelp" }, - { name = "sphinxcontrib-htmlhelp" }, - { name = "sphinxcontrib-jsmath" }, - { name = "sphinxcontrib-qthelp" }, - { name = "sphinxcontrib-serializinghtml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c3/7a/bc303eb950025a2cfa8f6968471fda8b28e8114621e2ab43f518094a4225/sphinx-7.4.3.tar.gz", hash = "sha256:bd846bcb09fd2b6e94ce3e1ad50f4618bccf03cc7c17d0f3fa87393c0bd9178b", size = 8113870 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/b8/8594be28e66d19c287c13dbc609a7695e5330ea59abce654a3f41b8a589e/sphinx-7.4.3-py3-none-any.whl", hash = "sha256:a3c295d0e8be6277e0a5ba5c6909a308bd208876b0f4f68c7cc591f566129412", size = 3454542 }, -] - -[[distribution]] -name = "sphinxcontrib-applehelp" -version = "1.0.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/6b/68f470fc337ed24043fec987b101f25b35010970bd958970c2ae5990859f/sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619", size = 19674 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/89/fea3fbf6785b388e6cb8a1beaf62f96e80b37311bdeed6e133388a732426/sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4", size = 120035 }, -] - -[[distribution]] -name = "sphinxcontrib-devhelp" -version = "1.0.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/a1/80b7e9f677abc673cb9320bf255ad4e08931ccbc2e66bde4b59bad3809ad/sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3", size = 12480 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/52/1049d918d1d1c72857d285c3f0c64c1cbe0be394ce1c93a3d2aa4f39fe3b/sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f", size = 83499 }, -] - -[[distribution]] -name = "sphinxcontrib-htmlhelp" -version = "2.0.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/03/2f9d699fbfdf03ecb3b6d0e2a268a8998d009f2a9f699c2dcc936899257d/sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015", size = 21925 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/e9/74c4cda5b409af3222fda38f0774e616011bc935f639dbc0da5ca2d1be7d/sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04", size = 99217 }, -] - -[[distribution]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, -] - -[[distribution]] -name = "sphinxcontrib-qthelp" -version = "1.0.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/29/705cd4e93e98a8473d62b5c32288e6de3f0c9660d3c97d4e80d3dbbad82b/sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6", size = 16685 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/80/b3/1beac14a88654d2e5120d0143b49be5ad450b86eb1963523d8dbdcc51eb2/sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182", size = 89441 }, -] - -[[distribution]] -name = "sphinxcontrib-serializinghtml" -version = "1.1.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/13/8dd7a7ed9c58e16e20c7f4ce8e4cb6943eb580955236d0c0d00079a73c49/sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f", size = 15592 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/24/228bb903ea87b9e08ab33470e6102402a644127108c7117ac9c00d849f82/sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7", size = 92725 }, -] - [[distribution]] name = "spidev" version = "3.6" @@ -5320,14 +5120,14 @@ sdist = { url = "https://files.pythonhosted.org/packages/c7/d9/401c0a7be089e0282 [[distribution]] name = "sympy" -version = "1.13.0" +version = "1.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cb/f5/8c7d91ce35816b72c2dd061dc4a33f00f59053aeffe881d42aed17279381/sympy-1.13.0.tar.gz", hash = "sha256:3b6af8f4d008b9a1a6a4268b335b984b23835f26d1d60b0526ebc71d48a25f57", size = 7532455 } +sdist = { url = "https://files.pythonhosted.org/packages/ca/99/5a5b6f19ff9f083671ddf7b9632028436167cd3d33e11015754e41b249a4/sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f", size = 7533040 } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/74/7e6c65ee89ff43942bffffdbb238634f16967bf327aee3c76efcf6e49587/sympy-1.13.0-py3-none-any.whl", hash = "sha256:6b0b32a4673fb91bd3cac3b55406c8e01d53ae22780be467301cc452f6680c92", size = 6188245 }, + { url = "https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8", size = 6189177 }, ] [[distribution]]