chore: Add mypy Python type check.

Also fix the types in all Python files.
This commit is contained in:
iphydf 2022-01-14 13:03:32 +00:00
parent 62cbd5f667
commit 8d19757f8e
No known key found for this signature in database
GPG Key ID: 3855DBA2D74403C9
7 changed files with 88 additions and 78 deletions

View File

@ -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:

View File

@ -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:

View File

@ -8,7 +8,6 @@ on:
jobs:
sonar-scan:
name: Build
runs-on: ubuntu-latest
env:
SONAR_SCANNER_VERSION: 4.4.0.2170

View File

@ -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)

View File

@ -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)

View File

@ -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] + " <ipv4|ipv6> <ip/hostname> <port>")
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} <ipv4|ipv6> <ip/hostname> <port>")
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]),

View File

@ -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 <public key> <private key> <user name> <out file>" % (sys.argv[0]))
abort("Usage: %s <public key> <private key> <user name> <out file>" %
(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("<I", h_length) +
struct.pack("<H", h_type) +
struct.pack("<H", MESSENGER_STATE_COOKIE_TYPE))
def make_subheader(h_type: int, h_length: int) -> bytes:
return (struct.pack("<I", h_length) + struct.pack("<H", h_type) +
struct.pack("<H", MESSENGER_STATE_COOKIE_TYPE))
data = (
# Main header
struct.pack("<I", 0) +
struct.pack("<I", MESSENGER_STATE_COOKIE_GLOBAL) +
struct.pack("<I", 0) + struct.pack("<I", MESSENGER_STATE_COOKIE_GLOBAL) +
# Keys
make_subheader(MESSENGER_STATE_TYPE_NOSPAMKEYS,
len(nospam) + PUBLIC_KEY_LENGTH + PRIVATE_KEY_LENGTH) +
nospam + public_key + private_key +
make_subheader(
MESSENGER_STATE_TYPE_NOSPAMKEYS,
len(nospam) + PUBLIC_KEY_LENGTH + PRIVATE_KEY_LENGTH,
) + nospam + public_key + private_key +
# Name (not really needed, but helps)
make_subheader(MESSENGER_STATE_TYPE_NAME, len(user_name)) +
user_name +
make_subheader(MESSENGER_STATE_TYPE_NAME, len(user_name)) + user_name +
# Status message (not really needed, but helps)
make_subheader(MESSENGER_STATE_TYPE_STATUSMESSAGE, len(STATUS_MESSAGE)) +
STATUS_MESSAGE
)
STATUS_MESSAGE)
try:
with open(out_file_name, "wb") as fp: