diff --git a/.gitignore b/.gitignore index 8f21086a7..9f2de0181 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,4 @@ cppcheck_report.txt htmlcov pandaextra +.mypy_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 96ba5e5e9..71f442a53 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,6 +6,11 @@ repos: - id: check-json - id: check-xml - id: check-yaml +- repo: https://github.com/pre-commit/mirrors-mypy + rev: master + hooks: + - id: mypy + exclude: '^(pyextra)|(external)|(cereal)|(rednose)|(panda)|(laika)|(laika_repo)|(rednose_repo)/' - repo: https://gitlab.com/PyCQA/flake8 rev: master hooks: diff --git a/Pipfile b/Pipfile index d18512d0a..5fb643ad8 100644 --- a/Pipfile +++ b/Pipfile @@ -73,6 +73,7 @@ pygame = "==2.0.0.dev8" pprofile = "*" pyprof2calltree = "*" pre-commit = "*" +mypy = "*" [packages] atomicwrites = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 572eb9a07..e297d667e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "681eef4e45758b560f2f76736c039d051c62cc910e6bc7556b3add318110dea0" + "sha256": "ebed80be69f5b38143ddf30e96b8d7f6d3214a4296088276e01795f15ad6e1c2" }, "pipfile-spec": 6, "requires": { @@ -90,9 +90,9 @@ }, "crcmod": { "hashes": [ - "sha256:737fb308fa2ce9aed2e29075f0d5980d4a89bfbec48a368c607c5c63b3efb90e", - "sha256:69a2e5c6c36d0f096a7beb4cd34e5f882ec5fd232efb710cdb85d4ff196bd52e", "sha256:50586ab48981f11e5b117523d97bb70864a2a1af246cf6e4f5c4a21ef4611cd1", + "sha256:69a2e5c6c36d0f096a7beb4cd34e5f882ec5fd232efb710cdb85d4ff196bd52e", + "sha256:737fb308fa2ce9aed2e29075f0d5980d4a89bfbec48a368c607c5c63b3efb90e", "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e" ], "index": "pypi", @@ -361,29 +361,29 @@ }, "pillow": { "hashes": [ - "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7", - "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523", - "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3", "sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107", + "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3", + "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9", + "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523", "sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3", + "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079", + "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd", + "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0", + "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705", + "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd", "sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3", "sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891", + "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f", "sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088", + "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac", + "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7", "sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d", - "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9", + "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa", "sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344", "sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2", "sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457", - "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac", - "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079", - "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705", - "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d", - "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa", "sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276", - "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f", - "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd", - "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0", - "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd" + "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d" ], "index": "pypi", "version": "==7.1.2" @@ -1229,11 +1229,11 @@ }, "google-auth": { "hashes": [ - "sha256:73b141d122942afe12e8bfdcb6900d5df35c27d39700f078363ba0b1298ad33b", - "sha256:fbf25fee328c0828ef293459d9c649ef84ee44c0b932bb999d19df0ead1b40cf" + "sha256:1b3732b121917124adfe602de148ef5cba351792cf9527f99e6b61b84f74a7f5", + "sha256:7a9119c4ed518e4ea596cc896e6c567b923b57db40be70e5aec990055aea85d3" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.15.0" + "version": "==1.16.0" }, "google-auth-oauthlib": { "hashes": [ @@ -1739,6 +1739,33 @@ "markers": "python_version >= '3.5'", "version": "==4.7.6" }, + "mypy": { + "hashes": [ + "sha256:15b948e1302682e3682f11f50208b726a246ab4e6c1b39f9264a8796bb416aa2", + "sha256:219a3116ecd015f8dca7b5d2c366c973509dfb9a8fc97ef044a36e3da66144a1", + "sha256:3b1fc683fb204c6b4403a1ef23f0b1fac8e4477091585e0c8c54cbdf7d7bb164", + "sha256:3beff56b453b6ef94ecb2996bea101a08f1f8a9771d3cbf4988a61e4d9973761", + "sha256:7687f6455ec3ed7649d1ae574136835a4272b65b3ddcf01ab8704ac65616c5ce", + "sha256:7ec45a70d40ede1ec7ad7f95b3c94c9cf4c186a32f6bacb1795b60abd2f9ef27", + "sha256:86c857510a9b7c3104cf4cde1568f4921762c8f9842e987bc03ed4f160925754", + "sha256:8a627507ef9b307b46a1fea9513d5c98680ba09591253082b4c48697ba05a4ae", + "sha256:8dfb69fbf9f3aeed18afffb15e319ca7f8da9642336348ddd6cab2713ddcf8f9", + "sha256:a34b577cdf6313bf24755f7a0e3f3c326d5c1f4fe7422d1d06498eb25ad0c600", + "sha256:a8ffcd53cb5dfc131850851cc09f1c44689c2812d0beb954d8138d4f5fc17f65", + "sha256:b90928f2d9eb2f33162405f32dde9f6dcead63a0971ca8a1b50eb4ca3e35ceb8", + "sha256:c56ffe22faa2e51054c5f7a3bc70a370939c2ed4de308c690e7949230c995913", + "sha256:f91c7ae919bbc3f96cd5e5b2e786b2b108343d1d7972ea130f7de27fdd547cf3" + ], + "index": "pypi", + "version": "==0.770" + }, + "mypy-extensions": { + "hashes": [ + "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" + ], + "version": "==0.4.3" + }, "nbconvert": { "hashes": [ "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523", @@ -1945,29 +1972,29 @@ }, "pillow": { "hashes": [ - "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7", - "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523", - "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3", "sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107", + "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3", + "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9", + "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523", "sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3", + "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079", + "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd", + "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0", + "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705", + "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd", "sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3", "sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891", + "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f", "sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088", + "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac", + "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7", "sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d", - "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9", + "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa", "sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344", "sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2", "sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457", - "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac", - "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079", - "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705", - "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d", - "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa", "sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276", - "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f", - "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd", - "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0", - "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd" + "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d" ], "index": "pypi", "version": "==7.1.2" @@ -2019,6 +2046,7 @@ "protobuf": { "hashes": [ "sha256:304e08440c4a41a0f3592d2a38934aad6919d692bb0edfb355548786728f9a5e", + "sha256:49ef8ab4c27812a89a76fa894fe7a08f42f2147078392c0dee51d4a444ef6df5", "sha256:50b5fee674878b14baea73b4568dc478c46a31dd50157a5b5d2f71138243b1a9", "sha256:5524c7020eb1fb7319472cb75c4c3206ef18b34d6034d2ee420a60f99cddeb07", "sha256:612bc97e42b22af10ba25e4140963fbaa4c5181487d163f4eb55b0b15b3dfcd2", @@ -2026,6 +2054,7 @@ "sha256:85b94d2653b0fdf6d879e39d51018bf5ccd86c81c04e18a98e9888694b98226f", "sha256:87535dc2d2ef007b9d44e309d2b8ea27a03d2fa09556a72364d706fcb7090828", "sha256:a7ab28a8f1f043c58d157bceb64f80e4d2f7f1b934bc7ff5e7f7a55a337ea8b0", + "sha256:a96f8fc625e9ff568838e556f6f6ae8eca8b4837cdfb3f90efcb7c00e342a2eb", "sha256:b5a114ea9b7fc90c2cc4867a866512672a47f66b154c6d7ee7e48ddb68b68122", "sha256:be04fe14ceed7f8641e30f36077c1a654ff6f17d0c7a5283b699d057d150d82a", "sha256:bff02030bab8b969f4de597543e55bd05e968567acb25c0a87495a31eb09e925", @@ -2722,10 +2751,10 @@ }, "tensorboard": { "hashes": [ - "sha256:9a2a2dc9856187679e93f3c95e5dc771dd47e3257db09767b4be118d734b4dc2" + "sha256:a3feb73e1221c0a512398ad2cd08570fb082d8a2ba364aa0562543ecbd3659ef" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.2.1" + "version": "==2.2.2" }, "tensorboard-plugin-wit": { "hashes": [ @@ -2816,6 +2845,40 @@ ], "version": "==4.3.3" }, + "typed-ast": { + "hashes": [ + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" + ], + "version": "==1.4.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5", + "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae", + "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392" + ], + "version": "==3.7.4.2" + }, "urllib3": { "hashes": [ "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", diff --git a/common/params.py b/common/params.py index 787235bf1..0a7e6daf9 100755 --- a/common/params.py +++ b/common/params.py @@ -22,10 +22,7 @@ file in place without messing with /d. """ import time import os -import string -import binascii import errno -import sys import shutil import fcntl import tempfile @@ -401,22 +398,3 @@ def put_nonblocking(key, val): t = threading.Thread(target=f, args=(key, val)) t.start() return t - - -if __name__ == "__main__": - params = Params() - if len(sys.argv) > 2: - params.put(sys.argv[1], sys.argv[2]) - else: - for k in keys: - pp = params.get(k) - if pp is None: - print("%s is None" % k) - elif all(chr(c) in string.printable for c in pp): - print("%s = %s" % (k, pp)) - else: - print("%s = %s" % (k, binascii.hexlify(pp))) - - # Test multiprocess: - # seq 0 100000 | xargs -P20 -I{} python common/params.py DongleId {} && sleep 0.05 - # while python common/params.py DongleId; do sleep 0.05; done diff --git a/common/spinner.py b/common/spinner.py index da8084037..370d54c81 100644 --- a/common/spinner.py +++ b/common/spinner.py @@ -40,7 +40,7 @@ class Spinner(): self.close() -class FakeSpinner(): +class FakeSpinner(Spinner): def __init__(self): pass diff --git a/common/text_window.py b/common/text_window.py index 0d94bc747..50fdcb644 100755 --- a/common/text_window.py +++ b/common/text_window.py @@ -43,7 +43,7 @@ class TextWindow(): self.close() -class FakeTextWindow(): +class FakeTextWindow(TextWindow): def __init__(self, s): pass diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 000000000..66b82bd5d --- /dev/null +++ b/mypy.ini @@ -0,0 +1,4 @@ +[mypy] +python_version = 3.8 +ignore_missing_imports = True + diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index b9e8d79e6..cbebb08e5 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -1,29 +1,31 @@ #!/usr/bin/env python3 -import json -import os +import base64 import hashlib import io +import json +import os +import queue import random import select import socket -import time import threading -import base64 -import requests -import queue +import time from collections import namedtuple from functools import partial +from typing import Any + +import requests from jsonrpc import JSONRPCResponseManager, dispatcher -from websocket import create_connection, WebSocketTimeoutException, ABNF -from selfdrive.loggerd.config import ROOT +from websocket import ABNF, WebSocketTimeoutException, create_connection import cereal.messaging as messaging +from cereal.services import service_list from common import android -from common.basedir import PERSIST from common.api import Api +from common.basedir import PERSIST from common.params import Params from common.realtime import sec_since_boot -from cereal.services import service_list +from selfdrive.loggerd.config import ROOT from selfdrive.swaglog import cloudlog ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai') @@ -31,10 +33,10 @@ HANDLER_THREADS = os.getenv('HANDLER_THREADS', 4) LOCAL_PORT_WHITELIST = set([8022]) dispatcher["echo"] = lambda s: s -payload_queue = queue.Queue() -response_queue = queue.Queue() -upload_queue = queue.Queue() -cancelled_uploads = set() +payload_queue: Any = queue.Queue() +response_queue: Any = queue.Queue() +upload_queue: Any = queue.Queue() +cancelled_uploads: Any = set() UploadItem = namedtuple('UploadItem', ['path', 'url', 'headers', 'created_at', 'id']) def handle_long_poll(ws): diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 673b16942..f42e1c09d 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -1,15 +1,17 @@ #!/usr/bin/env python3 -import traceback import struct +import traceback +from typing import Any + from tqdm import tqdm -from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery -from selfdrive.swaglog import cloudlog -from selfdrive.car.fingerprints import get_attr_from_cars, FW_VERSIONS -from selfdrive.car.toyota.values import CAR as TOYOTA import panda.python.uds as uds - from cereal import car +from selfdrive.car.fingerprints import FW_VERSIONS, get_attr_from_cars +from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery +from selfdrive.car.toyota.values import CAR as TOYOTA +from selfdrive.swaglog import cloudlog + Ecu = car.CarParams.Ecu @@ -213,7 +215,7 @@ if __name__ == "__main__": logcan = messaging.sub_sock('can') sendcan = messaging.pub_sock('sendcan') - extra = None + extra: Any = None if args.scan: extra = {} # Honda diff --git a/selfdrive/crash.py b/selfdrive/crash.py index a8cb758a7..000109dc9 100644 --- a/selfdrive/crash.py +++ b/selfdrive/crash.py @@ -9,7 +9,7 @@ from selfdrive.swaglog import cloudlog from common.android import ANDROID if os.getenv("NOLOG") or os.getenv("NOCRASH") or not ANDROID: - def capture_exception(*exc_info): + def capture_exception(*args, **kwargs): pass def bind_user(**kwargs): pass diff --git a/selfdrive/debug/check_freq.py b/selfdrive/debug/check_freq.py index 75c0b8f89..fd4f510c2 100755 --- a/selfdrive/debug/check_freq.py +++ b/selfdrive/debug/check_freq.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import argparse import numpy as np from collections import defaultdict, deque diff --git a/selfdrive/debug/check_lag.py b/selfdrive/debug/check_lag.py index 418f1f872..c92264298 100755 --- a/selfdrive/debug/check_lag.py +++ b/selfdrive/debug/check_lag.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import cereal.messaging as messaging from cereal.services import service_list diff --git a/selfdrive/debug/cpu_usage_stat.py b/selfdrive/debug/cpu_usage_stat.py index d59a14855..c3f54f943 100755 --- a/selfdrive/debug/cpu_usage_stat.py +++ b/selfdrive/debug/cpu_usage_stat.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# type: ignore import psutil import time import os diff --git a/selfdrive/debug/internal/get_fingerprint_from_route.py b/selfdrive/debug/internal/get_fingerprint_from_route.py index 278aaadd4..2a0f99fab 100755 --- a/selfdrive/debug/internal/get_fingerprint_from_route.py +++ b/selfdrive/debug/internal/get_fingerprint_from_route.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# type: ignore import sys from tools.lib.logreader import MultiLogIterator diff --git a/selfdrive/debug/internal/measure_steering_accuracy.py b/selfdrive/debug/internal/measure_steering_accuracy.py index fabf8030d..706af7398 100755 --- a/selfdrive/debug/internal/measure_steering_accuracy.py +++ b/selfdrive/debug/internal/measure_steering_accuracy.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import os import argparse import signal @@ -28,7 +30,7 @@ if __name__ == "__main__": stats = defaultdict(lambda: {'err': 0, "cnt": 0, "=": 0, "+": 0, "-": 0}) cnt = 0 total_error = 0 - + while messaging.recv_one(carControl): sm.update() msg_cnt += 1 diff --git a/selfdrive/debug/internal/measure_torque_time_to_max.py b/selfdrive/debug/internal/measure_torque_time_to_max.py index d1beeae44..58a29532c 100755 --- a/selfdrive/debug/internal/measure_torque_time_to_max.py +++ b/selfdrive/debug/internal/measure_torque_time_to_max.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import os import argparse import struct diff --git a/selfdrive/debug/mpc/test_mpc_wobble.py b/selfdrive/debug/mpc/test_mpc_wobble.py index 5f9f1b335..6117779d8 100755 --- a/selfdrive/debug/mpc/test_mpc_wobble.py +++ b/selfdrive/debug/mpc/test_mpc_wobble.py @@ -1,4 +1,5 @@ #! /usr/bin/env python +# type: ignore import matplotlib.pyplot as plt from selfdrive.controls.lib.lateral_mpc import libmpc_py from selfdrive.controls.lib.drive_helpers import MPC_COST_LAT diff --git a/selfdrive/debug/mpc/tune_lateral.py b/selfdrive/debug/mpc/tune_lateral.py index 4a8ec2ce0..95bf6023b 100755 --- a/selfdrive/debug/mpc/tune_lateral.py +++ b/selfdrive/debug/mpc/tune_lateral.py @@ -1,4 +1,6 @@ #! /usr/bin/env python +# type: ignore + import numpy as np from collections import OrderedDict import matplotlib.pyplot as plt diff --git a/selfdrive/debug/mpc/tune_longitudinal.py b/selfdrive/debug/mpc/tune_longitudinal.py index ed3eb6378..f7fd43c48 100755 --- a/selfdrive/debug/mpc/tune_longitudinal.py +++ b/selfdrive/debug/mpc/tune_longitudinal.py @@ -1,4 +1,5 @@ #! /usr/bin/env python +# type: ignore import numpy as np import matplotlib.pyplot as plt from selfdrive.controls.lib.longitudinal_mpc import libmpc_py diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py index 2e668046e..0cba85a48 100755 --- a/selfdrive/debug/test_fw_query_on_routes.py +++ b/selfdrive/debug/test_fw_query_on_routes.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import argparse import os import traceback diff --git a/selfdrive/locationd/models/car_kf.py b/selfdrive/locationd/models/car_kf.py index b984bf766..dda5cea1b 100755 --- a/selfdrive/locationd/models/car_kf.py +++ b/selfdrive/locationd/models/car_kf.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -import sys import math +import sys +from typing import Any, Dict import numpy as np import sympy as sp @@ -58,7 +59,7 @@ class CarKalman(KalmanFilter): ]) P_initial = Q.copy() - obs_noise = { + obs_noise : Dict[int, Any] = { ObservationKind.STEER_ANGLE: np.atleast_2d(math.radians(0.01)**2), ObservationKind.ANGLE_OFFSET_FAST: np.atleast_2d(math.radians(10.0)**2), ObservationKind.STEER_RATIO: np.atleast_2d(5.0**2), diff --git a/selfdrive/locationd/models/gnss_kf.py b/selfdrive/locationd/models/gnss_kf.py index d3f8885f8..59c3877e4 100755 --- a/selfdrive/locationd/models/gnss_kf.py +++ b/selfdrive/locationd/models/gnss_kf.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 import sys +from typing import List import numpy as np import sympy as sp -from selfdrive.locationd.models.constants import ObservationKind from rednose.helpers.ekf_sym import EKF_sym, gen_code +from selfdrive.locationd.models.constants import ObservationKind from selfdrive.locationd.models.loc_kf import parse_pr, parse_prr @@ -39,7 +40,7 @@ class GNSSKalman(): (.1)**2, (0)**2, (0.005)**2, .1**2, (.01)**2]) - maha_test_kinds = [] # ObservationKind.PSEUDORANGE_RATE, ObservationKind.PSEUDORANGE, ObservationKind.PSEUDORANGE_GLONASS] + maha_test_kinds: List[int] = [] # ObservationKind.PSEUDORANGE_RATE, ObservationKind.PSEUDORANGE, ObservationKind.PSEUDORANGE_GLONASS] @staticmethod def generate_code(generated_dir): diff --git a/selfdrive/locationd/test/ci_test.py b/selfdrive/locationd/test/ci_test.py index 5b23e8326..b715a499a 100755 --- a/selfdrive/locationd/test/ci_test.py +++ b/selfdrive/locationd/test/ci_test.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# type: ignore import subprocess import os import sys diff --git a/selfdrive/locationd/test/ubloxd.py b/selfdrive/locationd/test/ubloxd.py index 65fdfce9b..5dbe8cff4 100755 --- a/selfdrive/locationd/test/ubloxd.py +++ b/selfdrive/locationd/test/ubloxd.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# type: ignore import os import serial diff --git a/selfdrive/locationd/test/ubloxd_easy.py b/selfdrive/locationd/test/ubloxd_easy.py index 8f226604e..0f90b012b 100755 --- a/selfdrive/locationd/test/ubloxd_easy.py +++ b/selfdrive/locationd/test/ubloxd_easy.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# type: ignore import os from selfdrive.locationd.test import ublox diff --git a/selfdrive/locationd/test/ubloxd_py_test.py b/selfdrive/locationd/test/ubloxd_py_test.py index bca9ddc42..7a573631b 100755 --- a/selfdrive/locationd/test/ubloxd_py_test.py +++ b/selfdrive/locationd/test/ubloxd_py_test.py @@ -1,3 +1,5 @@ +# type: ignore + import sys import os diff --git a/selfdrive/manager.py b/selfdrive/manager.py index 1fe4a0278..bf237ee76 100755 --- a/selfdrive/manager.py +++ b/selfdrive/manager.py @@ -9,8 +9,10 @@ import shutil import subprocess import datetime import textwrap +from typing import Dict, List from selfdrive.swaglog import cloudlog, add_logentries_handler + from common.basedir import BASEDIR, PARAMS from common.android import ANDROID WEBCAM = os.getenv("WEBCAM") is not None @@ -99,7 +101,7 @@ if not prebuilt: # Read progress from stderr and update spinner while scons.poll() is None: try: - line = scons.stderr.readline() + line = scons.stderr.readline() # type: ignore if line is None: continue line = line.rstrip() @@ -117,7 +119,7 @@ if not prebuilt: if scons.returncode != 0: # Read remaining output - r = scons.stderr.read().split(b'\n') + r = scons.stderr.read().split(b'\n') # type: ignore compile_output += r if retry: @@ -194,7 +196,7 @@ daemon_processes = { "manage_athenad": ("selfdrive.athena.manage_athenad", "AthenadPid"), } -running = {} +running: Dict[str, Process] = {} def get_running(): return running @@ -202,7 +204,7 @@ def get_running(): unkillable_processes = ['camerad'] # processes to end with SIGINT instead of SIGTERM -interrupt_processes = [] +interrupt_processes: List[str] = [] # processes to end with SIGKILL instead of SIGTERM kill_processes = ['sensord', 'paramsd'] diff --git a/selfdrive/test/longitudinal_maneuvers/plant_ui.py b/selfdrive/test/longitudinal_maneuvers/plant_ui.py deleted file mode 100755 index 3c73f8329..000000000 --- a/selfdrive/test/longitudinal_maneuvers/plant_ui.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 -import pygame # pylint: disable=import-error -from selfdrive.test.longitudinal_maneuvers.plant import Plant -from selfdrive.car.honda.values import CruiseButtons -import numpy as np -import cereal.messaging as messaging -import math - -CAR_WIDTH = 2.0 -CAR_LENGTH = 4.5 - -METER = 8 - -def rot_center(image, angle): - """rotate an image while keeping its center and size""" - orig_rect = image.get_rect() - rot_image = pygame.transform.rotate(image, angle) - rot_rect = orig_rect.copy() - rot_rect.center = rot_image.get_rect().center - rot_image = rot_image.subsurface(rot_rect).copy() - return rot_image - -def car_w_color(c): - car = pygame.Surface((METER*CAR_LENGTH, METER*CAR_LENGTH)) # pylint: disable=too-many-function-args - car.set_alpha(0) - car.fill((10,10,10)) - car.set_alpha(128) - pygame.draw.rect(car, c, (METER*1.25, 0, METER*CAR_WIDTH, METER*CAR_LENGTH), 1) - return car - -if __name__ == "__main__": - pygame.init() - display = pygame.display.set_mode((1000, 1000)) - pygame.display.set_caption('Plant UI') - - car = car_w_color((255,0,255)) - leadcar = car_w_color((255,0,0)) - - carx, cary, heading = 10.0, 50.0, 0.0 - - plant = Plant(100, distance_lead = 40.0) - - control_offset = 2.0 - control_pts = list(zip(np.arange(0, 100.0, 10.0), [50.0 + control_offset]*10)) - - def pt_to_car(pt): - x,y = pt - x -= carx - y -= cary - rx = x * math.cos(-heading) + y * -math.sin(-heading) - ry = x * math.sin(-heading) + y * math.cos(-heading) - return rx, ry - - def pt_from_car(pt): - x,y = pt - rx = x * math.cos(heading) + y * -math.sin(heading) - ry = x * math.sin(heading) + y * math.cos(heading) - rx += carx - ry += cary - return rx, ry - - while 1: - if plant.rk.frame%100 >= 20 and plant.rk.frame%100 <= 25: - cruise_buttons = CruiseButtons.RES_ACCEL - else: - cruise_buttons = 0 - - md = messaging.new_message('model') - md.model.frameId = 0 - for x in [md.model.path, md.model.leftLane, md.model.rightLane]: - x.points = [0.0]*50 - x.prob = 0.0 - x.std = 1.0 - - car_pts = [pt_to_car(pt) for pt in control_pts] - - print(car_pts) - - car_poly = np.polyfit([x[0] for x in car_pts], [x[1] for x in car_pts], 3) - md.model.path.points = np.polyval(car_poly, np.arange(0, 50)).tolist() - md.model.path.prob = 1.0 - Plant.model.send(md.to_bytes()) - - plant.step(cruise_buttons = cruise_buttons, v_lead = 2.0, publish_model = False) - - display.fill((10,10,10)) - - carx += plant.speed * plant.ts * math.cos(heading) - cary += plant.speed * plant.ts * math.sin(heading) - - # positive steering angle = steering right - print(plant.angle_steer) - heading += plant.angle_steer * plant.ts - print(heading) - - # draw my car - display.blit(pygame.transform.rotate(car, 90-math.degrees(heading)), (carx*METER, cary*METER)) - - # draw control pts - for x,y in control_pts: - pygame.draw.circle(display, (255,255,0), (int(x * METER),int(y * METER)), 2) - - # draw path - path_pts = zip(np.arange(0, 50), md.model.path.points) - - for x,y in path_pts: - x,y = pt_from_car((x,y)) - pygame.draw.circle(display, (0,255,0), (int(x * METER),int(y * METER)), 1) - - """ - # draw lead car - dl = (plant.distance_lead - plant.distance) + 4.5 - lx = carx + dl * math.cos(heading) - ly = cary + dl * math.sin(heading) - - display.blit(pygame.transform.rotate(leadcar, 90-math.degrees(heading)), (lx*METER, ly*METER)) - """ - - pygame.display.flip() diff --git a/selfdrive/test/process_replay/compare_logs.py b/selfdrive/test/process_replay/compare_logs.py index 731e71672..addcfa931 100755 --- a/selfdrive/test/process_replay/compare_logs.py +++ b/selfdrive/test/process_replay/compare_logs.py @@ -8,7 +8,7 @@ import dictdiffer if "CI" in os.environ: tqdm = lambda x: x else: - from tqdm import tqdm + from tqdm import tqdm # type: ignore from tools.lib.logreader import LogReader diff --git a/selfdrive/test/process_replay/flycheck_compare_logs.py b/selfdrive/test/process_replay/flycheck_compare_logs.py new file mode 100644 index 000000000..addcfa931 --- /dev/null +++ b/selfdrive/test/process_replay/flycheck_compare_logs.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +import bz2 +import os +import sys +import numbers + +import dictdiffer +if "CI" in os.environ: + tqdm = lambda x: x +else: + from tqdm import tqdm # type: ignore + +from tools.lib.logreader import LogReader + +def save_log(dest, log_msgs): + dat = b"" + for msg in tqdm(log_msgs): + dat += msg.as_builder().to_bytes() + dat = bz2.compress(dat) + + with open(dest, "wb") as f: + f.write(dat) + +def remove_ignored_fields(msg, ignore): + msg = msg.as_builder() + for key in ignore: + attr = msg + keys = key.split(".") + if msg.which() not in key and len(keys) > 1: + continue + + for k in keys[:-1]: + try: + attr = getattr(msg, k) + except: + break + else: + v = getattr(attr, keys[-1]) + if isinstance(v, bool): + val = False + elif isinstance(v, numbers.Number): + val = 0 + else: + raise NotImplementedError + setattr(attr, keys[-1], val) + return msg.as_reader() + +def compare_logs(log1, log2, ignore_fields=[], ignore_msgs=[]): + filter_msgs = lambda m: m.which() not in ignore_msgs + log1, log2 = [list(filter(filter_msgs, log)) for log in (log1, log2)] + assert len(log1) == len(log2), "logs are not same length: " + str(len(log1)) + " VS " + str(len(log2)) + + diff = [] + for msg1, msg2 in tqdm(zip(log1, log2)): + if msg1.which() != msg2.which(): + print(msg1, msg2) + raise Exception("msgs not aligned between logs") + + msg1_bytes = remove_ignored_fields(msg1, ignore_fields).as_builder().to_bytes() + msg2_bytes = remove_ignored_fields(msg2, ignore_fields).as_builder().to_bytes() + + if msg1_bytes != msg2_bytes: + msg1_dict = msg1.to_dict(verbose=True) + msg2_dict = msg2.to_dict(verbose=True) + dd = dictdiffer.diff(msg1_dict, msg2_dict, ignore=ignore_fields, tolerance=0) + diff.extend(dd) + return diff + +if __name__ == "__main__": + log1 = list(LogReader(sys.argv[1])) + log2 = list(LogReader(sys.argv[2])) + print(compare_logs(log1, log2, sys.argv[3:])) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 2687b2421..46eb5a09e 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -7,7 +7,7 @@ import importlib if "CI" in os.environ: tqdm = lambda x: x else: - from tqdm import tqdm + from tqdm import tqdm # type: ignore from cereal import car, log from selfdrive.car.car_helpers import get_car diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 06f1b9bcd..c4315bfc5 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -2,13 +2,14 @@ import argparse import os import sys +from typing import Any from selfdrive.car.car_helpers import interface_names -from selfdrive.test.process_replay.process_replay import replay_process, CONFIGS from selfdrive.test.process_replay.compare_logs import compare_logs +from selfdrive.test.process_replay.process_replay import (CONFIGS, + replay_process) from tools.lib.logreader import LogReader - INJECT_MODEL = 0 segments = [ @@ -134,7 +135,7 @@ if __name__ == "__main__": untested = (set(interface_names) - set(excluded_interfaces)) - tested_cars assert len(untested) == 0, "Cars missing routes: %s" % (str(untested)) - results = {} + results: Any = {} for car_brand, segment in segments: if (cars_whitelisted and car_brand.upper() not in args.whitelist_cars) or \ (not cars_whitelisted and car_brand.upper() in args.blacklist_cars): diff --git a/selfdrive/test/test_car_models.py b/selfdrive/test/test_car_models.py index 954f20418..685cb485f 100755 --- a/selfdrive/test/test_car_models.py +++ b/selfdrive/test/test_car_models.py @@ -1,27 +1,28 @@ #!/usr/bin/env python3 -import time import os -import sys import signal import subprocess +import sys +import time +from typing import List, cast + import requests -from cereal import car -import selfdrive.manager as manager import cereal.messaging as messaging -from common.params import Params +import selfdrive.manager as manager +from cereal import car from common.basedir import BASEDIR -from selfdrive.car.fingerprints import all_known_cars -from selfdrive.car.honda.values import CAR as HONDA -from selfdrive.car.toyota.values import CAR as TOYOTA -from selfdrive.car.gm.values import CAR as GM -from selfdrive.car.ford.values import CAR as FORD -from selfdrive.car.hyundai.values import CAR as HYUNDAI +from common.params import Params from selfdrive.car.chrysler.values import CAR as CHRYSLER -from selfdrive.car.subaru.values import CAR as SUBARU -from selfdrive.car.volkswagen.values import CAR as VOLKSWAGEN +from selfdrive.car.fingerprints import all_known_cars +from selfdrive.car.ford.values import CAR as FORD +from selfdrive.car.gm.values import CAR as GM +from selfdrive.car.honda.values import CAR as HONDA +from selfdrive.car.hyundai.values import CAR as HYUNDAI from selfdrive.car.nissan.values import CAR as NISSAN - +from selfdrive.car.subaru.values import CAR as SUBARU +from selfdrive.car.toyota.values import CAR as TOYOTA +from selfdrive.car.volkswagen.values import CAR as VOLKSWAGEN os.environ['NOCRASH'] = '1' @@ -363,7 +364,7 @@ routes = { }, } -passive_routes = [ +passive_routes: List[str] = [ ] forced_dashcam_routes = [ @@ -436,7 +437,7 @@ if __name__ == "__main__": os.environ['SKIP_FW_QUERY'] = "1" if checks.get('fingerprintSource', None) == 'fixed': - os.environ['FINGERPRINT'] = checks['carFingerprint'] + os.environ['FINGERPRINT'] = cast(str, checks['carFingerprint']) else: os.environ['FINGERPRINT'] = "" diff --git a/tools/lib/auth.py b/tools/lib/auth.py index 57e0eb0ae..870eb6b0b 100755 --- a/tools/lib/auth.py +++ b/tools/lib/auth.py @@ -5,9 +5,10 @@ from http.server import HTTPServer, BaseHTTPRequestHandler from urllib.parse import urlencode, parse_qs from tools.lib.api import CommaApi, APIError from tools.lib.auth_config import set_token +from typing import Dict, Any class ClientRedirectServer(HTTPServer): - query_params = {} + query_params: Dict[str, Any] = {} class ClientRedirectHandler(BaseHTTPRequestHandler): def do_GET(self): diff --git a/tools/replay/lib/ui_helpers.py b/tools/replay/lib/ui_helpers.py index 8aaf40afc..4debec40e 100644 --- a/tools/replay/lib/ui_helpers.py +++ b/tools/replay/lib/ui_helpers.py @@ -1,15 +1,16 @@ from collections import namedtuple +from typing import Any, Dict, Tuple import matplotlib import matplotlib.pyplot as plt import numpy as np import pygame -from tools.lib.lazy_property import lazy_property -from selfdrive.config import UIParams as UP from selfdrive.config import RADAR_TO_CAMERA +from selfdrive.config import UIParams as UP from selfdrive.controls.lib.lane_planner import (compute_path_pinv, model_polyfit) +from tools.lib.lazy_property import lazy_property RED = (255, 0, 0) GREEN = (0, 255, 0) @@ -34,7 +35,7 @@ METER_WIDTH = 20 ModelUIData = namedtuple("ModelUIData", ["cpath", "lpath", "rpath", "lead", "lead_future"]) -_COLOR_CACHE = {} +_COLOR_CACHE : Dict[Tuple[int, int, int], Any] = {} def find_color(lidar_surface, color): if color in _COLOR_CACHE: return _COLOR_CACHE[color] diff --git a/tools/replay/rqplot.py b/tools/replay/rqplot.py index 3c3c5239c..8886cf7f3 100755 --- a/tools/replay/rqplot.py +++ b/tools/replay/rqplot.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# type: ignore import sys import matplotlib.pyplot as plt import numpy as np @@ -78,4 +79,3 @@ if __name__ == "__main__": # just a bit of wait to avoid 100% CPU usage time.sleep(0.001) - diff --git a/tools/sim/bridge.py b/tools/sim/bridge.py index b3857683c..b0ea6fa7c 100755 --- a/tools/sim/bridge.py +++ b/tools/sim/bridge.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# type: ignore import time import math import atexit diff --git a/tools/sim/lib/keyboard_ctrl.py b/tools/sim/lib/keyboard_ctrl.py index 84436d538..18a491fec 100644 --- a/tools/sim/lib/keyboard_ctrl.py +++ b/tools/sim/lib/keyboard_ctrl.py @@ -1,8 +1,9 @@ import sys import termios import time -from termios import (BRKINT, VMIN, CS8, CSIZE, ECHO, ICANON, ICRNL, IEXTEN, - INPCK, ISIG, ISTRIP, IXON, PARENB, VTIME) +from termios import (BRKINT, CS8, CSIZE, ECHO, ICANON, ICRNL, IEXTEN, INPCK, + ISIG, ISTRIP, IXON, PARENB, VMIN, VTIME) +from typing import Any # Indexes for termios list. IFLAG = 0 @@ -53,7 +54,7 @@ def test(q): if __name__ == '__main__': from multiprocessing import Process, Queue - q = Queue() + q : Any = Queue() p = Process(target=test, args=(q,)) p.daemon = True p.start()