CI: Pylint to ruff (#29294)

* pylint to riff

* pylint to riff

* pylint to riff

* revert more

* undo exclude removal

* exclude tinygrad

* set line length

* pylint exclusions to ruff

* same excludes as old linter

* fix tools QA

* remove unrequired check

* revert linting third_party

* ignore e402
old-commit-hash: 7fdd9fc37c
beeps
Justin Newberry 2 years ago committed by GitHub
parent 7b677910df
commit 3ee0786de3
  1. 26
      .pre-commit-config.yaml
  2. 4
      poetry.lock
  3. 10
      pyproject.toml
  4. 2
      selfdrive/athena/tests/helpers.py
  5. 2
      selfdrive/car/body/carcontroller.py
  6. 2
      selfdrive/car/chrysler/values.py
  7. 2
      selfdrive/car/docs_definitions.py
  8. 2
      selfdrive/car/gm/values.py
  9. 5
      selfdrive/car/hyundai/values.py
  10. 2
      selfdrive/car/nissan/values.py
  11. 2
      selfdrive/car/tesla/values.py
  12. 2
      selfdrive/controls/lib/events.py
  13. 2
      selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py
  14. 2
      selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py
  15. 2
      selfdrive/debug/clear_dtc.py
  16. 7
      selfdrive/debug/dump.py
  17. 2
      selfdrive/debug/show_matching_cars.py
  18. 2
      selfdrive/locationd/models/loc_kf.py
  19. 6
      selfdrive/locationd/test/test_laikad.py
  20. 2
      selfdrive/modeld/runners/onnx_runner.py
  21. 3
      selfdrive/modeld/thneed/lib.py
  22. 2
      selfdrive/monitoring/driver_monitor.py
  23. 2
      selfdrive/monitoring/test_monitoring.py
  24. 2
      selfdrive/navd/map_renderer.py
  25. 16
      selfdrive/navd/tests/test_map_renderer.py
  26. 4
      selfdrive/test/process_replay/capture.py
  27. 4
      selfdrive/test/process_replay/migration.py
  28. 28
      selfdrive/test/process_replay/process_replay.py
  29. 2
      selfdrive/test/process_replay/regen.py
  30. 34
      selfdrive/test/process_replay/test_processes.py
  31. 14
      selfdrive/thermald/tests/test_power_monitoring.py
  32. 2
      selfdrive/updated.py
  33. 4
      system/sensord/pigeond.py
  34. 4
      system/sensord/rawgps/structs.py
  35. 2
      tools/plotjuggler/juggle.py
  36. 1
      tools/replay/can_replay.py

@ -34,31 +34,11 @@ repos:
types: [python] types: [python]
args: ['--explicit-package-bases'] args: ['--explicit-package-bases']
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)' exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)'
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/astral-sh/ruff-pre-commit
rev: 6.1.0 rev: v0.0.282
hooks: hooks:
- id: flake8 - id: ruff
exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(selfdrive/debug/)/'
additional_dependencies: ['flake8-no-implicit-concat']
args:
- --indent-size=2
- --enable-extensions=NIC
- --select=F,E112,E113,E304,E502,E701,E702,E703,E71,E72,E731,W191,W6
- --statistics
- -j4
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)' exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)'
args:
- -j0
- -rn
- -sn
- --rcfile=.pylintrc
- repo: local - repo: local
hooks: hooks:
- id: cppcheck - id: cppcheck

4
poetry.lock generated

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4bdf2a7ffee6dd09d6532b7e2a2cd5d6af889658cfbbe0d02deac92e14be33e9 oid sha256:36187dd8afc0afe0abdb6976b5d31bb07294ec91c96022b426e86a0484216d8e
size 809997 size 792009

