From a8a9c6878bf51ffea8cfe9c063efa2af4cbb3474 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 22 Oct 2024 11:44:20 +0100 Subject: [PATCH 01/18] assert not None --- spinnman/transceiver/base_transceiver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/spinnman/transceiver/base_transceiver.py b/spinnman/transceiver/base_transceiver.py index 89c5bf8d6..30b13a2eb 100644 --- a/spinnman/transceiver/base_transceiver.py +++ b/spinnman/transceiver/base_transceiver.py @@ -1146,6 +1146,7 @@ def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False): for connection in connections: # Convert the host string host_string = ip_tag.ip_address + assert host_string is not None if host_string in ("localhost", ".", "0.0.0.0"): host_string = connection.local_ip_address ip_string = socket.gethostbyname(host_string) From 00750e55e6a6bfbd7077418f362fadb1d23b0d23 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 22 Oct 2024 12:08:43 +0100 Subject: [PATCH 02/18] stricter mypy in bash files --- mypy.bash | 2 +- mypyd.bash | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100755 mypyd.bash diff --git a/mypy.bash b/mypy.bash index 918ce5e9a..3d0ddb5b9 100755 --- a/mypy.bash +++ b/mypy.bash @@ -22,4 +22,4 @@ utils="../SpiNNUtils/spinn_utilities" machine="../SpiNNMachine/spinn_machine" -mypy --python-version 3.8 $utils $machine spinnman +mypy --python-version 3.8 $utils $machine spinnman unittests diff --git a/mypyd.bash b/mypyd.bash new file mode 100755 index 000000000..3c6d7a73d --- /dev/null +++ b/mypyd.bash @@ -0,0 +1,25 @@ +#!/bin/bash + +# Copyright (c) 2024 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This bash assumes that other repositories are installed in paralled + +# requires the latest mypy +# pip install --upgrade mypy + +utils="../SpiNNUtils/spinn_utilities" +machine="../SpiNNMachine/spinn_machine" + +mypy --python-version 3.8 --disallow-untyped-defs $utils $machine spinnman From 8e9875b5fa647df2f33f71030901249eb4dfe749 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 22 Oct 2024 16:32:46 +0100 Subject: [PATCH 03/18] typing --- spinnman/config_setup.py | 4 +- spinnman/data/spinnman_data_writer.py | 2 +- spinnman/get_cores_in_run_state.py | 32 +++++++----- spinnman/spalloc/spalloc_boot_connection.py | 2 +- spinnman/spalloc/spalloc_client.py | 54 ++++++++++---------- spinnman/spalloc/spalloc_eieio_connection.py | 8 +-- spinnman/spalloc/spalloc_eieio_listener.py | 15 +++--- spinnman/spalloc/spalloc_job.py | 16 +++--- spinnman/spalloc/spalloc_scp_connection.py | 4 +- 9 files changed, 75 insertions(+), 62 deletions(-) diff --git a/spinnman/config_setup.py b/spinnman/config_setup.py index 9a13d44be..9357cbb1b 100644 --- a/spinnman/config_setup.py +++ b/spinnman/config_setup.py @@ -21,7 +21,7 @@ BASE_CONFIG_FILE = "spinnman.cfg" -def unittest_setup(): +def unittest_setup() -> None: """ Resets the configurations so only the local default configuration is included. @@ -34,7 +34,7 @@ def unittest_setup(): SpiNNManDataWriter.mock() -def add_spinnman_cfg(): +def add_spinnman_cfg() -> None: """ Add the local configuration and all dependent configuration files. """ diff --git a/spinnman/data/spinnman_data_writer.py b/spinnman/data/spinnman_data_writer.py index 8cc7d8c97..ee277158b 100644 --- a/spinnman/data/spinnman_data_writer.py +++ b/spinnman/data/spinnman_data_writer.py @@ -94,7 +94,7 @@ def _soft_reset(self) -> None: MachineDataWriter._soft_reset(self) self._local_soft_reset() - def set_transceiver(self, transceiver: Transceiver): + def set_transceiver(self, transceiver: Transceiver) -> None: """ Sets the transceiver object. diff --git a/spinnman/get_cores_in_run_state.py b/spinnman/get_cores_in_run_state.py index 2c55a2c55..3cd291b27 100644 --- a/spinnman/get_cores_in_run_state.py +++ b/spinnman/get_cores_in_run_state.py @@ -18,6 +18,7 @@ import argparse import sys +from typing import List, Optional from spinn_utilities.config_holder import set_config from spinn_machine import CoreSubsets, CoreSubset @@ -31,7 +32,8 @@ IGNORED_IDS = {SCAMP_ID, 16} # WHY 16? -def get_cores_in_run_state(txrx, app_id, print_all_chips): +def get_cores_in_run_state( + txrx: Transceiver, app_id: int, print_all_chips: bool) -> None: """ :param Transceiver txrx: :param int app_id: @@ -51,27 +53,28 @@ def get_cores_in_run_state(txrx, app_id, print_all_chips): all_cores.append(CoreSubset( chip.x, chip.y, chip.placable_processors_ids)) - all_cores = CoreSubsets(core_subsets=all_cores) + all_cores_subsets = CoreSubsets(core_subsets=all_cores) cpu_infos = txrx.get_cpu_infos( - all_cores, + all_cores_subsets, [CPUState.FINISHED, CPUState.RUNNING, CPUState.WATCHDOG], True) cores_finished = cpu_infos.infos_for_state(CPUState.FINISHED) cores_running = cpu_infos.infos_for_state(CPUState.RUNNING) cores_watchdog = cpu_infos.infos_for_state(CPUState.WATCHDOG) - for (x, y, p), _ in cores_running: + for x, y, p in cores_running: if p not in IGNORED_IDS: print(f'run core: {x} {y} {p}') - for (x, y, p), _ in cores_finished: + for x, y, p in cores_finished: print(f'finished core: {x} {y} {p}') - for (x, y, p), _ in cores_watchdog: + for x, y, p in cores_watchdog: print(f'watchdog core: {x} {y} {p}') -def _make_transceiver(host, version, bmp_names) -> Transceiver: +def _make_transceiver(host: Optional[str], version: Optional[int], + bmp_names: Optional[str]) -> Transceiver: """ :param host: Host to use or `None` to use test configuration for all parameters @@ -97,15 +100,17 @@ def _make_transceiver(host, version, bmp_names) -> Transceiver: else: version = 5 auto_detect_bmp = False - set_config("Machine", "version", version) + set_config("Machine", "version", str(version)) print(f"talking to SpiNNaker system at {host}") + # TODO https://github.com/SpiNNakerManchester/SpiNNMan/issues/423 + assert bmp_names is None return create_transceiver_from_hostname( host, bmp_connection_data=bmp_names, auto_detect_bmp=auto_detect_bmp) -def main(args): +def main(args: List[str]) -> None: """ Runs the script. """ @@ -130,12 +135,13 @@ def main(args): ap.add_argument( "host", default=None, nargs='?', help="the hostname or IP address of the SpiNNaker machine to inspect") - args = ap.parse_args(args) + _args: argparse.Namespace = ap.parse_args(args) # These ought to be parsed from command line arguments - app_id = args.appid - print_chips = not args.noprintchips + app_id = _args.appid + print_chips = not _args.noprintchips - transceiver = _make_transceiver(args.host, args.version, args.bmp_names) + transceiver = _make_transceiver( + _args.host, _args.version, _args.bmp_names) try: get_cores_in_run_state(transceiver, app_id, print_chips) finally: diff --git a/spinnman/spalloc/spalloc_boot_connection.py b/spinnman/spalloc/spalloc_boot_connection.py index 0a2c30a2c..182fb8583 100644 --- a/spinnman/spalloc/spalloc_boot_connection.py +++ b/spinnman/spalloc/spalloc_boot_connection.py @@ -45,7 +45,7 @@ class SpallocBootConnection( __slots__ = () @overrides(BootConnection.send_boot_message) - def send_boot_message(self, boot_message: SpinnakerBootMessage): + def send_boot_message(self, boot_message: SpinnakerBootMessage) -> None: self.send(boot_message.bytestring) # Sleep between messages to avoid flooding the machine diff --git a/spinnman/spalloc/spalloc_client.py b/spinnman/spalloc/spalloc_client.py index 53c036710..6ec12fcfb 100644 --- a/spinnman/spalloc/spalloc_client.py +++ b/spinnman/spalloc/spalloc_client.py @@ -151,7 +151,8 @@ def get_job(self, job_id: str) -> SpallocJob: @staticmethod def open_job_from_database( - service_url, job_url, cookies, headers) -> SpallocJob: + service_url: str, job_url: str, cookies: Dict[str, str], + headers: Dict[str, str]) -> SpallocJob: """ Create a job from the description in the attached database. This is intended to allow for access to the job's allocated resources from @@ -365,7 +366,7 @@ def dead_links(self) -> list: def area(self) -> Tuple[int, int]: return (self.width, self.height) - def __repr__(self): + def __repr__(self) -> str: return "SpallocMachine" + str(( self.name, self.tags, self.width, self.height, self.dead_boards, self.dead_links)) @@ -376,14 +377,14 @@ class _ProxyPing(threading.Thread): Sends ping messages to an open websocket """ - def __init__(self, ws, sleep_time=30): + def __init__(self, ws: WebSocket, sleep_time: int = 30): super().__init__(daemon=True) self.__ws = ws self.__sleep_time = sleep_time self.__closed = False self.start() - def run(self): + def run(self) -> None: """ The handler loop of this thread """ @@ -399,7 +400,7 @@ def run(self): logger.exception("Error in websocket before close") sleep(self.__sleep_time) - def close(self): + def close(self) -> None: """ Mark as closed to avoid error messages. """ @@ -467,13 +468,13 @@ def expect_return(self, handler: _WSCB) -> int: self.__returns[c] = handler return c - def listen(self, channel_id: int, handler: _WSCB): + def listen(self, channel_id: int, handler: _WSCB) -> None: """ Register a persistent listener for one-way messages. """ self.__handlers[channel_id] = handler - def dispatch_return(self, correlation_id: int, msg: bytes): + def dispatch_return(self, correlation_id: int, msg: bytes) -> None: """ Dispatch a received call-return message. """ @@ -481,7 +482,7 @@ def dispatch_return(self, correlation_id: int, msg: bytes): if handler: handler(msg) - def dispatch_message(self, channel_id: int, msg: bytes): + def dispatch_message(self, channel_id: int, msg: bytes) -> None: """ Dispatch a received one-way message. """ @@ -489,7 +490,7 @@ def dispatch_message(self, channel_id: int, msg: bytes): if handler: handler(msg) - def unlisten(self, channel_id: int): + def unlisten(self, channel_id: int) -> None: """ Deregister a listener for a channel """ @@ -643,7 +644,7 @@ def wait_for_state_change(self, old_state: SpallocState, @overrides(SpallocJob.wait_until_ready) def wait_until_ready(self, timeout: Optional[int] = None, - n_retries: Optional[int] = None): + n_retries: Optional[int] = None) -> None: state = self.get_state() retries = 0 while (state != SpallocState.READY and @@ -654,7 +655,7 @@ def wait_until_ready(self, timeout: Optional[int] = None, raise SpallocException("job was unexpectedly destroyed") @overrides(SpallocJob.destroy) - def destroy(self, reason: str = "finished"): + def destroy(self, reason: str = "finished") -> None: self._keepalive_url = None if self.__proxy_handle is not None: if self.__proxy_thread: @@ -711,7 +712,7 @@ def create_transceiver(self) -> Transceiver: proxies.append(self.connect_for_booting()) return create_transceiver_from_connections(connections=proxies) - def __repr__(self): + def __repr__(self) -> str: return f"SpallocJob({self._url})" @@ -739,7 +740,7 @@ def _open_connection(self) -> int: raise NotImplementedError def _call(self, protocol: ProxyProtocol, packer: struct.Struct, - unpacker: struct.Struct, *args) -> Tuple[Any, ...]: + unpacker: struct.Struct, *args: int) -> Tuple[Any, ...]: """ Do a synchronous call. @@ -804,7 +805,7 @@ def _close(self) -> None: self.__ws = None self.__receiver = None - def _send(self, message: bytes): + def _send(self, message: bytes) -> None: self._throw_if_closed() # Put the header on the front and send it if not self.__ws: @@ -812,7 +813,7 @@ def _send(self, message: bytes): self.__ws.send_binary(_msg.pack( ProxyProtocol.MSG, self.__handle) + message) - def _send_to(self, message: bytes, x: int, y: int, port: int): + def _send_to(self, message: bytes, x: int, y: int, port: int) -> None: self._throw_if_closed() # Put the header on the front and send it if not self.__ws: @@ -897,7 +898,7 @@ def close(self) -> None: self._close() @overrides(SpallocProxiedConnection.send) - def send(self, data: bytes): + def send(self, data: bytes) -> None: if not isinstance(data, (bytes, bytearray)): data = bytes(data) self._send(data) @@ -961,7 +962,7 @@ def close(self) -> None: self._close() @overrides(SpallocProxiedConnection.send) - def send(self, data: bytes): + def send(self, data: bytes) -> None: self._throw_if_closed() raise IOError("socket is not open for sending") @@ -988,7 +989,7 @@ def __init__( super().__init__(ws, receiver, x, y, port) SpallocSCPConnection.__init__(self, x, y) - def __str__(self): + def __str__(self) -> str: return f"SCAMPConnection[proxied]({self.chip_x},{self.chip_y})" @@ -999,7 +1000,7 @@ class _ProxiedBootConnection( def __init__(self, ws: WebSocket, receiver: _ProxyReceiver): super().__init__(ws, receiver, 0, 0, UDP_BOOT_CONNECTION_DEFAULT_PORT) - def __str__(self): + def __str__(self) -> str: return "BootConnection[proxied]()" @@ -1023,14 +1024,15 @@ def _coords(self) -> XY: def send_to( self, - data: bytes, address: tuple): # pylint: disable=unused-argument + data: bytes, address: tuple # pylint: disable=unused-argument + ) -> None: """ Direct ``send_to`` is unsupported. """ self._throw_if_closed() raise IOError("socket is not open for sending") - def __str__(self): + def __str__(self) -> str: return (f"EIEIOConnection[proxied](remote:{self.__chip_x}," f"{self.__chip_y})") @@ -1045,8 +1047,8 @@ def __init__(self, ws: WebSocket, receiver: _ProxyReceiver, self.__conns = {ip: xy for (xy, ip) in conns.items()} @overrides(SpallocEIEIOListener.send_to_chip) - def send_to_chip( - self, message: bytes, x: int, y: int, port: int = SCP_SCAMP_PORT): + def send_to_chip(self, message: bytes, x: int, y: int, + port: int = SCP_SCAMP_PORT) -> None: if not isinstance(message, (bytes, bytearray)): message = bytes(message) self._send_to(bytes(message), x, y, port) @@ -1065,7 +1067,7 @@ def local_port(self) -> int: def _get_chip_coords(self, ip_address: str) -> XY: return self.__conns[str(ip_address)] - def __str__(self): + def __str__(self) -> str: return f"EIEIOConnection[proxied](local:{self._addr}:{self._port})" @@ -1079,7 +1081,7 @@ def __init__(self, ws: WebSocket, receiver: _ProxyReceiver, self.__conns = {ip: xy for (xy, ip) in conns.items()} @overrides(UDPConnection.send_to) - def send_to(self, data: bytes, address: Tuple[str, int]): + def send_to(self, data: bytes, address: Tuple[str, int]) -> None: ip, port = address x, y = self.__conns[ip] self._send_to(data, x, y, port) @@ -1094,5 +1096,5 @@ def local_ip_address(self) -> str: def local_port(self) -> int: return self._port or 0 - def __str__(self): + def __str__(self) -> str: return f"UDPConnection[proxied](local:{self._addr}:{self._port})" diff --git a/spinnman/spalloc/spalloc_eieio_connection.py b/spinnman/spalloc/spalloc_eieio_connection.py index 6cfbb063a..4ed9c6603 100644 --- a/spinnman/spalloc/spalloc_eieio_connection.py +++ b/spinnman/spalloc/spalloc_eieio_connection.py @@ -45,12 +45,12 @@ class SpallocEIEIOConnection( __slots__ = () @overrides(EIEIOConnection.send_eieio_message) - def send_eieio_message(self, eieio_message: AbstractEIEIOMessage): + def send_eieio_message(self, eieio_message: AbstractEIEIOMessage) -> None: # Not normally used, as packets need headers to go to SpiNNaker self.send(eieio_message.bytestring) - def send_eieio_message_to_core( - self, eieio_message: AbstractEIEIOMessage, x: int, y: int, p: int): + def send_eieio_message_to_core(self, eieio_message: AbstractEIEIOMessage, + x: int, y: int, p: int) -> None: """ :param AbstractEIEIOMessage eieio_message: @@ -88,7 +88,7 @@ def _coords(self) -> XY: """ raise NotImplementedError - def update_tag(self, tag: int, do_receive: bool = True): + def update_tag(self, tag: int, do_receive: bool = True) -> None: """ Update the given tag on the connected Ethernet-enabled chip to send messages to this connection. diff --git a/spinnman/spalloc/spalloc_eieio_listener.py b/spinnman/spalloc/spalloc_eieio_listener.py index 9e7e2b94a..c825001c3 100644 --- a/spinnman/spalloc/spalloc_eieio_listener.py +++ b/spinnman/spalloc/spalloc_eieio_listener.py @@ -57,7 +57,7 @@ def receive_eieio_message( return read_eieio_data_message(data, 0) @overrides(SpallocProxiedConnection.send) - def send(self, data: bytes): + def send(self, data: bytes) -> None: """ .. note:: This class does not allow sending. @@ -76,8 +76,8 @@ def _get_chip_coords(self, ip_address: str) -> XY: raise NotImplementedError @abstractmethod - def send_to_chip( - self, message: bytes, x: int, y: int, port: int = SCP_SCAMP_PORT): + def send_to_chip(self, message: bytes, x: int, y: int, + port: int = SCP_SCAMP_PORT) -> None: """ Send a message on an open socket to a particular board. @@ -94,7 +94,7 @@ def send_to_chip( """ raise NotImplementedError - def send_to(self, data: bytes, address: Tuple[str, int]): + def send_to(self, data: bytes, address: Tuple[str, int]) -> None: """ Send a message on an open socket. @@ -133,7 +133,7 @@ def local_port(self) -> int: # type: ignore[override] def send_eieio_message_to_core( self, eieio_message: AbstractEIEIOMessage, x: int, y: int, p: int, - ip_address: str): + ip_address: str) -> None: """ Send an EIEIO message (one way) to a given core. @@ -160,7 +160,8 @@ def send_eieio_message_to_core( self.send_to( _TWO_SKIP + sdp_message.bytestring, (ip_address, SCP_SCAMP_PORT)) - def update_tag(self, x: int, y: int, tag: int, do_receive: bool = True): + def update_tag( + self, x: int, y: int, tag: int, do_receive: bool = True) -> None: """ Update the given tag on the given Ethernet-enabled chip to send messages to this connection. @@ -191,7 +192,7 @@ def update_tag(self, x: int, y: int, tag: int, do_receive: bool = True): if _try + 1 == _NUM_UPDATE_TAG_TRIES: raise e - def update_tag_by_ip(self, ip_address: str, tag: int): + def update_tag_by_ip(self, ip_address: str, tag: int) -> None: """ Update a tag on a board at a given IP address to send messages to this connection. diff --git a/spinnman/spalloc/spalloc_job.py b/spinnman/spalloc/spalloc_job.py index 04ffa8715..d096b26fb 100644 --- a/spinnman/spalloc/spalloc_job.py +++ b/spinnman/spalloc/spalloc_job.py @@ -12,7 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Mapping, Optional, Tuple +from types import TracebackType +from typing import Dict, Mapping, Optional, Tuple, Type +from typing_extensions import Literal, Self + from spinn_utilities.abstract_base import AbstractBase, abstractmethod from spinnman.constants import SCP_SCAMP_PORT from spinnman.transceiver.transceiver import Transceiver @@ -159,7 +162,7 @@ def wait_for_state_change(self, old_state: SpallocState, @abstractmethod def wait_until_ready(self, timeout: Optional[int] = None, - n_retries: Optional[int] = None): + n_retries: Optional[int] = None) -> None: """ Wait until the allocation is in the ``READY`` state. @@ -173,7 +176,7 @@ def wait_until_ready(self, timeout: Optional[int] = None, raise NotImplementedError() @abstractmethod - def destroy(self, reason: str = "finished"): + def destroy(self, reason: str = "finished") -> None: """ Destroy the job. @@ -207,13 +210,14 @@ def get_session_credentials_for_db(self) -> Mapping[Tuple[str, str], str]: """ raise NotImplementedError() - def __enter__(self): + def __enter__(self) -> Self: """ Return self on entering context. """ return self - def __exit__(self, exc_type, exc_value, traceback): + def __exit__(self, exc_type: Optional[Type], exc_value: Exception, + exc_tb: TracebackType) -> Literal[False]: """ Handle exceptions by killing the job and logging the exception in the job's destroy reason. @@ -223,4 +227,4 @@ def __exit__(self, exc_type, exc_value, traceback): except Exception: # pylint: disable=broad-except # Ignore this exception; there's not much we can do with it pass - return None + return False diff --git a/spinnman/spalloc/spalloc_scp_connection.py b/spinnman/spalloc/spalloc_scp_connection.py index 6b2bff7a0..cbb275feb 100644 --- a/spinnman/spalloc/spalloc_scp_connection.py +++ b/spinnman/spalloc/spalloc_scp_connection.py @@ -36,7 +36,7 @@ class SpallocSCPConnection( """ __slots__ = () - def __init__(self, x, y): + def __init__(self, x: int, y: int) -> None: super(SpallocSCPConnection, self).__init__(x, y) @overrides(SCAMPConnection.receive_sdp_message) @@ -46,7 +46,7 @@ def receive_sdp_message( return SDPMessage.from_bytestring(data, 2) @overrides(SCAMPConnection.send_sdp_message) - def send_sdp_message(self, sdp_message: SDPMessage): + def send_sdp_message(self, sdp_message: SDPMessage) -> None: # If a reply is expected, the connection should if sdp_message.sdp_header.flags == SDPFlag.REPLY_EXPECTED: sdp_message.sdp_header.update_for_send(self.chip_x, self.chip_y) From 3fda297a5dfdfc817460009e271c4b936c181da0 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 28 Oct 2024 06:27:37 +0000 Subject: [PATCH 04/18] typing --- spinnman/spalloc/session.py | 48 +++++++++++-------- .../spalloc/spalloc_proxied_connection.py | 2 +- .../locate_connected_machine_ip_address.py | 9 ++-- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/spinnman/spalloc/session.py b/spinnman/spalloc/session.py index 63c892969..86ea00f9b 100644 --- a/spinnman/spalloc/session.py +++ b/spinnman/spalloc/session.py @@ -16,7 +16,7 @@ from logging import getLogger from json.decoder import JSONDecodeError import re -from typing import Dict, Tuple, cast, Optional +from typing import Any, Callable, Dict, Tuple, cast, Optional import websocket # type: ignore import requests @@ -34,8 +34,8 @@ _debug_pretty_print = False -def _may_renew(method): - def pp_req(request: requests.PreparedRequest): +def _may_renew(method: Callable) -> Callable: + def pp_req(request: requests.PreparedRequest) -> None: """ :param ~requests.PreparedRequest request: """ @@ -47,7 +47,7 @@ def pp_req(request: requests.PreparedRequest): if request.body: print(request.body) - def pp_resp(response: requests.Response): + def pp_resp(response: requests.Response) -> None: """ :param ~requests.Response response: """ @@ -61,7 +61,7 @@ def pp_resp(response: requests.Response): str(response.content, "UTF-8") if response.content else "")) @wraps(method) - def call(self, *args, **kwargs): + def call(self: 'Session', *args: Any, **kwargs: Any) -> None: renew_count = 0 while True: r = method(self, *args, **kwargs) @@ -115,16 +115,17 @@ def __init__( if session_credentials: cookies, headers = session_credentials if _SESSION_COOKIE in cookies: - self._session_id = cookies[_SESSION_COOKIE] + self._session_id: Optional[str] = cookies[_SESSION_COOKIE] for key, value in headers.items(): if key == "Authorization": # TODO: extract this? pass else: self.__csrf_header = key - self.__csrf = value + self.__csrf: Optional[str] = value - def __handle_error_or_return(self, response: requests.Response): + def __handle_error_or_return(self, response: requests.Response + ) -> Optional[requests.Response]: code = response.status_code if code >= 200 and code < 400: return response @@ -133,7 +134,8 @@ def __handle_error_or_return(self, response: requests.Response): f" {str(result)}") @_may_renew - def get(self, url: str, timeout: int = 10, **kwargs) -> requests.Response: + def get(self, url: str, timeout: int = 10, **kwargs: Any + ) -> Optional[requests.Response]: """ Do an HTTP ``GET`` in the session. @@ -143,6 +145,7 @@ def get(self, url: str, timeout: int = 10, **kwargs) -> requests.Response: :raise ValueError: If the server rejects a request """ params = kwargs if kwargs else None + assert self._session_id is not None cookies = {_SESSION_COOKIE: self._session_id} r = requests.get(url, params=params, cookies=cookies, allow_redirects=False, timeout=timeout) @@ -151,7 +154,7 @@ def get(self, url: str, timeout: int = 10, **kwargs) -> requests.Response: @_may_renew def post(self, url: str, json_dict: dict, timeout: int = 10, - **kwargs) -> requests.Response: + **kwargs: Any) -> Optional[requests.Response]: """ Do an HTTP ``POST`` in the session. @@ -171,7 +174,7 @@ def post(self, url: str, json_dict: dict, timeout: int = 10, @_may_renew def put(self, url: str, data: str, timeout: int = 10, - **kwargs) -> requests.Response: + **kwargs: Any) -> Optional[requests.Response]: """ Do an HTTP ``PUT`` in the session. Puts plain text *OR* JSON! @@ -193,7 +196,7 @@ def put(self, url: str, data: str, timeout: int = 10, @_may_renew def delete(self, url: str, timeout: int = 10, - **kwargs) -> requests.Response: + **kwargs: Any) -> Optional[requests.Response]: """ Do an HTTP ``DELETE`` in the session. @@ -288,6 +291,8 @@ def _credentials(self) -> Tuple[Dict[str, str], Dict[str, str]]: """ The credentials for requests. *Serializable.* """ + assert self._session_id is not None + assert self.__csrf is not None cookies = {_SESSION_COOKIE: self._session_id} headers = {self.__csrf_header: self.__csrf} if self.__token: @@ -297,7 +302,7 @@ def _credentials(self) -> Tuple[Dict[str, str], Dict[str, str]]: def websocket( self, url: str, header: Optional[dict] = None, - cookie: Optional[str] = None, **kwargs) -> websocket.WebSocket: + cookie: Optional[str] = None, **kwargs: Any) -> websocket.WebSocket: """ Create a websocket that uses the session credentials to establish itself. @@ -313,6 +318,7 @@ def websocket( if header is None: header = {} header[self.__csrf_header] = self.__csrf + assert self._session_id is not None if cookie is not None: cookie += ";" + _SESSION_COOKIE + "=" + self._session_id else: @@ -320,7 +326,7 @@ def websocket( return websocket.create_connection( url, header=header, cookie=cookie, **kwargs) - def _purge(self): + def _purge(self) -> None: """ Clears out all credentials from this session, rendering the session completely inoperable henceforth. @@ -345,7 +351,7 @@ def __init__(self, session: Session, url: str): self._url = clean_url(url) @property - def _session_credentials(self): + def _session_credentials(self) -> Tuple[Dict[str, str], Dict[str, str]]: """ The current session credentials. Only supposed to be called by subclasses. @@ -356,7 +362,7 @@ def _session_credentials(self): return self.__session._credentials @property - def _service_url(self): + def _service_url(self) -> str: """ The main service URL. @@ -365,19 +371,19 @@ def _service_url(self): # pylint: disable=protected-access return self.__session._service_url - def _get(self, url: str, **kwargs) -> requests.Response: + def _get(self, url: str, **kwargs: Any) -> requests.Response: return self.__session.get(url, **kwargs) - def _post(self, url: str, json_dict: dict, **kwargs) -> requests.Response: + def _post(self, url: str, json_dict: dict, **kwargs: Any) -> requests.Response: return self.__session.post(url, json_dict, **kwargs) - def _put(self, url: str, data: str, **kwargs) -> requests.Response: + def _put(self, url: str, data: str, **kwargs: Any) -> requests.Response: return self.__session.put(url, data, **kwargs) - def _delete(self, url: str, **kwargs) -> requests.Response: + def _delete(self, url: str, **kwargs: Any) -> requests.Response: return self.__session.delete(url, **kwargs) - def _websocket(self, url: str, **kwargs) -> websocket.WebSocket: + def _websocket(self, url: str, **kwargs: Any) -> websocket.WebSocket: """ Create a websocket that uses the session credentials to establish itself. diff --git a/spinnman/spalloc/spalloc_proxied_connection.py b/spinnman/spalloc/spalloc_proxied_connection.py index cc193e1f8..3a8e2f543 100644 --- a/spinnman/spalloc/spalloc_proxied_connection.py +++ b/spinnman/spalloc/spalloc_proxied_connection.py @@ -26,7 +26,7 @@ class SpallocProxiedConnection(Listenable, metaclass=AbstractBase): __slots__ = () @abstractmethod - def send(self, data: bytes): + def send(self, data: bytes) -> None: """ Send a message on an open socket. diff --git a/spinnman/utilities/locate_connected_machine_ip_address.py b/spinnman/utilities/locate_connected_machine_ip_address.py index 6ed26c419..0f1fdd884 100644 --- a/spinnman/utilities/locate_connected_machine_ip_address.py +++ b/spinnman/utilities/locate_connected_machine_ip_address.py @@ -16,11 +16,14 @@ import sys import signal import socket -from typing import Callable +from types import FrameType +from typing import Callable, Optional + +from typing_extensions import Never from spinnman.connections.udp_packet_connections import IPAddressesConnection -def locate_connected_machine(handler: Callable[[str, float], bool]): +def locate_connected_machine(handler: Callable[[str, float], bool]) -> None: """ Locates any SpiNNaker machines IP addresses from the auto-transmitted packets from non-booted SpiNNaker machines. @@ -43,7 +46,7 @@ def locate_connected_machine(handler: Callable[[str, float], bool]): if __name__ == "__main__": - def _ctrlc_handler(sig, frame): + def _ctrlc_handler(sig: int, frame: Optional[FrameType]) -> Never: """ :return: Never returns as it causes a sys.exit() """ From a217c3d4c7f2aa6d95d5c6d03afed91038d747aa Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 28 Oct 2024 07:24:35 +0000 Subject: [PATCH 05/18] typing --- spinnman/transceiver/base_transceiver.py | 45 ++++++++++---------- spinnman/transceiver/mockable_transceiver.py | 35 +++++++-------- spinnman/transceiver/transceiver.py | 35 +++++++-------- spinnman/utilities/reports.py | 9 ++-- 4 files changed, 65 insertions(+), 59 deletions(-) diff --git a/spinnman/transceiver/base_transceiver.py b/spinnman/transceiver/base_transceiver.py index 30b13a2eb..1d37901f6 100644 --- a/spinnman/transceiver/base_transceiver.py +++ b/spinnman/transceiver/base_transceiver.py @@ -900,7 +900,7 @@ def _bmp_call(self, req: AbstractSCPRequest[_AbstractSCPResponse], SendSingleCommandProcess(self._bmp_selector, **kwargs) return proc.execute(req) - def _power(self, power_command: PowerCommand): + def _power(self, power_command: PowerCommand) -> None: """ Send a power request to the machine. @@ -925,8 +925,8 @@ def read_fpga_register( return response.fpga_register @overrides(Transceiver.write_fpga_register) - def write_fpga_register( - self, fpga_num: int, register: int, value: int, board: int = 0): + def write_fpga_register(self, fpga_num: int, register: int, value: int, + board: int = 0) -> None: self._bmp_call( WriteFPGARegister(fpga_num, register, value, board)) @@ -967,8 +967,8 @@ def write_memory( return n_bytes, chksum @overrides(Transceiver.write_user) - def write_user( - self, x: int, y: int, p: int, user: UserRegister, value: int): + def write_user(self, x: int, y: int, p: int, + user: UserRegister, value: int) -> None: addr = self.__get_user_register_address_from_core(p, user) self.write_memory(x, y, addr, int(value)) @@ -997,7 +997,7 @@ def read_word( raise @overrides(Transceiver.stop_application) - def stop_application(self, app_id: int): + def stop_application(self, app_id: int) -> None: if not self._machine_off: self._call(AppStop(app_id)) else: @@ -1006,7 +1006,7 @@ def stop_application(self, app_id: int): "Please fix and try again") def __log_where_is_info(self, cpu_infos: Iterable[ - Union[CPUInfo, Sequence[int]]]): + Union[CPUInfo, Sequence[int]]]) -> None: """ Logs the where_is info for each chip in cpu_infos. @@ -1039,7 +1039,7 @@ def wait_for_cores_to_be_in_state( error_states: FrozenSet[CPUState] = frozenset(( CPUState.RUN_TIME_EXCEPTION, CPUState.WATCHDOG)), counts_between_full_check: int = 100, - progress_bar: Optional[ProgressBar] = None): + progress_bar: Optional[ProgressBar] = None) -> None: processors_ready = 0 max_processors_ready = 0 timeout_time = None if timeout is None else time.time() + timeout @@ -1112,7 +1112,7 @@ def wait_for_cores_to_be_in_state( timeout, target_states, cores_not_in_state) @overrides(Transceiver.send_signal) - def send_signal(self, app_id: int, signal: Signal): + def send_signal(self, app_id: int, signal: Signal) -> None: self._call(SendSignal(app_id, signal)) def _locate_spinnaker_connection_for_board_address( @@ -1129,7 +1129,7 @@ def _locate_spinnaker_connection_for_board_address( return self._udp_scamp_connections.get(board_address, None) @overrides(Transceiver.set_ip_tag) - def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False): + def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False) -> None: # Check that the tag has a port assigned if ip_tag.port is None: raise SpinnmanInvalidParameterException( @@ -1182,7 +1182,7 @@ def __get_connection_list( return [connection] @overrides(Transceiver.set_reverse_ip_tag) - def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag): + def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag) -> None: if reverse_ip_tag.port is None: raise SpinnmanInvalidParameterException( "reverse_ip_tag.port", "None", @@ -1214,7 +1214,7 @@ def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag): reverse_ip_tag.sdp_port)) @overrides(Transceiver.clear_ip_tag) - def clear_ip_tag(self, tag: int, board_address: Optional[str] = None): + def clear_ip_tag(self, tag: int, board_address: Optional[str] = None) -> None: for conn in self.__get_connection_list(board_address=board_address): self._call(IPTagClear(conn.chip_x, conn.chip_y, tag)) @@ -1241,7 +1241,7 @@ def malloc_sdram( @overrides(Transceiver.load_multicast_routes) def load_multicast_routes( self, x: int, y: int, routes: Collection[MulticastRoutingEntry], - app_id: int): + app_id: int) -> None: try: process = LoadMultiCastRoutesProcess( self._scamp_connection_selector) @@ -1251,8 +1251,8 @@ def load_multicast_routes( raise @overrides(Transceiver.load_fixed_route) - def load_fixed_route( - self, x: int, y: int, fixed_route: RoutingEntry, app_id: int): + def load_fixed_route(self, x: int, y: int, fixed_route: RoutingEntry, + app_id: int) -> None: try: process = LoadFixedRouteRoutingEntryProcess( self._scamp_connection_selector) @@ -1286,7 +1286,7 @@ def get_multicast_routes( raise @overrides(Transceiver.clear_multicast_routes) - def clear_multicast_routes(self, x: int, y: int): + def clear_multicast_routes(self, x: int, y: int) -> None: try: self._call(RouterClear(x, y)) except Exception: @@ -1310,7 +1310,7 @@ def get_scamp_connection_selector(self) -> MostDirectConnectionSelector: @overrides(Transceiver.set_router_diagnostic_filter) def set_router_diagnostic_filter( self, x: int, y: int, position: int, - diagnostic_filter: DiagnosticFilter): + diagnostic_filter: DiagnosticFilter) -> None: try: self.__set_router_diagnostic_filter( x, y, position, diagnostic_filter) @@ -1320,7 +1320,7 @@ def set_router_diagnostic_filter( def __set_router_diagnostic_filter( self, x: int, y: int, position: int, - diagnostic_filter: DiagnosticFilter): + diagnostic_filter: DiagnosticFilter) -> None: data_to_send = diagnostic_filter.filter_word if position > NO_ROUTER_DIAGNOSTIC_FILTERS: raise SpinnmanInvalidParameterException( @@ -1342,7 +1342,7 @@ def __set_router_diagnostic_filter( (x, y, 0), memory_position, _ONE_WORD.pack(data_to_send))) @overrides(Transceiver.clear_router_diagnostic_counters) - def clear_router_diagnostic_counters(self, x: int, y: int): + def clear_router_diagnostic_counters(self, x: int, y: int) -> None: try: # Clear all self._call(WriteMemory( @@ -1361,11 +1361,11 @@ def close(self) -> None: connection.close() @overrides(Transceiver.control_sync) - def control_sync(self, do_sync: bool): + def control_sync(self, do_sync: bool) -> None: self._call(DoSync(do_sync)) @overrides(Transceiver.update_provenance_and_exit) - def update_provenance_and_exit(self, x: int, y: int, p: int): + def update_provenance_and_exit(self, x: int, y: int, p: int) -> None: # Send these signals to make sure the application isn't stuck self.send_sdp_message(SDPMessage( sdp_header=SDPHeader( @@ -1376,7 +1376,8 @@ def update_provenance_and_exit(self, x: int, y: int, p: int): .SDP_UPDATE_PROVENCE_REGION_AND_EXIT.value))) @overrides(Transceiver.send_chip_update_provenance_and_exit) - def send_chip_update_provenance_and_exit(self, x: int, y: int, p: int): + def send_chip_update_provenance_and_exit( + self, x: int, y: int, p: int) -> None: cmd = SDP_RUNNING_MESSAGE_CODES.SDP_UPDATE_PROVENCE_REGION_AND_EXIT port = SDP_PORTS.RUNNING_COMMAND_SDP_PORT diff --git a/spinnman/transceiver/mockable_transceiver.py b/spinnman/transceiver/mockable_transceiver.py index 496a3a23b..d9c32a2ee 100644 --- a/spinnman/transceiver/mockable_transceiver.py +++ b/spinnman/transceiver/mockable_transceiver.py @@ -122,8 +122,8 @@ def read_fpga_register( raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.write_fpga_register) - def write_fpga_register( - self, fpga_num: int, register: int, value: int, board: int = 0): + def write_fpga_register(self, fpga_num: int, register: int, value: int, + board: int = 0) -> None: pass @overrides(Transceiver.read_bmp_version) @@ -143,8 +143,8 @@ def write_memory( return (-1, -1) @overrides(Transceiver.write_user) - def write_user( - self, x: int, y: int, p: int, user: UserRegister, value: int): + def write_user(self, x: int, y: int, p: int, user: UserRegister, + value: int) -> None: pass @overrides(Transceiver.read_memory) @@ -159,7 +159,7 @@ def read_word( raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.stop_application) - def stop_application(self, app_id: int): + def stop_application(self, app_id: int) -> None: pass @overrides(Transceiver.wait_for_cores_to_be_in_state) @@ -171,11 +171,11 @@ def wait_for_cores_to_be_in_state( error_states: FrozenSet[CPUState] = frozenset(( CPUState.RUN_TIME_EXCEPTION, CPUState.WATCHDOG)), counts_between_full_check: int = 100, - progress_bar: Optional[ProgressBar] = None): + progress_bar: Optional[ProgressBar] = None) -> None: pass @overrides(Transceiver.send_signal) - def send_signal(self, app_id: int, signal: Signal): + def send_signal(self, app_id: int, signal: Signal) -> None: pass @overrides(Transceiver.set_ip_tag) @@ -183,7 +183,7 @@ def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False): pass @overrides(Transceiver.set_reverse_ip_tag) - def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag): + def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag) -> None: pass @overrides(Transceiver.clear_ip_tag) @@ -203,12 +203,12 @@ def malloc_sdram( @overrides(Transceiver.load_multicast_routes) def load_multicast_routes( self, x: int, y: int, routes: Collection[MulticastRoutingEntry], - app_id: int): + app_id: int) -> None: pass @overrides(Transceiver.load_fixed_route) - def load_fixed_route( - self, x: int, y: int, fixed_route: RoutingEntry, app_id: int): + def load_fixed_route(self, x: int, y: int, fixed_route: RoutingEntry, + app_id: int) -> None: pass @overrides(Transceiver.read_fixed_route) @@ -222,7 +222,7 @@ def get_multicast_routes( raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.clear_multicast_routes) - def clear_multicast_routes(self, x: int, y: int): + def clear_multicast_routes(self, x: int, y: int) -> None: pass @overrides(Transceiver.get_router_diagnostics) @@ -236,11 +236,11 @@ def get_scamp_connection_selector(self) -> MostDirectConnectionSelector: @overrides(Transceiver.set_router_diagnostic_filter) def set_router_diagnostic_filter( self, x: int, y: int, position: int, - diagnostic_filter: DiagnosticFilter): + diagnostic_filter: DiagnosticFilter) -> None: pass @overrides(Transceiver.clear_router_diagnostic_counters) - def clear_router_diagnostic_counters(self, x: int, y: int): + def clear_router_diagnostic_counters(self, x: int, y: int) -> None: pass @overrides(Transceiver.close) @@ -248,15 +248,16 @@ def close(self) -> None: pass @overrides(Transceiver.control_sync) - def control_sync(self, do_sync: bool): + def control_sync(self, do_sync: bool) -> None: pass @overrides(Transceiver.update_provenance_and_exit) - def update_provenance_and_exit(self, x: int, y: int, p: int): + def update_provenance_and_exit(self, x: int, y: int, p: int) -> None: pass @overrides(Transceiver.send_chip_update_provenance_and_exit) - def send_chip_update_provenance_and_exit(self, x: int, y: int, p: int): + def send_chip_update_provenance_and_exit( + self, x: int, y: int, p: int) -> None: pass @property diff --git a/spinnman/transceiver/transceiver.py b/spinnman/transceiver/transceiver.py index b02c129a6..087626a48 100644 --- a/spinnman/transceiver/transceiver.py +++ b/spinnman/transceiver/transceiver.py @@ -392,8 +392,8 @@ def read_fpga_register( raise NotImplementedError("abstractmethod") @abstractmethod - def write_fpga_register( - self, fpga_num: int, register: int, value: int, board: int = 0): + def write_fpga_register(self, fpga_num: int, register: int, value: int, + board: int = 0) -> None: """ Write a register on a FPGA of a board. The meaning of setting the register's contents will depend on the FPGA's configuration. @@ -471,8 +471,8 @@ def write_memory( raise NotImplementedError("abstractmethod") @abstractmethod - def write_user( - self, x: int, y: int, p: int, user: UserRegister, value: int): + def write_user(self, x: int, y: int, p: int, user: UserRegister, + value: int) -> None: """ Write to the user *N* "register" for the given processor. @@ -557,7 +557,7 @@ def read_word( raise NotImplementedError("abstractmethod") @abstractmethod - def stop_application(self, app_id: int): + def stop_application(self, app_id: int) -> None: """ Sends a stop request for an app_id. @@ -583,7 +583,7 @@ def wait_for_cores_to_be_in_state( error_states: FrozenSet[CPUState] = frozenset(( CPUState.RUN_TIME_EXCEPTION, CPUState.WATCHDOG)), counts_between_full_check: int = 100, - progress_bar: Optional[ProgressBar] = None): + progress_bar: Optional[ProgressBar] = None) -> None: """ Waits for the specified cores running the given application to be in some target state or states. Handles failures. @@ -613,7 +613,7 @@ def wait_for_cores_to_be_in_state( raise NotImplementedError("abstractmethod") @abstractmethod - def send_signal(self, app_id: int, signal: Signal): + def send_signal(self, app_id: int, signal: Signal) -> None: """ Send a signal to an application. @@ -660,7 +660,7 @@ def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False): raise NotImplementedError("abstractmethod") @abstractmethod - def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag): + def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag) -> None: """ Set up a reverse IP tag. @@ -753,7 +753,7 @@ def malloc_sdram( @abstractmethod def load_multicast_routes( self, x: int, y: int, routes: Collection[MulticastRoutingEntry], - app_id: int): + app_id: int) -> None: """ Load a set of multicast routes on to a chip. @@ -778,8 +778,8 @@ def load_multicast_routes( raise NotImplementedError("abstractmethod") @abstractmethod - def load_fixed_route( - self, x: int, y: int, fixed_route: RoutingEntry, app_id: int): + def load_fixed_route(self, x: int, y: int, fixed_route: RoutingEntry, + app_id: int) -> None: """ Loads a fixed route routing table entry onto a chip's router. @@ -847,7 +847,7 @@ def get_multicast_routes( raise NotImplementedError("abstractmethod") @abstractmethod - def clear_multicast_routes(self, x: int, y: int): + def clear_multicast_routes(self, x: int, y: int) -> None: """ Remove all the multicast routes on a chip. @@ -898,7 +898,7 @@ def get_scamp_connection_selector(self) -> MostDirectConnectionSelector: @abstractmethod def set_router_diagnostic_filter( self, x: int, y: int, position: int, - diagnostic_filter: DiagnosticFilter): + diagnostic_filter: DiagnosticFilter) -> None: """ Sets a router diagnostic filter in a router. @@ -929,7 +929,7 @@ def set_router_diagnostic_filter( raise NotImplementedError("abstractmethod") @abstractmethod - def clear_router_diagnostic_counters(self, x: int, y: int): + def clear_router_diagnostic_counters(self, x: int, y: int) -> None: """ Clear router diagnostic information on a chip. @@ -955,7 +955,7 @@ def close(self) -> None: raise NotImplementedError("abstractmethod") @abstractmethod - def control_sync(self, do_sync: bool): + def control_sync(self, do_sync: bool) -> None: """ Control the synchronisation of the chips. @@ -964,7 +964,7 @@ def control_sync(self, do_sync: bool): raise NotImplementedError("abstractmethod") @abstractmethod - def update_provenance_and_exit(self, x: int, y: int, p: int): + def update_provenance_and_exit(self, x: int, y: int, p: int) -> None: """ Sends a command to update provenance and exit @@ -978,7 +978,8 @@ def update_provenance_and_exit(self, x: int, y: int, p: int): raise NotImplementedError("abstractmethod") @abstractmethod - def send_chip_update_provenance_and_exit(self, x: int, y: int, p: int): + def send_chip_update_provenance_and_exit( + self, x: int, y: int, p: int) -> None: """ Sends a signal to update the provenance and exit diff --git a/spinnman/utilities/reports.py b/spinnman/utilities/reports.py index e19861ba6..12320fdd9 100644 --- a/spinnman/utilities/reports.py +++ b/spinnman/utilities/reports.py @@ -12,10 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from io import TextIOBase import logging import os.path import time from typing import List + from spinn_utilities.log import FormatAdapter from spinn_machine import Machine, Chip from spinnman.connections.abstract_classes import Connection @@ -26,7 +28,7 @@ def generate_machine_report( report_directory: str, machine: Machine, - connections: List[Connection]): + connections: List[Connection]) -> None: """ Generate report on the physical structure of the target SpiNNaker machine. @@ -51,7 +53,8 @@ def generate_machine_report( raise -def _write_header(f, timestamp: str, machine: Machine, connections): +def _write_header(f: TextIOBase, timestamp: str, machine: Machine, + connections: List[Connection]) -> None: """ :param str timestamp: :param ~spinn_machine.Machine machine: @@ -66,7 +69,7 @@ def _write_header(f, timestamp: str, machine: Machine, connections): f.write("\t\t==========================\n") -def _write_chip_router_report(f, chip: Chip): +def _write_chip_router_report(f: TextIOBase, chip: Chip) -> None: """ :param ~spinn_machine.Chip chip: """ From 742faa86cc1c9556ec4d9c36f485238f98fbad09 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 28 Oct 2024 10:54:45 +0000 Subject: [PATCH 06/18] typing --- spinnman/transceiver/base_transceiver.py | 49 +++++++++++++------- spinnman/transceiver/mockable_transceiver.py | 17 +++---- spinnman/transceiver/transceiver.py | 17 +++---- spinnman/transceiver/virtual5transceiver.py | 2 +- 4 files changed, 51 insertions(+), 34 deletions(-) diff --git a/spinnman/transceiver/base_transceiver.py b/spinnman/transceiver/base_transceiver.py index 1d37901f6..c0b67f00d 100644 --- a/spinnman/transceiver/base_transceiver.py +++ b/spinnman/transceiver/base_transceiver.py @@ -352,7 +352,7 @@ def _check_connection( @overrides(Transceiver.send_sdp_message) def send_sdp_message(self, message: SDPMessage, - connection: Optional[SDPConnection] = None): + connection: Optional[SDPConnection] = None) -> None: if connection is None: connection_to_use: SDPConnection = self._scamp_connections[ random.randint(0, len(self._scamp_connections) - 1)] @@ -361,7 +361,7 @@ def send_sdp_message(self, message: SDPMessage, connection_to_use.send_sdp_message(message) def _check_and_add_scamp_connections( - self, x: int, y: int, ip_address: str): + self, x: int, y: int, ip_address: str) -> None: """ :param int x: X coordinate of target chip :param int y: Y coordinate of target chip @@ -414,7 +414,7 @@ def discover_scamp_connections(self) -> None: self._scamp_connections) @overrides(Transceiver.add_scamp_connections) - def add_scamp_connections(self, connections: Dict[XY, str]): + def add_scamp_connections(self, connections: Dict[XY, str]) -> None: for ((x, y), ip_address) in connections.items(): self._check_and_add_scamp_connections(x, y, ip_address) self._scamp_connection_selector = MostDirectConnectionSelector( @@ -513,7 +513,7 @@ def boot_led_0_value(self) -> int: raise NotImplementedError def _boot_board(self, extra_boot_values: Optional[Dict[ - SystemVariableDefinition, object]] = None): + SystemVariableDefinition, object]] = None) -> None: """ Attempt to boot the board. No check is performed to see if the board is already booted. @@ -542,14 +542,14 @@ def _boot_board(self, extra_boot_values: Optional[Dict[ self._boot_send_connection.send_boot_message(boot_message) time.sleep(2.0) - def _call(self, req: AbstractSCPRequest[_AbstractSCPResponse], - **kwargs) -> _AbstractSCPResponse: + def _call(self, req: AbstractSCPRequest[_AbstractSCPResponse] + ) -> _AbstractSCPResponse: """ Wrapper that makes doing simple SCP calls easier, especially with types. """ proc: SendSingleCommandProcess[_AbstractSCPResponse] = \ - SendSingleCommandProcess(self._scamp_connection_selector, **kwargs) + SendSingleCommandProcess(self._scamp_connection_selector) return proc.execute(req) @staticmethod @@ -575,7 +575,7 @@ def _is_scamp_version_compabible(version: Tuple[int, int, int]) -> bool: def _ensure_board_is_ready( self, n_retries: int = 5, extra_boot_values: Optional[Dict[ - SystemVariableDefinition, object]] = None): + SystemVariableDefinition, object]] = None) -> None: """ Ensure that the board is ready to interact with this version of the transceiver. Boots the board if not already booted and verifies that @@ -753,7 +753,8 @@ def _get_sv_data( self.read_memory(x, y, addr, data_item.data_type.value))[0] @staticmethod - def __get_user_register_address_from_core(p: int, user: UserRegister): + def __get_user_register_address_from_core( + p: int, user: UserRegister) -> int: """ Get the address of user *N* for a given processor on the board. @@ -773,21 +774,21 @@ def __get_user_register_address_from_core(p: int, user: UserRegister): CPU_USER_OFFSET * user) @overrides(Transceiver.read_user) - def read_user(self, x: int, y: int, p: int, user: UserRegister): + def read_user(self, x: int, y: int, p: int, user: UserRegister) -> int: addr = self.__get_user_register_address_from_core(p, user) return self.read_word(x, y, addr) @overrides(Transceiver.add_cpu_information_from_core) def add_cpu_information_from_core( self, cpu_infos: CPUInfos, x: int, y: int, p: int, - states: Iterable[CPUState]): + states: Iterable[CPUState]) -> None: core_subsets = CoreSubsets() core_subsets.add_processor(x, y, p) new_infos = self.get_cpu_infos(core_subsets) cpu_infos.add_infos(new_infos, states) @overrides(Transceiver.get_region_base_address) - def get_region_base_address(self, x: int, y: int, p: int): + def get_region_base_address(self, x: int, y: int, p: int) -> int: return self.read_user(x, y, p, UserRegister.USER_0) @overrides(Transceiver.get_iobuf) @@ -840,7 +841,7 @@ def __flood_execute_lock(self) -> Iterator[Condition]: def execute_flood( self, core_subsets: CoreSubsets, executable: Union[BinaryIO, bytes, str], app_id: int, *, - n_bytes: Optional[int] = None, wait: bool = False,): + n_bytes: Optional[int] = None, wait: bool = False) -> None : if isinstance(executable, int): # No executable is 4 bytes long raise TypeError("executable may not be int") @@ -888,7 +889,8 @@ def _power_off_machine(self) -> None: logger.warning("Power cycle wait complete") def _bmp_call(self, req: AbstractSCPRequest[_AbstractSCPResponse], - **kwargs) -> _AbstractSCPResponse: + timeout: Optional[float] = None, + n_retries: Optional[int] = None) -> _AbstractSCPResponse: """ Wrapper that makes doing simple BMP calls easier, especially with types. @@ -896,8 +898,20 @@ def _bmp_call(self, req: AbstractSCPRequest[_AbstractSCPResponse], if self._bmp_selector is None: raise SpinnmanException( "this transceiver does not support BMP operations") - proc: SendSingleCommandProcess[_AbstractSCPResponse] =\ - SendSingleCommandProcess(self._bmp_selector, **kwargs) + proc: SendSingleCommandProcess[_AbstractSCPResponse] + if timeout is None: + if n_retries is None: + proc = SendSingleCommandProcess(self._bmp_selector) + else: + proc = SendSingleCommandProcess( + self._bmp_selector, n_retries=n_retries) + else: + if n_retries is None: + proc = SendSingleCommandProcess( + self._bmp_selector, timeout=timeout) + else: + proc = SendSingleCommandProcess( + self._bmp_selector, n_retries=n_retries, timeout=timeout) return proc.execute(req) def _power(self, power_command: PowerCommand) -> None: @@ -1214,7 +1228,8 @@ def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag) -> None: reverse_ip_tag.sdp_port)) @overrides(Transceiver.clear_ip_tag) - def clear_ip_tag(self, tag: int, board_address: Optional[str] = None) -> None: + def clear_ip_tag( + self, tag: int, board_address: Optional[str] = None) -> None: for conn in self.__get_connection_list(board_address=board_address): self._call(IPTagClear(conn.chip_x, conn.chip_y, tag)) diff --git a/spinnman/transceiver/mockable_transceiver.py b/spinnman/transceiver/mockable_transceiver.py index d9c32a2ee..004152603 100644 --- a/spinnman/transceiver/mockable_transceiver.py +++ b/spinnman/transceiver/mockable_transceiver.py @@ -54,7 +54,7 @@ def __init__(self) -> None: @overrides(Transceiver.send_sdp_message) def send_sdp_message(self, message: SDPMessage, - connection: Optional[SDPConnection] = None): + connection: Optional[SDPConnection] = None) -> None: pass @overrides(Transceiver.discover_scamp_connections) @@ -62,7 +62,7 @@ def discover_scamp_connections(self) -> None: raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.add_scamp_connections) - def add_scamp_connections(self, connections: Dict[XY, str]): + def add_scamp_connections(self, connections: Dict[XY, str]) -> None: pass @overrides(Transceiver.get_machine_details) @@ -85,17 +85,17 @@ def get_clock_drift(self, x: int, y: int) -> float: raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.read_user) - def read_user(self, x: int, y: int, p: int, user: UserRegister): + def read_user(self, x: int, y: int, p: int, user: UserRegister) -> int: raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.add_cpu_information_from_core) def add_cpu_information_from_core( self, cpu_infos: CPUInfos, x: int, y: int, p: int, - states: Iterable[CPUState]): + states: Iterable[CPUState]) -> None: raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.get_region_base_address) - def get_region_base_address(self, x: int, y: int, p: int): + def get_region_base_address(self, x: int, y: int, p: int) -> int: raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.get_iobuf) @@ -113,7 +113,7 @@ def get_core_state_count( def execute_flood( self, core_subsets: CoreSubsets, executable: Union[BinaryIO, bytes, str], app_id: int, *, - n_bytes: Optional[int] = None, wait: bool = False): + n_bytes: Optional[int] = None, wait: bool = False) -> None: pass @overrides(Transceiver.read_fpga_register) @@ -179,7 +179,7 @@ def send_signal(self, app_id: int, signal: Signal) -> None: pass @overrides(Transceiver.set_ip_tag) - def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False): + def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False) -> None: pass @overrides(Transceiver.set_reverse_ip_tag) @@ -187,7 +187,8 @@ def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag) -> None: pass @overrides(Transceiver.clear_ip_tag) - def clear_ip_tag(self, tag: int, board_address: Optional[str] = None): + def clear_ip_tag( + self, tag: int, board_address: Optional[str] = None) -> None: pass @overrides(Transceiver.get_tags) diff --git a/spinnman/transceiver/transceiver.py b/spinnman/transceiver/transceiver.py index 087626a48..b88e69d7c 100644 --- a/spinnman/transceiver/transceiver.py +++ b/spinnman/transceiver/transceiver.py @@ -55,7 +55,7 @@ class Transceiver(object): @abstractmethod def send_sdp_message(self, message: SDPMessage, - connection: Optional[SDPConnection] = None): + connection: Optional[SDPConnection] = None) -> None: """ Sends an SDP message using one of the connections. @@ -89,7 +89,7 @@ def discover_scamp_connections(self) -> None: raise NotImplementedError("abstractmethod") @abstractmethod - def add_scamp_connections(self, connections: Dict[XY, str]): + def add_scamp_connections(self, connections: Dict[XY, str]) -> None: """ Check connections to the board and store these for future use. @@ -193,7 +193,7 @@ def get_clock_drift(self, x: int, y: int) -> float: raise NotImplementedError("abstractmethod") @abstractmethod - def read_user(self, x: int, y: int, p: int, user: UserRegister): + def read_user(self, x: int, y: int, p: int, user: UserRegister) -> int: """ Get the contents of the this user register for the given processor. @@ -226,7 +226,7 @@ def read_user(self, x: int, y: int, p: int, user: UserRegister): @abstractmethod def add_cpu_information_from_core( self, cpu_infos: CPUInfos, x: int, y: int, p: int, - states: Iterable[CPUState]): + states: Iterable[CPUState]) -> None: """ Adds information about a specific processor on the board to the info @@ -252,7 +252,7 @@ def add_cpu_information_from_core( raise NotImplementedError("abstractmethod") @abstractmethod - def get_region_base_address(self, x: int, y: int, p: int): + def get_region_base_address(self, x: int, y: int, p: int) -> int: """ Gets the base address of the Region Table @@ -329,7 +329,7 @@ def get_core_state_count( def execute_flood( self, core_subsets: CoreSubsets, executable: Union[BinaryIO, bytes, str], app_id: int, *, - n_bytes: Optional[int] = None, wait: bool = False): + n_bytes: Optional[int] = None, wait: bool = False) -> None: """ Start an executable running on multiple places on the board. This will be optimised based on the selected cores, but it may still @@ -634,7 +634,7 @@ def send_signal(self, app_id: int, signal: Signal) -> None: raise NotImplementedError("abstractmethod") @abstractmethod - def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False): + def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False) -> None: """ Set up an IP tag. @@ -685,7 +685,8 @@ def set_reverse_ip_tag(self, reverse_ip_tag: ReverseIPTag) -> None: raise NotImplementedError("abstractmethod") @abstractmethod - def clear_ip_tag(self, tag: int, board_address: Optional[str] = None): + def clear_ip_tag( + self, tag: int, board_address: Optional[str] = None) -> None: """ Clear the setting of an IP tag. diff --git a/spinnman/transceiver/virtual5transceiver.py b/spinnman/transceiver/virtual5transceiver.py index 9513f2823..56948ce07 100644 --- a/spinnman/transceiver/virtual5transceiver.py +++ b/spinnman/transceiver/virtual5transceiver.py @@ -37,7 +37,7 @@ class Virtual5Transceiver(Version5Transceiver): @overrides(Version5Transceiver._boot_board) def _boot_board(self, extra_boot_values: Optional[Dict[ - SystemVariableDefinition, object]] = None): + SystemVariableDefinition, object]] = None) -> None: try: super()._boot_board(extra_boot_values) except SpinnmanIOException: From 4a33a08dfab3d35ea729c48d4e2c4c94a799e187 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Mon, 28 Oct 2024 16:47:24 +0000 Subject: [PATCH 07/18] typing attempted --- spinnman/extended/extended_transceiver.py | 184 +++++++++++------- .../transceiver/extendable_transceiver.py | 2 +- 2 files changed, 118 insertions(+), 68 deletions(-) diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index 3d5fb272f..9be3e20f5 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -14,26 +14,31 @@ # pylint: disable=too-many-arguments from contextlib import contextmanager -import io import os import logging import struct +from threading import Condition import time -from typing import Optional -from spinn_utilities.overrides import overrides +from typing import (BinaryIO, Generator, Iterable, List, Mapping, Optional, + Sequence, Union) + from spinn_utilities.abstract_base import ( AbstractBase, abstractmethod) from spinn_utilities.log import FormatAdapter from spinn_utilities.logger_utils import warn_once from spinn_utilities.require_subclass import require_subclass + from spinn_machine import CoreSubsets + +from spinnman.connections.abstract_classes import Connection from spinnman.constants import ( ROUTER_REGISTER_BASE_ADDRESS, ROUTER_FILTER_CONTROLS_OFFSET, ROUTER_DIAGNOSTIC_FILTER_SIZE) from spinnman.exceptions import SpinnmanException from spinnman.extended import ( BMPSetLed, DeAllocSDRAMProcess, ReadADC, SetLED, WriteMemoryFloodProcess) -from spinnman.model import DiagnosticFilter +from spinnman.model import ( + ADCInfo, DiagnosticFilter, ExecutableTargets, HeapElement, IOBuffer) from spinnman.model.enums import CPUState from spinnman.messages.scp.enums import Signal from spinnman.messages.scp.impl import ( @@ -41,10 +46,15 @@ from spinnman.connections.udp_packet_connections import SCAMPConnection from spinnman.constants import SYSTEM_VARIABLE_BASE_ADDRESS from spinnman.data import SpiNNManDataView +from spinnman.messages.scp.enums.led_action import LEDAction from spinnman.messages.spinnaker_boot import SystemVariableDefinition from spinnman.processes import ( - ConnectionSelector, GetHeapProcess, ReadMemoryProcess, - SendSingleCommandProcess, WriteMemoryProcess) + GetHeapProcess, ReadMemoryProcess, SendSingleCommandProcess, + WriteMemoryProcess) + +from spinnman.transceiver import Transceiver +from spinnman.transceiver.base_transceiver import ( + BaseTransceiver, _EXECUTABLE_ADDRESS) from spinnman.transceiver.extendable_transceiver import ExtendableTransceiver _ONE_BYTE = struct.Struct("B") @@ -64,8 +74,10 @@ class ExtendedTransceiver(object, metaclass=AbstractBase): If any method here is considered important to keep please move it to Transceiver and its implementations + + Typing is best effort as without use there is no way to check """ - __slots__ = () + __slots__: List[str] = [] # calls many methods only reachable do to require_subclass # pylint: disable=no-member,assigning-non-slot @@ -77,18 +89,7 @@ class ExtendedTransceiver(object, metaclass=AbstractBase): def _where_is_xy(self, x: int, y: int) -> Optional[str]: raise NotImplementedError - @property - @abstractmethod - @overrides(ExtendableTransceiver.scamp_connection_selector) - def scamp_connection_selector(self) -> ConnectionSelector: - """ - Returns the scamp selector - - :rtype: AbstractMultiConnectionProcessConnectionSelector - """ - raise NotImplementedError - - def is_connected(self, connection=None): + def is_connected(self, connection: Optional[Connection] = None) -> bool: """ Determines if the board can be contacted via SCAMP @@ -102,10 +103,11 @@ def is_connected(self, connection=None): """ if connection is not None: return connection.is_connected() + assert isinstance(self, BaseTransceiver) return any(c.is_connected() and isinstance(c, SCAMPConnection) - for c in self.scamp_connections) + for c in self._scamp_connections) - def get_iobuf_from_core(self, x, y, p): + def get_iobuf_from_core(self, x: int, y: int, p: int) -> IOBuffer: """ Get the contents of IOBUF for a given core. @@ -129,12 +131,17 @@ def get_iobuf_from_core(self, x, y, p): """ warn_once(logger, "The get_iobuf_from_core method is deprecated and " "likely to be removed.") + assert isinstance(self, Transceiver) core_subsets = CoreSubsets() core_subsets.add_processor(x, y, p) - return next(self.get_iobuf(core_subsets)) + iobufs: Iterable[IOBuffer] = self.get_iobuf(core_subsets) + for iobuf in iobufs: + return iobuf + raise ValueError("No iobuf found") @contextmanager - def _chip_execute_lock(self, x, y): + def _chip_execute_lock( + self, x: int, y: int) -> Generator[Condition, None, None]: """ Get a lock for executing an executable on a chip. @@ -145,6 +152,7 @@ def _chip_execute_lock(self, x, y): :param int x: :param int y: """ + assert isinstance(self, BaseTransceiver) # Check if there is a lock for the given chip with self._chip_execute_lock_condition: chip_lock = self._chip_execute_locks[x, y] @@ -165,8 +173,9 @@ def _chip_execute_lock(self, x, y): self._n_chip_execute_locks -= 1 self._chip_execute_lock_condition.notify_all() - def execute(self, x, y, processors, executable, app_id, n_bytes=None, - wait=False): + def execute(self, x: int, y: int, processors: List[int], + executable: Union[BinaryIO, bytes, int, str], app_id: int, + n_bytes: Optional[int] = None, wait: bool = False) -> None: """ Start an executable running on a single chip. @@ -214,17 +223,20 @@ def execute(self, x, y, processors, executable, app_id, n_bytes=None, """ warn_once(logger, "The Transceiver's execute method is deprecated " "likely to be removed.") + assert isinstance(self, Transceiver) # Lock against updates with self._chip_execute_lock(x, y): # Write the executable self.write_memory( - x, y, self._EXECUTABLE_ADDRESS, executable, n_bytes=n_bytes) + x, y, _EXECUTABLE_ADDRESS, executable, n_bytes=n_bytes) # Request the start of the executable - process = SendSingleCommandProcess(self._scamp_connection_selector) + process: SendSingleCommandProcess = SendSingleCommandProcess( + self.get_scamp_connection_selector()) process.execute(ApplicationRun(app_id, x, y, processors, wait)) - def execute_application(self, executable_targets, app_id): + def execute_application( + self, executable_targets: ExecutableTargets, app_id: int) -> None: """ Execute a set of binaries that make up a complete application on specified cores, wait for them to be ready and then start all of the @@ -238,6 +250,7 @@ def execute_application(self, executable_targets, app_id): The binaries to be executed and the cores to execute them on :param int app_id: The app_id to give this application """ + assert isinstance(self, Transceiver) # Execute each of the binaries and get them in to a "wait" state for binary in executable_targets.binaries: core_subsets = executable_targets.get_cores_for_binary(binary) @@ -261,7 +274,8 @@ def execute_application(self, executable_targets, app_id): # Send a signal telling the application to start self.send_signal(app_id, Signal.START) - def set_led(self, led, action, board): + def set_led(self, led: Union[int, Iterable[int]], action: LEDAction, + board: Union[int, Iterable[int]]) -> None: """ Set the LED state of a board in the machine. @@ -282,10 +296,13 @@ def set_led(self, led, action, board): """ warn_once(logger, "The set_led method is deprecated and " "untested due to no known use.") - process = SendSingleCommandProcess(self.bmp_selector) + assert isinstance(self, ExtendableTransceiver) + assert self.bmp_selector is not None + process: SendSingleCommandProcess = SendSingleCommandProcess( + self.bmp_selector) process.execute(BMPSetLed(led, action, board)) - def read_adc_data(self, board): + def read_adc_data(self, board: int) -> ADCInfo: """ Read the BMP ADC data. @@ -300,12 +317,18 @@ def read_adc_data(self, board): """ warn_once(logger, "The read_adc_data method is deprecated and " "untested due to no known use.") - process = SendSingleCommandProcess(self.bmp_selector) + assert isinstance(self, ExtendableTransceiver) + assert self.bmp_selector is not None + process: SendSingleCommandProcess = SendSingleCommandProcess( + self.bmp_selector) response = process.execute(ReadADC(board)) return response.adc_info # pylint: disable=no-member - def write_neighbour_memory(self, x, y, link, base_address, data, - n_bytes=None, offset=0, cpu=0): + def write_neighbour_memory( + self, x: int, y: int, link: int, base_address: int, + data: Union[BinaryIO, str, int, bytes], + n_bytes: Optional[int] = None, offset: int = 0, + cpu: int = 0) -> None: """ Write to the memory of a neighbouring chip using a LINK_READ SCP command. If sent to a BMP, this command can be used to communicate @@ -358,21 +381,26 @@ def write_neighbour_memory(self, x, y, link, base_address, data, """ warn_once(logger, "The write_neighbour_memory method is deprecated " "and untested due to no known use.") - process = WriteMemoryProcess(self.scamp_connection_selector) - if isinstance(data, io.RawIOBase): + assert isinstance(self, Transceiver) + process = WriteMemoryProcess(self.get_scamp_connection_selector()) + if isinstance(data, BinaryIO): + assert n_bytes is not None process.write_link_memory_from_reader( (x, y, cpu), link, base_address, data, n_bytes) elif isinstance(data, int): - data_to_write = self._ONE_WORD.pack(data) + data_to_write = _ONE_WORD.pack(data) process.write_link_memory_from_bytearray( (x, y, cpu), link, base_address, data_to_write, 0, 4) else: + assert isinstance(data, bytes) if n_bytes is None: n_bytes = len(data) process.write_link_memory_from_bytearray( (x, y, cpu), link, base_address, data, offset, n_bytes) - def read_neighbour_memory(self, x, y, link, base_address, length, cpu=0): + def read_neighbour_memory( + self, x: int, y: int, link: int, base_address: int, length: int, + cpu: int = 0) -> bytearray: """ Read some areas of memory on a neighbouring chip using a LINK_READ SCP command. If sent to a BMP, this command can be used to @@ -406,25 +434,29 @@ def read_neighbour_memory(self, x, y, link, base_address, length, cpu=0): :raise SpinnmanUnexpectedResponseCodeException: If a response indicates an error during the exchange """ + assert isinstance(self, Transceiver) try: warn_once(logger, "The read_neighbour_memory method is deprecated " "and untested due to no known use.") - process = ReadMemoryProcess(self.scamp_connection_selector) + process = ReadMemoryProcess(self.get_scamp_connection_selector()) return process.read_link_memory( (x, y, cpu), link, base_address, length) except Exception: - logger.info(self.where_is_xy(x, y)) + logger.info(self._where_is_xy(x, y)) raise - def _get_next_nearest_neighbour_id(self): + def _get_next_nearest_neighbour_id(self) -> int: + assert isinstance(self, ExtendableTransceiver) with self._nearest_neighbour_lock: next_nearest_neighbour_id = (self._nearest_neighbour_id + 1) % 127 - self._nearest_neighbour_id = next_nearest_neighbour_id + self._nearest_neighbour_id: int = next_nearest_neighbour_id return next_nearest_neighbour_id def write_memory_flood( - self, base_address, data, n_bytes=None, offset=0, - is_filename=False): + self, base_address: int, + data: Union[BinaryIO, str, int, bytes], + n_bytes: Optional[int] = None, offset: int = 0, + is_filename: bool = False) -> None: """ Write to the SDRAM of all chips. @@ -465,12 +497,15 @@ def write_memory_flood( :raise SpinnmanUnexpectedResponseCodeException: If a response indicates an error during the exchange """ - process = WriteMemoryFloodProcess(self._scamp_connection_selector) + assert isinstance(self, Transceiver) + assert isinstance(self, ExtendableTransceiver) + process = WriteMemoryFloodProcess(self.get_scamp_connection_selector()) # Ensure only one flood fill occurs at any one time with self._flood_write_lock: # Start the flood fill nearest_neighbour_id = self._get_next_nearest_neighbour_id() - if isinstance(data, io.RawIOBase): + if isinstance(data, BinaryIO): + assert n_bytes is not None process.write_memory_from_reader( nearest_neighbour_id, base_address, data, n_bytes) elif isinstance(data, str) and is_filename: @@ -480,16 +515,18 @@ def write_memory_flood( process.write_memory_from_reader( nearest_neighbour_id, base_address, reader, n_bytes) elif isinstance(data, int): - data_to_write = self._ONE_WORD.pack(data) + data_to_write = _ONE_WORD.pack(data) process.write_memory_from_bytearray( nearest_neighbour_id, base_address, data_to_write, 0) else: + assert isinstance(data, bytes) if n_bytes is None: n_bytes = len(data) process.write_memory_from_bytearray( nearest_neighbour_id, base_address, data, offset, n_bytes) - def set_leds(self, x, y, cpu, led_states): + def set_leds(self, x: int, y: int, cpu: int, + led_states: Mapping[int, int]) -> None: """ Set LED states. @@ -511,16 +548,18 @@ def set_leds(self, x, y, cpu, led_states): :raise SpinnmanUnexpectedResponseCodeException: If a response indicates an error during the exchange """ + assert isinstance(self, Transceiver) try: warn_once(logger, "The set_leds is deprecated and " "untested due to no known use.") - process = SendSingleCommandProcess(self._scamp_connection_selector) + process: SendSingleCommandProcess = SendSingleCommandProcess( + self.get_scamp_connection_selector()) process.execute(SetLED(x, y, cpu, led_states)) except Exception: - logger.info(self.where_is_xy(x, y)) + logger.info(self._where_is_xy(x, y)) raise - def free_sdram(self, x, y, base_address): + def free_sdram(self, x: int, y: int, base_address: int) -> None: """ Free allocated SDRAM. @@ -531,16 +570,18 @@ def free_sdram(self, x, y, base_address): :param int y: The y-coordinate of the chip onto which to ask for memory :param int base_address: The base address of the allocated memory """ + assert isinstance(self, Transceiver) try: warn_once(logger, "The free_sdram method is deprecated and " "likely to be removed.") - process = DeAllocSDRAMProcess(self._scamp_connection_selector) + process = DeAllocSDRAMProcess(self.get_scamp_connection_selector()) process.de_alloc_sdram(x, y, base_address) except Exception: - logger.info(self.where_is_xy(x, y)) + logger.info(self._where_is_xy(x, y)) raise - def free_sdram_by_app_id(self, x, y, app_id): + def free_sdram_by_app_id( + self, x: int, y: int, app_id: int) -> Optional[int]: """ Free all SDRAM allocated to a given app ID. @@ -555,14 +596,15 @@ def free_sdram_by_app_id(self, x, y, app_id): :return: The number of blocks freed :rtype: int """ + assert isinstance(self, Transceiver) try: warn_once(logger, "The free_sdram_by_app_id method is deprecated " "and untested due to no known use.") - process = DeAllocSDRAMProcess(self._scamp_connection_selector) + process = DeAllocSDRAMProcess(self.get_scamp_connection_selector()) process.de_alloc_sdram(x, y, app_id) return process.no_blocks_freed except Exception: - logger.info(self.where_is_xy(x, y)) + logger.info(self._where_is_xy(x, y)) raise def get_router_diagnostic_filter( @@ -592,13 +634,14 @@ def get_router_diagnostic_filter( :raise SpinnmanUnexpectedResponseCodeException: If a response indicates an error during the exchange """ + assert isinstance(self, Transceiver) try: memory_position = ( ROUTER_REGISTER_BASE_ADDRESS + ROUTER_FILTER_CONTROLS_OFFSET + position * ROUTER_DIAGNOSTIC_FILTER_SIZE) process: SendSingleCommandProcess = SendSingleCommandProcess( - self.scamp_connection_selector) + self.get_scamp_connection_selector()) response = process.execute( ReadMemory((x, y, 0), memory_position, 4)) return DiagnosticFilter.read_from_int(_ONE_WORD.unpack_from( @@ -609,7 +652,7 @@ def get_router_diagnostic_filter( raise @property - def number_of_boards_located(self): + def number_of_boards_located(self) -> int: """ The number of boards currently configured. @@ -620,13 +663,17 @@ def number_of_boards_located(self): """ warn_once(logger, "The number_of_boards_located method is deprecated " "and likely to be removed.") - if self.bmp_connection is not None: - return max(1, len(self.bmp_connection.boards)) + assert isinstance(self, BaseTransceiver) + if self._bmp_connection is not None: + return max(1, len(self._bmp_connection.boards)) else: # if no BMPs are available, then there's still at least one board return 1 - def get_heap(self, x, y, heap=SystemVariableDefinition.sdram_heap_address): + def get_heap(self, x: int, y: int, + heap: SystemVariableDefinition = + SystemVariableDefinition.sdram_heap_address + ) -> Sequence[HeapElement]: """ Get the contents of the given heap on a given chip. @@ -634,16 +681,18 @@ def get_heap(self, x, y, heap=SystemVariableDefinition.sdram_heap_address): :param int y: The y-coordinate of the chip :param SystemVariableDefinition heap: The SystemVariableDefinition which is the heap to read - :rtype: list(HeapElement) """ + assert isinstance(self, Transceiver) try: - process = GetHeapProcess(self.scamp_connection_selector) + process = GetHeapProcess( + self.get_scamp_connection_selector()) return process.get_heap((x, y), heap) except Exception: - logger.info(self.where_is_xy(x, y)) + logger.info(self._where_is_xy(x, y)) raise - def __set_watch_dog_on_chip(self, x, y, watch_dog): + def __set_watch_dog_on_chip( + self, x: int, y: int, watch_dog: Union[int, bool]) -> None: """ Enable, disable or set the value of the watch dog timer on a specific chip. @@ -664,7 +713,8 @@ def __set_watch_dog_on_chip(self, x, y, watch_dog): # build what we expect it to be warn_once(logger, "The set_watch_dog_on_chip method is deprecated " "and untested due to no known use.") - value_to_set = watch_dog + assert isinstance(self, Transceiver) + value_to_set: Union[int, bool, bytes] = watch_dog watchdog = SystemVariableDefinition.software_watchdog_count if isinstance(watch_dog, bool): value_to_set = watchdog.default if watch_dog else 0 @@ -676,7 +726,7 @@ def __set_watch_dog_on_chip(self, x, y, watch_dog): address = SYSTEM_VARIABLE_BASE_ADDRESS + watchdog.offset self.write_memory(x=x, y=y, base_address=address, data=data) - def set_watch_dog(self, watch_dog): + def set_watch_dog(self, watch_dog: Union[int, bool]) -> None: """ Enable, disable or set the value of the watch dog timer. diff --git a/spinnman/transceiver/extendable_transceiver.py b/spinnman/transceiver/extendable_transceiver.py index 953ce9886..53fe4b7b9 100644 --- a/spinnman/transceiver/extendable_transceiver.py +++ b/spinnman/transceiver/extendable_transceiver.py @@ -39,7 +39,7 @@ class ExtendableTransceiver(Transceiver, metaclass=AbstractBase): "_nearest_neighbour_lock" ] - def __init__(self): + def __init__(self) -> None: # A lock against multiple flood fill writes - needed as SCAMP cannot # cope with this From 7691d3ced892f80aa0ee374f2697b11b557b67c0 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 29 Oct 2024 07:58:47 +0000 Subject: [PATCH 08/18] typing --- .../abstract_scp_connection.py | 2 +- spinnman/connections/connection_listener.py | 6 ++-- spinnman/connections/scp_request_pipeline.py | 28 +++++++++++-------- .../udp_packet_connections/bmp_connection.py | 2 +- .../udp_packet_connections/boot_connection.py | 4 +-- .../eieio_connection.py | 4 +-- .../ip_address_connection.py | 6 ++-- .../scamp_connection.py | 2 +- .../udp_packet_connections/sdp_connection.py | 2 +- .../udp_packet_connections/udp_connection.py | 6 ++-- spinnman/exceptions.py | 8 +++--- spinnman/extended/de_alloc_sdram_process.py | 12 ++++---- spinnman/extended/read_adc.py | 2 +- .../extended/write_memory_flood_process.py | 9 +++--- spinnman/messages/scp/impl/app_copy_run.py | 2 +- spinnman/messages/scp/impl/app_stop.py | 2 +- .../messages/scp/impl/check_ok_response.py | 7 +++-- spinnman/messages/scp/impl/iptag_set.py | 5 +++- .../abstract_multi_connection_process.py | 6 ++-- .../processes/application_copy_run_process.py | 4 +-- spinnman/processes/application_run_process.py | 2 +- spinnman/processes/get_cpu_info_process.py | 3 +- spinnman/processes/get_heap_process.py | 8 +++--- spinnman/processes/get_machine_process.py | 23 +++++++++------ .../processes/get_n_cores_in_state_process.py | 15 ++++++---- spinnman/processes/get_routes_process.py | 4 +-- spinnman/processes/get_tags_process.py | 7 +++-- spinnman/processes/get_version_process.py | 2 +- .../load_fixed_route_routing_entry_process.py | 2 +- spinnman/processes/load_routes_process.py | 5 ++-- spinnman/processes/malloc_sdram_process.py | 5 ++-- .../read_fixed_route_routing_entry_process.py | 2 +- spinnman/processes/read_iobuf_process.py | 13 +++++---- spinnman/processes/read_memory_process.py | 2 +- .../read_router_diagnostics_process.py | 6 ++-- .../processes/send_single_command_process.py | 2 +- spinnman/utilities/utility_functions.py | 7 +++-- 37 files changed, 128 insertions(+), 99 deletions(-) diff --git a/spinnman/connections/abstract_classes/abstract_scp_connection.py b/spinnman/connections/abstract_classes/abstract_scp_connection.py index 8b05f40a4..b81471614 100644 --- a/spinnman/connections/abstract_classes/abstract_scp_connection.py +++ b/spinnman/connections/abstract_classes/abstract_scp_connection.py @@ -26,7 +26,7 @@ class AbstractSCPConnection(Connection, metaclass=AbstractBase): __slots__ = () @abstractmethod - def is_ready_to_receive(self, timeout: float = 0): + def is_ready_to_receive(self, timeout: float = 0) -> bool: """ Determines if there is an SCP packet to be read without blocking. diff --git a/spinnman/connections/connection_listener.py b/spinnman/connections/connection_listener.py index 01b51f388..f0ea79cac 100644 --- a/spinnman/connections/connection_listener.py +++ b/spinnman/connections/connection_listener.py @@ -58,7 +58,7 @@ def __init__(self, connection: Listenable[T], self.__done = False self.__callbacks: List[Callable[[T], None]] = [] - def __run_step(self, handler: Callable[[], T]): + def __run_step(self, handler: Callable[[], T]) -> None: """ :param ~collections.abc.Callable handler: """ @@ -69,7 +69,7 @@ def __run_step(self, handler: Callable[[], T]): callback, message) future.add_done_callback(self.__done_callback) - def __done_callback(self, future: Future[None]): + def __done_callback(self, future: Future[None]) -> None: """ :param ~concurrent.futures.Future future: """ @@ -94,7 +94,7 @@ def run(self) -> None: logger.warning("problem when dispatching message", exc_info=True) - def add_callback(self, callback: Callable[[T], None]): + def add_callback(self, callback: Callable[[T], None]) -> None: """ Add a callback to be called when a message is received. diff --git a/spinnman/connections/scp_request_pipeline.py b/spinnman/connections/scp_request_pipeline.py index f234cf87c..dfe972bfb 100644 --- a/spinnman/connections/scp_request_pipeline.py +++ b/spinnman/connections/scp_request_pipeline.py @@ -16,7 +16,8 @@ from threading import RLock import time from types import TracebackType -from typing import Callable, Dict, Generic, List, Optional, TypeVar, cast +from typing import (Callable, Dict, Generic, List, Optional, Set, TypeVar, + cast) from typing_extensions import TypeAlias from spinnman.messages.scp.enums import SCPResult from spinnman.exceptions import SpinnmanTimeoutException, SpinnmanIOException @@ -77,10 +78,11 @@ class SCPRequestPipeLine(Generic[R]): "_retries", "_send_time") - def __init__(self, connection: SCAMPConnection, n_channels=1, - intermediate_channel_waits=0, - n_retries=N_RETRIES, packet_timeout=SCP_TIMEOUT, - non_fail_retry_codes=None): + def __init__(self, connection: SCAMPConnection, n_channels: int = 1, + intermediate_channel_waits: int = 0, + n_retries: int = N_RETRIES, + packet_timeout: float = SCP_TIMEOUT, + non_fail_retry_codes: Optional[Set[SCPResult]] = None): """ :param SCAMPConnection connection: The connection over which the communication is to take place @@ -134,10 +136,11 @@ def __init__(self, connection: SCAMPConnection, n_channels=1, # The number of packets that have been resent self._n_resent = 0 self._n_retry_code_resent = 0 - self._non_fail_retry_codes = non_fail_retry_codes - if self._non_fail_retry_codes is None: + self._non_fail_retry_codes: Set[SCPResult] + if non_fail_retry_codes is None: self._non_fail_retry_codes = set() - + else: + self._non_fail_retry_codes = non_fail_retry_codes # self._token_bucket = TokenBucket(43750, 4375000) # self._token_bucket = TokenBucket(3408, 700000) @@ -159,7 +162,7 @@ def __get_next_sequence_number() -> int: def send_request( self, request: AbstractSCPRequest[R], callback: Optional[CB], - error_callback: ECB): + error_callback: ECB) -> None: """ Add an SCP request to the set to be sent. @@ -260,7 +263,7 @@ def _remove_record(self, seq: int) -> None: del self._error_callbacks[seq] del self._retry_reason[seq] - def _single_retrieve(self, timeout: float): + def _single_retrieve(self, timeout: float) -> None: # Receive the next response result, seq, raw_data, offset = \ self._connection.receive_scp_response(timeout) @@ -320,7 +323,8 @@ def _handle_receive_timeout(self) -> None: for seq in to_remove: self._remove_record(seq) - def _resend(self, seq: int, request_sent, reason: str): + def _resend(self, seq: int, request_sent: AbstractSCPRequest, + reason: str) -> None: if self._retries[seq] <= 0: # Report timeouts as timeout exception @@ -346,7 +350,7 @@ def _resend(self, seq: int, request_sent, reason: str): self._connection.send(self._request_data[seq]) self._n_resent += 1 - def _do_retrieve(self, n_packets: int, timeout: float): + def _do_retrieve(self, n_packets: int, timeout: float) -> None: """ Receives responses until there are only n_packets responses left. diff --git a/spinnman/connections/udp_packet_connections/bmp_connection.py b/spinnman/connections/udp_packet_connections/bmp_connection.py index 4b123b85b..12d8583b5 100644 --- a/spinnman/connections/udp_packet_connections/bmp_connection.py +++ b/spinnman/connections/udp_packet_connections/bmp_connection.py @@ -83,7 +83,7 @@ def receive_scp_response(self, timeout: Optional[float] = 1.0) -> Tuple[ result, sequence = _TWO_SHORTS.unpack_from(data, 10) return SCPResult(result), sequence, data, 2 - def __repr__(self): + def __repr__(self) -> str: return ( f"BMPConnection(" f"boards={self._boards}, local_host={self.local_ip_address}, " diff --git a/spinnman/connections/udp_packet_connections/boot_connection.py b/spinnman/connections/udp_packet_connections/boot_connection.py index f7c41536c..a5c39473c 100644 --- a/spinnman/connections/udp_packet_connections/boot_connection.py +++ b/spinnman/connections/udp_packet_connections/boot_connection.py @@ -44,7 +44,7 @@ def __init__(self, remote_host: Optional[str] = None): super().__init__(remote_host=remote_host, remote_port=UDP_BOOT_CONNECTION_DEFAULT_PORT) - def send_boot_message(self, boot_message: SpinnakerBootMessage): + def send_boot_message(self, boot_message: SpinnakerBootMessage) -> None: """ Sends a SpiNNaker boot message using this connection. @@ -80,7 +80,7 @@ def receive_boot_message( data = self.receive(timeout) return SpinnakerBootMessage.from_bytestring(data, 0) - def __repr__(self): + def __repr__(self) -> str: return self._REPR_TEMPLATE.format( self.local_ip_address, self.local_port, self.remote_ip_address, self.remote_port) diff --git a/spinnman/connections/udp_packet_connections/eieio_connection.py b/spinnman/connections/udp_packet_connections/eieio_connection.py index c3b228b2e..d774c76b8 100644 --- a/spinnman/connections/udp_packet_connections/eieio_connection.py +++ b/spinnman/connections/udp_packet_connections/eieio_connection.py @@ -61,7 +61,7 @@ def receive_eieio_message( return read_eieio_command_message(data, 0) return read_eieio_data_message(data, 0) - def send_eieio_message(self, eieio_message: AbstractEIEIOMessage): + def send_eieio_message(self, eieio_message: AbstractEIEIOMessage) -> None: """ Sends an EIEIO message down this connection. @@ -74,7 +74,7 @@ def send_eieio_message(self, eieio_message: AbstractEIEIOMessage): def send_eieio_message_to( self, eieio_message: AbstractEIEIOMessage, - ip_address: str, port: int): + ip_address: str, port: int) -> None: """ :param AbstractEIEIOMessage eieio_message: diff --git a/spinnman/connections/udp_packet_connections/ip_address_connection.py b/spinnman/connections/udp_packet_connections/ip_address_connection.py index 42b6ed142..f13d032a3 100644 --- a/spinnman/connections/udp_packet_connections/ip_address_connection.py +++ b/spinnman/connections/udp_packet_connections/ip_address_connection.py @@ -26,8 +26,8 @@ class IPAddressesConnection(UDPConnection): """ __slots__ = () - def __init__(self, local_host=None, - local_port=UDP_BOOT_CONNECTION_DEFAULT_PORT): + def __init__(self, local_host: Optional[str] = None, + local_port: int = UDP_BOOT_CONNECTION_DEFAULT_PORT): super().__init__(local_host=local_host, local_port=local_port) def receive_ip_address(self, timeout: Optional[float] = None @@ -44,6 +44,6 @@ def receive_ip_address(self, timeout: Optional[float] = None return ip_address return None - def __repr__(self): + def __repr__(self) -> str: return f"IPAddressesConnection(local_host={self.local_ip_address}," \ f" local_port={self.local_port})" diff --git a/spinnman/connections/udp_packet_connections/scamp_connection.py b/spinnman/connections/udp_packet_connections/scamp_connection.py index 738317d4d..7d9875cae 100644 --- a/spinnman/connections/udp_packet_connections/scamp_connection.py +++ b/spinnman/connections/udp_packet_connections/scamp_connection.py @@ -68,7 +68,7 @@ def chip_x(self) -> int: def chip_y(self) -> int: return self._chip_y - def update_chip_coordinates(self, x: int, y: int): + def update_chip_coordinates(self, x: int, y: int) -> None: """ Sets the coordinates without checking they are valid. diff --git a/spinnman/connections/udp_packet_connections/sdp_connection.py b/spinnman/connections/udp_packet_connections/sdp_connection.py index f5e1d3467..e9457af50 100644 --- a/spinnman/connections/udp_packet_connections/sdp_connection.py +++ b/spinnman/connections/udp_packet_connections/sdp_connection.py @@ -84,7 +84,7 @@ def receive_sdp_message( data = self.receive(timeout) return SDPMessage.from_bytestring(data, 2) - def send_sdp_message(self, sdp_message: SDPMessage): + def send_sdp_message(self, sdp_message: SDPMessage) -> None: """ Sends an SDP message down this connection. diff --git a/spinnman/connections/udp_packet_connections/udp_connection.py b/spinnman/connections/udp_packet_connections/udp_connection.py index bf8f87101..3aae551d1 100644 --- a/spinnman/connections/udp_packet_connections/udp_connection.py +++ b/spinnman/connections/udp_packet_connections/udp_connection.py @@ -219,7 +219,7 @@ def receive_with_address(self, timeout: Optional[float] = None) -> Tuple[ raise SpinnmanEOFException() return receive_message_and_address(self._socket, timeout, _MSG_MAX) - def send(self, data: bytes): + def send(self, data: bytes) -> None: """ Send data down this connection. @@ -237,7 +237,7 @@ def send(self, data: bytes): if self.__is_closed: raise SpinnmanEOFException() - def send_to(self, data: bytes, address: Tuple[str, int]): + def send_to(self, data: bytes, address: Tuple[str, int]) -> None: """ Send data down this connection. @@ -261,7 +261,7 @@ def close(self) -> None: self._socket.shutdown(socket.SHUT_WR) self._socket.close() - def is_ready_to_receive(self, timeout: float = 0): + def is_ready_to_receive(self, timeout: float = 0) -> bool: if self.__is_closed: return True return len(select.select([self._socket], [], [], timeout)[0]) == 1 diff --git a/spinnman/exceptions.py b/spinnman/exceptions.py index a89962eb7..628bf8630 100644 --- a/spinnman/exceptions.py +++ b/spinnman/exceptions.py @@ -14,7 +14,7 @@ from __future__ import annotations import traceback from types import TracebackType -from typing import List, Optional, FrozenSet, Union, TYPE_CHECKING +from typing import Any, List, Optional, FrozenSet, Union, TYPE_CHECKING if TYPE_CHECKING: from spinnman.messages.scp.enums import SCPResult from spinnman.model.enums import CPUState @@ -192,11 +192,11 @@ class SpinnmanTimeoutException(SpinnmanException): could finish. """ - def __init__(self, operation: str, timeout: Optional[float], + def __init__(self, operation: Any, timeout: Optional[float], msg: Optional[str] = None): """ - :param str operation: The operation being performed - :param float timeout: The timeout value in seconds + :param operation: The operation being performed + :param timeout: The timeout value in seconds """ if msg is None: msg = f"Operation {operation} timed out after {timeout} seconds" diff --git a/spinnman/extended/de_alloc_sdram_process.py b/spinnman/extended/de_alloc_sdram_process.py index b70cca50d..331338b33 100644 --- a/spinnman/extended/de_alloc_sdram_process.py +++ b/spinnman/extended/de_alloc_sdram_process.py @@ -13,7 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. from typing import Optional -from spinnman.messages.scp.impl import SDRAMDeAlloc +from spinnman.messages.scp.impl.sdram_de_alloc import ( + SDRAMDeAlloc, _SCPSDRAMDeAllocResponse) from spinnman.processes import AbstractMultiConnectionProcess from spinnman.processes import ConnectionSelector @@ -27,14 +28,14 @@ class DeAllocSDRAMProcess(AbstractMultiConnectionProcess): """ __slots__ = ("_no_blocks_freed", ) - def __init__(self, connection_selector: ConnectionSelector): + def __init__(self, connection_selector: ConnectionSelector) -> None: """ :param ConnectionSelector connection_selector: """ super().__init__(connection_selector) self._no_blocks_freed: Optional[int] = None - def de_alloc_all_app_sdram(self, x: int, y: int, app_id: int): + def de_alloc_all_app_sdram(self, x: int, y: int, app_id: int) -> None: """ :param int x: :param int y: @@ -47,7 +48,7 @@ def de_alloc_all_app_sdram(self, x: int, y: int, app_id: int): self._send_request(SDRAMDeAlloc(x, y, app_id=app_id), callback=self.__handle_sdram_alloc_response) - def de_alloc_sdram(self, x: int, y: int, base_address: int): + def de_alloc_sdram(self, x: int, y: int, base_address: int) -> None: """ :param int x: :param int y: @@ -57,7 +58,8 @@ def de_alloc_sdram(self, x: int, y: int, base_address: int): self._send_request(SDRAMDeAlloc(x, y, base_address=base_address), callback=None) - def __handle_sdram_alloc_response(self, response): + def __handle_sdram_alloc_response( + self, response: _SCPSDRAMDeAllocResponse) -> None: self._no_blocks_freed = response.number_of_blocks_freed @property diff --git a/spinnman/extended/read_adc.py b/spinnman/extended/read_adc.py index 2c82978e5..c82b8ca26 100644 --- a/spinnman/extended/read_adc.py +++ b/spinnman/extended/read_adc.py @@ -62,7 +62,7 @@ def _parse_payload(self, data: bytes, offset: int) -> ADCInfo: return ADCInfo(data, offset) @property - def adc_info(self): + def adc_info(self) -> ADCInfo: """ The ADC information. """ diff --git a/spinnman/extended/write_memory_flood_process.py b/spinnman/extended/write_memory_flood_process.py index 6cecb6297..f3b3349bd 100644 --- a/spinnman/extended/write_memory_flood_process.py +++ b/spinnman/extended/write_memory_flood_process.py @@ -32,20 +32,21 @@ def __init__(self, next_connection_selector: ConnectionSelector): self, next_connection_selector, n_channels=3, intermediate_channel_waits=2) - def _start_flood_fill(self, n_bytes: int, nearest_neighbour_id: int): + def _start_flood_fill( + self, n_bytes: int, nearest_neighbour_id: int) -> None: n_blocks = int(math.ceil(math.ceil(n_bytes / 4.0) / UDP_MESSAGE_MAX_SIZE)) with self._collect_responses(): self._send_request( FloodFillStart(nearest_neighbour_id, n_blocks)) - def _end_flood_fill(self, nearest_neighbour_id: int): + def _end_flood_fill(self, nearest_neighbour_id: int) -> None: with self._collect_responses(): self._send_request(FloodFillEnd(nearest_neighbour_id)) def write_memory_from_bytearray( self, nearest_neighbour_id: int, base_address: int, - data: bytes, offset: int, n_bytes: Optional[int] = None): + data: bytes, offset: int, n_bytes: Optional[int] = None) -> None: """ :param int nearest_neighbour_id: :param int base_address: @@ -79,7 +80,7 @@ def write_memory_from_bytearray( def write_memory_from_reader( self, nearest_neighbour_id: int, base_address: int, - reader: BinaryIO, n_bytes: int): + reader: BinaryIO, n_bytes: int) -> None: """ :param int nearest_neighbour_id: :param int base_address: diff --git a/spinnman/messages/scp/impl/app_copy_run.py b/spinnman/messages/scp/impl/app_copy_run.py index 4e52403f3..c09456a84 100644 --- a/spinnman/messages/scp/impl/app_copy_run.py +++ b/spinnman/messages/scp/impl/app_copy_run.py @@ -70,7 +70,7 @@ def __init__(self, x: int, y: int, link: int, size: int, app_id: int, SCPRequestHeader(command=SCPCommand.CMD_APP_COPY_RUN), argument_1=arg1, argument_2=size, argument_3=processor_mask) - def __repr__(self): + def __repr__(self) -> str: return f"{super(AppCopyRun, self).__repr__()} (Link {self.__link})" @overrides(AbstractSCPRequest.get_scp_response) diff --git a/spinnman/messages/scp/impl/app_stop.py b/spinnman/messages/scp/impl/app_stop.py index 263009d73..aae57f064 100644 --- a/spinnman/messages/scp/impl/app_stop.py +++ b/spinnman/messages/scp/impl/app_stop.py @@ -22,7 +22,7 @@ _APP_MASK = 0xFF -def _get_data(app_id, signal): +def _get_data(app_id: int, signal: Signal) -> int: data = (_APP_MASK << 8) | app_id data += signal.value << 16 return data diff --git a/spinnman/messages/scp/impl/check_ok_response.py b/spinnman/messages/scp/impl/check_ok_response.py index 4f4a140b0..be627c42f 100644 --- a/spinnman/messages/scp/impl/check_ok_response.py +++ b/spinnman/messages/scp/impl/check_ok_response.py @@ -12,6 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from enum import Enum +from typing import Union + from spinn_utilities.overrides import overrides from spinnman.messages.scp.abstract_messages import AbstractSCPResponse from spinnman.messages.scp.enums import SCPResult @@ -26,7 +29,7 @@ class CheckOKResponse(AbstractSCPResponse): "_command", "_operation") - def __init__(self, operation: str, command): + def __init__(self, operation: str, command: Union[Enum, int, str]): """ :param str operation: The operation being performed :param command: The command that was sent @@ -37,7 +40,7 @@ def __init__(self, operation: str, command): self._command = command @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/iptag_set.py b/spinnman/messages/scp/impl/iptag_set.py index 92f4b7ffc..bf9eff044 100644 --- a/spinnman/messages/scp/impl/iptag_set.py +++ b/spinnman/messages/scp/impl/iptag_set.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import List, Union + from spinn_utilities.overrides import overrides from spinnman.messages.scp import SCPRequestHeader from spinnman.messages.scp.abstract_messages import AbstractSCPRequest @@ -28,7 +30,8 @@ class IPTagSet(AbstractSCPRequest[CheckOKResponse]): """ __slots__ = () - def __init__(self, x: int, y: int, host, port: int, tag: int, *, + def __init__(self, x: int, y: int, host: Union[bytearray, List[int]], + port: int, tag: int, *, strip: bool = False, use_sender: bool = False): """ :param int x: The x-coordinate of a chip, between 0 and 255 diff --git a/spinnman/processes/abstract_multi_connection_process.py b/spinnman/processes/abstract_multi_connection_process.py index 406c744f6..46be758cd 100644 --- a/spinnman/processes/abstract_multi_connection_process.py +++ b/spinnman/processes/abstract_multi_connection_process.py @@ -101,7 +101,7 @@ def __init__(self, next_connection_selector: ConnectionSelector, def _send_request(self, request: AbstractSCPRequest[R], callback: Optional[Callable[[R], None]] = None, - error_callback: Optional[ECB] = None): + error_callback: Optional[ECB] = None) -> None: if error_callback is None: error_callback = self._receive_error connection = self._conn_selector.get_next_connection(request) @@ -117,7 +117,7 @@ def _send_request(self, request: AbstractSCPRequest[R], def _receive_error( self, request: AbstractSCPRequest[R], exception: Exception, - tb: TracebackType, connection: SCAMPConnection): + tb: TracebackType, connection: SCAMPConnection) -> None: self._error_requests.append(request) self._exceptions.append(exception) self._tracebacks.append(tb) @@ -171,7 +171,7 @@ def connection_selector(self) -> ConnectionSelector: """ return self._conn_selector - def check_for_error(self, print_exception: bool = False): + def check_for_error(self, print_exception: bool = False) -> None: """ Check if any errors have been cached and raises them diff --git a/spinnman/processes/application_copy_run_process.py b/spinnman/processes/application_copy_run_process.py index 33c80a538..03d4884db 100644 --- a/spinnman/processes/application_copy_run_process.py +++ b/spinnman/processes/application_copy_run_process.py @@ -23,7 +23,7 @@ APP_COPY_RUN_TIMEOUT = 6.0 -def _on_same_board(chip_1: Chip, chip_2: Chip): +def _on_same_board(chip_1: Chip, chip_2: Chip) -> bool: return (chip_1.nearest_ethernet_x == chip_2.nearest_ethernet_x and chip_1.nearest_ethernet_y == chip_2.nearest_ethernet_y) @@ -104,7 +104,7 @@ def __init__(self, next_connection_selector: ConnectionSelector, self, next_connection_selector, timeout=timeout) def run(self, size: int, app_id: int, core_subsets: CoreSubsets, - checksum: int, wait: bool): + checksum: int, wait: bool) -> None: """ Run the process. diff --git a/spinnman/processes/application_run_process.py b/spinnman/processes/application_run_process.py index 2057f1211..87c5f8486 100644 --- a/spinnman/processes/application_run_process.py +++ b/spinnman/processes/application_run_process.py @@ -23,7 +23,7 @@ class ApplicationRunProcess(AbstractMultiConnectionProcess[CheckOKResponse]): """ __slots__ = () - def run(self, app_id: int, core_subsets: CoreSubsets, wait: bool): + def run(self, app_id: int, core_subsets: CoreSubsets, wait: bool) -> None: """ Runs the application. diff --git a/spinnman/processes/get_cpu_info_process.py b/spinnman/processes/get_cpu_info_process.py index c825c6392..c78a0b7b4 100644 --- a/spinnman/processes/get_cpu_info_process.py +++ b/spinnman/processes/get_cpu_info_process.py @@ -44,7 +44,8 @@ def _is_desired(self, cpu_info: CPUInfo) -> bool: # pylint: disable=unused-argument return True - def __handle_response(self, x: int, y: int, p: int, response: Response): + def __handle_response( + self, x: int, y: int, p: int, response: Response) -> None: cpu_data = cast(_vcpu_t, _VCPU_PATTERN.unpack_from( response.data, response.offset)) cpu_info = CPUInfo(x, y, p, cpu_data) diff --git a/spinnman/processes/get_heap_process.py b/spinnman/processes/get_heap_process.py index c9cd7663c..813c103cc 100644 --- a/spinnman/processes/get_heap_process.py +++ b/spinnman/processes/get_heap_process.py @@ -51,15 +51,15 @@ def __init__(self, connection_selector: ConnectionSelector): self._next_block_address = 0 self._blocks: List[HeapElement] = list() - def _read_heap_address_response(self, response: Response): + def _read_heap_address_response(self, response: Response) -> None: self._heap_address = _ADDRESS.unpack_from( response.data, response.offset)[0] - def _read_heap_pointer(self, response: Response): + def _read_heap_pointer(self, response: Response) -> None: self._next_block_address = _HEAP_POINTER.unpack_from( response.data, response.offset)[0] - def _read_next_block(self, block_address: int, response: Response): + def _read_next_block(self, block_address: int, response: Response) -> None: self._next_block_address, free = _ELEMENT_HEADER.unpack_from( response.data, response.offset) if self._next_block_address != 0: @@ -68,7 +68,7 @@ def _read_next_block(self, block_address: int, response: Response): def __read_address( self, core_coords: XYP, address: int, size: int, - callback: Callable[[Response], None]): + callback: Callable[[Response], None]) -> None: with self._collect_responses(): self._send_request( ReadMemory(core_coords, address, size), callback) diff --git a/spinnman/processes/get_machine_process.py b/spinnman/processes/get_machine_process.py index 00b104300..fef163b21 100644 --- a/spinnman/processes/get_machine_process.py +++ b/spinnman/processes/get_machine_process.py @@ -17,12 +17,14 @@ import logging import functools from os.path import join -from typing import Dict, List, Optional, Set, Tuple, cast +from types import TracebackType +from typing import Any, Dict, List, Optional, Set, Tuple, cast from spinn_utilities.config_holder import ( get_config_bool, get_config_int_or_none, get_config_str_or_none) from spinn_utilities.data import UtilsDataView from spinn_utilities.log import FormatAdapter +from spinn_utilities.overrides import overrides from spinn_utilities.progress_bar import ProgressBar from spinn_utilities.typing.coords import XY @@ -30,6 +32,7 @@ from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink from spinn_machine.machine_factory import machine_repair +from spinnman.connections.udp_packet_connections import SCAMPConnection from spinnman.constants import ( ROUTER_REGISTER_P2P_ADDRESS, SYSTEM_VARIABLE_BASE_ADDRESS) from spinnman.data import SpiNNManDataView @@ -176,7 +179,7 @@ def _make_router( chip_info.n_free_multicast_routing_entries)) def __receive_p2p_data( - self, column: int, scp_read_response: Response): + self, column: int, scp_read_response: Response) -> None: """ :param int column: :param Response scp_read_response: @@ -185,7 +188,7 @@ def __receive_p2p_data( scp_read_response.data, scp_read_response.offset) def _receive_chip_info( - self, scp_read_chip_info_response: GetChipInfoResponse): + self, scp_read_chip_info_response: GetChipInfoResponse) -> None: """ :param GetChipInfoResponse scp_read_chip_info_response: """ @@ -195,7 +198,7 @@ def _receive_chip_info( self._progress.update() def _receive_p_maps( - self, x: int, y: int, scp_read_response: Response): + self, x: int, y: int, scp_read_response: Response) -> None: """ Receive the physical-to-virtual and virtual-to-physical maps. @@ -207,8 +210,10 @@ def _receive_p_maps( off += _P_TO_V_SIZE self._virtual_to_physical_map[x, y] = data[off:] + @overrides(AbstractMultiConnectionProcess._receive_error) def _receive_error( - self, request: AbstractSCPRequest, exception, tb, connection): + self, request: AbstractSCPRequest, exception: Exception, + tb: TracebackType, connection: SCAMPConnection) -> None: """ :param AbstractSCPRequest request: :param Exception exception: @@ -307,7 +312,7 @@ def _fill_machine(self, machine: Machine) -> Machine: # Stuff below here is purely for dealing with ignores - def _process_ignore_links(self, machine: Machine): + def _process_ignore_links(self, machine: Machine) -> None: """ Processes the collection of ignore links to remove then from chip info. @@ -356,7 +361,7 @@ def _process_ignore_links(self, machine: Machine): "Discarding ignore link {} on chip {} as it is not/" "no longer in info", link, global_xy) - def _preprocess_ignore_cores(self, machine: Machine): + def _preprocess_ignore_cores(self, machine: Machine) -> None: """ Converts the collection of ignore cores into a map of ignore by x,y. @@ -382,7 +387,7 @@ def _preprocess_ignore_cores(self, machine: Machine): if p is not None: self._ignore_cores_map[global_xy].add(p) - def _preprocess_ignore_chips(self, machine: Machine): + def _preprocess_ignore_chips(self, machine: Machine) -> None: """ Processes the collection of ignore chips and discards their chip info. @@ -494,7 +499,7 @@ def _get_virtual_p(self, xy: XY, p: int) -> Optional[int]: "core {}", xy, virtual_p, physical) return virtual_p - def _report_ignore(self, message: str, *args): + def _report_ignore(self, message: str, *args: Any) -> None: """ Writes the ignore message by either creating or appending the report. diff --git a/spinnman/processes/get_n_cores_in_state_process.py b/spinnman/processes/get_n_cores_in_state_process.py index 7183fc00b..1710d9b07 100644 --- a/spinnman/processes/get_n_cores_in_state_process.py +++ b/spinnman/processes/get_n_cores_in_state_process.py @@ -12,9 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import Iterable, Tuple + +from spinnman.model.enums import CPUState from spinnman.messages.scp.impl import CountState +from spinnman.messages.scp.impl.count_state_response import CountStateResponse from spinnman.messages.scp.enums.scp_result import SCPResult from .abstract_multi_connection_process import AbstractMultiConnectionProcess +from .abstract_multi_connection_process_connection_selector import ( + ConnectionSelector) # Timeout for getting core state count; higher due to more waiting needed GET_CORE_COUNT_TIMEOUT = 2.0 @@ -27,20 +33,19 @@ class GetNCoresInStateProcess(AbstractMultiConnectionProcess): __slots__ = [ "_n_cores"] - def __init__(self, connection_selector): + def __init__(self, connection_selector: ConnectionSelector): """ :param connection_selector: - :type connection_selector: - AbstractMultiConnectionProcessConnectionSelector """ super().__init__(connection_selector, timeout=GET_CORE_COUNT_TIMEOUT, non_fail_retry_codes={SCPResult.RC_P2P_NOREPLY}) self._n_cores = 0 - def __handle_response(self, response): + def __handle_response(self, response: CountStateResponse) -> None: self._n_cores += response.count - def get_n_cores_in_state(self, xys, app_id, state): + def get_n_cores_in_state(self, xys: Iterable[Tuple[int, int]], + app_id: int, state: CPUState) -> int: """ :param list(int,int) xys: :param int app_id: diff --git a/spinnman/processes/get_routes_process.py b/spinnman/processes/get_routes_process.py index 971c41f91..932c787a7 100644 --- a/spinnman/processes/get_routes_process.py +++ b/spinnman/processes/get_routes_process.py @@ -57,7 +57,7 @@ def __init__(self, connection_selector: ConnectionSelector, def _add_routing_entry( self, route_no: int, offset: int, app_id: int, route: int, - key: int, mask: int): + key: int, mask: int) -> None: # pylint: disable=too-many-arguments if route >= 0xFF000000: return @@ -67,7 +67,7 @@ def _add_routing_entry( self._entries[route_no + offset] = MulticastRoutingEntry( key, mask, RoutingEntry(spinnaker_route=route)) - def __handle_response(self, offset: int, response: Response): + def __handle_response(self, offset: int, response: Response) -> None: for route_no in range(_ENTRIES_PER_READ): entry = _ROUTE_ENTRY_PATTERN.unpack_from( response.data, diff --git a/spinnman/processes/get_tags_process.py b/spinnman/processes/get_tags_process.py index e51973379..d6a7c92f3 100644 --- a/spinnman/processes/get_tags_process.py +++ b/spinnman/processes/get_tags_process.py @@ -44,11 +44,12 @@ def __init__(self, connection_selector: ConnectionSelector): self._tag_info: Optional[IPTagGetInfoResponse] = None self._tags: List[Optional[AbstractTag]] = [] - def __handle_tag_info_response(self, response: IPTagGetInfoResponse): + def __handle_tag_info_response( + self, response: IPTagGetInfoResponse) -> None: self._tag_info = response - def __handle_get_tag_response( - self, tag: int, board_address, response: IPTagGetResponse): + def __handle_get_tag_response(self, tag: int, board_address: Optional[str], + response: IPTagGetResponse) -> None: if response.in_use: ip = response.ip_address host = f"{ip[0]}.{ip[1]}.{ip[2]}.{ip[3]}" diff --git a/spinnman/processes/get_version_process.py b/spinnman/processes/get_version_process.py index 1abcb1e7b..96ad4cea1 100644 --- a/spinnman/processes/get_version_process.py +++ b/spinnman/processes/get_version_process.py @@ -38,7 +38,7 @@ def __init__(self, connection_selector: ConnectionSelector, super().__init__(connection_selector, n_retries) self._version_info: Optional[VersionInfo] = None - def _get_response(self, version_response: GetVersionResponse): + def _get_response(self, version_response: GetVersionResponse) -> None: """ :param GetVersionResponse version_response: """ diff --git a/spinnman/processes/load_fixed_route_routing_entry_process.py b/spinnman/processes/load_fixed_route_routing_entry_process.py index b9c24fb12..a4cd0ef21 100644 --- a/spinnman/processes/load_fixed_route_routing_entry_process.py +++ b/spinnman/processes/load_fixed_route_routing_entry_process.py @@ -25,7 +25,7 @@ class LoadFixedRouteRoutingEntryProcess(AbstractMultiConnectionProcess): def load_fixed_route( self, x: int, y: int, fixed_route: RoutingEntry, - app_id: int = 0): + app_id: int = 0) -> None: """ :param int x: The x-coordinate of the chip, between 0 and 255; this is not checked due to speed restrictions. diff --git a/spinnman/processes/load_routes_process.py b/spinnman/processes/load_routes_process.py index 50bacd523..accfb55db 100644 --- a/spinnman/processes/load_routes_process.py +++ b/spinnman/processes/load_routes_process.py @@ -45,12 +45,13 @@ def __init__(self, connection_selector: ConnectionSelector): super().__init__(connection_selector) self._base_address = 0 - def __handle_router_alloc_response(self, response: RouterAllocResponse): + def __handle_router_alloc_response( + self, response: RouterAllocResponse) -> None: self._base_address = response.base_address def load_routes( self, x: int, y: int, routes: Collection[MulticastRoutingEntry], - app_id: int): + app_id: int) -> None: """ :param int x: :param int y: diff --git a/spinnman/processes/malloc_sdram_process.py b/spinnman/processes/malloc_sdram_process.py index 35567509c..1bfc03350 100644 --- a/spinnman/processes/malloc_sdram_process.py +++ b/spinnman/processes/malloc_sdram_process.py @@ -31,10 +31,11 @@ def __init__(self, connection_selector: ConnectionSelector): super().__init__(connection_selector) self._base_address = 0 - def __handle_sdram_alloc_response(self, response: _AllocResponse): + def __handle_sdram_alloc_response(self, response: _AllocResponse) -> None: self._base_address = response.base_address - def malloc_sdram(self, x: int, y: int, size: int, app_id: int, tag: int): + def malloc_sdram( + self, x: int, y: int, size: int, app_id: int, tag: int) -> None: """ Allocate space in the SDRAM space. diff --git a/spinnman/processes/read_fixed_route_routing_entry_process.py b/spinnman/processes/read_fixed_route_routing_entry_process.py index 9c9b8b9c8..4f5f56f0f 100644 --- a/spinnman/processes/read_fixed_route_routing_entry_process.py +++ b/spinnman/processes/read_fixed_route_routing_entry_process.py @@ -41,7 +41,7 @@ def __init__(self, connection_selector: ConnectionSelector): super().__init__(connection_selector) self._route: Optional[RoutingEntry] = None - def __handle_read_response(self, response: _FixedRouteResponse): + def __handle_read_response(self, response: _FixedRouteResponse) -> None: self._route = response.route def read_fixed_route( diff --git a/spinnman/processes/read_iobuf_process.py b/spinnman/processes/read_iobuf_process.py index 510c3d836..94f4a786d 100644 --- a/spinnman/processes/read_iobuf_process.py +++ b/spinnman/processes/read_iobuf_process.py @@ -108,7 +108,8 @@ def __init__(self, connection_selector: ConnectionSelector) -> None: # read = list of (x, y, p, n, next_address, first_read_size) self._next_reads: List[_NextRegion] = list() - def _request_iobuf_address(self, iobuf_size: int, x: int, y: int, p: int): + def _request_iobuf_address( + self, iobuf_size: int, x: int, y: int, p: int) -> None: scamp_coords = (x, y, 0) base_address = get_vcpu_address(p) + CPU_IOBUF_ADDRESS_OFFSET self._send_request( @@ -118,34 +119,34 @@ def _request_iobuf_address(self, iobuf_size: int, x: int, y: int, p: int): def __handle_iobuf_address_response( self, iobuf_size: int, scamp_coords: XYP, xyp: XYP, - response: Response): + response: Response) -> None: iobuf_address, = _ONE_WORD.unpack_from(response.data, response.offset) if iobuf_address != 0: first_read_size = min((iobuf_size + 16, UDP_MESSAGE_MAX_SIZE)) self._next_reads.append(_NextRegion( scamp_coords, xyp, 0, iobuf_address, first_read_size)) - def _request_iobuf_region_tail(self, tail: _RegionTail): + def _request_iobuf_region_tail(self, tail: _RegionTail) -> None: self._send_request( ReadMemory(tail.scamp_coords, tail.base_address, tail.size), functools.partial( self.__handle_extra_iobuf_response, tail)) def __handle_extra_iobuf_response( - self, tail: _RegionTail, response: Response): + self, tail: _RegionTail, response: Response) -> None: view = self._iobuf_view[tail.core_coords][tail.n] base = tail.offset view[base:base + response.length] = response.data[ response.offset:response.offset + response.length] - def _request_iobuf_region(self, region: _NextRegion): + def _request_iobuf_region(self, region: _NextRegion) -> None: self._send_request( ReadMemory(region.scamp_coords, region.next_address, region.first_read_size), functools.partial(self.__handle_first_iobuf_response, region)) def __handle_first_iobuf_response( - self, region: _NextRegion, response: Response): + self, region: _NextRegion, response: Response) -> None: base_address = region.next_address # Unpack the iobuf header diff --git a/spinnman/processes/read_memory_process.py b/spinnman/processes/read_memory_process.py index a3a8776f7..c5bf36b2a 100644 --- a/spinnman/processes/read_memory_process.py +++ b/spinnman/processes/read_memory_process.py @@ -40,7 +40,7 @@ def __init__(self, connection_selector: ConnectionSelector): super().__init__(connection_selector) self._view = memoryview(b'') - def __handle_response(self, offset: int, response: Response): + def __handle_response(self, offset: int, response: Response) -> None: self._view[offset:offset + response.length] = response.data[ response.offset:response.offset + response.length] diff --git a/spinnman/processes/read_router_diagnostics_process.py b/spinnman/processes/read_router_diagnostics_process.py index 1f7f0a138..7dff03343 100644 --- a/spinnman/processes/read_router_diagnostics_process.py +++ b/spinnman/processes/read_router_diagnostics_process.py @@ -42,15 +42,15 @@ def __init__(self, connection_selector: ConnectionSelector): self._error_status = 0 self._register_values = [0] * _N_REGISTERS - def __handle_control_register_response(self, response: Response): + def __handle_control_register_response(self, response: Response) -> None: self._control_register = _ONE_WORD.unpack_from( response.data, response.offset)[0] - def __handle_error_status_response(self, response: Response): + def __handle_error_status_response(self, response: Response) -> None: self._error_status = _ONE_WORD.unpack_from( response.data, response.offset)[0] - def __handle_register_response(self, response: Response): + def __handle_register_response(self, response: Response) -> None: for register in range(_N_REGISTERS): self._register_values[register] = _ONE_WORD.unpack_from( response.data, response.offset + (register * 4))[0] diff --git a/spinnman/processes/send_single_command_process.py b/spinnman/processes/send_single_command_process.py index 120d4d286..8583c3b63 100644 --- a/spinnman/processes/send_single_command_process.py +++ b/spinnman/processes/send_single_command_process.py @@ -54,7 +54,7 @@ def __init__(self, connection_selector: ConnectionSelector, non_fail_retry_codes=non_fail_retry_codes) self._response: Optional[R] = None - def __handle_response(self, response: R): + def __handle_response(self, response: R) -> None: self._response = response def execute(self, request: AbstractSCPRequest[R]) -> R: diff --git a/spinnman/utilities/utility_functions.py b/spinnman/utilities/utility_functions.py index 9fc4f86e3..7dfbf6102 100644 --- a/spinnman/utilities/utility_functions.py +++ b/spinnman/utilities/utility_functions.py @@ -60,7 +60,7 @@ def get_vcpu_address(p: int) -> int: def send_port_trigger_message( - connection: UDPConnection, board_address: str): + connection: UDPConnection, board_address: str) -> None: """ Sends a port trigger message using a connection to (hopefully) open a port in a NAT and/or firewall to allow incoming packets to be received. @@ -84,7 +84,8 @@ def send_port_trigger_message( trigger_message.bytestring, (board_address, SCP_SCAMP_PORT)) -def reprogram_tag(connection: SCAMPConnection, tag: int, strip: bool = True): +def reprogram_tag( + connection: SCAMPConnection, tag: int, strip: bool = True) -> None: """ Reprogram an IP Tag to send responses to a given SCAMPConnection. @@ -114,7 +115,7 @@ def reprogram_tag(connection: SCAMPConnection, tag: int, strip: bool = True): def reprogram_tag_to_listener( connection: UDPConnection, x: int, y: int, ip_address: str, tag: int, - strip: bool = True, read_response: bool = True): + strip: bool = True, read_response: bool = True) -> None: """ Reprogram an IP Tag to send responses to a given connection that is not connected to a specific board. Such connections are normally From 66ef6ea9929781b582405b692640bd430eb4d5b7 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 30 Oct 2024 12:25:52 +0000 Subject: [PATCH 09/18] add new method for typing --- .../spinnaker_boot/system_variable_boot_values.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py index aca5c767a..556cd0bf5 100644 --- a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py +++ b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py @@ -29,8 +29,12 @@ class _DataType(Enum): LONG = (8, " "_DataType" : + obj = object.__new__(cls) + obj._value_ = value + return obj + + def __init__(self, value: int, struct_code: str): self._struct_code = struct_code @property @@ -383,14 +387,14 @@ class SystemVariableBootValues(object): """ __slot__ = "_values", - def __init__(self): + def __init__(self) -> None: # Create a dict of variable values self._values = dict() for variable in SystemVariableDefinition: self._values[variable] = variable.default def set_value(self, system_variable_definition: SystemVariableDefinition, - value: Any): + value: Any) -> None: """ Save a value to the system_variable_definition Enum as the key From 2d8d46c6f845e89d6bee9dae31cd0aa9b1113186 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 30 Oct 2024 12:39:34 +0000 Subject: [PATCH 10/18] typing --- spinnman/board_test_configuration.py | 8 ++--- spinnman/connections/token_bucket.py | 7 ++--- .../udp_packet_connections/utils.py | 5 +++- spinnman/data/spinnman_data_view.py | 2 +- spinnman/exceptions.py | 26 ++++++++-------- .../command_messages/eieio_command_message.py | 4 +-- .../command_messages/event_stop_request.py | 2 +- .../notification_protocol_db_location.py | 15 ++++++---- .../notification_protocol_pause_stop.py | 7 +++-- .../notification_protocol_start_resume.py | 7 +++-- .../eieio/command_messages/padding_request.py | 4 +-- .../spinnaker_request_read_data.py | 10 +++---- .../eieio/command_messages/start_requests.py | 2 +- .../eieio/command_messages/stop_requests.py | 2 +- .../messages/eieio/create_eieio_command.py | 3 +- spinnman/messages/eieio/create_eieio_data.py | 2 +- .../eieio/data_messages/eieio_data_header.py | 9 +++--- .../eieio/data_messages/eieio_data_message.py | 30 +++++++++++-------- .../eieio/data_messages/key_data_element.py | 4 +-- .../data_messages/key_payload_data_element.py | 4 +-- spinnman/messages/eieio/eieio_type.py | 5 ++-- spinnman/messages/multicast_message.py | 12 ++++---- .../scp/abstract_messages/bmp_response.py | 2 +- .../scp/abstract_messages/scp_request.py | 4 +-- .../scp/abstract_messages/scp_response.py | 4 +-- spinnman/messages/scp/enums/signal.py | 4 +-- .../messages/scp/impl/count_state_response.py | 9 +++--- .../messages/scp/impl/fixed_route_read.py | 2 +- .../scp/impl/get_chip_info_response.py | 2 +- .../messages/scp/impl/get_version_response.py | 2 +- spinnman/messages/scp/impl/iptag_get.py | 2 +- .../scp/impl/iptag_get_info_response.py | 2 +- spinnman/messages/scp/impl/read_memory.py | 2 +- spinnman/messages/scp/impl/router_alloc.py | 2 +- spinnman/messages/scp/impl/sdram_alloc.py | 2 +- spinnman/messages/scp/impl/sdram_de_alloc.py | 2 +- spinnman/messages/scp/impl/set_power.py | 2 +- spinnman/messages/scp/scp_request_header.py | 2 +- spinnman/messages/scp/scp_response_header.py | 2 +- spinnman/messages/sdp/sdp_header.py | 24 +++++++-------- spinnman/model/cpu_info.py | 4 +-- spinnman/model/cpu_infos.py | 5 ++-- spinnman/model/enums/executable_type.py | 11 ++++--- spinnman/model/executable_targets.py | 7 +++-- spinnman/model/p2p_table.py | 8 ++--- spinnman/utilities/appid_tracker.py | 4 +-- spinnman/utilities/socket_utils.py | 11 +++---- 47 files changed, 162 insertions(+), 129 deletions(-) diff --git a/spinnman/board_test_configuration.py b/spinnman/board_test_configuration.py index 19ac94cd4..889038b10 100644 --- a/spinnman/board_test_configuration.py +++ b/spinnman/board_test_configuration.py @@ -24,11 +24,11 @@ class BoardTestConfiguration(object): Configuration to use for a test board """ - def __init__(self): - self.remotehost = None - self.auto_detect_bmp = None + def __init__(self) -> None: + self.remotehost: str = "UNSET" + self.auto_detect_bmp: bool = False - def set_up_remote_board(self, version: Optional[int] = None): + def set_up_remote_board(self, version: Optional[int] = None) -> None: """ Gets a remote board to test, returning the first that it finds. diff --git a/spinnman/connections/token_bucket.py b/spinnman/connections/token_bucket.py index b3da65280..65c0f3f81 100644 --- a/spinnman/connections/token_bucket.py +++ b/spinnman/connections/token_bucket.py @@ -27,7 +27,7 @@ class TokenBucket(object): """ __slots__ = ('_capacity', '_tokens', '_fill_rate', '_timestamp') - def __init__(self, tokens, fill_rate): + def __init__(self, tokens: int, fill_rate: float): """ :param int tokens: the total tokens in the bucket :param float fill_rate: @@ -38,7 +38,7 @@ def __init__(self, tokens, fill_rate): self._fill_rate = float(fill_rate) self._timestamp = time.time() - def consume(self, tokens, block=True): + def consume(self, tokens: int, block: bool = True) -> bool: """ Consume tokens from the bucket. Returns True if there were sufficient tokens. @@ -65,11 +65,10 @@ def consume(self, tokens, block=True): return False @property - def tokens(self): + def tokens(self) -> float: """ The number of tokens currently in the bucket. - :rtype: int """ if self._tokens < self._capacity: now = time.time() diff --git a/spinnman/connections/udp_packet_connections/utils.py b/spinnman/connections/udp_packet_connections/utils.py index 007dff016..f55f667e1 100644 --- a/spinnman/connections/udp_packet_connections/utils.py +++ b/spinnman/connections/udp_packet_connections/utils.py @@ -12,9 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from spinnman.messages.sdp import SDPHeader + # Kept for spalloc_server to use -def update_sdp_header_for_udp_send(sdp_header, source_x, source_y): +def update_sdp_header_for_udp_send( + sdp_header: SDPHeader, source_x: int, source_y: int) -> None: """ Apply defaults to the SDP header for sending over UDP. diff --git a/spinnman/data/spinnman_data_view.py b/spinnman/data/spinnman_data_view.py index ebb9ab73c..ad467c952 100644 --- a/spinnman/data/spinnman_data_view.py +++ b/spinnman/data/spinnman_data_view.py @@ -251,7 +251,7 @@ def get_new_id(cls) -> int: return cls.__data._app_id_tracker.get_new_id() @classmethod - def free_id(cls, app_id: int): + def free_id(cls, app_id: int) -> None: """ Frees up an app_id. diff --git a/spinnman/exceptions.py b/spinnman/exceptions.py index 628bf8630..018ad71f9 100644 --- a/spinnman/exceptions.py +++ b/spinnman/exceptions.py @@ -14,7 +14,8 @@ from __future__ import annotations import traceback from types import TracebackType -from typing import Any, List, Optional, FrozenSet, Union, TYPE_CHECKING +from typing import ( + Any, Generic, List, Optional, FrozenSet, TYPE_CHECKING, TypeVar, Union) if TYPE_CHECKING: from spinnman.messages.scp.enums import SCPResult from spinnman.model.enums import CPUState @@ -22,6 +23,8 @@ from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.connections.udp_packet_connections import SCAMPConnection +T = TypeVar("T") + class SpinnmanException(Exception): """ @@ -64,13 +67,13 @@ def problem(self) -> str: return self._problem -class SpinnmanInvalidParameterException(SpinnmanException): +class SpinnmanInvalidParameterException(SpinnmanException, Generic[T]): """ An exception that indicates that the value of one of the parameters passed was invalid. """ - def __init__(self, parameter: str, value, problem: str): + def __init__(self, parameter: str, value: T, problem: str): """ :param str parameter: The name of the parameter that is invalid :param str value: The value of the parameter that is invalid @@ -93,7 +96,7 @@ def parameter(self) -> str: return self._parameter @property - def value(self): + def value(self) -> T: """ The value that is invalid. """ @@ -115,7 +118,7 @@ class SpinnmanInvalidParameterTypeException(SpinnmanException): passed was invalid. """ - def __init__(self, parameter: str, param_type, problem: str): + def __init__(self, parameter: str, param_type: str, problem: str): """ :param str parameter: The name of the parameter that is invalid :param str param_type: The type of the parameter that is invalid @@ -138,7 +141,7 @@ def parameter(self) -> str: return self._parameter @property - def type(self): + def type(self) -> str: """ The value that is invalid. """ @@ -186,13 +189,13 @@ def __init__(self) -> None: super().__init__("connection is closed") -class SpinnmanTimeoutException(SpinnmanException): +class SpinnmanTimeoutException(SpinnmanException, Generic[T]): """ An exception that indicates that a timeout occurred before an operation could finish. """ - def __init__(self, operation: Any, timeout: Optional[float], + def __init__(self, operation: T, timeout: Optional[float], msg: Optional[str] = None): """ :param operation: The operation being performed @@ -206,11 +209,10 @@ def __init__(self, operation: Any, timeout: Optional[float], self._timeout = timeout @property - def operation(self) -> str: + def operation(self) -> T: """ The operation that was performed. - :rtype: str """ return self._operation @@ -230,7 +232,7 @@ class SpinnmanUnexpectedResponseCodeException(SpinnmanException): for the current operation. """ - def __init__(self, operation: str, command, + def __init__(self, operation: str, command: str, response: Union[str, SCPResult]): """ :param str operation: The operation being performed @@ -254,7 +256,7 @@ def operation(self) -> str: return self._operation @property - def command(self): + def command(self) -> str: """ The command being executed. """ diff --git a/spinnman/messages/eieio/command_messages/eieio_command_message.py b/spinnman/messages/eieio/command_messages/eieio_command_message.py index b3ccc48b4..eb0bd61b4 100644 --- a/spinnman/messages/eieio/command_messages/eieio_command_message.py +++ b/spinnman/messages/eieio/command_messages/eieio_command_message.py @@ -101,8 +101,8 @@ def get_min_packet_length() -> int: """ return 2 - def __str__(self): + def __str__(self) -> str: return f"EIEIOCommandMessage:{self._eieio_command_header}" - def __repr__(self): + def __repr__(self) -> str: return self.__str__() diff --git a/spinnman/messages/eieio/command_messages/event_stop_request.py b/spinnman/messages/eieio/command_messages/event_stop_request.py index 46dc68ab0..b3be8e3ea 100644 --- a/spinnman/messages/eieio/command_messages/event_stop_request.py +++ b/spinnman/messages/eieio/command_messages/event_stop_request.py @@ -24,5 +24,5 @@ class EventStopRequest(EIEIOCommandMessage): """ __slots__ = () - def __init__(self): + def __init__(self) -> None: super().__init__(EIEIOCommandHeader(EIEIO_COMMAND_IDS.EVENT_STOP)) diff --git a/spinnman/messages/eieio/command_messages/notification_protocol_db_location.py b/spinnman/messages/eieio/command_messages/notification_protocol_db_location.py index 8e576d585..8ec60e258 100644 --- a/spinnman/messages/eieio/command_messages/notification_protocol_db_location.py +++ b/spinnman/messages/eieio/command_messages/notification_protocol_db_location.py @@ -13,6 +13,7 @@ # limitations under the License. from typing import Optional + from spinnman.constants import EIEIO_COMMAND_IDS from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader @@ -29,9 +30,9 @@ class NotificationProtocolDatabaseLocation(EIEIOCommandMessage): """ __slots__ = "_database_path", - def __init__(self, database_path=None): + def __init__(self, database_path: Optional[str] = None): """ - :param str database_path: + :param database_path: The location of the database. If ``None``, this is an acknowledgement, stating that the database has now been read. """ @@ -55,15 +56,19 @@ def database_path(self) -> Optional[str]: return None @property - def bytestring(self): + def bytestring(self) -> bytes: data = super().bytestring if self._database_path is not None: data += self._database_path return data @staticmethod - def from_bytestring(command_header, data, offset): + def from_bytestring( + command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> 'NotificationProtocolDatabaseLocation': database_path = None if len(data) - offset > 0: - database_path = data[offset:] + raise Exception( + "https://github.com/SpiNNakerManchester/SpiNNMan/issues/424") + # database_path = data[offset:] return NotificationProtocolDatabaseLocation(database_path) diff --git a/spinnman/messages/eieio/command_messages/notification_protocol_pause_stop.py b/spinnman/messages/eieio/command_messages/notification_protocol_pause_stop.py index 8f77c6738..ca0f56020 100644 --- a/spinnman/messages/eieio/command_messages/notification_protocol_pause_stop.py +++ b/spinnman/messages/eieio/command_messages/notification_protocol_pause_stop.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from spinn_utilities.overrides import overrides from spinnman.constants import EIEIO_COMMAND_IDS from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader @@ -26,10 +27,12 @@ class NotificationProtocolPauseStop(EIEIOCommandMessage): """ __slots__ = () - def __init__(self): + def __init__(self) -> None: super().__init__(EIEIOCommandHeader( EIEIO_COMMAND_IDS.STOP_PAUSE_NOTIFICATION)) @staticmethod - def from_bytestring(command_header, data, offset): + @overrides(EIEIOCommandMessage.from_bytestring) + def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> "NotificationProtocolPauseStop": return NotificationProtocolPauseStop() diff --git a/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py b/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py index 9a036da97..2558337e8 100644 --- a/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py +++ b/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from spinn_utilities.overrides import overrides from spinnman.constants import EIEIO_COMMAND_IDS from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader @@ -26,10 +27,12 @@ class NotificationProtocolStartResume(EIEIOCommandMessage): """ __slots__ = () - def __init__(self): + def __init__(self) -> None: super().__init__(EIEIOCommandHeader( EIEIO_COMMAND_IDS.START_RESUME_NOTIFICATION)) @staticmethod - def from_bytestring(command_header, data, offset): + @overrides(EIEIOCommandMessage.from_bytestring) + def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> "NotificationProtocolStartResume": return NotificationProtocolStartResume() diff --git a/spinnman/messages/eieio/command_messages/padding_request.py b/spinnman/messages/eieio/command_messages/padding_request.py index 0fe179c0a..095783a6e 100644 --- a/spinnman/messages/eieio/command_messages/padding_request.py +++ b/spinnman/messages/eieio/command_messages/padding_request.py @@ -23,9 +23,9 @@ class PaddingRequest(EIEIOCommandMessage): """ __slots__ = () - def __init__(self): + def __init__(self) -> None: super().__init__(EIEIOCommandHeader(EIEIO_COMMAND_IDS.EVENT_PADDING)) @staticmethod - def get_min_packet_length(): + def get_min_packet_length() -> int: return 2 diff --git a/spinnman/messages/eieio/command_messages/spinnaker_request_read_data.py b/spinnman/messages/eieio/command_messages/spinnaker_request_read_data.py index 96fb1b9b0..ebdba1ef8 100644 --- a/spinnman/messages/eieio/command_messages/spinnaker_request_read_data.py +++ b/spinnman/messages/eieio/command_messages/spinnaker_request_read_data.py @@ -149,7 +149,7 @@ def channel(self, request_id: int) -> int: """ return self._requests.channel(request_id) - def region_id(self, request_id) -> int: + def region_id(self, request_id: int) -> int: """ The region_id for this request_id. @@ -159,7 +159,7 @@ def region_id(self, request_id) -> int: """ return self._requests.region_id(request_id) - def start_address(self, request_id) -> int: + def start_address(self, request_id: int) -> int: """ The start_address for this request_id. @@ -169,7 +169,7 @@ def start_address(self, request_id) -> int: """ return self._requests.start_address(request_id) - def space_to_be_read(self, request_id) -> int: + def space_to_be_read(self, request_id: int) -> int: """ The space_to_be_read for this request_id. @@ -356,7 +356,7 @@ def __init__(self, channel: Union[List[int], int], else: self._space_to_be_read = space_to_be_read - def channel(self, request_id) -> int: + def channel(self, request_id: int) -> int: """ Gets the channel for this request_id @@ -373,7 +373,7 @@ def channel(self, request_id) -> int: f"channel request needs to be comprised between 0 and " f"{len(self._channel) - 1:d}; current value: {request_id:d}") - def region_id(self, request_id) -> int: + def region_id(self, request_id: int) -> int: """ Gets the region_id for this request_id diff --git a/spinnman/messages/eieio/command_messages/start_requests.py b/spinnman/messages/eieio/command_messages/start_requests.py index 26340407e..3d8e60299 100644 --- a/spinnman/messages/eieio/command_messages/start_requests.py +++ b/spinnman/messages/eieio/command_messages/start_requests.py @@ -25,6 +25,6 @@ class StartRequests(EIEIOCommandMessage): """ __slots__ = () - def __init__(self): + def __init__(self) -> None: super().__init__(EIEIOCommandHeader( EIEIO_COMMAND_IDS.START_SENDING_REQUESTS)) diff --git a/spinnman/messages/eieio/command_messages/stop_requests.py b/spinnman/messages/eieio/command_messages/stop_requests.py index e7726eccf..9e6d1f942 100644 --- a/spinnman/messages/eieio/command_messages/stop_requests.py +++ b/spinnman/messages/eieio/command_messages/stop_requests.py @@ -25,6 +25,6 @@ class StopRequests(EIEIOCommandMessage): """ __slots__ = () - def __init__(self): + def __init__(self) -> None: super().__init__(EIEIOCommandHeader( EIEIO_COMMAND_IDS.STOP_SENDING_REQUESTS)) diff --git a/spinnman/messages/eieio/create_eieio_command.py b/spinnman/messages/eieio/create_eieio_command.py index 612dbd0d1..7a3638705 100644 --- a/spinnman/messages/eieio/create_eieio_command.py +++ b/spinnman/messages/eieio/create_eieio_command.py @@ -20,7 +20,8 @@ from spinnman.constants import EIEIO_COMMAND_IDS -def read_eieio_command_message(data, offset): +def read_eieio_command_message( + data: bytes, offset: int) -> EIEIOCommandMessage: """ Reads the content of an EIEIO command message and returns an object identifying the command which was contained in the packet, including diff --git a/spinnman/messages/eieio/create_eieio_data.py b/spinnman/messages/eieio/create_eieio_data.py index 9195787f4..a09478c8a 100644 --- a/spinnman/messages/eieio/create_eieio_data.py +++ b/spinnman/messages/eieio/create_eieio_data.py @@ -16,7 +16,7 @@ EIEIODataMessage, EIEIODataHeader) -def read_eieio_data_message(data, offset): +def read_eieio_data_message(data: bytes, offset: int) -> EIEIODataMessage: """ Reads the content of an EIEIO data message and returns an object identifying the data which was contained in the packet. diff --git a/spinnman/messages/eieio/data_messages/eieio_data_header.py b/spinnman/messages/eieio/data_messages/eieio_data_header.py index ecded471c..5eee2a74a 100644 --- a/spinnman/messages/eieio/data_messages/eieio_data_header.py +++ b/spinnman/messages/eieio/data_messages/eieio_data_header.py @@ -137,7 +137,7 @@ def count(self) -> int: return self._count @count.setter - def count(self, count: int): + def count(self, count: int) -> None: """ Sets the Count of the number of items in the packet @@ -157,7 +157,8 @@ def size(self) -> int: self._payload_base is not None) @staticmethod - def get_header_size(eieio_type, is_prefix=False, is_payload_base=False): + def get_header_size(eieio_type: EIEIOType, is_prefix: bool = False, + is_payload_base: bool = False) -> int: """ Get the size of a header with the given parameters. @@ -297,12 +298,12 @@ def from_bytestring(data: bytes, offset: int) -> 'EIEIODataHeader': prefix_type=prefix_type, payload_base=payload_prefix, is_time=bool(payload_is_timestamp), count=count) - def __str__(self): + def __str__(self) -> str: return (f"EIEIODataHeader:prefix={self._prefix}:" f"prefix_type={self._prefix_type}:" f"payload_base={self._payload_base}:" "is_time={self._is_time}:type={self._eieio_type.value}:" "tag={self._tag}:count={self._count}") - def __repr__(self): + def __repr__(self) -> str: return self.__str__() diff --git a/spinnman/messages/eieio/data_messages/eieio_data_message.py b/spinnman/messages/eieio/data_messages/eieio_data_message.py index 9da649a33..567d730e0 100644 --- a/spinnman/messages/eieio/data_messages/eieio_data_message.py +++ b/spinnman/messages/eieio/data_messages/eieio_data_message.py @@ -42,7 +42,8 @@ class EIEIODataMessage(AbstractEIEIOMessage): "_header", "_offset") - def __init__(self, eieio_header, data=None, offset=0): + def __init__(self, eieio_header: EIEIODataHeader, + data: Optional[bytes] = None, offset: int = 0): """ :param EIEIODataHeader eieio_header: The header of the message :param bytes data: Optional data contained within the packet @@ -61,9 +62,13 @@ def __init__(self, eieio_header, data=None, offset=0): @staticmethod def create( - eieio_type, count=0, data=None, offset=0, key_prefix=None, - payload_prefix=None, timestamp=None, - prefix_type=EIEIOPrefix.LOWER_HALF_WORD): + eieio_type: EIEIOType, count: int = 0, + data: Optional[bytes] = None, offset: int = 0, + key_prefix: Optional[int] = None, + payload_prefix: Optional[int] = None, + timestamp: Optional[int] = None, + prefix_type: EIEIOPrefix = EIEIOPrefix.LOWER_HALF_WORD + ) -> "EIEIODataMessage": """ Create a data message. @@ -98,8 +103,8 @@ def eieio_header(self) -> EIEIODataHeader: @staticmethod def min_packet_length( - eieio_type, is_prefix=False, is_payload_base=False, - is_timestamp=False): + eieio_type: EIEIOType, is_prefix: bool = False, + is_payload_base: bool = False, is_timestamp: bool = False) -> int: """ The minimum length of a message with the given header, in bytes. @@ -158,7 +163,7 @@ def size(self) -> int: return (self._header.size + (ty.key_bytes + ty.payload_bytes) * self._header.count) - def add_key_and_payload(self, key: int, payload: int): + def add_key_and_payload(self, key: int, payload: int) -> None: """ Adds a key and payload to the packet. @@ -180,7 +185,7 @@ def add_key_and_payload(self, key: int, payload: int): self.add_element(KeyPayloadDataElement( key, payload, self._header.is_time)) - def add_key(self, key: int): + def add_key(self, key: int) -> None: """ Add a key to the packet. @@ -195,7 +200,7 @@ def add_key(self, key: int): f"{self._header.eieio_type.max_value}") self.add_element(KeyDataElement(key)) - def add_element(self, element: AbstractDataElement): + def add_element(self, element: AbstractDataElement) -> None: """ Add an element to the message. The correct type of element must be added, depending on the header values. @@ -235,6 +240,7 @@ def next_element(self) -> Optional[AbstractDataElement]: return None self._elements_read += 1 payload: Optional[int] = None + assert self._data is not None if self._header.eieio_type == EIEIOType.KEY_16_BIT: key = _ONE_SHORT.unpack_from(self._data, self._offset)[0] self._offset += 2 @@ -272,10 +278,10 @@ def next_element(self) -> Optional[AbstractDataElement]: def bytestring(self) -> bytes: return self._header.bytestring + self._elements - def __str__(self): + def __str__(self) -> str: if self._data is not None: return f"EIEIODataMessage:{self._header}:{self._header.count}" - return f"EIEIODataMessage:{self._header}:{self._elements}" + return f"EIEIODataMessage:{self._header}:{self._elements!r}" - def __repr__(self): + def __repr__(self) -> str: return self.__str__() diff --git a/spinnman/messages/eieio/data_messages/key_data_element.py b/spinnman/messages/eieio/data_messages/key_data_element.py index 8ba2c6237..6d7c1f3f4 100644 --- a/spinnman/messages/eieio/data_messages/key_data_element.py +++ b/spinnman/messages/eieio/data_messages/key_data_element.py @@ -55,8 +55,8 @@ def get_bytestring(self, eieio_type: EIEIOType) -> bytes: raise SpinnmanInvalidParameterException( "eieio_type", eieio_type, "Unknown type") - def __str__(self): + def __str__(self) -> str: return f"KeyDataElement:0x{self._key:x}" - def __repr__(self): + def __repr__(self) -> str: return self.__str__() diff --git a/spinnman/messages/eieio/data_messages/key_payload_data_element.py b/spinnman/messages/eieio/data_messages/key_payload_data_element.py index 252cce6a7..2425c5dfd 100644 --- a/spinnman/messages/eieio/data_messages/key_payload_data_element.py +++ b/spinnman/messages/eieio/data_messages/key_payload_data_element.py @@ -79,8 +79,8 @@ def get_bytestring(self, eieio_type: EIEIOType) -> bytes: raise SpinnmanInvalidParameterException( "eieio_type", eieio_type, "Unknown type") - def __str__(self): + def __str__(self) -> str: return f"KeyPayloadDataElement:0x{self._key:x}:0x{self._payload:x}" - def __repr__(self): + def __repr__(self) -> str: return self.__str__() diff --git a/spinnman/messages/eieio/eieio_type.py b/spinnman/messages/eieio/eieio_type.py index 955357a49..76ba80ae1 100644 --- a/spinnman/messages/eieio/eieio_type.py +++ b/spinnman/messages/eieio/eieio_type.py @@ -29,9 +29,10 @@ class EIEIOType(Enum): #: Indicates that data is keys and payloads of 32 bits. KEY_PAYLOAD_32_BIT = (3, 4, 4) - def __new__(cls, *args) -> 'EIEIOType': + def __new__(cls, encoded_value: int, key_bytes: int, + payload_bytes: int) -> 'EIEIOType': obj = object.__new__(cls) - obj._value_ = args[0] + obj._value_ = encoded_value return obj def __init__(self, encoded_value: int, diff --git a/spinnman/messages/multicast_message.py b/spinnman/messages/multicast_message.py index 21451e456..022a04ea9 100644 --- a/spinnman/messages/multicast_message.py +++ b/spinnman/messages/multicast_message.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import Optional + class MulticastMessage(object): """ @@ -22,16 +24,16 @@ class MulticastMessage(object): "_key", "_payload") - def __init__(self, key, payload=None): + def __init__(self, key: int, payload: Optional[int] = None): """ - :param int key: The key of the packet - :param int payload: The optional payload of the packet + :param key: The key of the packet + :param payload: The optional payload of the packet """ self._key = key self._payload = payload @property - def key(self): + def key(self) -> int: """ The key of the packet. @@ -40,7 +42,7 @@ def key(self): return self._key @property - def payload(self): + def payload(self) -> Optional[int]: """ The payload of the packet if there is one, or `None` if there is no payload. diff --git a/spinnman/messages/scp/abstract_messages/bmp_response.py b/spinnman/messages/scp/abstract_messages/bmp_response.py index aeaf96c7f..fc53f7ef1 100644 --- a/spinnman/messages/scp/abstract_messages/bmp_response.py +++ b/spinnman/messages/scp/abstract_messages/bmp_response.py @@ -49,7 +49,7 @@ def _value(self) -> T: return self.__value @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/abstract_messages/scp_request.py b/spinnman/messages/scp/abstract_messages/scp_request.py index 4fbae6a07..03f6a70fd 100644 --- a/spinnman/messages/scp/abstract_messages/scp_request.py +++ b/spinnman/messages/scp/abstract_messages/scp_request.py @@ -138,11 +138,11 @@ def bytestring(self) -> bytes: data += bytes(self._data) return data - def __repr__(self): + def __repr__(self) -> str: # Default is to return just the command, but can be overridden return str(self._scp_request_header.command) - def __str__(self): + def __str__(self) -> str: return self.__repr__() @abstractmethod diff --git a/spinnman/messages/scp/abstract_messages/scp_response.py b/spinnman/messages/scp/abstract_messages/scp_response.py index 7061910d6..d40ce2c2b 100644 --- a/spinnman/messages/scp/abstract_messages/scp_response.py +++ b/spinnman/messages/scp/abstract_messages/scp_response.py @@ -37,7 +37,7 @@ def __init__(self) -> None: self._sdp_header: Optional[SDPHeader] = None self._scp_response_header: Optional[SCPResponseHeader] = None - def read_bytestring(self, data: bytes, offset: int): + def read_bytestring(self, data: bytes, offset: int) -> None: """ Reads a packet from a byte-string of data. @@ -51,7 +51,7 @@ def read_bytestring(self, data: bytes, offset: int): self.read_data_bytestring(data, _SCP_DATA_OFFSET + offset) @abstractmethod - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: """ Reads the remainder of the data following the header. diff --git a/spinnman/messages/scp/enums/signal.py b/spinnman/messages/scp/enums/signal.py index cd5a6f7e9..4eacaee79 100644 --- a/spinnman/messages/scp/enums/signal.py +++ b/spinnman/messages/scp/enums/signal.py @@ -43,9 +43,9 @@ class Signal(Enum): USER_2 = (12, SignalType.MULTICAST) USER_3 = (13, SignalType.MULTICAST) - def __new__(cls, *args) -> 'Signal': + def __new__(cls, value: int, signal_type: SignalType) -> 'Signal': obj = object.__new__(cls) - obj._value_ = args[0] + obj._value_ = value return obj def __init__(self, value: int, signal_type: SignalType) -> None: diff --git a/spinnman/messages/scp/impl/count_state_response.py b/spinnman/messages/scp/impl/count_state_response.py index ba3b4608f..d03f97169 100644 --- a/spinnman/messages/scp/impl/count_state_response.py +++ b/spinnman/messages/scp/impl/count_state_response.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import Optional import struct from spinn_utilities.overrides import overrides from spinnman.messages.scp.abstract_messages import AbstractSCPResponse @@ -27,12 +28,12 @@ class CountStateResponse(AbstractSCPResponse): """ __slots__ = "_count", - def __init__(self): + def __init__(self) -> None: super().__init__() - self._count = None + self._count: Optional[int] = None @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result # We can accept a no-reply response here; that could just mean # that the count wasn't complete (but might be enough anyway) @@ -46,6 +47,6 @@ def count(self) -> int: """ The count of the number of cores with the requested state. - :rtype: int """ + assert self._count is not None return self._count diff --git a/spinnman/messages/scp/impl/fixed_route_read.py b/spinnman/messages/scp/impl/fixed_route_read.py index 5b31746c4..3c7dccf38 100644 --- a/spinnman/messages/scp/impl/fixed_route_read.py +++ b/spinnman/messages/scp/impl/fixed_route_read.py @@ -39,7 +39,7 @@ def __init__(self) -> None: self._route = 0 @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/get_chip_info_response.py b/spinnman/messages/scp/impl/get_chip_info_response.py index 913adc654..6992f92a4 100644 --- a/spinnman/messages/scp/impl/get_chip_info_response.py +++ b/spinnman/messages/scp/impl/get_chip_info_response.py @@ -30,7 +30,7 @@ def __init__(self) -> None: self._chip_info: Optional[ChipSummaryInfo] = None @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/get_version_response.py b/spinnman/messages/scp/impl/get_version_response.py index f8017c4d0..e0960ae65 100644 --- a/spinnman/messages/scp/impl/get_version_response.py +++ b/spinnman/messages/scp/impl/get_version_response.py @@ -30,7 +30,7 @@ def __init__(self) -> None: self._version_info: Optional[VersionInfo] = None @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/iptag_get.py b/spinnman/messages/scp/impl/iptag_get.py index d6903982b..73529becb 100644 --- a/spinnman/messages/scp/impl/iptag_get.py +++ b/spinnman/messages/scp/impl/iptag_get.py @@ -60,7 +60,7 @@ def __init__(self) -> None: self._spin_port = 0 @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/iptag_get_info_response.py b/spinnman/messages/scp/impl/iptag_get_info_response.py index 232caa7ad..98f3cd0a8 100644 --- a/spinnman/messages/scp/impl/iptag_get_info_response.py +++ b/spinnman/messages/scp/impl/iptag_get_info_response.py @@ -37,7 +37,7 @@ def __init__(self) -> None: self._fixed_size = 0 @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/read_memory.py b/spinnman/messages/scp/impl/read_memory.py index 204f721e5..be1e4dbfa 100644 --- a/spinnman/messages/scp/impl/read_memory.py +++ b/spinnman/messages/scp/impl/read_memory.py @@ -43,7 +43,7 @@ def __init__(self, operation: str, command: str) -> None: self.__cmd = command @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: assert self._scp_response_header is not None if self._scp_response_header.result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/router_alloc.py b/spinnman/messages/scp/impl/router_alloc.py index 26289308d..87765a832 100644 --- a/spinnman/messages/scp/impl/router_alloc.py +++ b/spinnman/messages/scp/impl/router_alloc.py @@ -37,7 +37,7 @@ def __init__(self) -> None: self._base_address: Optional[int] = None @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/sdram_alloc.py b/spinnman/messages/scp/impl/sdram_alloc.py index 025908f28..ee775243b 100644 --- a/spinnman/messages/scp/impl/sdram_alloc.py +++ b/spinnman/messages/scp/impl/sdram_alloc.py @@ -42,7 +42,7 @@ def __init__(self, size: int): self._base_address: Optional[int] = None @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/sdram_de_alloc.py b/spinnman/messages/scp/impl/sdram_de_alloc.py index 919dc7e38..6a9ff0b97 100644 --- a/spinnman/messages/scp/impl/sdram_de_alloc.py +++ b/spinnman/messages/scp/impl/sdram_de_alloc.py @@ -41,7 +41,7 @@ def __init__(self, read_n_blocks_freed: bool = False): self._read_n_blocks_freed = read_n_blocks_freed @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int): + def read_data_bytestring(self, data: bytes, offset: int) -> None: result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/set_power.py b/spinnman/messages/scp/impl/set_power.py index 5051ffc90..e258b41da 100644 --- a/spinnman/messages/scp/impl/set_power.py +++ b/spinnman/messages/scp/impl/set_power.py @@ -32,7 +32,7 @@ class SetPower(BMPRequest[BMPOKResponse]): def __init__( self, power_command: PowerCommand, boards: Boards, *, - delay=0.0, board_to_send_to=0): + delay: float = 0.0, board_to_send_to: int = 0): """ .. note:: There is currently a bug in the BMP that means some boards don't diff --git a/spinnman/messages/scp/scp_request_header.py b/spinnman/messages/scp/scp_request_header.py index 6a3c4f662..2928e39ed 100644 --- a/spinnman/messages/scp/scp_request_header.py +++ b/spinnman/messages/scp/scp_request_header.py @@ -59,7 +59,7 @@ def sequence(self) -> int: return self._sequence @sequence.setter - def sequence(self, sequence: int): + def sequence(self, sequence: int) -> None: """ Set the sequence number of the SCP packet. diff --git a/spinnman/messages/scp/scp_response_header.py b/spinnman/messages/scp/scp_response_header.py index 55907e59f..97dbb9fce 100644 --- a/spinnman/messages/scp/scp_response_header.py +++ b/spinnman/messages/scp/scp_response_header.py @@ -26,7 +26,7 @@ class SCPResponseHeader(object): "_result", "_sequence") - def __init__(self, result, sequence): + def __init__(self, result: SCPResult, sequence: int): """ :param SCPResult result: :param int sequence: diff --git a/spinnman/messages/sdp/sdp_header.py b/spinnman/messages/sdp/sdp_header.py index 4afdb35d1..2f24b905c 100644 --- a/spinnman/messages/sdp/sdp_header.py +++ b/spinnman/messages/sdp/sdp_header.py @@ -98,7 +98,7 @@ def flags(self) -> SDPFlag: return self._flags @flags.setter - def flags(self, flags: SDPFlag): + def flags(self, flags: SDPFlag) -> None: """ Set the flags of the packet. @@ -117,7 +117,7 @@ def tag(self) -> int: return self._tag @tag.setter - def tag(self, tag: int): + def tag(self, tag: int) -> None: """ Set the tag of the packet. @@ -135,7 +135,7 @@ def destination_port(self) -> int: return self._destination_port @destination_port.setter - def destination_port(self, destination_port: int): + def destination_port(self, destination_port: int) -> None: """ Set the destination port of the packet. @@ -154,7 +154,7 @@ def destination_cpu(self) -> int: return self._destination_cpu @destination_cpu.setter - def destination_cpu(self, destination_cpu: int): + def destination_cpu(self, destination_cpu: int) -> None: """ Set the ID of the destination processor of the packet. @@ -174,7 +174,7 @@ def destination_chip_x(self) -> int: return self._destination_chip_x @destination_chip_x.setter - def destination_chip_x(self, destination_chip_x: int): + def destination_chip_x(self, destination_chip_x: int) -> None: """ Set the x-coordinate of the destination chip of the packet. @@ -194,7 +194,7 @@ def destination_chip_y(self) -> int: return self._destination_chip_y @destination_chip_y.setter - def destination_chip_y(self, destination_chip_y: int): + def destination_chip_y(self, destination_chip_y: int) -> None: """ Set the y-coordinate of the destination chip of the packet. @@ -214,7 +214,7 @@ def source_port(self) -> int: return self._source_port @source_port.setter - def source_port(self, source_port: int): + def source_port(self, source_port: int) -> None: """ Set the source port of the packet. @@ -233,7 +233,7 @@ def source_cpu(self) -> int: return self._source_cpu @source_cpu.setter - def source_cpu(self, source_cpu: int): + def source_cpu(self, source_cpu: int) -> None: """ Set the ID of the source processor of the packet. @@ -254,7 +254,7 @@ def source_chip_x(self) -> int: return self._source_chip_x @source_chip_x.setter - def source_chip_x(self, source_chip_x: int): + def source_chip_x(self, source_chip_x: int) -> None: """ Set the x-coordinate of the source chip of the packet. @@ -276,7 +276,7 @@ def source_chip_y(self) -> int: return self._source_chip_y @source_chip_y.setter - def source_chip_y(self, source_chip_y: int): + def source_chip_y(self, source_chip_y: int) -> None: """ Set the y-coordinate of the source chip of the packet. @@ -303,7 +303,7 @@ def bytestring(self) -> bytes: self.source_chip_y, self.source_chip_x) @staticmethod - def from_bytestring(data: bytes, offset: int): + def from_bytestring(data: bytes, offset: int) -> "SDPHeader": """ Read the header from a byte-string. @@ -334,7 +334,7 @@ def get_physical_cpu_id(self) -> str: (self._destination_chip_x, self._destination_chip_y), self._destination_cpu) - def update_for_send(self, source_x: int, source_y: int): + def update_for_send(self, source_x: int, source_y: int) -> None: """ Apply defaults to the header for sending over UDP. diff --git a/spinnman/model/cpu_info.py b/spinnman/model/cpu_info.py index fb726f959..4499ace68 100644 --- a/spinnman/model/cpu_info.py +++ b/spinnman/model/cpu_info.py @@ -377,8 +377,8 @@ def get_status_string(self) -> str: f"in state {self.__state.name}\n") @staticmethod - def mock_info( - x: int, y: int, p: int, physical_cpu_id: int, state: CPUState): + def mock_info(x: int, y: int, p: int, physical_cpu_id: int, + state: CPUState) -> "CPUInfo": """ Makes a CPU_info object for Testing purposes diff --git a/spinnman/model/cpu_infos.py b/spinnman/model/cpu_infos.py index 730ddf506..8a18a155d 100644 --- a/spinnman/model/cpu_infos.py +++ b/spinnman/model/cpu_infos.py @@ -13,6 +13,7 @@ # limitations under the License. from typing import Dict, Iterable, Iterator +from typing_extensions import Self from spinn_utilities.typing.coords import XYP from spinnman.model.enums import CPUState from .cpu_info import CPUInfo @@ -28,7 +29,7 @@ class CPUInfos(object): def __init__(self) -> None: self._cpu_infos: Dict[XYP, CPUInfo] = dict() - def add_info(self, cpu_info: CPUInfo): + def add_info(self, cpu_info: CPUInfo) -> None: """ Add a info on using its core coordinates. @@ -36,7 +37,7 @@ def add_info(self, cpu_info: CPUInfo): """ self._cpu_infos[cpu_info.x, cpu_info.y, cpu_info.p] = cpu_info - def add_infos(self, other, states: Iterable[CPUState]): + def add_infos(self, other: Self, states: Iterable[CPUState]) -> None: """ Adds all the infos in the other CPUInfos if the have one of the required states diff --git a/spinnman/model/enums/executable_type.py b/spinnman/model/enums/executable_type.py index dc4d67bf4..823f88089 100644 --- a/spinnman/model/enums/executable_type.py +++ b/spinnman/model/enums/executable_type.py @@ -13,7 +13,7 @@ # limitations under the License. from __future__ import annotations from enum import Enum -from typing import FrozenSet, Sequence +from typing import FrozenSet, Sequence, Tuple from spinnman.model.enums import CPUState @@ -67,10 +67,13 @@ class ExecutableType(Enum): True, "Runs immediately without waiting for barrier and never ends") - def __new__(cls, *args) -> 'ExecutableType': + def __new__(cls, value: int, start_state: Sequence[CPUState], + end_state: Sequence[CPUState], + supports_auto_pause_and_resume: bool, + doc: str = "") -> 'ExecutableType': obj = object.__new__(cls) - obj._value_ = args[0] - obj. __doc__ = args[-1] + obj._value_ = value + obj. __doc__ = doc return obj def __init__(self, value: int, start_state: Sequence[CPUState], diff --git a/spinnman/model/executable_targets.py b/spinnman/model/executable_targets.py index d50a0e694..8ad5900b8 100644 --- a/spinnman/model/executable_targets.py +++ b/spinnman/model/executable_targets.py @@ -43,7 +43,7 @@ def __init__(self) -> None: def add_subsets( self, binary: str, subsets: CoreSubsets, - executable_type: Optional[ExecutableType] = None): + executable_type: Optional[ExecutableType] = None) -> None: """ Add core subsets to a binary. @@ -66,7 +66,7 @@ def add_subsets( def add_processor( self, binary: str, chip_x: int, chip_y: int, chip_p: int, - executable_type: Optional[ExecutableType] = None): + executable_type: Optional[ExecutableType] = None) -> None: """ Add a processor to the executable targets @@ -160,7 +160,8 @@ def all_core_subsets(self) -> CoreSubsets: """ return self._all_core_subsets - def known(self, binary, chip_x, chip_y, chip_p) -> bool: + def known( + self, binary: str, chip_x: int, chip_y: int, chip_p: int) -> bool: """ :param str binary: :param int chip_x: diff --git a/spinnman/model/p2p_table.py b/spinnman/model/p2p_table.py index e40c04f75..7c6f689ab 100644 --- a/spinnman/model/p2p_table.py +++ b/spinnman/model/p2p_table.py @@ -13,7 +13,7 @@ # limitations under the License. import struct -from typing import Dict, List, Tuple +from typing import Dict, Iterable, List, Tuple from spinnman.model.enums import P2PTableRoute _ONE_WORD = struct.Struct(" int: """ return self._height - def iterchips(self): + def iterchips(self) -> Iterable[Tuple[int, int]]: """ Get an iterator of tuples of (x, y) coordinates in the table. @@ -95,7 +95,7 @@ def iterchips(self): """ return iter(self._routes.keys()) - def is_route(self, x, y): + def is_route(self, x: int, y: int) -> bool: """ Determines if there is a route in the P2P table to the given chip. @@ -118,7 +118,7 @@ def get_route(self, x: int, y: int) -> P2PTableRoute: return self._routes.get((x, y), P2PTableRoute.NONE) @property - def n_routes(self): + def n_routes(self) -> int: """ The number of routes in the table :rtype: int diff --git a/spinnman/utilities/appid_tracker.py b/spinnman/utilities/appid_tracker.py index 6ece8d458..2b9cfb257 100644 --- a/spinnman/utilities/appid_tracker.py +++ b/spinnman/utilities/appid_tracker.py @@ -53,7 +53,7 @@ def get_new_id(self) -> int: """ return self._free_ids.pop() - def allocate_id(self, allocated_id: int): + def allocate_id(self, allocated_id: int) -> None: """ Allocate a given ID. @@ -62,7 +62,7 @@ def allocate_id(self, allocated_id: int): """ self._free_ids.remove(allocated_id) - def free_id(self, id_to_free: int): + def free_id(self, id_to_free: int) -> None: """ Free a given ID. diff --git a/spinnman/utilities/socket_utils.py b/spinnman/utilities/socket_utils.py index 69463294a..c9d421551 100644 --- a/spinnman/utilities/socket_utils.py +++ b/spinnman/utilities/socket_utils.py @@ -53,7 +53,7 @@ def get_tcp_socket() -> socket.socket: # pylint: disable=wrong-spelling-in-docstring -def set_receive_buffer_size(sock: socket.socket, size: int): +def set_receive_buffer_size(sock: socket.socket, size: int) -> None: """ Wrapper round setsockopt() system call. """ @@ -66,7 +66,7 @@ def set_receive_buffer_size(sock: socket.socket, size: int): "receive buffer", exc_info=True) -def bind_socket(sock: socket.socket, host: str, port: int): +def bind_socket(sock: socket.socket, host: str, port: int) -> None: """ Wrapper round bind() system call. """ @@ -89,7 +89,8 @@ def resolve_host(host: str) -> str: f"Error getting IP address for {host}: {e}") from e -def connect_socket(sock: socket.socket, remote_address: str, remote_port: int): +def connect_socket( + sock: socket.socket, remote_address: str, remote_port: int) -> None: """ Wrapper round connect() system call. """ @@ -144,7 +145,7 @@ def receive_message_and_address( raise SpinnmanIOException(f"Error receiving: {e}") from e -def send_message(sock: socket.socket, data: bytes): +def send_message(sock: socket.socket, data: bytes) -> int: """ Wrapper round send() system call. """ @@ -155,7 +156,7 @@ def send_message(sock: socket.socket, data: bytes): def send_message_to_address( - sock: socket.socket, data: bytes, address: Tuple[str, int]): + sock: socket.socket, data: bytes, address: Tuple[str, int]) -> int: """ Wrapper round sendto() system call. """ From 9d9b195fec943fbc253df11d4b6b1c95073adc95 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 30 Oct 2024 12:40:38 +0000 Subject: [PATCH 11/18] mypy-full_packages: spinnman --- .github/workflows/python_actions.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python_actions.yml b/.github/workflows/python_actions.yml index de69522ee..6f975ee00 100644 --- a/.github/workflows/python_actions.yml +++ b/.github/workflows/python_actions.yml @@ -27,5 +27,6 @@ jobs: coverage-package: spinnman flake8-packages: spinnman unittests spinnman_integration_tests pylint-packages: spinnman - mypy-packages: spinnman unittests spinnman_integration_tests + mypy-packages: unittests spinnman_integration_tests + mypy-full_packages: spinnman secrets: inherit \ No newline at end of file From c994238c9ebaba26501c957f6f38d6d75bb0143e Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 30 Oct 2024 13:16:44 +0000 Subject: [PATCH 12/18] flake8 --- spinnman/exceptions.py | 2 +- .../notification_protocol_start_resume.py | 2 +- .../spinnaker_boot/system_variable_boot_values.py | 2 +- spinnman/model/enums/executable_type.py | 8 ++++---- spinnman/spalloc/session.py | 6 ++++-- spinnman/transceiver/base_transceiver.py | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/spinnman/exceptions.py b/spinnman/exceptions.py index 018ad71f9..29aebdcad 100644 --- a/spinnman/exceptions.py +++ b/spinnman/exceptions.py @@ -15,7 +15,7 @@ import traceback from types import TracebackType from typing import ( - Any, Generic, List, Optional, FrozenSet, TYPE_CHECKING, TypeVar, Union) + Generic, List, Optional, FrozenSet, TYPE_CHECKING, TypeVar, Union) if TYPE_CHECKING: from spinnman.messages.scp.enums import SCPResult from spinnman.model.enums import CPUState diff --git a/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py b/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py index 2558337e8..2898b47c3 100644 --- a/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py +++ b/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py @@ -34,5 +34,5 @@ def __init__(self) -> None: @staticmethod @overrides(EIEIOCommandMessage.from_bytestring) def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, - offset: int) -> "NotificationProtocolStartResume": + offset: int) -> "NotificationProtocolStartResume": return NotificationProtocolStartResume() diff --git a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py index 556cd0bf5..01e1579de 100644 --- a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py +++ b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py @@ -29,7 +29,7 @@ class _DataType(Enum): LONG = (8, " "_DataType" : + def __new__(cls, value: int, struct_code: str) -> "_DataType": obj = object.__new__(cls) obj._value_ = value return obj diff --git a/spinnman/model/enums/executable_type.py b/spinnman/model/enums/executable_type.py index 823f88089..ba95c47d1 100644 --- a/spinnman/model/enums/executable_type.py +++ b/spinnman/model/enums/executable_type.py @@ -13,7 +13,7 @@ # limitations under the License. from __future__ import annotations from enum import Enum -from typing import FrozenSet, Sequence, Tuple +from typing import FrozenSet, Sequence from spinnman.model.enums import CPUState @@ -68,9 +68,9 @@ class ExecutableType(Enum): "Runs immediately without waiting for barrier and never ends") def __new__(cls, value: int, start_state: Sequence[CPUState], - end_state: Sequence[CPUState], - supports_auto_pause_and_resume: bool, - doc: str = "") -> 'ExecutableType': + end_state: Sequence[CPUState], + supports_auto_pause_and_resume: bool, + doc: str = "") -> 'ExecutableType': obj = object.__new__(cls) obj._value_ = value obj. __doc__ = doc diff --git a/spinnman/spalloc/session.py b/spinnman/spalloc/session.py index 86ea00f9b..253128312 100644 --- a/spinnman/spalloc/session.py +++ b/spinnman/spalloc/session.py @@ -302,7 +302,8 @@ def _credentials(self) -> Tuple[Dict[str, str], Dict[str, str]]: def websocket( self, url: str, header: Optional[dict] = None, - cookie: Optional[str] = None, **kwargs: Any) -> websocket.WebSocket: + cookie: Optional[str] = None, + **kwargs: Any) -> websocket.WebSocket: """ Create a websocket that uses the session credentials to establish itself. @@ -374,7 +375,8 @@ def _service_url(self) -> str: def _get(self, url: str, **kwargs: Any) -> requests.Response: return self.__session.get(url, **kwargs) - def _post(self, url: str, json_dict: dict, **kwargs: Any) -> requests.Response: + def _post(self, url: str, json_dict: dict, + **kwargs: Any) -> requests.Response: return self.__session.post(url, json_dict, **kwargs) def _put(self, url: str, data: str, **kwargs: Any) -> requests.Response: diff --git a/spinnman/transceiver/base_transceiver.py b/spinnman/transceiver/base_transceiver.py index c0b67f00d..c57f56f73 100644 --- a/spinnman/transceiver/base_transceiver.py +++ b/spinnman/transceiver/base_transceiver.py @@ -841,7 +841,7 @@ def __flood_execute_lock(self) -> Iterator[Condition]: def execute_flood( self, core_subsets: CoreSubsets, executable: Union[BinaryIO, bytes, str], app_id: int, *, - n_bytes: Optional[int] = None, wait: bool = False) -> None : + n_bytes: Optional[int] = None, wait: bool = False) -> None: if isinstance(executable, int): # No executable is 4 bytes long raise TypeError("executable may not be int") From a4279f400b112d0b73f517ccd3fae0cbb55d1bfb Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 30 Oct 2024 13:31:51 +0000 Subject: [PATCH 13/18] pylint --- spinnman/messages/spinnaker_boot/system_variable_boot_values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py index 01e1579de..274ac849b 100644 --- a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py +++ b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py @@ -30,6 +30,7 @@ class _DataType(Enum): BYTE_ARRAY = (16, "s") def __new__(cls, value: int, struct_code: str) -> "_DataType": + # pylint: disable=unused-argument obj = object.__new__(cls) obj._value_ = value return obj From 46bd4cd2b775292edb6f919782a24d21361e8589 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 30 Oct 2024 13:40:57 +0000 Subject: [PATCH 14/18] more pylint --- spinnman/messages/spinnaker_boot/system_variable_boot_values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py index 274ac849b..cb443eb1e 100644 --- a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py +++ b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py @@ -30,12 +30,12 @@ class _DataType(Enum): BYTE_ARRAY = (16, "s") def __new__(cls, value: int, struct_code: str) -> "_DataType": - # pylint: disable=unused-argument obj = object.__new__(cls) obj._value_ = value return obj def __init__(self, value: int, struct_code: str): + # pylint: disable=unused-argument self._struct_code = struct_code @property From aa6c69fb9b7c87a79ef7c33aad9e410cdc884ebf Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 13 Nov 2024 08:46:52 +0000 Subject: [PATCH 15/18] assert not needed as guaranteed by typing --- spinnman/transceiver/base_transceiver.py | 1 - 1 file changed, 1 deletion(-) diff --git a/spinnman/transceiver/base_transceiver.py b/spinnman/transceiver/base_transceiver.py index 30b13a2eb..89c5bf8d6 100644 --- a/spinnman/transceiver/base_transceiver.py +++ b/spinnman/transceiver/base_transceiver.py @@ -1146,7 +1146,6 @@ def set_ip_tag(self, ip_tag: IPTag, use_sender: bool = False): for connection in connections: # Convert the host string host_string = ip_tag.ip_address - assert host_string is not None if host_string in ("localhost", ".", "0.0.0.0"): host_string = connection.local_ip_address ip_string = socket.gethostbyname(host_string) From 8fb4eca0f42f7eaa9f7a0bf9a50fae91a612dc22 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 13 Nov 2024 10:10:38 +0000 Subject: [PATCH 16/18] add assert --- spinnman/processes/get_tags_process.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spinnman/processes/get_tags_process.py b/spinnman/processes/get_tags_process.py index d6a7c92f3..b85337481 100644 --- a/spinnman/processes/get_tags_process.py +++ b/spinnman/processes/get_tags_process.py @@ -48,7 +48,7 @@ def __handle_tag_info_response( self, response: IPTagGetInfoResponse) -> None: self._tag_info = response - def __handle_get_tag_response(self, tag: int, board_address: Optional[str], + def __handle_get_tag_response(self, tag: int, board_address: str, response: IPTagGetResponse) -> None: if response.in_use: ip = response.ip_address @@ -82,6 +82,8 @@ def get_tags(self, connection: SCAMPConnection) -> List[AbstractTag]: n_tags = self._tag_info.pool_size + self._tag_info.fixed_size self._tags = [None] * n_tags with self._collect_responses(): + board_address = connection.remote_ip_address + assert board_address is not None for tag in range(n_tags): self._send_request(IPTagGet( connection.chip_x, connection.chip_y, tag), From 6a501aebaca1cdff5bdceea39d42f4915ab167a1 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 13 Nov 2024 10:29:35 +0000 Subject: [PATCH 17/18] use asserted value --- spinnman/processes/get_tags_process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spinnman/processes/get_tags_process.py b/spinnman/processes/get_tags_process.py index b85337481..c327462f6 100644 --- a/spinnman/processes/get_tags_process.py +++ b/spinnman/processes/get_tags_process.py @@ -89,7 +89,7 @@ def get_tags(self, connection: SCAMPConnection) -> List[AbstractTag]: connection.chip_x, connection.chip_y, tag), partial( self.__handle_get_tag_response, tag, - connection.remote_ip_address)) + board_address)) # Return the tags return [tag for tag in self._tags if tag is not None] From ddeef41c44e648041c2f4027d15d55380180e33b Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 13 Nov 2024 10:57:00 +0000 Subject: [PATCH 18/18] make SpallocJob a contextlib.AbstractContextManager --- spinnman/spalloc/spalloc_job.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/spinnman/spalloc/spalloc_job.py b/spinnman/spalloc/spalloc_job.py index d096b26fb..b9e228592 100644 --- a/spinnman/spalloc/spalloc_job.py +++ b/spinnman/spalloc/spalloc_job.py @@ -12,11 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from contextlib import AbstractContextManager from types import TracebackType from typing import Dict, Mapping, Optional, Tuple, Type from typing_extensions import Literal, Self -from spinn_utilities.abstract_base import AbstractBase, abstractmethod +from spinn_utilities.abstract_base import abstractmethod from spinnman.constants import SCP_SCAMP_PORT from spinnman.transceiver.transceiver import Transceiver from spinnman.connections.udp_packet_connections import UDPConnection @@ -27,7 +28,7 @@ from .spalloc_scp_connection import SpallocSCPConnection -class SpallocJob(object, metaclass=AbstractBase): +class SpallocJob(AbstractContextManager): """ Represents a job in Spalloc. @@ -216,8 +217,9 @@ def __enter__(self) -> Self: """ return self - def __exit__(self, exc_type: Optional[Type], exc_value: Exception, - exc_tb: TracebackType) -> Literal[False]: + def __exit__(self, exc_type: Optional[Type], + exc_value: Optional[BaseException], + exc_tb: Optional[TracebackType]) -> Literal[False]: """ Handle exceptions by killing the job and logging the exception in the job's destroy reason.