From 8d19757f8e679527cf22bba21f631191a2856e26 Mon Sep 17 00:00:00 2001 From: iphydf Date: Fri, 14 Jan 2022 13:03:32 +0000 Subject: [PATCH] chore: Add mypy Python type check. Also fix the types in all Python files. --- .github/settings.yml | 4 ++ .github/workflows/ci.yml | 17 ++++++ .github/workflows/sonar-scan.yml | 1 - other/analysis/check_recursion | 16 ++--- other/bootstrap_daemon/docker/get-nodes.py | 38 ++++++------ other/fun/bootstrap_node_info.py | 21 +++---- other/fun/make-funny-savefile.py | 69 +++++++++------------- 7 files changed, 88 insertions(+), 78 deletions(-) diff --git a/.github/settings.yml b/.github/settings.yml index 64e7d1d5..8f2c7932 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -17,6 +17,7 @@ branches: - "bazel-msan" - "bazel-release" - "bazel-tsan" + - "bazel-valgrind" - "build-bootstrapd-docker" - "build-compcert" - "build-macos" @@ -30,11 +31,14 @@ branches: - "ci/circleci: clang-analyze" - "ci/circleci: clang-tidy" - "ci/circleci: infer" + - "ci/circleci: msan" - "ci/circleci: static-analysis" - "ci/circleci: tsan" - "cimple" - "code-review/reviewable" - "continuous-integration/appveyor/pr" + - "mypy" + - "sonar-scan" # Labels specific to c-toxcore. labels: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 497f668f..64deab83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,23 @@ on: branches: [master] jobs: + mypy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.9 + uses: actions/setup-python@v1 + with: + python-version: 3.9 + - name: Install mypy + run: pip install mypy + - name: Run mypy + run: | + mypy --strict \ + $(echo $(find . -name "*.py" -and -not -name "conanfile.py") \ + $(grep -lR '^#!.*python3' .) \ + | tr ' ' '\n' | sort -u | tr '\n' ' ') + build-msan: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml index 86d5290f..a845a11d 100644 --- a/.github/workflows/sonar-scan.yml +++ b/.github/workflows/sonar-scan.yml @@ -8,7 +8,6 @@ on: jobs: sonar-scan: - name: Build runs-on: ubuntu-latest env: SONAR_SCANNER_VERSION: 4.4.0.2170 diff --git a/other/analysis/check_recursion b/other/analysis/check_recursion index a8a6e0ef..28dd5746 100755 --- a/other/analysis/check_recursion +++ b/other/analysis/check_recursion @@ -20,7 +20,7 @@ from typing import List from typing import Set -def load_callgraph() -> Dict: +def load_callgraph() -> Dict[str, List[str]]: """ Parses the output from opt -print-callgraph from stdin or argv. @@ -42,10 +42,10 @@ def load_callgraph() -> Dict: def walk( - visited: Set, - callgraph: Dict, - cycles: Set, - stack: List, + visited: Set[str], + callgraph: Dict[str, List[str]], + cycles: Set[str], + stack: List[str], cur: str, ) -> None: """ @@ -70,7 +70,7 @@ def get_time() -> int: return int(round(time.time() * 1000)) -def find_recursion(expected: Set) -> None: +def find_recursion(expected: Set[str]) -> None: """ Main function: detects cycles and prints them. @@ -85,8 +85,8 @@ def find_recursion(expected: Set) -> None: print("[+%04d=%04d] Finding recursion" % (now - prev, now - start)) prev = now - cycles = set() - visited = set() + cycles: Set[str] = set() + visited: Set[str] = set() for func in sorted(callgraph.keys()): walk(visited, callgraph, cycles, [], func) diff --git a/other/bootstrap_daemon/docker/get-nodes.py b/other/bootstrap_daemon/docker/get-nodes.py index f38bd492..f6ff483a 100755 --- a/other/bootstrap_daemon/docker/get-nodes.py +++ b/other/bootstrap_daemon/docker/get-nodes.py @@ -20,36 +20,36 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ - # Gets a list of nodes from https://nodes.tox.chat/json and prints them out # in the format of tox-bootstrapd config file. - import json import sys import urllib.request +from typing import Dict -response = urllib.request.urlopen('https://nodes.tox.chat/json') -raw_json = response.read().decode('ascii', 'ignore') -nodes = json.loads(raw_json)['nodes'] +response = urllib.request.urlopen("https://nodes.tox.chat/json") +raw_json = response.read().decode("ascii", "ignore") +nodes = json.loads(raw_json)["nodes"] -def node_to_string(node): - node_output = ' { // ' + node['maintainer'] + '\n' - node_output += ' public_key = "' + node['public_key'] + '"\n' - node_output += ' port = ' + str(node['port']) + '\n' + +def node_to_string(node: Dict[str, str]) -> str: + node_output = " { // " + node["maintainer"] + "\n" + node_output += ' public_key = "' + node["public_key"] + '"\n' + node_output += " port = " + str(node["port"]) + "\n" node_output += ' address = "' - if len(node['ipv4']) > 4: - return node_output + node['ipv4'] + '"\n }' - if len(node['ipv6']) > 4: - return node_output + node['ipv6'] + '"\n }' - raise Exception('no IP address found for node ' + json.dumps(node)) + if len(node["ipv4"]) > 4: + return node_output + node["ipv4"] + '"\n }' + if len(node["ipv6"]) > 4: + return node_output + node["ipv6"] + '"\n }' + raise Exception("no IP address found for node " + json.dumps(node)) -output = ('bootstrap_nodes = (\n' + - ',\n'.join(map(node_to_string, nodes)) + - '\n)') + +output = "bootstrap_nodes = (\n" + ",\n".join(map(node_to_string, + nodes)) + "\n)" if len(sys.argv) > 1: - with open(sys.argv[1], 'a') as fh: - fh.write(output + '\n') + with open(sys.argv[1], "a") as fh: + fh.write(output + "\n") print("Wrote %d nodes to %s" % (len(nodes), sys.argv[1])) else: print(output) diff --git a/other/fun/bootstrap_node_info.py b/other/fun/bootstrap_node_info.py index 5cf09166..61ac4d16 100755 --- a/other/fun/bootstrap_node_info.py +++ b/other/fun/bootstrap_node_info.py @@ -28,14 +28,14 @@ if sys.version_info[0] == 2: sys.exit(1) -def print_help() -> None: +def print_help(prog: str) -> None: """Print program usage to stdout.""" - print("Usage: " + sys.argv[0] + " ") - print(" Example: " + sys.argv[0] + " ipv4 192.210.149.121 33445") - print(" Example: " + sys.argv[0] + " ipv4 23.226.230.47 33445") - print(" Example: " + sys.argv[0] + " ipv4 node.tox.biribiri.org 33445") - print(" Example: " + sys.argv[0] + " ipv4 cerberus.zodiaclabs.org 33445") - print(" Example: " + sys.argv[0] + " ipv6 2604:180:1::3ded:b280 33445") + print(f"Usage: {prog} ") + print(f" Example: {prog} ipv4 192.210.149.121 33445") + print(f" Example: {prog} ipv4 23.226.230.47 33445") + print(f" Example: {prog} ipv4 node.tox.biribiri.org 33445") + print(f" Example: {prog} ipv4 cerberus.zodiaclabs.org 33445") + print(f" Example: {prog} ipv6 2604:180:1::3ded:b280 33445") print("") print("Return values:") print(" 0 - received info reply from a node") @@ -64,7 +64,7 @@ MAX_INFO_RESPONSE_PACKET_LENGTH = PACKET_ID_LENGTH + VERSION_LENGTH + MAX_MOTD_L SOCK_TIMEOUT_SECONDS = 1.0 -def main(protocol: str, host: str, port: int) -> None: +def main(prog: str, protocol: str, host: str, port: int) -> None: """Call the bootstrap node info RPC and output the response.""" if protocol == "ipv4": sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -72,7 +72,7 @@ def main(protocol: str, host: str, port: int) -> None: sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) else: print("Invalid first argument") - print_help() + print_help(prog) sys.exit(1) sock.sendto(INFO_REQUEST_PACKET, (host, port)) @@ -111,10 +111,11 @@ def main(protocol: str, host: str, port: int) -> None: if __name__ == "__main__": if len(sys.argv) != 4: - print_help() + print_help(sys.argv[0]) sys.exit(1) main( + prog=sys.argv[0], protocol=sys.argv[1], host=sys.argv[2], port=int(sys.argv[3]), diff --git a/other/fun/make-funny-savefile.py b/other/fun/make-funny-savefile.py index ccdf7217..59d3deff 100755 --- a/other/fun/make-funny-savefile.py +++ b/other/fun/make-funny-savefile.py @@ -1,5 +1,4 @@ #!/usr/bin/python - """ Generate a new (and empty) save file with predefined keys. Used to play with externally generated keys. @@ -30,47 +29,44 @@ Example (of course, do not try using this key for anything real): """ - +import os +import struct +import sys PUBLIC_KEY_LENGTH = 32 PRIVATE_KEY_LENGTH = 32 # Constants taken from messenger.c -MESSENGER_STATE_COOKIE_GLOBAL = 0x15ed1b1f -MESSENGER_STATE_COOKIE_TYPE = 0x01ce -MESSENGER_STATE_TYPE_NOSPAMKEYS = 1 -MESSENGER_STATE_TYPE_DHT = 2 -MESSENGER_STATE_TYPE_FRIENDS = 3 -MESSENGER_STATE_TYPE_NAME = 4 -MESSENGER_STATE_TYPE_STATUSMESSAGE = 5 -MESSENGER_STATE_TYPE_STATUS = 6 -MESSENGER_STATE_TYPE_TCP_RELAY = 10 -MESSENGER_STATE_TYPE_PATH_NODE = 11 +MESSENGER_STATE_COOKIE_GLOBAL = 0x15ED1B1F +MESSENGER_STATE_COOKIE_TYPE = 0x01CE +MESSENGER_STATE_TYPE_NOSPAMKEYS = 1 +MESSENGER_STATE_TYPE_DHT = 2 +MESSENGER_STATE_TYPE_FRIENDS = 3 +MESSENGER_STATE_TYPE_NAME = 4 +MESSENGER_STATE_TYPE_STATUSMESSAGE = 5 +MESSENGER_STATE_TYPE_STATUS = 6 +MESSENGER_STATE_TYPE_TCP_RELAY = 10 +MESSENGER_STATE_TYPE_PATH_NODE = 11 STATUS_MESSAGE = "New user".encode("utf-8") - -import sys -import struct -import os - -def abort(msg): +def abort(msg: str) -> None: print(msg) exit(1) - if len(sys.argv) != 5: - abort("Usage: %s " % (sys.argv[0])) + abort("Usage: %s " % + (sys.argv[0])) try: - public_key = sys.argv[1].decode("hex") + public_key = bytes.fromhex(sys.argv[1]) except: abort("Bad public key") try: - private_key = sys.argv[2].decode("hex") + private_key = bytes.fromhex(sys.argv[2]) except: abort("Bad private key") @@ -89,31 +85,24 @@ out_file_name = sys.argv[4] nospam = os.urandom(4) -def make_subheader(h_type, h_length): - return ( - struct.pack(" bytes: + return (struct.pack("