@ -19,7 +19,6 @@ cffi = "*"
crcmod = "*" crcmod = "*"
cryptography = "*" cryptography = "*"
Cython = "*" Cython = "*"
flake8 = "*"
Flask = "*" Flask = "*"
future-fstrings = "*" # for acados future-fstrings = "*" # for acados
gunicorn = "*" gunicorn = "*"
@ -92,7 +91,6 @@ pprofile = "*"
pre-commit = "*" pre-commit = "*"
pycurl = "*" pycurl = "*"
pygame = "*" pygame = "*"
pylint = "*"
pyprof2calltree = "*" pyprof2calltree = "*"
pytest = "*" pytest = "*"
pytest-xdist = "*" pytest-xdist = "*"
@ -161,6 +159,7 @@ PyMySQL = "~0.9"
pyproj = "*" pyproj = "*"
python-logstash = "*" python-logstash = "*"
redis = "*" redis = "*"
ruff = "*"
s2sphere = "*" s2sphere = "*"
scikit-image = "*" scikit-image = "*"
scikit-learn = "*" scikit-learn = "*"
@ -186,3 +185,10 @@ opencv-python-headless = { url = "https://github.com/commaai/opencv-python-build
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
# https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml
[tool.ruff]
select = ["E", "F", "W"]
ignore = ["W292", "E741", "E402"]
line-length = 160
target-version="py311"

@ -52,7 +52,7 @@ class MockApi():
class MockParams(): class MockParams():
default_params = { default_params = {
"DongleId": b"0000000000000000", "DongleId": b"0000000000000000",
"GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private", # pylint: disable=C0301 "GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private", # noqa: E501
"GithubUsername": b"commaci", "GithubUsername": b"commaci",
"GsmMetered": True, "GsmMetered": True,
"AthenadUploadQueue": '[]', "AthenadUploadQueue": '[]',

@ -56,7 +56,7 @@ class CarController:
speed_error = speed_desired - speed_measured speed_error = speed_desired - speed_measured
if self.wheeled_body is None: if self.wheeled_body is None:
freeze_integrator = ((speed_error < 0 and self.speed_pid.error_integral <= -MAX_POS_INTEGRATOR) or freeze_integrator = ((speed_error < 0 and self.speed_pid.error_integral <= -MAX_POS_INTEGRATOR) or
(speed_error > 0 and self.speed_pid.error_integral >= MAX_POS_INTEGRATOR)) (speed_error > 0 and self.speed_pid.error_integral >= MAX_POS_INTEGRATOR))
angle_setpoint = self.speed_pid.update(speed_error, freeze_integrator=freeze_integrator) angle_setpoint = self.speed_pid.update(speed_error, freeze_integrator=freeze_integrator)

@ -1,3 +1,4 @@
# ruff: noqa: E501
from enum import IntFlag from enum import IntFlag
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Dict, List, Optional, Union from typing import Dict, List, Optional, Union
@ -93,7 +94,6 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = {
# For 924, Trailhawk 2017 has length 3, whereas 2018 V6 has length 8. # For 924, Trailhawk 2017 has length 3, whereas 2018 V6 has length 8.
FINGERPRINTS = { FINGERPRINTS = {
# pylint: disable=C0301
CAR.PACIFICA_2017_HYBRID: [{ CAR.PACIFICA_2017_HYBRID: [{
168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 788: 3, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 840: 8, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 3, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1284: 8, 1537: 8, 1538: 8, 1562: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1892: 8, 2016: 8, 2024: 8 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 788: 3, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 840: 8, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 3, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1284: 8, 1537: 8, 1538: 8, 1562: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1892: 8, 2016: 8, 2024: 8
}], }],

@ -178,7 +178,7 @@ class CommonFootnote(Enum):
"the toggle is only available in non-release branches such as `devel` or `master-ci`. ", "the toggle is only available in non-release branches such as `devel` or `master-ci`. ",
Column.LONGITUDINAL, docs_only=True) Column.LONGITUDINAL, docs_only=True)
EXP_LONG_DSU = CarFootnote( EXP_LONG_DSU = CarFootnote(
"By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. " + "By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. " +
"If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace " + "If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace " +
"stock ACC. <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b>", "stock ACC. <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b>",
Column.LONGITUDINAL) Column.LONGITUDINAL)

@ -1,3 +1,4 @@
# ruff: noqa: E501
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum from enum import Enum
@ -142,7 +143,6 @@ class CanBus:
DROPPED = 192 DROPPED = 192
FINGERPRINTS = { FINGERPRINTS = {
# pylint: disable=C0301
CAR.HOLDEN_ASTRA: [ CAR.HOLDEN_ASTRA: [
# Astra BK MY17, ASCM unplugged # Astra BK MY17, ASCM unplugged
{ {

@ -1,3 +1,4 @@
# ruff: noqa: E501
import re import re
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum, IntFlag from enum import Enum, IntFlag
@ -229,7 +230,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
HyundaiCarInfo("Kia Niro Hybrid 2021-22", car_parts=CarParts.common([CarHarness.hyundai_f])), # TODO: 2021 could be hyundai_d, verify HyundaiCarInfo("Kia Niro Hybrid 2021-22", car_parts=CarParts.common([CarHarness.hyundai_f])), # TODO: 2021 could be hyundai_d, verify
], ],
CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_a])), CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_a])),
CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control", CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control",
car_parts=CarParts.common([CarHarness.hyundai_b])), # TODO: may support 2016, 2018 car_parts=CarParts.common([CarHarness.hyundai_b])), # TODO: may support 2016, 2018
CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", car_parts=CarParts.common([CarHarness.hyundai_g])), CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", car_parts=CarParts.common([CarHarness.hyundai_g])),
CAR.KIA_OPTIMA_H: [ CAR.KIA_OPTIMA_H: [
@ -284,7 +285,6 @@ class Buttons:
CANCEL = 4 # on newer models, this is a pause/resume button CANCEL = 4 # on newer models, this is a pause/resume button
FINGERPRINTS = { FINGERPRINTS = {
# pylint: disable=C0301
CAR.ELANTRA: [{ CAR.ELANTRA: [{
66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 897: 8, 832: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2001: 8, 2003: 8, 2004: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 897: 8, 832: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2001: 8, 2003: 8, 2004: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
}], }],
@ -518,7 +518,6 @@ FW_QUERY_CONFIG = FwQueryConfig(
) )
FW_VERSIONS = { FW_VERSIONS = {
# pylint: disable=C0301
CAR.HYUNDAI_GENESIS: { CAR.HYUNDAI_GENESIS: {
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DH LKAS 1.1 -150210', b'\xf1\x00DH LKAS 1.1 -150210',

@ -1,3 +1,4 @@
# ruff: noqa: E501
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Dict, List, Optional, Union from typing import Dict, List, Optional, Union
@ -45,7 +46,6 @@ CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = {
} }
FINGERPRINTS = { FINGERPRINTS = {
# pylint: disable=C0301
CAR.XTRAIL: [ CAR.XTRAIL: [
{ {
2: 5, 42: 6, 346: 6, 347: 5, 348: 8, 349: 7, 361: 8, 386: 8, 389: 8, 397: 8, 398: 8, 403: 8, 520: 2, 523: 6, 548: 8, 645: 8, 658: 8, 665: 8, 666: 8, 674: 2, 682: 8, 683: 8, 689: 8, 723: 8, 758: 3, 768: 2, 783: 3, 851: 8, 855: 8, 1041: 8, 1055: 2, 1104: 4, 1105: 6, 1107: 4, 1108: 8, 1111: 4, 1227: 8, 1228: 8, 1247: 4, 1266: 8, 1273: 7, 1342: 1, 1376: 6, 1401: 8, 1474: 2, 1497: 3, 1821: 8, 1823: 8, 1837: 8, 2015: 8, 2016: 8, 2024: 8 2: 5, 42: 6, 346: 6, 347: 5, 348: 8, 349: 7, 361: 8, 386: 8, 389: 8, 397: 8, 398: 8, 403: 8, 520: 2, 523: 6, 548: 8, 645: 8, 658: 8, 665: 8, 666: 8, 674: 2, 682: 8, 683: 8, 689: 8, 723: 8, 758: 3, 768: 2, 783: 3, 851: 8, 855: 8, 1041: 8, 1055: 2, 1104: 4, 1105: 6, 1107: 4, 1108: 8, 1111: 4, 1227: 8, 1228: 8, 1247: 4, 1266: 8, 1273: 7, 1342: 1, 1376: 6, 1401: 8, 1474: 2, 1497: 3, 1821: 8, 1823: 8, 1837: 8, 2015: 8, 2016: 8, 2024: 8

@ -1,3 +1,4 @@
# ruff: noqa: E501
from collections import namedtuple from collections import namedtuple
from typing import Dict, List, Union from typing import Dict, List, Union
@ -22,7 +23,6 @@ CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
} }
FINGERPRINTS = { FINGERPRINTS = {
# pylint: disable=C0301
CAR.AP1_MODELS: [ CAR.AP1_MODELS: [
{ {
1: 8, 3: 8, 14: 8, 21: 4, 69: 8, 109: 4, 257: 3, 264: 8, 267: 5, 277: 6, 280: 6, 283: 5, 293: 4, 296: 4, 309: 5, 325: 8, 328: 5, 336: 8, 341: 8, 360: 7, 373: 8, 389: 8, 415: 8, 513: 5, 516: 8, 520: 4, 522: 8, 524: 8, 526: 8, 532: 3, 536: 8, 537: 3, 542: 8, 551: 5, 552: 2, 556: 8, 558: 8, 568: 8, 569: 8, 574: 8, 577: 8, 582: 5, 584: 4, 585: 8, 590: 8, 606: 8, 622: 8, 627: 6, 638: 8, 641: 8, 643: 8, 660: 5, 693: 8, 696: 8, 697: 8, 712: 8, 728: 8, 744: 8, 760: 8, 772: 8, 775: 8, 776: 8, 777: 8, 778: 8, 782: 8, 788: 8, 791: 8, 792: 8, 796: 2, 797: 8, 798: 6, 799: 8, 804: 8, 805: 8, 807: 8, 808: 1, 809: 8, 812: 8, 813: 8, 814: 5, 815: 8, 820: 8, 823: 8, 824: 8, 829: 8, 830: 5, 836: 8, 840: 8, 841: 8, 845: 8, 846: 5, 852: 8, 856: 4, 857: 6, 861: 8, 862: 5, 872: 8, 873: 8, 877: 8, 878: 8, 879: 8, 880: 8, 884: 8, 888: 8, 889: 8, 893: 8, 896: 8, 901: 6, 904: 3, 905: 8, 908: 2, 909: 8, 920: 8, 921: 8, 925: 4, 936: 8, 937: 8, 941: 8, 949: 8, 952: 8, 953: 6, 957: 8, 968: 8, 973: 8, 984: 8, 987: 8, 989: 8, 990: 8, 1000: 8, 1001: 8, 1006: 8, 1016: 8, 1026: 8, 1028: 8, 1029: 8, 1030: 8, 1032: 1, 1033: 1, 1034: 8, 1048: 1, 1064: 8, 1070: 8, 1080: 8, 1160: 4, 1281: 8, 1329: 8, 1332: 8, 1335: 8, 1337: 8, 1368: 8, 1412: 8, 1436: 8, 1465: 8, 1476: 8, 1497: 8, 1524: 8, 1527: 8, 1601: 8, 1605: 8, 1611: 8, 1614: 8, 1617: 8, 1621: 8, 1627: 8, 1630: 8, 1800: 4, 1804: 8, 1812: 8, 1815: 8, 1816: 8, 1828: 8, 1831: 8, 1832: 8, 1840: 8, 1848: 8, 1864: 8, 1880: 8, 1892: 8, 1896: 8, 1912: 8, 1960: 8, 1992: 8, 2008: 3, 2043: 5, 2045: 4 1: 8, 3: 8, 14: 8, 21: 4, 69: 8, 109: 4, 257: 3, 264: 8, 267: 5, 277: 6, 280: 6, 283: 5, 293: 4, 296: 4, 309: 5, 325: 8, 328: 5, 336: 8, 341: 8, 360: 7, 373: 8, 389: 8, 415: 8, 513: 5, 516: 8, 520: 4, 522: 8, 524: 8, 526: 8, 532: 3, 536: 8, 537: 3, 542: 8, 551: 5, 552: 2, 556: 8, 558: 8, 568: 8, 569: 8, 574: 8, 577: 8, 582: 5, 584: 4, 585: 8, 590: 8, 606: 8, 622: 8, 627: 6, 638: 8, 641: 8, 643: 8, 660: 5, 693: 8, 696: 8, 697: 8, 712: 8, 728: 8, 744: 8, 760: 8, 772: 8, 775: 8, 776: 8, 777: 8, 778: 8, 782: 8, 788: 8, 791: 8, 792: 8, 796: 2, 797: 8, 798: 6, 799: 8, 804: 8, 805: 8, 807: 8, 808: 1, 809: 8, 812: 8, 813: 8, 814: 5, 815: 8, 820: 8, 823: 8, 824: 8, 829: 8, 830: 5, 836: 8, 840: 8, 841: 8, 845: 8, 846: 5, 852: 8, 856: 4, 857: 6, 861: 8, 862: 5, 872: 8, 873: 8, 877: 8, 878: 8, 879: 8, 880: 8, 884: 8, 888: 8, 889: 8, 893: 8, 896: 8, 901: 6, 904: 3, 905: 8, 908: 2, 909: 8, 920: 8, 921: 8, 925: 4, 936: 8, 937: 8, 941: 8, 949: 8, 952: 8, 953: 6, 957: 8, 968: 8, 973: 8, 984: 8, 987: 8, 989: 8, 990: 8, 1000: 8, 1001: 8, 1006: 8, 1016: 8, 1026: 8, 1028: 8, 1029: 8, 1030: 8, 1032: 1, 1033: 1, 1034: 8, 1048: 1, 1064: 8, 1070: 8, 1080: 8, 1160: 4, 1281: 8, 1329: 8, 1332: 8, 1335: 8, 1337: 8, 1368: 8, 1412: 8, 1436: 8, 1465: 8, 1476: 8, 1497: 8, 1524: 8, 1527: 8, 1601: 8, 1605: 8, 1611: 8, 1614: 8, 1617: 8, 1621: 8, 1627: 8, 1630: 8, 1800: 4, 1804: 8, 1812: 8, 1815: 8, 1816: 8, 1828: 8, 1831: 8, 1832: 8, 1840: 8, 1848: 8, 1864: 8, 1880: 8, 1892: 8, 1896: 8, 1912: 8, 1960: 8, 1992: 8, 2008: 3, 2043: 5, 2045: 4

@ -724,7 +724,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
ET.SOFT_DISABLE: soft_disable_alert("Calibration Incomplete"), ET.SOFT_DISABLE: soft_disable_alert("Calibration Incomplete"),
ET.NO_ENTRY: NoEntryAlert("Calibration in Progress"), ET.NO_ENTRY: NoEntryAlert("Calibration in Progress"),
}, },
EventName.calibrationRecalibrating: { EventName.calibrationRecalibrating: {
ET.PERMANENT: calibration_incomplete_alert, ET.PERMANENT: calibration_incomplete_alert,
ET.SOFT_DISABLE: soft_disable_alert("Device Remount Detected: Recalibrating"), ET.SOFT_DISABLE: soft_disable_alert("Device Remount Detected: Recalibrating"),

@ -10,7 +10,7 @@ from selfdrive.modeld.constants import T_IDXS
if __name__ == '__main__': # generating code if __name__ == '__main__': # generating code
from third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver from third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
else: else:
from selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython # pylint: disable=no-name-in-module, import-error from selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython
LAT_MPC_DIR = os.path.dirname(os.path.abspath(__file__)) LAT_MPC_DIR = os.path.dirname(os.path.abspath(__file__))
EXPORT_DIR = os.path.join(LAT_MPC_DIR, "c_generated_code") EXPORT_DIR = os.path.join(LAT_MPC_DIR, "c_generated_code")

@ -13,7 +13,7 @@ from selfdrive.controls.radard import _LEAD_ACCEL_TAU
if __name__ == '__main__': # generating code if __name__ == '__main__': # generating code
from third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver from third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
else: else:
from selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython # pylint: disable=no-name-in-module, import-error from selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython
from casadi import SX, vertcat from casadi import SX, vertcat

@ -35,6 +35,6 @@ try:
except MessageTimeoutError: except MessageTimeoutError:
# functional address isn't properly handled so a timeout occurs # functional address isn't properly handled so a timeout occurs
if args.addr != 0x7DF: if args.addr != 0x7DF:
pass pass
print("") print("")
print("you may need to power cycle your vehicle now") print("you may need to power cycle your vehicle now")

@ -3,14 +3,15 @@ import os
import sys import sys
import argparse import argparse
import json import json
from hexdump import hexdump
import codecs import codecs
codecs.register_error("strict", codecs.backslashreplace_errors) import cereal.messaging as messaging
from hexdump import hexdump
from cereal import log from cereal import log
import cereal.messaging as messaging
from cereal.services import service_list from cereal.services import service_list
codecs.register_error("strict", codecs.backslashreplace_errors)
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Dump communication sockets. See cereal/services.py for a complete list of available sockets.') parser = argparse.ArgumentParser(description='Dump communication sockets. See cereal/services.py for a complete list of available sockets.')

@ -4,7 +4,7 @@ import cereal.messaging as messaging
# rav4 2019 and corolla tss2 # rav4 2019 and corolla tss2
fingerprint = {896: 8, 898: 8, 900: 6, 976: 1, 1541: 8, 902: 6, 905: 8, 810: 2, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1552: 8, 1553: 8, 1556: 8, 1571: 8, 921: 8, 1056: 8, 544: 4, 1570: 8, 1059: 1, 36: 8, 37: 8, 550: 8, 935: 8, 552: 4, 170: 8, 812: 8, 944: 8, 945: 8, 562: 6, 180: 8, 1077: 8, 951: 8, 1592: 8, 1076: 8, 186: 4, 955: 8, 956: 8, 1001: 8, 705: 8, 452: 8, 1788: 8, 464: 8, 824: 8, 466: 8, 467: 8, 761: 8, 728: 8, 1572: 8, 1114: 8, 933: 8, 800: 8, 608: 8, 865: 8, 610: 8, 1595: 8, 934: 8, 998: 5, 1745: 8, 1000: 8, 764: 8, 1002: 8, 999: 7, 1789: 8, 1649: 8, 1779: 8, 1568: 8, 1017: 8, 1786: 8, 1787: 8, 1020: 8, 426: 6, 1279: 8} # pylint: disable=C0301 fingerprint = {896: 8, 898: 8, 900: 6, 976: 1, 1541: 8, 902: 6, 905: 8, 810: 2, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1552: 8, 1553: 8, 1556: 8, 1571: 8, 921: 8, 1056: 8, 544: 4, 1570: 8, 1059: 1, 36: 8, 37: 8, 550: 8, 935: 8, 552: 4, 170: 8, 812: 8, 944: 8, 945: 8, 562: 6, 180: 8, 1077: 8, 951: 8, 1592: 8, 1076: 8, 186: 4, 955: 8, 956: 8, 1001: 8, 705: 8, 452: 8, 1788: 8, 464: 8, 824: 8, 466: 8, 467: 8, 761: 8, 728: 8, 1572: 8, 1114: 8, 933: 8, 800: 8, 608: 8, 865: 8, 610: 8, 1595: 8, 934: 8, 998: 5, 1745: 8, 1000: 8, 764: 8, 1002: 8, 999: 7, 1789: 8, 1649: 8, 1779: 8, 1568: 8, 1017: 8, 1786: 8, 1787: 8, 1020: 8, 426: 6, 1279: 8} # noqa: E501
candidate_cars = all_legacy_fingerprint_cars() candidate_cars = all_legacy_fingerprint_cars()

@ -372,7 +372,7 @@ class LocKalman():
self.dim_state_err = self.dim_main_err + self.dim_augment_err * self.N self.dim_state_err = self.dim_main_err + self.dim_augment_err * self.N
if self.N > 0: if self.N > 0:
x_initial, P_initial, Q = self.pad_augmented(self.x_initial, self.P_initial, self.Q) # lgtm[py/mismatched-multiple-assignment] pylint: disable=unbalanced-tuple-unpacking x_initial, P_initial, Q = self.pad_augmented(self.x_initial, self.P_initial, self.Q) # lgtm[py/mismatched-multiple-assignment]
self.computer = LstSqComputer(generated_dir, N) self.computer = LstSqComputer(generated_dir, N)
self.quaternion_idxs = [3, ] + [(self.dim_main + i * self.dim_augment + 3)for i in range(self.N)] self.quaternion_idxs = [3, ] + [(self.dim_main + i * self.dim_augment + 3)for i in range(self.N)]

@ -111,7 +111,7 @@ class TestLaikad(unittest.TestCase):
laikad = Laikad() laikad = Laikad()
laikad.fetch_navs(gpstime, block=False) laikad.fetch_navs(gpstime, block=False)
laikad.orbit_fetch_future.result(30) laikad.orbit_fetch_future.result(30)
# Get results and save orbits to laikad: # Get results and save orbits to laikad:
laikad.fetch_navs(gpstime, block=False) laikad.fetch_navs(gpstime, block=False)
ephem = laikad.astro_dog.navs['G01'][0] ephem = laikad.astro_dog.navs['G01'][0]
@ -238,7 +238,7 @@ class TestLaikad(unittest.TestCase):
if len(out_msg.gnssMeasurements.ephemerisStatuses): if len(out_msg.gnssMeasurements.ephemerisStatuses):
seen_chip_eph = seen_chip_eph or any([x.source == 'gnssChip' for x in out_msg.gnssMeasurements.ephemerisStatuses]) seen_chip_eph = seen_chip_eph or any([x.source == 'gnssChip' for x in out_msg.gnssMeasurements.ephemerisStatuses])
seen_internet_eph = seen_internet_eph or any([x.source == 'internet' for x in out_msg.gnssMeasurements.ephemerisStatuses]) seen_internet_eph = seen_internet_eph or any([x.source == 'internet' for x in out_msg.gnssMeasurements.ephemerisStatuses])
self.assertTrue(has_navs or has_polys) self.assertTrue(has_navs or has_polys)
self.assertTrue(has_fix) self.assertTrue(has_fix)
self.assertTrue(seen_chip_eph or auto_fetch_navs) self.assertTrue(seen_chip_eph or auto_fetch_navs)
@ -281,7 +281,7 @@ class TestLaikad(unittest.TestCase):
self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses])) self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses]))
self.assertIsNotNone(msg) self.assertIsNotNone(msg)
#TODO test cache with only orbits #TODO test cache with only orbits
#with patch('selfdrive.locationd.laikad.get_orbit_data', return_value=None) as mock_method: #with patch('selfdrive.locationd.laikad.get_orbit_data', return_value=None) as mock_method:
# # Verify no orbit downloads even if orbit fetch times is reset since the cache has recently been saved and we don't want to download high frequently # # Verify no orbit downloads even if orbit fetch times is reset since the cache has recently been saved and we don't want to download high frequently
# laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() # laikad.astro_dog.orbit_fetched_times = TimeRangeHolder()

@ -8,7 +8,7 @@ from typing import Tuple, Dict, Union, Any
os.environ["OMP_NUM_THREADS"] = "4" os.environ["OMP_NUM_THREADS"] = "4"
os.environ["OMP_WAIT_POLICY"] = "PASSIVE" os.environ["OMP_WAIT_POLICY"] = "PASSIVE"
import onnxruntime as ort # pylint: disable=import-error import onnxruntime as ort
ORT_TYPES_TO_NP_TYPES = {'tensor(float16)': np.float16, 'tensor(float)': np.float32, 'tensor(uint8)': np.uint8} ORT_TYPES_TO_NP_TYPES = {'tensor(float16)': np.float16, 'tensor(float)': np.float32, 'tensor(uint8)': np.uint8}

@ -1,4 +1,5 @@
import struct, json import struct
import json
def load_thneed(fn): def load_thneed(fn):
with open(fn, "rb") as f: with open(fn, "rb") as f:

@ -272,7 +272,7 @@ class DriverStatus():
self.eev2 = driver_data.readyProb[0] self.eev2 = driver_data.readyProb[0]
self.distracted_types = self._get_distracted_types() self.distracted_types = self._get_distracted_types()
self.driver_distracted = (DistractedType.DISTRACTED_E2E in self.distracted_types or DistractedType.DISTRACTED_POSE in self.distracted_types self.driver_distracted = (DistractedType.DISTRACTED_E2E in self.distracted_types or DistractedType.DISTRACTED_POSE in self.distracted_types
or DistractedType.DISTRACTED_BLINK in self.distracted_types) \ or DistractedType.DISTRACTED_BLINK in self.distracted_types) \
and driver_data.faceProb > self.settings._FACE_THRESHOLD and self.pose.low_std and driver_data.faceProb > self.settings._FACE_THRESHOLD and self.pose.low_std
self.driver_distraction_filter.update(self.driver_distracted) self.driver_distraction_filter.update(self.driver_distracted)

@ -203,7 +203,7 @@ class TestMonitoring(unittest.TestCase):
ds_vector = [msg_DISTRACTED_BUT_SOMEHOW_UNCERTAIN] * int(TEST_TIMESPAN/DT_DMON) ds_vector = [msg_DISTRACTED_BUT_SOMEHOW_UNCERTAIN] * int(TEST_TIMESPAN/DT_DMON)
interaction_vector = always_false[:] interaction_vector = always_false[:]
events, d_status = self._run_seq(ds_vector, interaction_vector, always_true, always_false) events, d_status = self._run_seq(ds_vector, interaction_vector, always_true, always_false)
self.assertTrue(EventName.preDriverUnresponsive in self.assertTrue(EventName.preDriverUnresponsive in
events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME-0.1)/DT_DMON)].names) events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME-0.1)/DT_DMON)].names)
self.assertTrue(EventName.promptDriverUnresponsive in self.assertTrue(EventName.promptDriverUnresponsive in
events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names) events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names)

@ -74,7 +74,7 @@ if __name__ == "__main__":
renderer = lib.map_renderer_init(ffi.NULL, ffi.NULL) renderer = lib.map_renderer_init(ffi.NULL, ffi.NULL)
wait_ready(lib, renderer) wait_ready(lib, renderer)
geometry = r"{yxk}@|obn~Eg@@eCFqc@J{RFw@?kA@gA?q|@Riu@NuJBgi@ZqVNcRBaPBkG@iSD{I@_H@cH?gG@mG@gG?aD@{LDgDDkVVyQLiGDgX@q_@@qI@qKhS{R~[}NtYaDbGoIvLwNfP_b@|f@oFnF_JxHel@bf@{JlIuxAlpAkNnLmZrWqFhFoh@jd@kX|TkJxH_RnPy^|[uKtHoZ~Um`DlkCorC``CuShQogCtwB_ThQcr@fk@sVrWgRhVmSb\\oj@jxA{Qvg@u]tbAyHzSos@xjBeKbWszAbgEc~@~jCuTrl@cYfo@mRn\\_m@v}@ij@jp@om@lk@y|A`pAiXbVmWzUod@xj@wNlTw}@|uAwSn\\kRfYqOdS_IdJuK`KmKvJoOhLuLbHaMzGwO~GoOzFiSrEsOhD}PhCqw@vJmnAxSczA`Vyb@bHk[fFgl@pJeoDdl@}}@zIyr@hG}X`BmUdBcM^aRR}Oe@iZc@mR_@{FScHxAn_@vz@zCzH~GjPxAhDlB~DhEdJlIbMhFfG|F~GlHrGjNjItLnGvQ~EhLnBfOn@p`@AzAAvn@CfC?fc@`@lUrArStCfSxEtSzGxM|ElFlBrOzJlEbDnC~BfDtCnHjHlLvMdTnZzHpObOf^pKla@~G|a@dErg@rCbj@zArYlj@ttJ~AfZh@r]LzYg@`TkDbj@gIdv@oE|i@kKzhA{CdNsEfOiGlPsEvMiDpLgBpHyB`MkB|MmArPg@|N?|P^rUvFz~AWpOCdAkB|PuB`KeFfHkCfGy@tAqC~AsBPkDs@uAiAcJwMe@s@eKkPMoXQux@EuuCoH?eI?Kas@}Dy@wAUkMOgDL" # pylint: disable=C0301 geometry = r"{yxk}@|obn~Eg@@eCFqc@J{RFw@?kA@gA?q|@Riu@NuJBgi@ZqVNcRBaPBkG@iSD{I@_H@cH?gG@mG@gG?aD@{LDgDDkVVyQLiGDgX@q_@@qI@qKhS{R~[}NtYaDbGoIvLwNfP_b@|f@oFnF_JxHel@bf@{JlIuxAlpAkNnLmZrWqFhFoh@jd@kX|TkJxH_RnPy^|[uKtHoZ~Um`DlkCorC``CuShQogCtwB_ThQcr@fk@sVrWgRhVmSb\\oj@jxA{Qvg@u]tbAyHzSos@xjBeKbWszAbgEc~@~jCuTrl@cYfo@mRn\\_m@v}@ij@jp@om@lk@y|A`pAiXbVmWzUod@xj@wNlTw}@|uAwSn\\kRfYqOdS_IdJuK`KmKvJoOhLuLbHaMzGwO~GoOzFiSrEsOhD}PhCqw@vJmnAxSczA`Vyb@bHk[fFgl@pJeoDdl@}}@zIyr@hG}X`BmUdBcM^aRR}Oe@iZc@mR_@{FScHxAn_@vz@zCzH~GjPxAhDlB~DhEdJlIbMhFfG|F~GlHrGjNjItLnGvQ~EhLnBfOn@p`@AzAAvn@CfC?fc@`@lUrArStCfSxEtSzGxM|ElFlBrOzJlEbDnC~BfDtCnHjHlLvMdTnZzHpObOf^pKla@~G|a@dErg@rCbj@zArYlj@ttJ~AfZh@r]LzYg@`TkDbj@gIdv@oE|i@kKzhA{CdNsEfOiGlPsEvMiDpLgBpHyB`MkB|MmArPg@|N?|P^rUvFz~AWpOCdAkB|PuB`KeFfHkCfGy@tAqC~AsBPkDs@uAiAcJwMe@s@eKkPMoXQux@EuuCoH?eI?Kas@}Dy@wAUkMOgDL" # noqa: E501
lib.map_renderer_update_route(renderer, geometry.encode()) lib.map_renderer_update_route(renderer, geometry.encode())
POSITIONS = [ POSITIONS = [

@ -30,7 +30,7 @@ class MapBoxInternetDisabledRequestHandler(http.server.BaseHTTPRequestHandler):
def setup(self): def setup(self):
if self.INTERNET_ACTIVE: if self.INTERNET_ACTIVE:
super().setup() super().setup()
def handle(self): def handle(self):
if self.INTERNET_ACTIVE: if self.INTERNET_ACTIVE:
super().handle() super().handle()
@ -38,7 +38,7 @@ class MapBoxInternetDisabledRequestHandler(http.server.BaseHTTPRequestHandler):
def finish(self): def finish(self):
if self.INTERNET_ACTIVE: if self.INTERNET_ACTIVE:
super().finish() super().finish()
def do_GET(self): def do_GET(self):
url = f'https://api.mapbox.com{self.path}' url = f'https://api.mapbox.com{self.path}'
@ -50,7 +50,7 @@ class MapBoxInternetDisabledRequestHandler(http.server.BaseHTTPRequestHandler):
self.send_response(r.status_code) self.send_response(r.status_code)
self.end_headers() self.end_headers()
self.wfile.write(r.content) self.wfile.write(r.content)
def log_message(self, *args: Any) -> None: def log_message(self, *args: Any) -> None:
return return
@ -62,13 +62,13 @@ class MapBoxInternetDisabledServer(threading.Thread):
def run(self): def run(self):
self.server = http.server.HTTPServer(("127.0.0.1", 5000), MapBoxInternetDisabledRequestHandler) self.server = http.server.HTTPServer(("127.0.0.1", 5000), MapBoxInternetDisabledRequestHandler)
self.server.serve_forever() self.server.serve_forever()
def stop(self): def stop(self):
self.server.shutdown() self.server.shutdown()
def disable_internet(self): def disable_internet(self):
MapBoxInternetDisabledRequestHandler.INTERNET_ACTIVE = False MapBoxInternetDisabledRequestHandler.INTERNET_ACTIVE = False
def enable_internet(self): def enable_internet(self):
MapBoxInternetDisabledRequestHandler.INTERNET_ACTIVE = True MapBoxInternetDisabledRequestHandler.INTERNET_ACTIVE = True
@ -110,7 +110,7 @@ class TestMapRenderer(unittest.TestCase):
assert self.vipc.connect(False) assert self.vipc.connect(False)
self.vipc.recv() self.vipc.recv()
def _run_test(self, expect_valid, location=LOCATION1): def _run_test(self, expect_valid, location=LOCATION1):
starting_frame_id = None starting_frame_id = None
@ -127,7 +127,7 @@ class TestMapRenderer(unittest.TestCase):
else: else:
prev_valid = self.sm.valid['mapRenderState'] prev_valid = self.sm.valid['mapRenderState']
prev_frame_id = self.sm['mapRenderState'].frameId prev_frame_id = self.sm['mapRenderState'].frameId
if starting_frame_id is None: if starting_frame_id is None:
starting_frame_id = prev_frame_id starting_frame_id = prev_frame_id
@ -172,7 +172,7 @@ class TestMapRenderer(unittest.TestCase):
self.server.disable_internet() self.server.disable_internet()
self._setup_test() self._setup_test()
self._run_test(False) self._run_test(False)
def test_recover_from_no_internet(self): def test_recover_from_no_internet(self):
self._setup_test() self._setup_test()
self._run_test(True) self._run_test(True)

@ -22,7 +22,7 @@ class FdRedirect:
def read(self) -> bytes: def read(self) -> bytes:
with open(self.dest_fname, "rb") as f: with open(self.dest_fname, "rb") as f:
return f.read() or b"" return f.read() or b""
def link(self) -> None: def link(self) -> None:
os.dup2(self.dest_fd, self.source_fd) os.dup2(self.dest_fd, self.source_fd)
@ -39,7 +39,7 @@ class ProcessOutputCapture:
@no_type_check # ipython classes have incompatible signatures @no_type_check # ipython classes have incompatible signatures
def link_with_current_proc(self) -> None: def link_with_current_proc(self) -> None:
try: try:
# prevent ipykernel from redirecting stdout/stderr of python subprocesses # prevent ipykernel from redirecting stdout/stderr of python subprocesses
from ipykernel.iostream import OutStream from ipykernel.iostream import OutStream
if isinstance(sys.stdout, OutStream): if isinstance(sys.stdout, OutStream):

@ -20,13 +20,13 @@ def migrate_cameraStates(lr):
for msg in lr: for msg in lr:
if msg.which() not in ["roadEncodeIdx", "wideRoadEncodeIdx", "driverEncodeIdx"]: if msg.which() not in ["roadEncodeIdx", "wideRoadEncodeIdx", "driverEncodeIdx"]:
continue continue
encode_index = getattr(msg, msg.which()) encode_index = getattr(msg, msg.which())
meta = meta_from_encode_index(msg.which()) meta = meta_from_encode_index(msg.which())
assert encode_index.segmentId < 1200, f"Encoder index segmentId greater that 1200: {msg.which()} {encode_index.segmentId}" assert encode_index.segmentId < 1200, f"Encoder index segmentId greater that 1200: {msg.which()} {encode_index.segmentId}"
frame_to_encode_id[meta.camera_state][encode_index.frameId] = encode_index.segmentId frame_to_encode_id[meta.camera_state][encode_index.frameId] = encode_index.segmentId
for msg in lr: for msg in lr:
if msg.which() not in ["roadCameraState", "wideRoadCameraState", "driverCameraState"]: if msg.which() not in ["roadCameraState", "wideRoadCameraState", "driverCameraState"]:
all_msgs.append(msg) all_msgs.append(msg)

@ -52,7 +52,7 @@ class ReplayContext:
self.main_pub_drained = cfg.main_pub_drained self.main_pub_drained = cfg.main_pub_drained
self.unlocked_pubs = cfg.unlocked_pubs self.unlocked_pubs = cfg.unlocked_pubs
assert(len(self.pubs) != 0 or self.main_pub is not None) assert(len(self.pubs) != 0 or self.main_pub is not None)
def __enter__(self): def __enter__(self):
self.open() self.open()
@ -82,7 +82,7 @@ class ReplayContext:
@property @property
def all_recv_called_events(self): def all_recv_called_events(self):
return [man.recv_called_event for man in self.events.values()] return [man.recv_called_event for man in self.events.values()]
@property @property
def all_recv_ready_events(self): def all_recv_ready_events(self):
return [man.recv_ready_event for man in self.events.values()] return [man.recv_ready_event for man in self.events.values()]
@ -142,7 +142,7 @@ class ProcessContainer:
self.cnt = 0 self.cnt = 0
self.pm: Optional[messaging.PubMaster] = None self.pm: Optional[messaging.PubMaster] = None
self.sockets: Optional[List[messaging.SubSocket]] = None self.sockets: Optional[List[messaging.SubSocket]] = None
self.rc: Optional[ReplayContext] = None self.rc: Optional[ReplayContext] = None
self.vipc_server: Optional[VisionIpcServer] = None self.vipc_server: Optional[VisionIpcServer] = None
self.capture: Optional[ProcessOutputCapture] = None self.capture: Optional[ProcessOutputCapture] = None
@ -199,8 +199,8 @@ class ProcessContainer:
self.process.start() self.process.start()
def start( def start(
self, params_config: Dict[str, Any], environ_config: Dict[str, Any], self, params_config: Dict[str, Any], environ_config: Dict[str, Any],
all_msgs: Union[LogReader, List[capnp._DynamicStructReader]], all_msgs: Union[LogReader, List[capnp._DynamicStructReader]],
fingerprint: Optional[str], capture_output: bool fingerprint: Optional[str], capture_output: bool
): ):
with self.prefix as p: with self.prefix as p:
@ -336,7 +336,7 @@ def get_car_params_callback(rc, pm, msgs, fingerprint):
def controlsd_rcv_callback(msg, cfg, frame): def controlsd_rcv_callback(msg, cfg, frame):
# no sendcan until controlsd is initialized # no sendcan until controlsd is initialized
if msg.which() != "can": if msg.which() != "can":
return False return False
socks = [ socks = [
s for s in cfg.subs if s for s in cfg.subs if
@ -407,7 +407,7 @@ class FrequencyBasedRcvCallback:
if frame % max(1, int(service_list[msg.which()].frequency / service_list[s].frequency)) == 0 if frame % max(1, int(service_list[msg.which()].frequency / service_list[s].frequency)) == 0
] ]
return bool(len(resp_sockets)) return bool(len(resp_sockets))
def controlsd_config_callback(params, cfg, lr): def controlsd_config_callback(params, cfg, lr):
controlsState = None controlsState = None
@ -437,7 +437,7 @@ def laikad_config_pubsub_callback(params, cfg, lr):
def locationd_config_pubsub_callback(params, cfg, lr): def locationd_config_pubsub_callback(params, cfg, lr):
ublox = params.get_bool("UbloxAvailable") ublox = params.get_bool("UbloxAvailable")
sub_keys = ({"gpsLocation", } if ublox else {"gpsLocationExternal", }) sub_keys = ({"gpsLocation", } if ublox else {"gpsLocationExternal", })
cfg.pubs = set(cfg.pubs) - sub_keys cfg.pubs = set(cfg.pubs) - sub_keys
@ -495,7 +495,7 @@ CONFIGS = [
ProcessConfig( ProcessConfig(
proc_name="locationd", proc_name="locationd",
pubs=[ pubs=[
"cameraOdometry", "accelerometer", "gyroscope", "gpsLocationExternal", "cameraOdometry", "accelerometer", "gyroscope", "gpsLocationExternal",
"liveCalibration", "carState", "carParams", "gpsLocation" "liveCalibration", "carState", "carParams", "gpsLocation"
], ],
subs=["liveLocationKalman"], subs=["liveLocationKalman"],
@ -577,7 +577,7 @@ def get_process_config(name: str) -> ProcessConfig:
def get_custom_params_from_lr(lr: Union[LogReader, List[capnp._DynamicStructReader]], initial_state: str = "first") -> Dict[str, Any]: def get_custom_params_from_lr(lr: Union[LogReader, List[capnp._DynamicStructReader]], initial_state: str = "first") -> Dict[str, Any]:
""" """
Use this to get custom params dict based on provided logs. Use this to get custom params dict based on provided logs.
Useful when replaying following processes: calibrationd, paramsd, torqued Useful when replaying following processes: calibrationd, paramsd, torqued
The params may be based on first or last message of given type (carParams, liveCalibration, liveParameters, liveTorqueParameters) in the logs. The params may be based on first or last message of given type (carParams, liveCalibration, liveParameters, liveTorqueParameters) in the logs.
""" """
@ -620,7 +620,7 @@ def replay_process_with_name(name: Union[str, Iterable[str]], lr: Union[LogReade
def replay_process( def replay_process(
cfg: Union[ProcessConfig, Iterable[ProcessConfig]], lr: Union[LogReader, List[capnp._DynamicStructReader]], frs: Optional[Dict[str, Any]] = None, cfg: Union[ProcessConfig, Iterable[ProcessConfig]], lr: Union[LogReader, List[capnp._DynamicStructReader]], frs: Optional[Dict[str, Any]] = None,
fingerprint: Optional[str] = None, return_all_logs: bool = False, custom_params: Optional[Dict[str, Any]] = None, fingerprint: Optional[str] = None, return_all_logs: bool = False, custom_params: Optional[Dict[str, Any]] = None,
captured_output_store: Optional[Dict[str, Dict[str, str]]] = None, disable_progress: bool = False captured_output_store: Optional[Dict[str, Dict[str, str]]] = None, disable_progress: bool = False
) -> List[capnp._DynamicStructReader]: ) -> List[capnp._DynamicStructReader]:
@ -660,7 +660,7 @@ def _replay_multi_process(
for cfg in cfgs: for cfg in cfgs:
if len(cfg.vision_pubs) == 0: if len(cfg.vision_pubs) == 0:
continue continue
assert frs is not None, "frs must be provided when replaying process using vision streams" assert frs is not None, "frs must be provided when replaying process using vision streams"
assert all(meta_from_camera_state(st) is not None for st in cfg.vision_pubs),\ assert all(meta_from_camera_state(st) is not None for st in cfg.vision_pubs),\
f"undefined vision stream spotted, probably misconfigured process: {cfg.vision_pubs}" f"undefined vision stream spotted, probably misconfigured process: {cfg.vision_pubs}"
@ -722,7 +722,7 @@ def generate_params_config(lr=None, CP=None, fingerprint=None, custom_params=Non
"DisengageOnAccelerator": True, "DisengageOnAccelerator": True,
"DisableLogging": False, "DisableLogging": False,
} }
if custom_params is not None: if custom_params is not None:
params_dict.update(custom_params) params_dict.update(custom_params)
if lr is not None: if lr is not None:
@ -769,7 +769,7 @@ def generate_environ_config(CP=None, fingerprint=None, log_dir=None) -> Dict[str
else: else:
environ_dict["SKIP_FW_QUERY"] = "" environ_dict["SKIP_FW_QUERY"] = ""
environ_dict["FINGERPRINT"] = "" environ_dict["FINGERPRINT"] = ""
return environ_dict return environ_dict

@ -16,7 +16,7 @@ from tools.lib.helpers import save_log
def regen_segment( def regen_segment(
lr: Union[LogReader, List[capnp._DynamicStructReader]], frs: Optional[Dict[str, Any]] = None, lr: Union[LogReader, List[capnp._DynamicStructReader]], frs: Optional[Dict[str, Any]] = None,
daemons: Union[str, Iterable[str]] = "all", disable_tqdm: bool = False daemons: Union[str, Iterable[str]] = "all", disable_tqdm: bool = False
) -> List[capnp._DynamicStructReader]: ) -> List[capnp._DynamicStructReader]:
if not isinstance(daemons, str) and not hasattr(daemons, "__iter__"): if not isinstance(daemons, str) and not hasattr(daemons, "__iter__"):

@ -41,23 +41,23 @@ source_segments = [
] ]
segments = [ segments = [
("BODY", "aregenECF15D9E559|2023-05-10--14-26-40--0"), ("BODY", "aregenECF15D9E559|2023-05-10--14-26-40--0"),
("HYUNDAI", "aregenAB9F543F70A|2023-05-10--14-28-25--0"), ("HYUNDAI", "aregenAB9F543F70A|2023-05-10--14-28-25--0"),
("HYUNDAI2", "aregen39F5A028F96|2023-05-10--14-31-00--0"), ("HYUNDAI2", "aregen39F5A028F96|2023-05-10--14-31-00--0"),
("TOYOTA", "aregen8D6A8B36E8D|2023-05-10--14-32-38--0"), ("TOYOTA", "aregen8D6A8B36E8D|2023-05-10--14-32-38--0"),
("TOYOTA2", "aregenB1933C49809|2023-05-10--14-34-14--0"), ("TOYOTA2", "aregenB1933C49809|2023-05-10--14-34-14--0"),
("TOYOTA3", "aregen5D9915223DC|2023-05-10--14-36-43--0"), ("TOYOTA3", "aregen5D9915223DC|2023-05-10--14-36-43--0"),
("HONDA", "aregen484B732B675|2023-05-10--14-38-23--0"), ("HONDA", "aregen484B732B675|2023-05-10--14-38-23--0"),
("HONDA2", "aregenAF6ACED4713|2023-05-10--14-40-01--0"), ("HONDA2", "aregenAF6ACED4713|2023-05-10--14-40-01--0"),
("CHRYSLER", "aregen99B094E1E2E|2023-05-10--14-41-40--0"), ("CHRYSLER", "aregen99B094E1E2E|2023-05-10--14-41-40--0"),
("RAM", "aregen5C2487E1EEB|2023-05-10--14-44-09--0"), ("RAM", "aregen5C2487E1EEB|2023-05-10--14-44-09--0"),
("SUBARU", "aregen98D277B792E|2023-05-10--14-46-46--0"), ("SUBARU", "aregen98D277B792E|2023-05-10--14-46-46--0"),
("GM", "aregen377BA28D848|2023-05-10--14-48-28--0"), ("GM", "aregen377BA28D848|2023-05-10--14-48-28--0"),
("GM2", "aregen7CA0CC0F0C2|2023-05-10--14-51-00--0"), ("GM2", "aregen7CA0CC0F0C2|2023-05-10--14-51-00--0"),
("NISSAN", "aregen7097BF01563|2023-05-10--14-52-43--0"), ("NISSAN", "aregen7097BF01563|2023-05-10--14-52-43--0"),
("VOLKSWAGEN", "aregen765AF3D2CB5|2023-05-10--14-54-23--0"), ("VOLKSWAGEN", "aregen765AF3D2CB5|2023-05-10--14-54-23--0"),
("MAZDA", "aregen3053762FF2E|2023-05-10--14-56-53--0"), ("MAZDA", "aregen3053762FF2E|2023-05-10--14-56-53--0"),
("FORD", "aregenDDE0F89FA1E|2023-05-10--14-59-26--0"), ("FORD", "aregenDDE0F89FA1E|2023-05-10--14-59-26--0"),
] ]
# dashcamOnly makes don't need to be tested until a full port is done # dashcamOnly makes don't need to be tested until a full port is done

@ -178,23 +178,23 @@ class TestPowerMonitoring(unittest.TestCase):
if i % 10 == 0: if i % 10 == 0:
self.assertFalse(pm.should_shutdown(ignition, False, ssb, False)) self.assertFalse(pm.should_shutdown(ignition, False, ssb, False))
self.assertFalse(pm.should_shutdown(ignition, False, ssb, False)) self.assertFalse(pm.should_shutdown(ignition, False, ssb, False))
def test_delay_shutdown_time(self): def test_delay_shutdown_time(self):
pm = PowerMonitoring() pm = PowerMonitoring()
pm.car_battery_capacity_uWh = 0 pm.car_battery_capacity_uWh = 0
ignition = False ignition = False
in_car = True in_car = True
offroad_timestamp = ssb offroad_timestamp = ssb
started_seen = True started_seen = True
pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition)
while ssb < offroad_timestamp + DELAY_SHUTDOWN_TIME_S: while ssb < offroad_timestamp + DELAY_SHUTDOWN_TIME_S:
self.assertFalse(pm.should_shutdown(ignition, in_car, self.assertFalse(pm.should_shutdown(ignition, in_car,
offroad_timestamp, offroad_timestamp,
started_seen), started_seen),
f"Should not shutdown before {DELAY_SHUTDOWN_TIME_S} seconds offroad time") f"Should not shutdown before {DELAY_SHUTDOWN_TIME_S} seconds offroad time")
self.assertTrue(pm.should_shutdown(ignition, in_car, self.assertTrue(pm.should_shutdown(ignition, in_car,
offroad_timestamp, offroad_timestamp,
started_seen), started_seen),
f"Should shutdown after {DELAY_SHUTDOWN_TIME_S} seconds offroad time") f"Should shutdown after {DELAY_SHUTDOWN_TIME_S} seconds offroad time")

@ -444,7 +444,7 @@ def main() -> None:
if not system_time_valid(): if not system_time_valid():
wait_helper.sleep(60) wait_helper.sleep(60)
continue continue
update_failed_count += 1 update_failed_count += 1
# check for update # check for update

@ -164,12 +164,12 @@ def initialize_pigeon(pigeon: TTYPigeon) -> bool:
pigeon.send_with_ack(b"\xB5\x62\x06\x08\x06\x00\x64\x00\x01\x00\x00\x00\x79\x10") pigeon.send_with_ack(b"\xB5\x62\x06\x08\x06\x00\x64\x00\x01\x00\x00\x00\x79\x10")
# UBX-CFG-NAV5 (0x06 0x24) # UBX-CFG-NAV5 (0x06 0x24)
pigeon.send_with_ack(b"\xB5\x62\x06\x24\x24\x00\x05\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5A\x63") # pylint: disable=C0301 pigeon.send_with_ack(b"\xB5\x62\x06\x24\x24\x00\x05\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5A\x63") # noqa: E501
# UBX-CFG-ODO (0x06 0x1E) # UBX-CFG-ODO (0x06 0x1E)
pigeon.send_with_ack(b"\xB5\x62\x06\x1E\x14\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x37") pigeon.send_with_ack(b"\xB5\x62\x06\x1E\x14\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x37")
pigeon.send_with_ack(b"\xB5\x62\x06\x39\x08\x00\xFF\xAD\x62\xAD\x1E\x63\x00\x00\x83\x0C") pigeon.send_with_ack(b"\xB5\x62\x06\x39\x08\x00\xFF\xAD\x62\xAD\x1E\x63\x00\x00\x83\x0C")
pigeon.send_with_ack(b"\xB5\x62\x06\x23\x28\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x24") # pylint: disable=C0301 pigeon.send_with_ack(b"\xB5\x62\x06\x23\x28\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x24") # noqa: E501
# UBX-CFG-NAV5 (0x06 0x24) # UBX-CFG-NAV5 (0x06 0x24)
pigeon.send_with_ack(b"\xB5\x62\x06\x24\x00\x00\x2A\x84") pigeon.send_with_ack(b"\xB5\x62\x06\x24\x00\x00\x2A\x84")

@ -255,7 +255,7 @@ position_report = """
uint32 q_FltRawAlt; /* Raw height-above-ellipsoid altitude in meters as computed by WLS */ uint32 q_FltRawAlt; /* Raw height-above-ellipsoid altitude in meters as computed by WLS */
uint32 q_FltRawAltSigma; /* Gaussian 1-sigma value for raw height-above-ellipsoid altitude in meters */ uint32 q_FltRawAltSigma; /* Gaussian 1-sigma value for raw height-above-ellipsoid altitude in meters */
uint32 align_Flt[14]; uint32 align_Flt[14];
uint32 q_FltPdop; /* 3D position dilution of precision as computed from the unweighted uint32 q_FltPdop; /* 3D position dilution of precision as computed from the unweighted
uint32 q_FltHdop; /* Horizontal position dilution of precision as computed from the unweighted least-squares covariance matrix */ uint32 q_FltHdop; /* Horizontal position dilution of precision as computed from the unweighted least-squares covariance matrix */
uint32 q_FltVdop; /* Vertical position dilution of precision as computed from the unweighted least-squares covariance matrix */ uint32 q_FltVdop; /* Vertical position dilution of precision as computed from the unweighted least-squares covariance matrix */
uint8 u_EllipseConfidence; /* Statistical measure of the confidence (percentage) associated with the uncertainty ellipse values */ uint8 u_EllipseConfidence; /* Statistical measure of the confidence (percentage) associated with the uncertainty ellipse values */
@ -276,7 +276,7 @@ position_report = """
uint8 u_TotalGloSvs; /* Total number of Glonass SVs detected by searcher, including ones not used in position calculation */ uint8 u_TotalGloSvs; /* Total number of Glonass SVs detected by searcher, including ones not used in position calculation */
uint8 u_NumBdsSvsUsed; /* The number of BeiDou SVs used in the fix */ uint8 u_NumBdsSvsUsed; /* The number of BeiDou SVs used in the fix */
uint8 u_TotalBdsSvs; /* Total number of BeiDou SVs detected by searcher, including ones not used in position calculation */ uint8 u_TotalBdsSvs; /* Total number of BeiDou SVs detected by searcher, including ones not used in position calculation */
""" """ # noqa: E501
def name_to_camelcase(nam): def name_to_camelcase(nam):
ret = [] ret = []

@ -168,7 +168,7 @@ if __name__ == "__main__":
if not os.path.exists(PLOTJUGGLER_BIN): if not os.path.exists(PLOTJUGGLER_BIN):
print("PlotJuggler is missing. Downloading...") print("PlotJuggler is missing. Downloading...")
install() install()
if get_plotjuggler_version() < MINIMUM_PLOTJUGGLER_VERSION: if get_plotjuggler_version() < MINIMUM_PLOTJUGGLER_VERSION:
print("PlotJuggler is out of date. Installing update...") print("PlotJuggler is out of date. Installing update...")
install() install()

@ -14,7 +14,6 @@ from tools.plotjuggler.juggle import load_segment
from tools.lib.logreader import logreader_from_route_or_segment from tools.lib.logreader import logreader_from_route_or_segment
from panda import Panda, PandaJungle from panda import Panda, PandaJungle
def send_thread(s, flock): def send_thread(s, flock):
if "Jungle" in str(type(s)): if "Jungle" in str(type(s)):
if "FLASH" in os.environ: if "FLASH" in os.environ:

Loading…
Cancel
Save