diff --git a/.github/workflows/python_actions.yml b/.github/workflows/python_actions.yml index 35ede4583..bfa4b0f19 100644 --- a/.github/workflows/python_actions.yml +++ b/.github/workflows/python_actions.yml @@ -65,7 +65,9 @@ jobs: uses: ./support/actions/pylint with: package: spinnman + exitcheck: 31 # Action fails on any message language: en_GB + rcfile: global_strict - name: Lint with mypy run: mypy spinnman diff --git a/.pylint_dict.txt b/.pylint_dict.txt index 93ab12355..adce7d510 100644 --- a/.pylint_dict.txt +++ b/.pylint_dict.txt @@ -12,52 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Our abbreviations/names -bmp -cpu -iobuf -scp -Spalloc -bmpc -ybug -txrx -url -xy -xys +# We use a single exception files for all the main repsitories +# It can be found at: +# https://github.com/SpiNNakerManchester/SupportScripts/blob/master/actions/pylint/default_dict.txt -# Our special words -keepalive -# Our special words ("wrap-arounds" gets split up) -arounds -# Python packages -spinnman -websocket - -# Python types -BMPConnectionData -BufferedIOBase -CoreSubset -CPUInfo -CPUInfos -CPUState -DiagnosticFilter -DiagnosticFilterDestination -DiagnosticFilterDefaultRoutingStatus -DiagnosticFilterEmergencyRoutingStatus -DiagnosticFilterPacketType -DiagnosticFilterPayloadStatus -DiagnosticFilterSource -ExecutableType -HeapElement -IOBuffer -PreparedRequest -RawIOBase -SCAMPConnection -SCPResult -SpallocJob -SpallocMachine -SpinnakerBootMessage -SystemVariableDefinition -WebSocket diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 2d054cde5..000000000 --- a/.pylintrc +++ /dev/null @@ -1,469 +0,0 @@ -# Copyright (c) 2019 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. - -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist=numpy - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages -suggestion-mode=yes - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=R,C - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable=c-extension-no-member,C0402,C0403 - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio).You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - -# Complete name of functions that never returns. When checking for -# inconsistent-return-statements if a never returning function is called then -# it will be considered as an explicit return statement and no message will be -# printed. -never-returning-functions=optparse.Values,sys.exit - - -[BASIC] - -# Naming style matching correct argument names -argument-naming-style=snake_case - -# Regular expression matching correct argument names. Overrides argument- -# naming-style -#argument-rgx= - -# Naming style matching correct attribute names -attr-naming-style=snake_case - -# Regular expression matching correct attribute names. Overrides attr-naming- -# style -#attr-rgx= - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo, - bar, - baz, - toto, - tutu, - tata - -# Naming style matching correct class attribute names -class-attribute-naming-style=any - -# Regular expression matching correct class attribute names. Overrides class- -# attribute-naming-style -#class-attribute-rgx= - -# Naming style matching correct class names -class-naming-style=PascalCase - -# Regular expression matching correct class names. Overrides class-naming-style -#class-rgx= - -# Naming style matching correct constant names -const-naming-style=UPPER_CASE - -# Regular expression matching correct constant names. Overrides const-naming- -# style -#const-rgx= - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming style matching correct function names -function-naming-style=snake_case - -# Regular expression matching correct function names. Overrides function- -# naming-style -#function-rgx= - -# Good variable names which should always be accepted, separated by a comma -good-names=i, - j, - k, - ex, - Run, - _ - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Naming style matching correct inline iteration names -inlinevar-naming-style=any - -# Regular expression matching correct inline iteration names. Overrides -# inlinevar-naming-style -#inlinevar-rgx= - -# Naming style matching correct method names -method-naming-style=snake_case - -# Regular expression matching correct method names. Overrides method-naming- -# style -#method-rgx= - -# Naming style matching correct module names -module-naming-style=snake_case - -# Regular expression matching correct module names. Overrides module-naming- -# style -#module-rgx= - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Naming style matching correct variable names -variable-naming-style=snake_case - -# Regular expression matching correct variable names. Overrides variable- -# naming-style -#variable-rgx= - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=100 - -# Maximum number of lines in a module -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging,FormatAdapter - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME, - XXX - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[SPELLING] - -# Limits count of emitted suggestions for spelling mistakes -max-spelling-suggestions=4 - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members=numpy.* - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local,numpy - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=numpy - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_, - _cb - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - _hard_reset, - - setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of statements in function / method body -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=optparse,tkinter.tix - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=builtins.Exception diff --git a/import_hook.py b/import_hook.py new file mode 100644 index 000000000..01a2d6900 --- /dev/null +++ b/import_hook.py @@ -0,0 +1,25 @@ +# Copyright (c) 2017 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 file is imported by init-hook in the rcfile +https://github.com/SpiNNakerManchester/SupportScripts/blob/master/actions/pylint/strict_rcfile + +It allows you to temporarily add the other spinnaker repositories without making them part of the permemnant python path + +Intended for use when running pylint.bash +""" +import sys +sys.path.append("../SpiNNUtils") +sys.path.append("../SpiNNMachine") \ No newline at end of file diff --git a/pylint.bash b/pylint.bash new file mode 100644 index 000000000..19336137c --- /dev/null +++ b/pylint.bash @@ -0,0 +1,37 @@ +#!/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 SupportScripts has been installed in parallel + +# requires the latest pylint and pyenchant +# pip install --upgrade pylint pyenchant + +# requires the spelling dicts +# sudo apt-get -o Dpkg::Use-Pty=0 install --fix-missing enchant-2 hunspell hunspell-en-gb + +rcfile="--rcfile=../SupportScripts/actions/pylint/strict_rcfile" +dict="--spelling-private-dict-file=../SupportScripts/actions/pylint/default_dict.txt" +params="--output-format=colorized --disable=R --persistent=no --jobs=1 --spelling-dict=en_GB" +check= +# one test +# check="--enable=wrong-import-order --disable=all" +# check docs +check="--enable=missing-function-docstring,missing-class-docstring,invalid-characters-in-docstring,wrong-spelling-in-comment,wrong-spelling-in-docstring --disable=all" + +pylint $check $rcfile $dict $params spinnman + + + diff --git a/spinnman/board_test_configuration.py b/spinnman/board_test_configuration.py index 0c5c46604..19ac94cd4 100644 --- a/spinnman/board_test_configuration.py +++ b/spinnman/board_test_configuration.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import Optional import unittest from spinn_utilities.config_holder import set_config from spinn_utilities.ping import Ping @@ -19,24 +20,45 @@ class BoardTestConfiguration(object): + """ + Configuration to use for a test board + """ def __init__(self): self.remotehost = None self.auto_detect_bmp = None - def set_up_remote_board(self, version=None): + def set_up_remote_board(self, version: Optional[int] = None): + """ + Gets a remote board to test, returning the first that it finds. + + Search order is + - Local 4 Chip board + - 48 Chip board "spinn-4.cs.man.ac.uk" + - Local 48 Chip board if at 192.168.240.1 + - Virtual machine + + The first three ignore the version param the last needs it + + Sets the version field in the configs. + + :param version: Version for a virtual if no physical board found + :type version: into or None + :raises unittest.SkipTest: + If no physical machine found and no version provided + """ if Ping.host_is_reachable("192.168.240.253"): self.remotehost = "192.168.240.253" - set_config("Machine", "version", 3) + set_config("Machine", "version", "3") self.auto_detect_bmp = False elif Ping.host_is_reachable("spinn-4.cs.man.ac.uk"): self.remotehost = "spinn-4.cs.man.ac.uk" - set_config("Machine", "version", 5) + set_config("Machine", "version", "5") elif Ping.host_is_reachable("192.168.240.1"): self.remotehost = "192.168.240.1" - set_config("Machine", "version", 5) + set_config("Machine", "version", "5") elif version is not None: self.remotehost = LOCAL_HOST - set_config("Machine", "version", version) + set_config("Machine", "version", str(version)) else: raise unittest.SkipTest("None of the test boards reachable") diff --git a/spinnman/connections/abstract_classes/abstract_scp_connection.py b/spinnman/connections/abstract_classes/abstract_scp_connection.py index 3168f47d7..8b05f40a4 100644 --- a/spinnman/connections/abstract_classes/abstract_scp_connection.py +++ b/spinnman/connections/abstract_classes/abstract_scp_connection.py @@ -66,29 +66,6 @@ def get_scp_data(self, scp_request: AbstractSCPRequest) -> bytes: """ raise NotImplementedError - @abstractmethod - def send_scp_request(self, scp_request: AbstractSCPRequest): - """ - Sends an SCP request down this connection. - - Messages must have the following properties: - - * source_port is `None` or 7 - * source_cpu is `None` or 31 - * source_chip_x is `None` or 0 - * source_chip_y is `None` or 0 - - tag in the message is optional; if not set, the default set in the - constructor will be used. - sequence in the message is optional; if not set, (sequence number - last assigned + 1) % 65536 will be used - - :param AbstractSCPRequest scp_request: message packet to send - :raise SpinnmanIOException: - If there is an error sending the message - """ - raise NotImplementedError - @property @abstractmethod def chip_x(self) -> int: diff --git a/spinnman/connections/abstract_classes/listenable.py b/spinnman/connections/abstract_classes/listenable.py index 481e03d80..901f0f337 100644 --- a/spinnman/connections/abstract_classes/listenable.py +++ b/spinnman/connections/abstract_classes/listenable.py @@ -17,7 +17,7 @@ T = TypeVar("T") -# Should inherit from Connection, but doesn't for MRO reasons +# Should inherit from Connection, but doesn't for Multiple Inheritance reasons class Listenable(Generic[T], metaclass=AbstractBase): """ An interface for connections that can listen for incoming messages. diff --git a/spinnman/connections/udp_packet_connections/bmp_connection.py b/spinnman/connections/udp_packet_connections/bmp_connection.py index 63e45379e..4b123b85b 100644 --- a/spinnman/connections/udp_packet_connections/bmp_connection.py +++ b/spinnman/connections/udp_packet_connections/bmp_connection.py @@ -13,15 +13,18 @@ # limitations under the License. import struct -from typing import Sequence, Tuple +from typing import Optional, Sequence, Tuple + from spinn_utilities.overrides import overrides -from .udp_connection import UDPConnection + from spinnman.constants import SCP_SCAMP_PORT from spinnman.messages.scp.enums import SCPResult from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.connections.abstract_classes import AbstractSCPConnection from spinnman.model import BMPConnectionData +from .udp_connection import UDPConnection + _TWO_SHORTS = struct.Struct("<2H") _TWO_SKIP = struct.Struct("<2x") @@ -74,16 +77,12 @@ def get_scp_data(self, scp_request: AbstractSCPRequest) -> bytes: return _TWO_SKIP.pack() + scp_request.bytestring @overrides(AbstractSCPConnection.receive_scp_response) - def receive_scp_response(self, timeout=1.0) -> Tuple[ + def receive_scp_response(self, timeout: Optional[float] = 1.0) -> Tuple[ SCPResult, int, bytes, int]: data = self.receive(timeout) result, sequence = _TWO_SHORTS.unpack_from(data, 10) return SCPResult(result), sequence, data, 2 - @overrides(AbstractSCPConnection.send_scp_request) - def send_scp_request(self, scp_request: AbstractSCPRequest): - self.send(self.get_scp_data(scp_request)) - def __repr__(self): return ( f"BMPConnection(" diff --git a/spinnman/connections/udp_packet_connections/boot_connection.py b/spinnman/connections/udp_packet_connections/boot_connection.py index 7ab0d5fd4..f7c41536c 100644 --- a/spinnman/connections/udp_packet_connections/boot_connection.py +++ b/spinnman/connections/udp_packet_connections/boot_connection.py @@ -14,10 +14,12 @@ import time from typing import Optional -from .udp_connection import UDPConnection + from spinnman.messages.spinnaker_boot import SpinnakerBootMessage from spinnman.constants import UDP_BOOT_CONNECTION_DEFAULT_PORT +from .udp_connection import UDPConnection + _ANTI_FLOOD_DELAY = 0.1 diff --git a/spinnman/connections/udp_packet_connections/eieio_connection.py b/spinnman/connections/udp_packet_connections/eieio_connection.py index 3d9b403b7..c3b228b2e 100644 --- a/spinnman/connections/udp_packet_connections/eieio_connection.py +++ b/spinnman/connections/udp_packet_connections/eieio_connection.py @@ -14,13 +14,16 @@ import struct from typing import Callable, Optional -from .udp_connection import UDPConnection + +from spinn_utilities.overrides import overrides + from spinnman.connections.abstract_classes import Listenable from spinnman.messages.eieio import ( read_eieio_command_message, read_eieio_data_message) -from spinn_utilities.overrides import overrides from spinnman.messages.eieio import AbstractEIEIOMessage +from .udp_connection import UDPConnection + _ONE_SHORT = struct.Struct(" Optional[str]: + """ + + :param timeout: + :type timeout: float or None + :rtype: str or None + """ with suppress(Exception): (_, (ip_address, port)) = self.receive_with_address(timeout) if port == _BOOTROM_SPINN_PORT: @@ -37,5 +45,5 @@ def receive_ip_address(self, timeout=None): return None def __repr__(self): - return "IPAddressesConnection(local_host={}, local_port={})".format( - self.local_ip_address, self.local_port) + 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 d0ae65973..738317d4d 100644 --- a/spinnman/connections/udp_packet_connections/scamp_connection.py +++ b/spinnman/connections/udp_packet_connections/scamp_connection.py @@ -69,6 +69,12 @@ def chip_y(self) -> int: return self._chip_y def update_chip_coordinates(self, x: int, y: int): + """ + Sets the coordinates without checking they are valid. + + :param int x: + :param int y: + """ self._chip_x = x self._chip_y = y @@ -99,21 +105,15 @@ def receive_scp_response(self, timeout: Optional[float] = 1.0) -> Tuple[ def receive_scp_response_with_address( self, timeout: float = 1.0) -> Tuple[ SCPResult, int, bytes, int, str, int]: + """ + + :param float timeout: + :rtype: tuple(SCPResult, int, bytes, int, str, int) + """ data, (addr, port) = self.receive_with_address(timeout) result, sequence = _TWO_SHORTS.unpack_from(data, 10) return SCPResult(result), sequence, data, 2, addr, port - @overrides(AbstractSCPConnection.send_scp_request) - def send_scp_request(self, scp_request: AbstractSCPRequest): - self.send(self.get_scp_data(scp_request)) - - def send_scp_request_to( - self, scp_request: AbstractSCPRequest, - x: int, y: int, ip_address: str): - self.send_to( - self.get_scp_data(scp_request, x, y), - (str(ip_address), SCP_SCAMP_PORT)) - def __repr__(self) -> str: return ( f"SCAMPConnection(chip_x={self._chip_x}, chip_y={self._chip_y}, " diff --git a/spinnman/connections/udp_packet_connections/sdp_connection.py b/spinnman/connections/udp_packet_connections/sdp_connection.py index 37915eccc..f5e1d3467 100644 --- a/spinnman/connections/udp_packet_connections/sdp_connection.py +++ b/spinnman/connections/udp_packet_connections/sdp_connection.py @@ -14,12 +14,14 @@ import struct from typing import Callable, Optional + from spinn_utilities.overrides import overrides from spinnman.messages.sdp import SDPMessage, SDPFlag -from .udp_connection import UDPConnection from spinnman.connections.abstract_classes import Listenable from spinnman.exceptions import SpinnmanUnsupportedOperationException +from .udp_connection import UDPConnection + _TWO_SKIP = struct.Struct("<2x") diff --git a/spinnman/connections/udp_packet_connections/udp_connection.py b/spinnman/connections/udp_packet_connections/udp_connection.py index 92d10f8c1..b4ae01e98 100644 --- a/spinnman/connections/udp_packet_connections/udp_connection.py +++ b/spinnman/connections/udp_packet_connections/udp_connection.py @@ -200,7 +200,8 @@ def receive(self, timeout: Optional[float] = None) -> bytes: raise SpinnmanEOFException() return receive_message(self._socket, timeout, _MSG_MAX) - def receive_with_address(self, timeout=None): + def receive_with_address(self, timeout: Optional[float] = None) -> Tuple[ + bytes, Tuple[str, int]]: """ Receive data from the connection along with the address where the data was received from. diff --git a/spinnman/constants.py b/spinnman/constants.py index 36e8ec5cb..f36f090f3 100644 --- a/spinnman/constants.py +++ b/spinnman/constants.py @@ -75,7 +75,7 @@ #: Max user requested tag value MAX_TAG_ID: int = 7 -#: The range of values the BMP's 12-bit ADCs can measure. +#: The range of values the BMP 12-bit ADCs can measure. BMP_ADC_MAX: int = 1 << 12 #: Multiplier to convert from ADC value to volts for lines less than 2.5 V. @@ -107,6 +107,7 @@ class EIEIO_COMMAND_IDS(Enum): + # pylint: disable=invalid-name """ A listing of what SpiNNaker specific EIEIO commands there are. """ @@ -139,6 +140,7 @@ class EIEIO_COMMAND_IDS(Enum): class IPTAG_TIME_OUT_WAIT_TIMES(Enum): + # pylint: disable=invalid-name """ The values used by the SCP IP tag time outs. These control how long to wait for any message request which requires a response, before raising an error. @@ -159,6 +161,7 @@ class IPTAG_TIME_OUT_WAIT_TIMES(Enum): class ROUTER_REGISTER_REGISTERS(Enum): + # pylint: disable=invalid-name """ The indices to the router registers. """ @@ -181,6 +184,7 @@ class ROUTER_REGISTER_REGISTERS(Enum): class READ_TYPES(Enum): + # pylint: disable=invalid-name """ The types of read available from SARK. These values are used to tell SARK how to read the data in a time efficient manner. diff --git a/spinnman/exceptions.py b/spinnman/exceptions.py index 95f5fa250..a89962eb7 100644 --- a/spinnman/exceptions.py +++ b/spinnman/exceptions.py @@ -283,19 +283,17 @@ def __init__(self, error_requests: List[AbstractSCPRequest], error_requests, exceptions, tracebacks, connections): sdp_header = error_request.sdp_header phys_p = sdp_header.get_physical_cpu_id() - location = "board {} with ethernet chip {}:{} [{}:{}:{}{}]".format( - connection.remote_ip_address, connection.chip_x, - connection.chip_y, sdp_header.destination_chip_x, - sdp_header.destination_chip_y, - sdp_header.destination_cpu, phys_p) + location = f"board {connection.remote_ip_address} with ethernet " \ + f"chip {connection.chip_x}:{connection.chip_y} " \ + f"[{sdp_header.destination_chip_x}:" \ + f"{sdp_header.destination_chip_y}:" \ + f"{sdp_header.destination_cpu}({phys_p})]" problem += \ - " Received exception class: {}\n" \ - " With message {}\n" \ - " When sending to {}\n" \ - " Stack trace: {}\n".format( - exception.__class__.__name__, str(exception), - location, - traceback.format_tb(trace_back)) + f" Received exception class: " \ + f"{exception.__class__.__name__}\n" \ + f" With message {str(exception)}\n" \ + f" When sending to {location}\n" \ + f" Stack trace: {traceback.format_tb(trace_back)}\n" super().__init__(problem) @@ -317,12 +315,10 @@ def __init__( """ # pylint: disable=too-many-arguments super().__init__( - " Received exception class: {} \n" - " With message: {} \n" - " When sending to {}:{}:{}{}\n" - " Stack trace: {}\n".format( - exception.__class__.__name__, str(exception), x, y, p, - phys_p, traceback.format_tb(tb))) + f" Received exception class: {exception.__class__.__name__} \n" + f" With message: {str(exception)} \n" + f" When sending to {x}:{y}:{p}{phys_p}\n" + f" Stack trace: {traceback.format_tb(tb)}\n") self._stored_exception = exception if tb2 is not None: diff --git a/spinnman/extended/extended_transceiver.py b/spinnman/extended/extended_transceiver.py index f65ce4ad3..3d5fb272f 100644 --- a/spinnman/extended/extended_transceiver.py +++ b/spinnman/extended/extended_transceiver.py @@ -17,10 +17,12 @@ import io import os import logging -import random import struct import time -from spinn_utilities.abstract_base import AbstractBase +from typing import Optional +from spinn_utilities.overrides import overrides +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 @@ -41,11 +43,12 @@ from spinnman.data import SpiNNManDataView from spinnman.messages.spinnaker_boot import SystemVariableDefinition from spinnman.processes import ( - GetHeapProcess, ReadMemoryProcess, SendSingleCommandProcess, - WriteMemoryProcess) + ConnectionSelector, GetHeapProcess, ReadMemoryProcess, + SendSingleCommandProcess, WriteMemoryProcess) from spinnman.transceiver.extendable_transceiver import ExtendableTransceiver _ONE_BYTE = struct.Struct("B") +_ONE_WORD = struct.Struct(" Optional[str]: + raise NotImplementedError + + @property + @abstractmethod + @overrides(ExtendableTransceiver.scamp_connection_selector) + def scamp_connection_selector(self) -> ConnectionSelector: """ - Sends an SCP message, without expecting a response. + Returns the scamp selector - :param message: The message to send - :type message: - spinnman.messages.scp.abstract_messages.AbstractSCPRequest - :param SCAMPConnection connection: - The connection to use (omit to pick a random one) - :raise SpinnmanTimeoutException: - If there is a timeout before a message is received - :raise SpinnmanInvalidParameterException: - If one of the fields of the received message is invalid - :raise SpinnmanInvalidPacketException: - * If the message is not a recognised packet type - * If a packet is received that is not a valid response - :raise SpinnmanUnsupportedOperationException: - If no connection can send the type of message given - :raise SpinnmanIOException: - If there is an error sending the message or receiving the response - :raise SpinnmanUnexpectedResponseCodeException: - If the response is not one of the expected codes + :rtype: AbstractMultiConnectionProcessConnectionSelector """ - if connection is None: - connection = self.scamp_connections[random.randint( - 0, len(self.scamp_connections) - 1)] - connection.send_scp_request(message) + raise NotImplementedError def is_connected(self, connection=None): """ @@ -574,7 +565,8 @@ def free_sdram_by_app_id(self, x, y, app_id): logger.info(self.where_is_xy(x, y)) raise - def get_router_diagnostic_filter(self, x, y, position): + def get_router_diagnostic_filter( + self, x: int, y: int, position: int) -> DiagnosticFilter: """ Gets a router diagnostic filter from a router. @@ -605,15 +597,15 @@ def get_router_diagnostic_filter(self, x, y, position): ROUTER_REGISTER_BASE_ADDRESS + ROUTER_FILTER_CONTROLS_OFFSET + position * ROUTER_DIAGNOSTIC_FILTER_SIZE) - process = SendSingleCommandProcess( + process: SendSingleCommandProcess = SendSingleCommandProcess( self.scamp_connection_selector) response = process.execute( ReadMemory((x, y, 0), memory_position, 4)) - return DiagnosticFilter.read_from_int(self._ONE_WORD.unpack_from( + return DiagnosticFilter.read_from_int(_ONE_WORD.unpack_from( response.data, response.offset)[0]) # pylint: disable=no-member except Exception: - logger.info(self.where_is_xy(x, y)) + logger.info(self._where_is_xy(x, y)) raise @property @@ -664,7 +656,7 @@ def __set_watch_dog_on_chip(self, x, y, watch_dog): :param int x: chip X coordinate to write new watchdog parameter to :param int y: chip Y coordinate to write new watchdog parameter to :param watch_dog: - Either a boolean indicating whether to enable (True) or + Either a Boolean indicating whether to enable (True) or disable (False) the watchdog timer, or an int value to set the timer count to :type watch_dog: bool or int @@ -694,7 +686,7 @@ def set_watch_dog(self, watch_dog): Retained in case needed for hardware debugging. :param watch_dog: - Either a boolean indicating whether to enable (True) or + Either a Boolean indicating whether to enable (True) or disable (False) the watch dog timer, or an int value to set the timer count to. :type watch_dog: bool or int diff --git a/spinnman/extended/version3transceiver.py b/spinnman/extended/version3transceiver.py index c2b8e6603..872a7976a 100644 --- a/spinnman/extended/version3transceiver.py +++ b/spinnman/extended/version3transceiver.py @@ -11,9 +11,12 @@ # 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. -from .extended_transceiver import ExtendedTransceiver + from spinnman.transceiver.version3transceiver import Version3Transceiver +from .extended_transceiver import ExtendedTransceiver class ExtendedVersion3Transceiver(Version3Transceiver, ExtendedTransceiver): - pass + """ + A Transceiver specific for a 4 chip (spin 1) with the extended methods. + """ diff --git a/spinnman/extended/version5transceiver.py b/spinnman/extended/version5transceiver.py index 24e1a7718..a5969e51a 100644 --- a/spinnman/extended/version5transceiver.py +++ b/spinnman/extended/version5transceiver.py @@ -11,9 +11,12 @@ # 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. -from .extended_transceiver import ExtendedTransceiver + from spinnman.transceiver.version5transceiver import Version5Transceiver +from .extended_transceiver import ExtendedTransceiver class ExtendedVersion5Transceiver(Version5Transceiver, ExtendedTransceiver): - pass + """ + A Transceiver specific for a 48 chip (spin 1) with the extended methods. + """ diff --git a/spinnman/get_cores_in_run_state.py b/spinnman/get_cores_in_run_state.py index 5d3fbfd98..2c55a2c55 100644 --- a/spinnman/get_cores_in_run_state.py +++ b/spinnman/get_cores_in_run_state.py @@ -16,15 +16,16 @@ This is a script used to check the state of a SpiNNaker machine. """ -import sys import argparse +import sys + from spinn_utilities.config_holder import set_config -from spinnman.transceiver import create_transceiver_from_hostname from spinn_machine import CoreSubsets, CoreSubset + from spinnman.board_test_configuration import BoardTestConfiguration from spinnman.config_setup import unittest_setup from spinnman.model.enums import CPUState -from spinnman.transceiver import Transceiver +from spinnman.transceiver import create_transceiver_from_hostname, Transceiver SCAMP_ID = 0 IGNORED_IDS = {SCAMP_ID, 16} # WHY 16? @@ -47,7 +48,8 @@ def get_cores_in_run_state(txrx, app_id, print_all_chips): all_cores = [] for chip in machine.chips: - all_cores.append(CoreSubset(chip.x, chip.y, range(1, 17))) + all_cores.append(CoreSubset( + chip.x, chip.y, chip.placable_processors_ids)) all_cores = CoreSubsets(core_subsets=all_cores) @@ -77,8 +79,9 @@ def _make_transceiver(host, version, bmp_names) -> Transceiver: :param version: Board version to use (`None` defaults to 5 unless host is 192.168.240.253 (spin 3) :type version: int or None - :param bmp: bmp connection or `None` to auto detect (if applicable) - :type bmp: str or None + :param bmp_names: names of BMP connection + or `None` to auto detect (if applicable) + :type bmp_names: str or None :rtype: Transceiver """ if host is None: diff --git a/spinnman/messages/eieio/command_messages/eieio_command_header.py b/spinnman/messages/eieio/command_messages/eieio_command_header.py index 482a5a5cd..cb1c3c125 100644 --- a/spinnman/messages/eieio/command_messages/eieio_command_header.py +++ b/spinnman/messages/eieio/command_messages/eieio_command_header.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import cast, Union import struct from enum import Enum from spinnman.exceptions import SpinnmanInvalidParameterException @@ -25,21 +26,33 @@ class EIEIOCommandHeader(object): """ __slots__ = "_command", - def __init__(self, command): + def __init__(self, command: Union[int, Enum]): + """ + + :param command: + :type command: int or Enum + """ if isinstance(command, Enum): - command = command.value - if command < 0 or command >= 16384: + command_value = command.value + else: + command_value = cast(int, command) + if command_value < 0 or command_value >= 16384: raise SpinnmanInvalidParameterException( "command", command, "parameter command is outside the allowed range (0 to 16383)") - self._command = command + self._command = command_value @property - def command(self): + def command(self) -> int: + """ + The command/ value of the command passed into the init. + + :rtype: int + """ return self._command @staticmethod - def from_bytestring(data, offset): + def from_bytestring(data: bytes, offset: int) -> "EIEIOCommandHeader": """ Read an EIEIO command header from a byte-string. @@ -59,7 +72,7 @@ def from_bytestring(data, offset): return EIEIOCommandHeader(command) @property - def bytestring(self): + def bytestring(self) -> bytes: """ The byte-string of the header. diff --git a/spinnman/messages/eieio/command_messages/eieio_command_message.py b/spinnman/messages/eieio/command_messages/eieio_command_message.py index 906af845c..b3ccc48b4 100644 --- a/spinnman/messages/eieio/command_messages/eieio_command_message.py +++ b/spinnman/messages/eieio/command_messages/eieio_command_message.py @@ -11,8 +11,11 @@ # 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. + +from typing import Optional from spinn_utilities.overrides import overrides from spinnman.messages.eieio import AbstractEIEIOMessage +from spinnman.messages.eieio.command_messages import EIEIOCommandHeader class EIEIOCommandMessage(AbstractEIEIOMessage): @@ -24,7 +27,8 @@ class EIEIOCommandMessage(AbstractEIEIOMessage): "_eieio_command_header", "_offset") - def __init__(self, eieio_command_header, data=None, offset=0): + def __init__(self, eieio_command_header: EIEIOCommandHeader, + data: Optional[bytes] = None, offset: int = 0): """ :param EIEIOCommandHeader eieio_command_header: The header of the message @@ -40,31 +44,61 @@ def __init__(self, eieio_command_header, data=None, offset=0): @property @overrides(AbstractEIEIOMessage.eieio_header) - def eieio_header(self): + def eieio_header(self) -> EIEIOCommandHeader: """ + Gets the eieio_header passed into the init. + :rtype: EIEIOCommandHeader """ return self._eieio_command_header @property - def data(self): + def data(self) -> Optional[bytes]: + """ + Gets the data passed into the init (if applicable). + + :rtype: bytes or None + """ return self._data @property - def offset(self): + def offset(self) -> int: + """ + Gets the offset passed into the init + + :rtype: int + """ return self._offset @staticmethod - def from_bytestring(command_header, data, offset): + def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> "EIEIOCommandMessage": + """ + Creates an EIEIOCommandMessage based on the supplied information. + + :param EIEIOCommandHeader command_header: + :param bytes data: + :param int offset: + :rtype: EIEIOCommandMessage + """ return EIEIOCommandMessage(command_header, data, offset) @property - @overrides(AbstractEIEIOMessage.bytestring) - def bytestring(self): + def bytestring(self) -> bytes: + """ + The eieio_command_header passed into the init as a byte string. + + :rtype: bytes + """ return self._eieio_command_header.bytestring @staticmethod - def get_min_packet_length(): + def get_min_packet_length() -> int: + """ + Gets the min packet length for this type. + + :rtype: int + """ return 2 def __str__(self): diff --git a/spinnman/messages/eieio/command_messages/host_data_read.py b/spinnman/messages/eieio/command_messages/host_data_read.py index 9f9016398..77d5ce7c0 100644 --- a/spinnman/messages/eieio/command_messages/host_data_read.py +++ b/spinnman/messages/eieio/command_messages/host_data_read.py @@ -13,11 +13,15 @@ # limitations under the License. import struct +from typing import List, Union + +from spinn_utilities.overrides import overrides from spinnman.exceptions import ( SpinnmanInvalidPacketException, SpinnmanInvalidParameterTypeException) +from spinnman.constants import EIEIO_COMMAND_IDS + from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader -from spinnman.constants import EIEIO_COMMAND_IDS _PATTERN_BB = struct.Struct(" int: + """ + Gets the n_requests passed into the init. + + :rtype: int + """ return self._header.n_requests @property - def sequence_no(self): + def sequence_no(self) -> int: + """ + Gets the sequence_no passed into the init. + + :rtype: int + """ return self._header.sequence_no - def channel(self, ack_id): + def channel(self, ack_id: int) -> int: + """ + Gets the channel value for this ack_id. + + :param int ack_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + If the ack_id is invalid + """ return self._acks.channel(ack_id) - def region_id(self, ack_id): + def region_id(self, ack_id: int) -> int: + """ + Gets the region_id value for this ack_id. + + :param int ack_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + If the ack_id is invalid + """ return self._acks.region_id(ack_id) - def space_read(self, ack_id): + def space_read(self, ack_id: int) -> int: + """ + Gets the space_read value for this ack_id. + + :param int ack_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + If the ack_id is invalid + """ return self._acks.space_read(ack_id) @staticmethod - def get_min_packet_length(): + @overrides(EIEIOCommandMessage.get_min_packet_length) + def get_min_packet_length() -> int: return 8 @staticmethod - def from_bytestring(command_header, data, offset): # @UnusedVariable + @overrides(EIEIOCommandMessage.from_bytestring) + def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> "HostDataRead": n_requests, sequence_no = _PATTERN_BB.unpack_from(data, offset) offset += 2 @@ -101,7 +155,8 @@ def from_bytestring(command_header, data, offset): # @UnusedVariable n_requests, sequence_no, channel, region_id, space_read) @property - def bytestring(self): + @overrides(EIEIOCommandMessage.bytestring) + def bytestring(self) -> bytes: byte_string = super().bytestring n_requests = self.n_requests byte_string += _PATTERN_BB.pack(n_requests, self.sequence_no) @@ -120,16 +175,31 @@ class _HostDataReadHeader(object): "_n_requests", "_sequence_no"] - def __init__(self, n_requests, sequence_no): + def __init__(self, n_requests: int, sequence_no: int): + """ + + :param int n_requests: + :param int sequence_no: + """ self._n_requests = n_requests self._sequence_no = sequence_no @property - def sequence_no(self): + def sequence_no(self) -> int: + """ + Gets the sequence_no passed into the init. + + :rtype: int + """ return self._sequence_no @property - def n_requests(self): + def n_requests(self) -> int: + """ + Gets the n_requests passed into the init. + + :rtype: int + """ return self._n_requests @@ -142,7 +212,18 @@ class _HostDataReadAck(object): "_region_id", "_space_read"] - def __init__(self, channel, region_id, space_read): + def __init__(self, channel: Union[List[int], int], + region_id: Union[List[int], int], + space_read: Union[List[int], int]): + """ + + :param channel: + :type channel: list(int) or int + :param region_id: + :type region_id: list(int) or int + :param space_read: + :type space_read: list(int) or int + """ if not isinstance(channel, list): self._channel = [channel] else: @@ -158,26 +239,50 @@ def __init__(self, channel, region_id, space_read): else: self._space_read = space_read - def channel(self, ack_id): + def channel(self, ack_id: int) -> int: + """ + Gets the channel value for this ack_id. + + :param int ack_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + If the ack_id is invalid + """ if len(self._channel) > ack_id: return self._channel[ack_id] raise SpinnmanInvalidParameterTypeException( - "request_id", "integer", "channel ack_id needs to be" - "comprised between 0 and {0:d}; current value: {1:d}".format( - len(self._channel) - 1, ack_id)) + "request_id", "integer", + f"channel ack_id needs to be comprised between 0 and " + f"{len(self._channel) - 1:d}; current value: {ack_id:d}") - def region_id(self, ack_id): + def region_id(self, ack_id: int) -> int: + """ + Gets the region_id value for this ack_id. + + :param int ack_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + If the ack_id is invalid + """ if len(self._region_id) > ack_id: return self._region_id[ack_id] raise SpinnmanInvalidParameterTypeException( - "request_id", "integer", "region ID ack_id needs to be" - "comprised between 0 and {0:d}; current value: {1:d}".format( - len(self._region_id) - 1, ack_id)) + "request_id", "integer", + f"region ID ack_id needs to be comprised between 0 and " + f"{len(self._region_id) - 1:d}; current value: {ack_id:d}") + + def space_read(self, ack_id: int) -> int: + """ + Gets the space_read value for this ack_id. - def space_read(self, ack_id): + :param int ack_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + If the ack_id is invalid + """ if len(self._space_read) > ack_id: return self._space_read[ack_id] raise SpinnmanInvalidParameterTypeException( - "request_id", "integer", "start address ack_id needs to be" - "comprised between 0 and {0:d}; current value: {1:d}".format( - len(self._space_read) - 1, ack_id)) + "request_id", "integer", + f"start address ack_id needs to be comprised between 0 and " + f"{len(self._space_read) - 1:d}; current value: {ack_id:d}") diff --git a/spinnman/messages/eieio/command_messages/host_data_read_ack.py b/spinnman/messages/eieio/command_messages/host_data_read_ack.py index 73817aa9f..b79f1e00c 100644 --- a/spinnman/messages/eieio/command_messages/host_data_read_ack.py +++ b/spinnman/messages/eieio/command_messages/host_data_read_ack.py @@ -12,10 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. + import struct +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 -from spinnman.constants import EIEIO_COMMAND_IDS _PATTERN_B = struct.Struct(" int: + """ + Gets the sequence_no passed into the init. + + :rtype: int + """ return self._sequence_no @staticmethod - def from_bytestring(command_header, data, offset): # @UnusedVariable + @overrides(EIEIOCommandMessage.from_bytestring) + def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> "HostDataReadAck": sequence_no = _PATTERN_B.unpack_from(data, offset)[0] return HostDataReadAck(sequence_no) @property - def bytestring(self): + @overrides(EIEIOCommandMessage.bytestring) + def bytestring(self) -> bytes: byte_string = super().bytestring byte_string += _PATTERN_B.pack(self.sequence_no) return byte_string diff --git a/spinnman/messages/eieio/command_messages/host_send_sequenced_data.py b/spinnman/messages/eieio/command_messages/host_send_sequenced_data.py index 5c84ecc8b..f04f70755 100644 --- a/spinnman/messages/eieio/command_messages/host_send_sequenced_data.py +++ b/spinnman/messages/eieio/command_messages/host_send_sequenced_data.py @@ -13,11 +13,16 @@ # limitations under the License. import struct -from .eieio_command_message import EIEIOCommandMessage -from .eieio_command_header import EIEIOCommandHeader + +from spinn_utilities.overrides import overrides from spinnman.constants import EIEIO_COMMAND_IDS +from spinnman.messages.eieio import AbstractEIEIOMessage from spinnman.messages.eieio.create_eieio_data import read_eieio_data_message +from .eieio_command_message import EIEIOCommandMessage +from .eieio_command_header import EIEIOCommandHeader + + _PATTERN_BB = struct.Struct(" int: + """ + The region_id passed into the init. + + :rtype: int + """ return self._region_id @property - def sequence_no(self): + def sequence_no(self) -> int: + """ + The sequence_no passed into the init. + + :rtype: int + """ return self._sequence_no @property - def eieio_data_message(self): + def eieio_data_message(self) -> AbstractEIEIOMessage: + """ + The eieio_data_message passed into the init. + + :return: AbstractEIEIOMessage + """ return self._eieio_data_message @staticmethod - def get_min_packet_length(): + @overrides(EIEIOCommandMessage.get_min_packet_length) + def get_min_packet_length() -> int: return 4 @staticmethod - def from_bytestring(command_header, data, offset): # @UnusedVariable + @overrides(EIEIOCommandMessage.from_bytestring) + def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> "HostSendSequencedData": region_id, sequence_no = _PATTERN_BB.unpack_from(data, offset) eieio_data_message = read_eieio_data_message(data, offset) return HostSendSequencedData( region_id, sequence_no, eieio_data_message) @property - def bytestring(self): + @overrides(EIEIOCommandMessage.bytestring) + def bytestring(self) -> bytes: return (super().bytestring + _PATTERN_BB.pack(self._region_id, self._sequence_no) + self._eieio_data_message.bytestring) 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 1c8dcefe1..8e576d585 100644 --- a/spinnman/messages/eieio/command_messages/notification_protocol_db_location.py +++ b/spinnman/messages/eieio/command_messages/notification_protocol_db_location.py @@ -12,9 +12,10 @@ # See the License for the specific language governing permissions and # 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 -from spinnman.constants import EIEIO_COMMAND_IDS class NotificationProtocolDatabaseLocation(EIEIOCommandMessage): @@ -40,7 +41,14 @@ def __init__(self, database_path=None): self._database_path = database_path.encode() @property - def database_path(self): + def database_path(self) -> Optional[str]: + """ + Gets the database path passed into the init. + + The path is encoded by the init and decode back to a str here. + + :rtype: str + """ if self._database_path is not None: return self._database_path.decode() else: 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 50a37c3c6..8f77c6738 100644 --- a/spinnman/messages/eieio/command_messages/notification_protocol_pause_stop.py +++ b/spinnman/messages/eieio/command_messages/notification_protocol_pause_stop.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from spinnman.constants import EIEIO_COMMAND_IDS from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader -from spinnman.constants import EIEIO_COMMAND_IDS class NotificationProtocolPauseStop(EIEIOCommandMessage): 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 d14105aad..9a036da97 100644 --- a/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py +++ b/spinnman/messages/eieio/command_messages/notification_protocol_start_resume.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from spinnman.constants import EIEIO_COMMAND_IDS from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader -from spinnman.constants import EIEIO_COMMAND_IDS class NotificationProtocolStartResume(EIEIOCommandMessage): diff --git a/spinnman/messages/eieio/command_messages/spinnaker_request_buffers.py b/spinnman/messages/eieio/command_messages/spinnaker_request_buffers.py index 662d801a2..e647cdd30 100644 --- a/spinnman/messages/eieio/command_messages/spinnaker_request_buffers.py +++ b/spinnman/messages/eieio/command_messages/spinnaker_request_buffers.py @@ -13,9 +13,10 @@ # limitations under the License. import struct +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 -from spinnman.constants import EIEIO_COMMAND_IDS _PATTERN_BBBxBBI = struct.Struct(" int: + """ + Gets the x value passed into the init + + :rtype: int + """ return self._x @property - def y(self): + def y(self) -> int: + """ + Gets the y value passed into the init + + :rtype: int + """ return self._y @property - def p(self): + def p(self) -> int: + """ + Gets the p value passed into the init + + :rtype: int + """ return self._p @property - def region_id(self): + def region_id(self) -> int: + """ + Gets the region_id value passed into the init + + :rtype: int + """ return self._region_id @property - def sequence_no(self): + def sequence_no(self) -> int: + """ + Gets the sequence_no value passed into the init + + :rtype: int + """ return self._sequence_no @property - def space_available(self): + def space_available(self) -> int: + """ + Gets the space_available value passed into the init + + :rtype: int + """ return self._space_available @staticmethod - def get_min_packet_length(): + @overrides(EIEIOCommandMessage.get_min_packet_length) + def get_min_packet_length() -> int: return 12 @staticmethod - def from_bytestring(command_header, data, offset): # @UnusedVariable + @overrides(EIEIOCommandMessage.from_bytestring) + def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> "SpinnakerRequestBuffers": y, x, processor, region_id, sequence_no, space = \ _PATTERN_BBBxBBI.unpack_from(data, offset) p = (processor >> 3) & 0x1F @@ -80,7 +125,8 @@ def from_bytestring(command_header, data, offset): # @UnusedVariable x, y, p, region_id & 0xF, sequence_no, space) @property - def bytestring(self): + @overrides(EIEIOCommandMessage.bytestring) + def bytestring(self) -> bytes: return (super().bytestring + _PATTERN_BBBxBBI.pack( self._y, self._x, self._p << 3, self._region_id, self._sequence_no, self._space_available)) 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 374ae2a8f..96fb1b9b0 100644 --- a/spinnman/messages/eieio/command_messages/spinnaker_request_read_data.py +++ b/spinnman/messages/eieio/command_messages/spinnaker_request_read_data.py @@ -12,12 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import List, Union import struct + +from spinn_utilities.overrides import overrides from spinnman.exceptions import ( SpinnmanInvalidPacketException, SpinnmanInvalidParameterTypeException) +from spinnman.constants import EIEIO_COMMAND_IDS + from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader -from spinnman.constants import EIEIO_COMMAND_IDS _PATTERN_BBBB = struct.Struct(" int: + """ + The x value passed into the init. + + :rtype: int + """ return self._header.x @property - def y(self): + def y(self) -> int: + """ + The y value passed into the init. + + :rtype: int + """ return self._header.y @property - def p(self): + def p(self) -> int: + """ + The p value passed into the init. + + :rtype: int + """ return self._header.p @property - def n_requests(self): + def n_requests(self) -> int: + """ + The n_requests value passed into the init. + + :rtype: int + """ return self._header.n_requests @property - def sequence_no(self): + def sequence_no(self) -> int: + """ + The sequence_no value passed into the init. + + :rtype: int + """ return self._header.sequence_no - def channel(self, request_id): + def channel(self, request_id: int) -> int: + """ + The channel for this request_id. + + :param int request_id: + :rtype: int + :raises IndexError: If the request_id is invalid + """ return self._requests.channel(request_id) - def region_id(self, request_id): + def region_id(self, request_id) -> int: + """ + The region_id for this request_id. + + :param int request_id: + :rtype: int + :raises IndexError: If the request_id is invalid + """ return self._requests.region_id(request_id) - def start_address(self, request_id): + def start_address(self, request_id) -> int: + """ + The start_address for this request_id. + + :param int request_id: + :rtype: int + :raises IndexError: If the request_id is invalid + """ return self._requests.start_address(request_id) - def space_to_be_read(self, request_id): + def space_to_be_read(self, request_id) -> int: + """ + The space_to_be_read for this request_id. + + :param int request_id: + :rtype: int + :raises IndexError: If the request_id is invalid + """ return self._requests.space_to_be_read(request_id) @staticmethod - def get_min_packet_length(): + @overrides(EIEIOCommandMessage.get_min_packet_length) + def get_min_packet_length() -> int: return 16 @staticmethod - def from_bytestring(command_header, data, offset): + @overrides(EIEIOCommandMessage.from_bytestring) + def from_bytestring(command_header: EIEIOCommandHeader, data: bytes, + offset: int) -> "SpinnakerRequestReadData": (y, x, processor_and_requests, sequence_no) = \ _PATTERN_BBBB.unpack_from(data, offset) p = (processor_and_requests >> 3) & 0x1F @@ -139,7 +218,8 @@ def from_bytestring(command_header, data, offset): start_address, space_to_be_read) @property - def bytestring(self): + @overrides(EIEIOCommandMessage.bytestring) + def bytestring(self) -> bytes: byte_string = super().bytestring byte_string += _PATTERN_BB.pack(self.x, self.y) n_requests = self.n_requests @@ -168,7 +248,16 @@ class _SpinnakerRequestReadDataHeader(object): "_sequence_no", "_p", "_x", "_y"] - def __init__(self, x, y, p, n_requests, sequence_no): + def __init__( + self, x: int, y: int, p: int, n_requests: int, sequence_no: int): + """ + + :param int x: + :param int y: + :param int p: + :param int n_requests: + :param int sequence_no: + """ # pylint: disable=too-many-arguments self._x = x self._y = y @@ -177,23 +266,48 @@ def __init__(self, x, y, p, n_requests, sequence_no): self._sequence_no = sequence_no @property - def x(self): + def x(self) -> int: + """ + The x value passed into the init. + + :rtype: int + """ return self._x @property - def y(self): + def y(self) -> int: + """ + The y value passed into the init. + + :rtype: int + """ return self._y @property - def p(self): + def p(self) -> int: + """ + The p value passed into the init. + + :rtype: int + """ return self._p @property - def sequence_no(self): + def sequence_no(self) -> int: + """ + The sequence_no value passed into the init. + + :rtype: int + """ return self._sequence_no @property - def n_requests(self): + def n_requests(self) -> int: + """ + The n_request value passed into the init. + + :rtype: int + """ return self._n_requests @@ -207,7 +321,21 @@ class _SpinnakerRequestReadDataRequest(object): "_start_address", "_space_to_be_read"] - def __init__(self, channel, region_id, start_address, space_to_be_read): + def __init__(self, channel: Union[List[int], int], + region_id: Union[List[int], int], + start_address: Union[List[int], int], + space_to_be_read: Union[List[int], int]): + """ + + :param channel: + :type channel: list(int) or int + :param region_id: + :type region_id: list(int) or int + :param start_address: + :type start_address: list(int) or int + :param space_to_be_read: + :type space_to_be_read: list(int) or int + """ if not isinstance(channel, list): self._channel = [channel] else: @@ -228,34 +356,67 @@ def __init__(self, channel, region_id, start_address, space_to_be_read): else: self._space_to_be_read = space_to_be_read - def channel(self, request_id): + def channel(self, request_id) -> int: + """ + Gets the channel for this request_id + + :param int request_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + if the request_id os too high + """ + if len(self._channel) > request_id: return self._channel[request_id] raise SpinnmanInvalidParameterTypeException( - "request_id", "integer", "channel request needs to be" - "comprised between 0 and {0:d}; current value: {1:d}".format( - len(self._channel) - 1, request_id)) - - def region_id(self, request_id): + "request_id", "integer", + 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: + """ + Gets the region_id for this request_id + + :param int request_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + if the request_id os too high + """ if len(self._region_id) > request_id: return self._region_id[request_id] raise SpinnmanInvalidParameterTypeException( - "request_id", "integer", "region ID request needs to be" - "comprised between 0 and {0:d}; current value: {1:d}".format( - len(self._region_id) - 1, request_id)) - - def start_address(self, request_id): + "request_id", "integer", + f"region ID request needs to be comprised between 0 and " + f"{len(self._region_id) - 1:d}; current value: {request_id:d}") + + def start_address(self, request_id: int) -> int: + """ + Gets the start address for this request_id + + :param int request_id: + :rtype: int + :raises SpinnmanInvalidParameterTypeException: + if the request_id os too high + """ if len(self._start_address) > request_id: return self._start_address[request_id] raise SpinnmanInvalidParameterTypeException( - "request_id", "integer", "start address request needs to be" - "comprised between 0 and {0:d}; current value: {1:d}".format( - len(self._start_address) - 1, request_id)) - - def space_to_be_read(self, request_id): + "request_id", "integer", + f"start address request needs to be comprised between 0 and " + f"{len(self._start_address) - 1:d}; current value: {request_id:d}") + + def space_to_be_read(self, request_id: int) -> int: + """ + Checks if there is enough space to request this id + + :rtype: bool + :raises SpinnmanInvalidParameterTypeException: + if the request_id os too high + """ if len(self._space_to_be_read) > request_id: return self._space_to_be_read[request_id] raise SpinnmanInvalidParameterTypeException( - "request_id", "integer", "space to be read request needs to be" - "comprised between 0 and {0:d}; current value: {1:d}".format( - len(self._space_to_be_read) - 1, request_id)) + "request_id", "integer", + f"space to be read request needs to be comprised between 0 and " + f"{len(self._space_to_be_read) - 1:d}; " + f"current value: {request_id:d}") diff --git a/spinnman/messages/eieio/command_messages/start_requests.py b/spinnman/messages/eieio/command_messages/start_requests.py index b301a0e6e..26340407e 100644 --- a/spinnman/messages/eieio/command_messages/start_requests.py +++ b/spinnman/messages/eieio/command_messages/start_requests.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from spinnman.constants import EIEIO_COMMAND_IDS from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader -from spinnman.constants import EIEIO_COMMAND_IDS class StartRequests(EIEIOCommandMessage): diff --git a/spinnman/messages/eieio/command_messages/stop_requests.py b/spinnman/messages/eieio/command_messages/stop_requests.py index 8a8fca967..e7726eccf 100644 --- a/spinnman/messages/eieio/command_messages/stop_requests.py +++ b/spinnman/messages/eieio/command_messages/stop_requests.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from spinnman.constants import EIEIO_COMMAND_IDS from .eieio_command_message import EIEIOCommandMessage from .eieio_command_header import EIEIOCommandHeader -from spinnman.constants import EIEIO_COMMAND_IDS class StopRequests(EIEIOCommandMessage): diff --git a/spinnman/messages/eieio/data_messages/eieio_data_header.py b/spinnman/messages/eieio/data_messages/eieio_data_header.py index ce2be76d2..ecded471c 100644 --- a/spinnman/messages/eieio/data_messages/eieio_data_header.py +++ b/spinnman/messages/eieio/data_messages/eieio_data_header.py @@ -13,6 +13,8 @@ # limitations under the License. import struct +from typing import Optional + from spinnman.messages.eieio import EIEIOType, EIEIOPrefix from spinnman.exceptions import SpinnmanInvalidPacketException @@ -28,6 +30,9 @@ class EIEIODataHeader(object): + """ + The header part of EIEIO data. + """ __slots__ = ( "_count", "_eieio_type", @@ -37,9 +42,11 @@ class EIEIODataHeader(object): "_prefix_type", "_tag") - def __init__(self, eieio_type, tag=0, prefix=None, - prefix_type=EIEIOPrefix.LOWER_HALF_WORD, - payload_base=None, is_time=False, count=0): + def __init__(self, eieio_type: EIEIOType, tag: int = 0, + prefix: Optional[int] = None, + prefix_type: EIEIOPrefix = EIEIOPrefix.LOWER_HALF_WORD, + payload_base: Optional[int] = None, is_time: bool = False, + count: int = 0): """ EIEIO header for data packets. @@ -67,39 +74,84 @@ def __init__(self, eieio_type, tag=0, prefix=None, self._count = count @property - def eieio_type(self): + def eieio_type(self) -> EIEIOType: + """ + Gets the eieio_type passed into the init. + + :rtype: EIEIOType + """ return self._eieio_type @property - def tag(self): + def tag(self) -> int: + """ + Gets the tag value passed into the init. + + :rtype: int + """ return self._tag @property - def prefix(self): + def prefix(self) -> Optional[int]: + """ + Gets prefix passed into the init (if applicable). + + :rtype: int or None + """ return self._prefix @property - def prefix_type(self): + def prefix_type(self) -> EIEIOPrefix: + """ + Gets the prefix_type passed into the init. + + :rtype: EIEIOPrefix + """ return self._prefix_type @property - def payload_base(self): + def payload_base(self) -> Optional[int]: + """ + Gets the payload_base value passed into the init (if applicable). + + :rtype: int or None + """ return self._payload_base @property def is_time(self) -> bool: + """ + Gets the is_time value passed into the init. + + :rtype: bool + """ return self._is_time @property def count(self) -> int: + """ + Count of the number of items in the packet + + :rtype: int + """ return self._count @count.setter - def count(self, count): + def count(self, count: int): + """ + Sets the Count of the number of items in the packet + + :param int count: the new value + """ self._count = count @property def size(self) -> int: + """ + Get the size of a header with the given parameters. + + :rtype: int + """ return EIEIODataHeader.get_header_size( self._eieio_type, self._prefix is not None, self._payload_base is not None) @@ -124,9 +176,15 @@ def get_header_size(eieio_type, is_prefix=False, is_payload_base=False): return size def increment_count(self) -> None: + """ + Increase the count by 1. + """ self._count += 1 def reset_count(self) -> None: + """ + Resets the count back to zero. + """ self._count = 0 @property @@ -240,11 +298,11 @@ def from_bytestring(data: bytes, offset: int) -> 'EIEIODataHeader': is_time=bool(payload_is_timestamp), count=count) def __str__(self): - return ("EIEIODataHeader:prefix={}:prefix_type={}:payload_base={}:" - "is_time={}:type={}:tag={}:count={}".format( - self._prefix, self._prefix_type, self._payload_base, - self._is_time, self._eieio_type.value, self._tag, - self._count)) + 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): 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 306b83b12..9da649a33 100644 --- a/spinnman/messages/eieio/data_messages/eieio_data_message.py +++ b/spinnman/messages/eieio/data_messages/eieio_data_message.py @@ -170,14 +170,12 @@ def add_key_and_payload(self, key: int, payload: int): """ if key > self._header.eieio_type.max_value: raise SpinnmanInvalidParameterException( - "key", key, - "Larger than the maximum allowed of {}".format( - self._header.eieio_type.max_value)) + "key", key, "Larger than the maximum allowed of " + f"{self._header.eieio_type.max_value}") if payload > self._header.eieio_type.max_value: raise SpinnmanInvalidParameterException( - "payload", payload, - "Larger than the maximum allowed of {}".format( - self._header.eieio_type.max_value)) + "payload", payload, "Larger than the maximum allowed of " + f"{self._header.eieio_type.max_value}") self.add_element(KeyPayloadDataElement( key, payload, self._header.is_time)) @@ -193,9 +191,8 @@ def add_key(self, key: int): """ if key > self._header.eieio_type.max_value: raise SpinnmanInvalidParameterException( - "key", key, - "Larger than the maximum allowed of {}".format( - self._header.eieio_type.max_value)) + "key", key, "Larger than the maximum allowed of " + f"{self._header.eieio_type.max_value}") self.add_element(KeyDataElement(key)) def add_element(self, element: AbstractDataElement): diff --git a/spinnman/messages/eieio/data_messages/key_data_element.py b/spinnman/messages/eieio/data_messages/key_data_element.py index 9122264df..8ba2c6237 100644 --- a/spinnman/messages/eieio/data_messages/key_data_element.py +++ b/spinnman/messages/eieio/data_messages/key_data_element.py @@ -33,6 +33,11 @@ def __init__(self, key: int): @property def key(self) -> int: + """ + The key value passed into the init. + + :rtype: int + """ return self._key @overrides(AbstractDataElement.get_bytestring) 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 9831e7232..252cce6a7 100644 --- a/spinnman/messages/eieio/data_messages/key_payload_data_element.py +++ b/spinnman/messages/eieio/data_messages/key_payload_data_element.py @@ -31,21 +31,37 @@ class KeyPayloadDataElement(AbstractDataElement): "_payload", "_payload_is_timestamp") - def __init__(self, key: int, payload: int, payload_is_timestamp=False): + def __init__( + self, key: int, payload: int, payload_is_timestamp: bool = False): self._key = key self._payload = payload self._payload_is_timestamp = payload_is_timestamp @property def key(self) -> int: + """ + The key value passed into the init. + + :rtype: int + """ return self._key @property def payload(self) -> int: + """ + Gets the payload value passed into the init. + + :rtype: int + """ return self._payload @property def payload_is_timestamp(self) -> bool: + """ + Gets the payload_is_timestamp passed into the init. + + :rtype: int + """ return self._payload_is_timestamp @overrides(AbstractDataElement.get_bytestring) diff --git a/spinnman/messages/eieio/eieio_type.py b/spinnman/messages/eieio/eieio_type.py index 51b30068c..955357a49 100644 --- a/spinnman/messages/eieio/eieio_type.py +++ b/spinnman/messages/eieio/eieio_type.py @@ -35,7 +35,7 @@ def __new__(cls, *args) -> 'EIEIOType': return obj def __init__(self, encoded_value: int, - # Optionals just to make mypy SHUT UP! + # Default values just to make mypy SHUT UP! # https://github.com/python/mypy/issues/10573 key_bytes: int = 0, payload_bytes: int = 0): self._encoded_value = encoded_value diff --git a/spinnman/messages/scp/abstract_messages/bmp_request.py b/spinnman/messages/scp/abstract_messages/bmp_request.py index 0594a971e..5b001bce3 100644 --- a/spinnman/messages/scp/abstract_messages/bmp_request.py +++ b/spinnman/messages/scp/abstract_messages/bmp_request.py @@ -11,12 +11,16 @@ # 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. + from typing import Generic, Iterable, Optional, TypeVar, Union from typing_extensions import TypeAlias -from .scp_request import AbstractSCPRequest + from spinnman.messages.sdp import SDPFlag, SDPHeader from spinnman.messages.scp import SCPRequestHeader + from .bmp_response import BMPResponse +from .scp_request import AbstractSCPRequest + #: The type of boards parameters. Boards: TypeAlias = Union[int, Iterable[int]] R = TypeVar("R", bound=BMPResponse) diff --git a/spinnman/messages/scp/enums/scp_command.py b/spinnman/messages/scp/enums/scp_command.py index 33c51e93a..94f532e46 100644 --- a/spinnman/messages/scp/enums/scp_command.py +++ b/spinnman/messages/scp/enums/scp_command.py @@ -59,7 +59,7 @@ class SCPCommand(Enum): CMD_DPRI = 30 #: Get Chip Summary Information. CMD_INFO = 31 - #: Control sending of synchronization messages. + #: Control sending of synchronisation messages. CMD_SYNC = 32 # ======== BMP ======== diff --git a/spinnman/messages/scp/enums/scp_result.py b/spinnman/messages/scp/enums/scp_result.py index 37b367f5b..af233ac4a 100644 --- a/spinnman/messages/scp/enums/scp_result.py +++ b/spinnman/messages/scp/enums/scp_result.py @@ -37,7 +37,7 @@ class SCPResult(Enum): RC_ROUTE = 0x87 #: Bad CPU number. RC_CPU = 0x88 - #: SHM destination dead. + #: destination dead. RC_DEAD = 0x89 #: No free Shared Memory buffers. RC_BUF = 0x8a diff --git a/spinnman/messages/scp/enums/signal.py b/spinnman/messages/scp/enums/signal.py index c4be8198d..cd5a6f7e9 100644 --- a/spinnman/messages/scp/enums/signal.py +++ b/spinnman/messages/scp/enums/signal.py @@ -58,4 +58,9 @@ def __init__(self, value: int, signal_type: SignalType) -> None: @property def signal_type(self) -> SignalType: + """ + The "type" of the signal + + :rtype: SignalType + """ return self._signal_type diff --git a/spinnman/messages/scp/impl/check_ok_response.py b/spinnman/messages/scp/impl/check_ok_response.py index 662ea9d9b..4f4a140b0 100644 --- a/spinnman/messages/scp/impl/check_ok_response.py +++ b/spinnman/messages/scp/impl/check_ok_response.py @@ -37,7 +37,7 @@ def __init__(self, operation: str, command): self._command = command @overrides(AbstractSCPResponse.read_data_bytestring) - def read_data_bytestring(self, data: bytes, offset: int) -> None: + def read_data_bytestring(self, data: bytes, offset: int): result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( diff --git a/spinnman/messages/scp/impl/do_sync.py b/spinnman/messages/scp/impl/do_sync.py index ccf074150..475a2ee9a 100644 --- a/spinnman/messages/scp/impl/do_sync.py +++ b/spinnman/messages/scp/impl/do_sync.py @@ -22,13 +22,13 @@ class DoSync(AbstractSCPRequest[CheckOKResponse]): """ - An SCP Request to control synchronization. + An SCP Request to control synchronisation. """ __slots__ = () def __init__(self, do_sync: bool): """ - :param bool do_sync: Whether to synchronize or not + :param bool do_sync: Whether to synchronise or not """ super().__init__( SDPHeader( diff --git a/spinnman/messages/scp/impl/fixed_route_init.py b/spinnman/messages/scp/impl/fixed_route_init.py index 924e9795a..9b20d81ec 100644 --- a/spinnman/messages/scp/impl/fixed_route_init.py +++ b/spinnman/messages/scp/impl/fixed_route_init.py @@ -13,12 +13,14 @@ # limitations under the License. from spinn_utilities.overrides import overrides + from spinnman.messages.scp import SCPRequestHeader from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.messages.scp.enums import SCPCommand -from .check_ok_response import CheckOKResponse from spinnman.messages.sdp import SDPHeader, SDPFlag +from .check_ok_response import CheckOKResponse + class FixedRouteInit(AbstractSCPRequest[CheckOKResponse]): """ diff --git a/spinnman/messages/scp/impl/fixed_route_read.py b/spinnman/messages/scp/impl/fixed_route_read.py index 4c3a5ae1b..8ddfa7a5c 100644 --- a/spinnman/messages/scp/impl/fixed_route_read.py +++ b/spinnman/messages/scp/impl/fixed_route_read.py @@ -49,6 +49,11 @@ def read_data_bytestring(self, data: bytes, offset: int): @property def route(self) -> FixedRouteEntry: + """ + Converts this response into a Route + + :rtype: FixedRouteEntry + """ processor_ids: List[int] = list() for processor_id in range(26): if self._route & (1 << (6 + processor_id)) != 0: diff --git a/spinnman/messages/scp/impl/iptag_get.py b/spinnman/messages/scp/impl/iptag_get.py index 085d8ff6a..d6903982b 100644 --- a/spinnman/messages/scp/impl/iptag_get.py +++ b/spinnman/messages/scp/impl/iptag_get.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import struct + from spinn_utilities.overrides import overrides from spinnman.messages.scp import SCPRequestHeader from spinnman.messages.scp.abstract_messages import ( @@ -20,8 +22,6 @@ from spinnman.messages.sdp import SDPFlag, SDPHeader from spinnman.exceptions import SpinnmanUnexpectedResponseCodeException -import struct - _IPTAG_GET = 2 diff --git a/spinnman/messages/scp/impl/router_alloc.py b/spinnman/messages/scp/impl/router_alloc.py index 9804465b5..26289308d 100644 --- a/spinnman/messages/scp/impl/router_alloc.py +++ b/spinnman/messages/scp/impl/router_alloc.py @@ -78,7 +78,7 @@ def __init__(self, x: int, y: int, app_id: int, n_entries: int): SCPRequestHeader(command=SCPCommand.CMD_ALLOC), argument_1=( (app_id << 8) | - AllocFree.ALLOC_ROUTING.value), # @UndefinedVariable + AllocFree.ALLOC_ROUTING.value), argument_2=n_entries) @overrides(AbstractSCPRequest.get_scp_response) diff --git a/spinnman/messages/scp/impl/router_init.py b/spinnman/messages/scp/impl/router_init.py index ed7787699..e968eb0b7 100644 --- a/spinnman/messages/scp/impl/router_init.py +++ b/spinnman/messages/scp/impl/router_init.py @@ -23,7 +23,7 @@ class RouterInit(AbstractSCPRequest[CheckOKResponse]): """ - A request to initialize the router on a chip. + A request to initialise the router on a chip. """ __slots__ = () diff --git a/spinnman/messages/scp/impl/sdram_alloc.py b/spinnman/messages/scp/impl/sdram_alloc.py index 30821d2f5..025908f28 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, offset): + def read_data_bytestring(self, data: bytes, offset: int): result = self.scp_response_header.result if result != SCPResult.RC_OK: raise SpinnmanUnexpectedResponseCodeException( @@ -112,7 +112,7 @@ def __init__(self, x: int, y: int, app_id: int, size: int, argument_1=( (extra_flag << 16) | (app_id << 8) | - AllocFree.ALLOC_SDRAM.value), # @UndefinedVariable + AllocFree.ALLOC_SDRAM.value), argument_2=size, argument_3=tag) self._size = size diff --git a/spinnman/messages/scp/impl/sdram_de_alloc.py b/spinnman/messages/scp/impl/sdram_de_alloc.py index ef8300d37..919dc7e38 100644 --- a/spinnman/messages/scp/impl/sdram_de_alloc.py +++ b/spinnman/messages/scp/impl/sdram_de_alloc.py @@ -107,7 +107,7 @@ def __init__(self, x: int, y: int, *, app_id: Optional[int] = None, SCPRequestHeader(command=SCPCommand.CMD_ALLOC), argument_1=( AllocFree. - FREE_SDRAM_BY_POINTER.value), # @UndefinedVariable + FREE_SDRAM_BY_POINTER.value), argument_2=base_address) self._read_n_blocks_freed = False else: @@ -121,7 +121,7 @@ def __init__(self, x: int, y: int, *, app_id: Optional[int] = None, argument_1=( app_id << 8 | AllocFree. - FREE_SDRAM_BY_APP_ID.value)) # @UndefinedVariable + FREE_SDRAM_BY_APP_ID.value)) self._read_n_blocks_freed = True @overrides(AbstractSCPRequest.get_scp_response) diff --git a/spinnman/messages/sdp/sdp_header.py b/spinnman/messages/sdp/sdp_header.py index 01d9b0a05..98523a341 100644 --- a/spinnman/messages/sdp/sdp_header.py +++ b/spinnman/messages/sdp/sdp_header.py @@ -14,8 +14,8 @@ import struct from typing import Optional -from .sdp_flag import SDPFlag from spinnman.data import SpiNNManDataView +from .sdp_flag import SDPFlag N_BYTES = 8 _EIGHT_BYTES = struct.Struct("<8B") @@ -325,6 +325,11 @@ def from_bytestring(data: bytes, offset: int): source_chip_x, source_chip_y) def get_physical_cpu_id(self) -> str: + """ + A String describing the physical core of the destination. + + :rtype: str + """ if SpiNNManDataView.has_machine(): chip = SpiNNManDataView.get_machine().get_chip_at( self._destination_chip_x, self._destination_chip_y) diff --git a/spinnman/messages/spinnaker_boot/spinnaker_boot_messages.py b/spinnman/messages/spinnaker_boot/spinnaker_boot_messages.py index 986c405dc..ef88be73a 100644 --- a/spinnman/messages/spinnaker_boot/spinnaker_boot_messages.py +++ b/spinnman/messages/spinnaker_boot/spinnaker_boot_messages.py @@ -12,17 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os +import array import math +import os import time from typing import Any, Dict, Iterable, Optional, Tuple -import array + from spinnman.data import SpiNNManDataView +from spinnman.exceptions import SpinnmanIOException + from .system_variable_boot_values import ( SystemVariableBootValues, SystemVariableDefinition) from .spinnaker_boot_message import SpinnakerBootMessage from .spinnaker_boot_op_code import SpinnakerBootOpCode -from spinnman.exceptions import SpinnmanIOException _BOOT_MESSAGE_DATA_WORDS = 256 _BOOT_MESSAGE_DATA_BYTES = _BOOT_MESSAGE_DATA_WORDS * 4 diff --git a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py index 04bd528ae..aca5c767a 100644 --- a/spinnman/messages/spinnaker_boot/system_variable_boot_values.py +++ b/spinnman/messages/spinnaker_boot/system_variable_boot_values.py @@ -13,7 +13,7 @@ # limitations under the License. import struct -from typing import NamedTuple, Union, Optional +from typing import Any, NamedTuple, Union, Optional from enum import Enum _SYSTEM_VARIABLES_BOOT_SIZE = 128 @@ -35,10 +35,20 @@ def __init__(self, value, struct_code): @property def struct_code(self) -> str: + """ + Gets the struct_code value passed into the init + + :rtype: str + """ return self._struct_code @property def is_byte_array(self) -> bool: + """ + Detects if enum is a BYTE_ARRAY without exposing the Class + + :rtype: bool + """ # can't use BYTE_ARRAY.value directly here return self._value_ == 16 @@ -58,7 +68,7 @@ class SystemVariableDefinition(Enum): """ Defines the system variables available. """ - + # pylint: disable=invalid-name y = _Definition( _DataType.BYTE, offset=0, doc="The y-coordinate of the chip") x = _Definition( @@ -331,18 +341,38 @@ def __init__( @property def data_type(self) -> _DataType: + """ + Gets the data_type passed into the init. + + :rtype: _DataType + """ return self._data_type @property def array_size(self) -> Optional[int]: + """ + Gets the array size passed into the init (if applicable) + + :rtype: int or None + """ return self._array_size @property def offset(self) -> int: + """ + Gets the Offset passed into the init + + :rtype: int + """ return self._offset @property def default(self) -> Union[int, bytes]: + """ + Gets the default Value passed into the init + + :rtype: int or bytes + """ return self._default @@ -359,11 +389,25 @@ def __init__(self): for variable in SystemVariableDefinition: self._values[variable] = variable.default - def set_value(self, system_variable_definition, value): + def set_value(self, system_variable_definition: SystemVariableDefinition, + value: Any): + """ + Save a value to the system_variable_definition Enum as the key + + :param system_variable_definition: Key to save value with + :type system_variable_definition: SystemVariableDefinition + :param value: + :return: + """ self._values[system_variable_definition] = value @property - def bytestring(self): + def bytestring(self) -> bytes: + """ + Gets all the SystemVariableDefinition as bytes + + :rtype: bytes + """ data = b"" for sys_var in SystemVariableDefinition: data += struct.pack(sys_var.data_type.struct_code, diff --git a/spinnman/model/chip_info.py b/spinnman/model/chip_info.py index dbd406e07..94a885245 100644 --- a/spinnman/model/chip_info.py +++ b/spinnman/model/chip_info.py @@ -61,10 +61,7 @@ def __init__(self, system_data: bytes, offset: int): "virtual_to_physical_core_map") self._virtual_core_ids: List[int] = list() - for physical_core_id in range( - 0, len(self._physical_to_virtual_core_map)): - virtual_core_id = self._physical_to_virtual_core_map[ - physical_core_id] + for virtual_core_id in self._physical_to_virtual_core_map: if virtual_core_id != 0xFF: self._virtual_core_ids.append(virtual_core_id) self._virtual_core_ids.sort() diff --git a/spinnman/model/chip_summary_info.py b/spinnman/model/chip_summary_info.py index e7e7e29c9..c7182996b 100644 --- a/spinnman/model/chip_summary_info.py +++ b/spinnman/model/chip_summary_info.py @@ -14,8 +14,8 @@ import struct from typing import List, Optional -from spinnman.model.enums import CPUState from spinn_machine.machine import Machine +from spinnman.model.enums import CPUState _THREE_WORDS = struct.Struct("<3I") _TWO_BYTES = struct.Struct(" int: return self.__software_version def __str__(self) -> str: - return "{}:{}:{:02n} ({:02n}) {:18} {:16s} {:3n}".format( - self.x, self.y, self.p, self.physical_cpu_id, self.__state.name, - self.__application_name, self.__application_id) + return (f"{self.x}:{self.y}:{self.p:02n} ({self.physical_cpu_id:02n}) " + f"{self.__state.name:18} {self.__application_name:16s} " + f"{self.__application_id:3n}") def get_status_string(self) -> str: """ diff --git a/spinnman/model/cpu_infos.py b/spinnman/model/cpu_infos.py index d230cb4fb..730ddf506 100644 --- a/spinnman/model/cpu_infos.py +++ b/spinnman/model/cpu_infos.py @@ -11,11 +11,11 @@ # 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. + from typing import Dict, Iterable, Iterator from spinn_utilities.typing.coords import XYP -from .cpu_info import CPUInfo - from spinnman.model.enums import CPUState +from .cpu_info import CPUInfo class CPUInfos(object): diff --git a/spinnman/model/diagnostic_filter.py b/spinnman/model/diagnostic_filter.py index 7069f54ae..7730798cd 100644 --- a/spinnman/model/diagnostic_filter.py +++ b/spinnman/model/diagnostic_filter.py @@ -129,36 +129,78 @@ def __init__(self, enable_interrupt_on_counter_event: bool, @property def enable_interrupt_on_counter_event(self) -> bool: + """ + Returns the enable interrupt on counter event passed into + the init unchanged + + Currently unused + """ return self._enable_interrupt_on_counter_event @property def match_emergency_routing_status_to_incoming_packet(self) -> bool: + """ + Returns the match emergency routing status to incoming packet passed + into the init unchanged + + Currently unused + """ return self._match_emergency_routing_status_to_incoming_packet @property def destinations(self) -> List[DiagnosticFilterDestination]: + """ + Returns the destinations passed into the init unchanged + + Currently unused + """ return self._destinations @property def sources(self) -> List[DiagnosticFilterSource]: + """ + Returns the sources passed into the init unchanged + + Currently unused + """ return self._sources @property def payload_statuses(self) -> List[DiagnosticFilterPayloadStatus]: + """ + Returns the payload statuses passed into the init unchanged + + Currently unused + """ return self._payload_statuses @property def default_routing_statuses(self) -> List[ DiagnosticFilterDefaultRoutingStatus]: + """ + Returns the default routing statuses passed into the init unchanged + + Currently unused + """ return self._default_routing_statuses @property def emergency_routing_statuses(self) -> List[ DiagnosticFilterEmergencyRoutingStatus]: + """ + Returns the emergency routing statuses passed into the init unchanged + + Currently unused + """ return self._emergency_routing_statuses @property def packet_types(self) -> List[DiagnosticFilterPacketType]: + """ + Returns the packet types passed into the init unchanged + + Currently unused + """ return self._packet_types @property @@ -194,6 +236,14 @@ def filter_word(self) -> int: @staticmethod def read_from_int(int_value: int) -> DiagnosticFilter: + """ + Claims to returns a filter that reads an int + + Currently only called by unused Transceiver methods + + :param int int_value: + :rtype: DiagnosticFilter + """ enable_interrupt_on_counter_event = ( (int_value >> _ENABLE_INTERRUPT_OFFSET) & 0x1) == 1 match_emergency_routing_status_to_incoming_packet = ( diff --git a/spinnman/model/enums/run_time_error.py b/spinnman/model/enums/run_time_error.py index 37bc619a2..c60e13e4c 100644 --- a/spinnman/model/enums/run_time_error.py +++ b/spinnman/model/enums/run_time_error.py @@ -25,17 +25,17 @@ class RunTimeError(Enum): RESET = 1 #: Undefined instruction UNDEF = 2 - #: Undefined SVC or no handler + #: Undefined Supervisor Call instruction or no handler SVC = 3 #: Prefetch abort PABT = 4 #: Data abort DABT = 5 - #: Unhandled IRQ + #: Unhandled interrupt request IRQ = 6 - #: Unhandled FIQ + #: Unhandled Fast interrupt request FIQ = 7 - #: Unconfigured VIC vector + #: Unconfigured Vectored Interrupt Controller VIC = 8 #: Generic user abort ABORT = 9 @@ -45,7 +45,7 @@ class RunTimeError(Enum): DIVBY0 = 11 #: Event startup failure EVENT = 12 - #: Fatal SW error + #: Fatal Software error SWERR = 13 #: Failed to allocate IO buffer IOBUF = 14 @@ -53,11 +53,11 @@ class RunTimeError(Enum): ENABLE = 15 #: Generic null pointer error NULL = 16 - #: Pkt startup failure + #: Packet startup failure PKT = 17 #: Timer startup failure TIMER = 18 #: API startup failure API = 19 - #: SW version conflict + #: Sark software version conflict SARK_VERSRION_INCORRECT = 20 diff --git a/spinnman/model/enums/sdp_ports.py b/spinnman/model/enums/sdp_ports.py index 078501dd7..d954d8287 100644 --- a/spinnman/model/enums/sdp_ports.py +++ b/spinnman/model/enums/sdp_ports.py @@ -15,6 +15,7 @@ from enum import Enum +# pylint: disable=invalid-name class SDP_PORTS(Enum): """ SDP port handling output buffering data streaming. diff --git a/spinnman/model/enums/sdp_running_message_codes.py b/spinnman/model/enums/sdp_running_message_codes.py index 708381d9a..8e16abe92 100644 --- a/spinnman/model/enums/sdp_running_message_codes.py +++ b/spinnman/model/enums/sdp_running_message_codes.py @@ -15,6 +15,7 @@ from enum import Enum +# pylint: disable=invalid-name class SDP_RUNNING_MESSAGE_CODES(Enum): """ Codes for sending control messages to spin1_api. diff --git a/spinnman/model/heap_element.py b/spinnman/model/heap_element.py index 80cdbf90b..aa41b7395 100644 --- a/spinnman/model/heap_element.py +++ b/spinnman/model/heap_element.py @@ -103,9 +103,8 @@ def app_id(self) -> Optional[int]: def __str__(self) -> str: if self._is_free: - return "FREE 0x{:8X} SIZE: {:9d}".format( - self._block_address, self.size) + return f"FREE 0x{self._block_address:8X} SIZE: {self.size:9d}" assert self._tag is not None assert self._app_id is not None - return "BLOCK 0x{:8X} SIZE: {:9d} TAG: {:3d} APP_ID: {:3d}".format( - self._block_address, self.size, self._tag, self._app_id) + return "BLOCK 0x{self._block_address:8X} SIZE: {self.size:9d} " \ + "TAG: {self._tag:3d} APP_ID: {self._app_id:3d}" diff --git a/spinnman/model/p2p_table.py b/spinnman/model/p2p_table.py index 32ae021a7..e40c04f75 100644 --- a/spinnman/model/p2p_table.py +++ b/spinnman/model/p2p_table.py @@ -38,11 +38,10 @@ def __init__(self, width: int, height: int, self._routes: Dict[Tuple[int, int], P2PTableRoute] = dict() self._width = width self._height = height - for x in range(len(column_data)): + for x, (data, offset) in enumerate(column_data): y = 0 pos = 0 while y < height: - data, offset = column_data[x] next_word, = _ONE_WORD.unpack_from(data, offset + (pos * 4)) pos += 1 for entry in range(min(8, height - y)): diff --git a/spinnman/model/version_info.py b/spinnman/model/version_info.py index 67feb5195..e0f10ac1e 100644 --- a/spinnman/model/version_info.py +++ b/spinnman/model/version_info.py @@ -146,6 +146,6 @@ def version_string(self) -> str: return self._version_string def __str__(self) -> str: - return "[Version: {} {} at {}:{}:{}:{} (built {})]".format( - self._name, self._version_string, self._hardware, self._x, self._y, - self._p, asctime(localtime(self._build_date))) + return (f"[Version: {self._name} {self._version_string} at " + f"{self._hardware}:{self._x}:{self._y}:{self._p} " + f"(built {asctime(localtime(self._build_date))})]") diff --git a/spinnman/processes/abstract_multi_connection_process.py b/spinnman/processes/abstract_multi_connection_process.py index 6c8715049..406c744f6 100644 --- a/spinnman/processes/abstract_multi_connection_process.py +++ b/spinnman/processes/abstract_multi_connection_process.py @@ -18,18 +18,23 @@ from types import TracebackType from typing import ( Callable, Dict, Generator, Generic, List, Optional, TypeVar, cast, Set) + from typing_extensions import Self, TypeAlias + from spinn_utilities.log import FormatAdapter + from spinnman.connections import SCPRequestPipeLine +from spinnman.connections.udp_packet_connections import SCAMPConnection from spinnman.constants import SCP_TIMEOUT, N_RETRIES from spinnman.exceptions import ( SpinnmanGenericProcessException, SpinnmanGroupedProcessException) -from .abstract_multi_connection_process_connection_selector import ( - ConnectionSelector) -from spinnman.connections.udp_packet_connections import SCAMPConnection from spinnman.messages.scp.abstract_messages import ( AbstractSCPRequest, AbstractSCPResponse) from spinnman.messages.scp.enums.scp_result import SCPResult + +from .abstract_multi_connection_process_connection_selector import ( + ConnectionSelector) + #: Type of responses. #: :meta private: R = TypeVar("R", bound=AbstractSCPResponse) @@ -119,6 +124,11 @@ def _receive_error( self._connections.append(connection) def is_error(self) -> bool: + """ + Checks if any errors have been cached. + + :rtype: bool + """ return bool(self._exceptions) def _finish(self) -> None: @@ -162,6 +172,14 @@ def connection_selector(self) -> ConnectionSelector: return self._conn_selector def check_for_error(self, print_exception: bool = False): + """ + Check if any errors have been cached and raises them + + if print_exception it also logs the error. + + :param bool print_exception: + :raises SpinnmanGenericProcessException: If any was found + """ if len(self._exceptions) == 1: exc_info = sys.exc_info() sdp_header = self._error_requests[0].sdp_header diff --git a/spinnman/processes/application_copy_run_process.py b/spinnman/processes/application_copy_run_process.py index ebc05fd56..33c80a538 100644 --- a/spinnman/processes/application_copy_run_process.py +++ b/spinnman/processes/application_copy_run_process.py @@ -54,7 +54,7 @@ def _get_next_chips( on_same_board = _on_same_board(chip, chip_xy) eth = (chip.nearest_ethernet_x, chip.nearest_ethernet_y) if (eth not in chips_done or - (chip.x, chip.y) not in chips_done[eth]): + chip not in chips_done[eth]): if on_same_board or not off_board_copy_done: next_chips.append(chip) if not on_same_board: @@ -119,7 +119,7 @@ def run(self, size: int, app_id: int, core_subsets: CoreSubsets, boot_chip = machine.boot_chip chips_done: Mapping[Tuple[int, int], List[Tuple[int, int]]] = \ defaultdict(list) - chips_done[boot_chip.x, boot_chip.y].append((boot_chip.x, boot_chip.y)) + chips_done[boot_chip].append((boot_chip)) parent_chips = _compute_parent_chips(machine) next_chips = _get_next_chips(chips_done, parent_chips, machine) @@ -131,7 +131,7 @@ def run(self, size: int, app_id: int, core_subsets: CoreSubsets, chip.x, chip.y, cast(int, chip.parent_link), size, app_id, subset.processor_ids, checksum, wait)) eth = (chip.nearest_ethernet_x, chip.nearest_ethernet_y) - chips_done[eth].append((chip.x, chip.y)) + chips_done[eth].append(chip) self._finish() self.check_for_error() next_chips = _get_next_chips(chips_done, parent_chips, machine) diff --git a/spinnman/processes/application_run_process.py b/spinnman/processes/application_run_process.py index 9f19e0534..2057f1211 100644 --- a/spinnman/processes/application_run_process.py +++ b/spinnman/processes/application_run_process.py @@ -12,15 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. +from spinn_machine.core_subsets import CoreSubsets from spinnman.messages.scp.impl import ApplicationRun, CheckOKResponse from .abstract_multi_connection_process import AbstractMultiConnectionProcess -from spinn_machine.core_subsets import CoreSubsets class ApplicationRunProcess(AbstractMultiConnectionProcess[CheckOKResponse]): + """ + A process to run an application. + """ __slots__ = () def run(self, app_id: int, core_subsets: CoreSubsets, wait: bool): + """ + Runs the application. + + :param int app_id: + :param CoreSubsets core_subsets: + :param bool wait: +` """ with self._collect_responses(): for core_subset in core_subsets: self._send_request(ApplicationRun( diff --git a/spinnman/processes/fixed_connection_selector.py b/spinnman/processes/fixed_connection_selector.py index e8972a76f..171881bb6 100644 --- a/spinnman/processes/fixed_connection_selector.py +++ b/spinnman/processes/fixed_connection_selector.py @@ -11,12 +11,13 @@ # 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. + from typing import Any, Generic, TypeVar from spinn_utilities.overrides import overrides -from .abstract_multi_connection_process_connection_selector import ( - ConnectionSelector) from spinnman.connections.udp_packet_connections import ( SCAMPConnection, BMPConnection) +from .abstract_multi_connection_process_connection_selector import ( + ConnectionSelector) #: Type of connections selected between. #: :meta private: diff --git a/spinnman/processes/get_cpu_info_process.py b/spinnman/processes/get_cpu_info_process.py index 20e19b2e6..c825c6392 100644 --- a/spinnman/processes/get_cpu_info_process.py +++ b/spinnman/processes/get_cpu_info_process.py @@ -26,6 +26,11 @@ class GetCPUInfoProcess(AbstractMultiConnectionProcess[Response]): + """ + Gets the CPU for processors over the provided connection. + + This base class returns info for all states. + """ __slots__ = ("__cpu_infos", ) def __init__(self, connection_selector: ConnectionSelector): diff --git a/spinnman/processes/get_exclude_cpu_info_process.py b/spinnman/processes/get_exclude_cpu_info_process.py index 7a5bbbbca..e0d63f96f 100644 --- a/spinnman/processes/get_exclude_cpu_info_process.py +++ b/spinnman/processes/get_exclude_cpu_info_process.py @@ -22,13 +22,26 @@ class GetExcludeCPUInfoProcess(GetCPUInfoProcess): + """ + Gets the CPU for processors over the provided connection. + + This class returns all but infos for the requested states. + """ + __slots__ = ("__states", ) def __init__(self, connection_selector: ConnectionSelector, states: Container[CPUState]): + """ + :param connection_selector: + :type connection_selector: + AbstractMultiConnectionProcessConnectionSelector + :param iterable(CPUState) states: + The states for which info is NOT required. + """ super().__init__(connection_selector) self.__states = states @overrides(GetCPUInfoProcess._is_desired) - def _is_desired(self, cpu_info: CPUInfo): + def _is_desired(self, cpu_info: CPUInfo) -> bool: return cpu_info.state not in self.__states diff --git a/spinnman/processes/get_heap_process.py b/spinnman/processes/get_heap_process.py index dc4c43f50..c9cd7663c 100644 --- a/spinnman/processes/get_heap_process.py +++ b/spinnman/processes/get_heap_process.py @@ -32,6 +32,10 @@ class GetHeapProcess(AbstractMultiConnectionProcess[Response]): + """ + Gets Heap information using the provided connector. + + """ __slots__ = ( "_blocks", "_heap_address", diff --git a/spinnman/processes/get_include_cpu_info_process.py b/spinnman/processes/get_include_cpu_info_process.py index 2fd1154c4..84069c995 100644 --- a/spinnman/processes/get_include_cpu_info_process.py +++ b/spinnman/processes/get_include_cpu_info_process.py @@ -22,6 +22,11 @@ class GetIncludeCPUInfoProcess(GetCPUInfoProcess): + """ + Gets the CPU for processors over the provided connection. + + This class returns only infos for the requested states. + """ __slots__ = ("__states", ) def __init__(self, connection_selector: ConnectionSelector, @@ -30,10 +35,12 @@ def __init__(self, connection_selector: ConnectionSelector, :param connection_selector: :type connection_selector: AbstractMultiConnectionProcessConnectionSelector + :param iterable(CPUState) states: + The states for which info is required. """ super().__init__(connection_selector) self.__states = states @overrides(GetCPUInfoProcess._is_desired) - def _is_desired(self, cpu_info: CPUInfo): + def _is_desired(self, cpu_info: CPUInfo) -> bool: return cpu_info.state in self.__states diff --git a/spinnman/processes/get_machine_process.py b/spinnman/processes/get_machine_process.py index d49e96029..7df2ab18d 100644 --- a/spinnman/processes/get_machine_process.py +++ b/spinnman/processes/get_machine_process.py @@ -18,31 +18,35 @@ import functools from os.path import join from typing import 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.progress_bar import ProgressBar from spinn_utilities.typing.coords import XY + from spinn_machine import (Router, Chip, Link, Machine) from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink from spinn_machine.machine_factory import machine_repair + from spinnman.constants import ( ROUTER_REGISTER_P2P_ADDRESS, SYSTEM_VARIABLE_BASE_ADDRESS) from spinnman.data import SpiNNManDataView -from spinnman.messages.spinnaker_boot import ( - SystemVariableDefinition) from spinnman.exceptions import SpinnmanUnexpectedResponseCodeException from spinnman.messages.scp.abstract_messages import AbstractSCPRequest from spinnman.messages.scp.impl import ReadMemory, ReadLink, GetChipInfo from spinnman.messages.scp.impl.get_chip_info_response import ( GetChipInfoResponse) from spinnman.messages.scp.impl.read_memory import Response +from spinnman.messages.spinnaker_boot import ( + SystemVariableDefinition) from spinnman.model import ChipSummaryInfo, P2PTable from spinnman.model.enums import CPUState + from .abstract_multi_connection_process import AbstractMultiConnectionProcess from .abstract_multi_connection_process_connection_selector import \ ConnectionSelector -from spinn_utilities.progress_bar import ProgressBar logger = FormatAdapter(logging.getLogger(__name__)) @@ -61,8 +65,8 @@ class GetMachineProcess(AbstractMultiConnectionProcess): """ __slots__ = ( "_chip_info", - # Used if there are any ignores with ip addresses - # Holds a mapping from ip to board root (x,y) + # Used if there are any ignores with IP addresses + # Holds a mapping from IP to board root (x,y) "_ethernets", # Holds a map from x,y to a set of virtual cores to ignores "_ignore_cores_map", @@ -87,7 +91,7 @@ def __init__(self, connection_selector: ConnectionSelector): # A dictionary of (x, y) -> ChipInfo self._chip_info: Dict[XY, ChipSummaryInfo] = dict() - # Set ethernets to None meaning not computed yet + # Set to None meaning not computed yet self._ethernets: Optional[Dict[str, XY]] = None # Maps between virtual and physical cores @@ -362,7 +366,7 @@ def _preprocess_ignore_cores(self, machine: Machine): :param ~spinn_machine.Machine machine: An empty machine to handle wrap-arounds """ - # Convert by ip to global + # Convert by IP to global for ignore in IgnoreCore.parse_string( get_config_str_or_none("Machine", "down_cores")): global_xy = self._ignores_local_to_global( @@ -389,7 +393,7 @@ def _preprocess_ignore_chips(self, machine: Machine): """ for ignore in IgnoreChip.parse_string( get_config_str_or_none("Machine", "down_chips")): - # Convert by ip to global + # Convert by IP to global global_xy = self._ignores_local_to_global( ignore.x, ignore.y, ignore.ip_address, machine) if global_xy is None: diff --git a/spinnman/processes/get_n_cores_in_state_process.py b/spinnman/processes/get_n_cores_in_state_process.py index d557c661c..7183fc00b 100644 --- a/spinnman/processes/get_n_cores_in_state_process.py +++ b/spinnman/processes/get_n_cores_in_state_process.py @@ -13,14 +13,17 @@ # limitations under the License. from spinnman.messages.scp.impl import CountState -from .abstract_multi_connection_process import AbstractMultiConnectionProcess from spinnman.messages.scp.enums.scp_result import SCPResult +from .abstract_multi_connection_process import AbstractMultiConnectionProcess # Timeout for getting core state count; higher due to more waiting needed GET_CORE_COUNT_TIMEOUT = 2.0 class GetNCoresInStateProcess(AbstractMultiConnectionProcess): + """ + Gets the state of a core over the provided connection. + """ __slots__ = [ "_n_cores"] diff --git a/spinnman/processes/get_routes_process.py b/spinnman/processes/get_routes_process.py index 958218ca2..ce30b8fde 100644 --- a/spinnman/processes/get_routes_process.py +++ b/spinnman/processes/get_routes_process.py @@ -15,12 +15,14 @@ import struct from functools import partial from typing import List, Optional -from spinnman.messages.scp.impl.read_memory import ReadMemory, Response + from spinn_machine import MulticastRoutingEntry, Router +from spinnman.messages.scp.impl.read_memory import ReadMemory, Response +from spinnman.constants import UDP_MESSAGE_MAX_SIZE + from .abstract_multi_connection_process import AbstractMultiConnectionProcess from .abstract_multi_connection_process_connection_selector import ( ConnectionSelector) -from spinnman.constants import UDP_MESSAGE_MAX_SIZE # There are 1024 entries in a routing table _N_ENTRIES = 1024 diff --git a/spinnman/processes/get_tags_process.py b/spinnman/processes/get_tags_process.py index 16671f33f..e51973379 100644 --- a/spinnman/processes/get_tags_process.py +++ b/spinnman/processes/get_tags_process.py @@ -14,18 +14,24 @@ from functools import partial from typing import List, Optional + from spinn_machine.tags import AbstractTag, ReverseIPTag, IPTag -from .abstract_multi_connection_process import AbstractMultiConnectionProcess + from spinnman.messages.scp.impl.iptag_get import IPTagGet, IPTagGetResponse from spinnman.messages.scp.impl.iptag_get_info import IPTagGetInfo from spinnman.messages.scp.impl.iptag_get_info_response import ( IPTagGetInfoResponse) from spinnman.connections.udp_packet_connections import SCAMPConnection + +from .abstract_multi_connection_process import AbstractMultiConnectionProcess from .abstract_multi_connection_process_connection_selector import ( ConnectionSelector) class GetTagsProcess(AbstractMultiConnectionProcess): + """ + Gets information about the tags over the provided connection. + """ __slots__ = ( "_tags", "_tag_info") diff --git a/spinnman/processes/get_version_process.py b/spinnman/processes/get_version_process.py index 54db03b7c..1abcb1e7b 100644 --- a/spinnman/processes/get_version_process.py +++ b/spinnman/processes/get_version_process.py @@ -11,14 +11,17 @@ # 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. + from typing import Optional + from spinnman.messages.scp.impl import GetVersion from spinnman.constants import N_RETRIES from spinnman.model import VersionInfo +from spinnman.messages.scp.impl.get_version_response import GetVersionResponse + from .abstract_multi_connection_process import AbstractMultiConnectionProcess from .abstract_multi_connection_process_connection_selector import ( ConnectionSelector) -from spinnman.messages.scp.impl.get_version_response import GetVersionResponse class GetVersionProcess(AbstractMultiConnectionProcess[GetVersionResponse]): diff --git a/spinnman/processes/load_routes_process.py b/spinnman/processes/load_routes_process.py index 7dc3f1a31..3985e6a46 100644 --- a/spinnman/processes/load_routes_process.py +++ b/spinnman/processes/load_routes_process.py @@ -14,15 +14,18 @@ import struct from typing import Collection + from spinn_machine import Router +from spinn_machine.multicast_routing_entry import MulticastRoutingEntry + from spinnman.exceptions import SpinnmanInvalidParameterException from spinnman.messages.scp.impl import RouterInit, RouterAlloc -from .abstract_multi_connection_process import AbstractMultiConnectionProcess -from spinn_machine.multicast_routing_entry import MulticastRoutingEntry from spinnman.messages.scp.impl.router_alloc import RouterAllocResponse -from .write_memory_process import WriteMemoryProcess + +from .abstract_multi_connection_process import AbstractMultiConnectionProcess from .abstract_multi_connection_process_connection_selector import ( ConnectionSelector) +from .write_memory_process import WriteMemoryProcess _ROUTE_PATTERN = struct.Struct(" '_NextRegion': + """ + + :param int address: + :rtype: _NextRegion + """ return _NextRegion( self.scamp_coords, self.core_coords, self.n + 1, address, self.first_read_size) def tail(self, address: int, size: int, offset: int) -> _RegionTail: + """ + + :param int address: + :param int size: + :param int offset: + :rtype: _RegionTail + """ return _RegionTail( self.scamp_coords, self.core_coords, self.n, address, size, offset) diff --git a/spinnman/processes/read_memory_process.py b/spinnman/processes/read_memory_process.py index cad527977..a3a8776f7 100644 --- a/spinnman/processes/read_memory_process.py +++ b/spinnman/processes/read_memory_process.py @@ -14,12 +14,15 @@ import functools from typing import Callable + from spinn_utilities.typing.coords import XYP + from spinnman.messages.scp.impl import ReadLink, ReadMemory from spinnman.messages.scp.impl.read_memory import Response -from .abstract_multi_connection_process import AbstractMultiConnectionProcess from spinnman.constants import UDP_MESSAGE_MAX_SIZE from spinnman.messages.scp.abstract_messages import AbstractSCPRequest + +from .abstract_multi_connection_process import AbstractMultiConnectionProcess from .abstract_multi_connection_process_connection_selector import ( ConnectionSelector) diff --git a/spinnman/processes/send_single_command_process.py b/spinnman/processes/send_single_command_process.py index b16c79248..120d4d286 100644 --- a/spinnman/processes/send_single_command_process.py +++ b/spinnman/processes/send_single_command_process.py @@ -11,14 +11,18 @@ # 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. + from typing import Generic, Optional, TypeVar, Set -from .abstract_multi_connection_process import AbstractMultiConnectionProcess + from spinnman.constants import SCP_TIMEOUT + from spinnman.messages.scp.abstract_messages import AbstractSCPResponse from spinnman.messages.scp.abstract_messages import AbstractSCPRequest +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) -from spinnman.messages.scp.enums.scp_result import SCPResult #: Type of responses. #: :meta private: R = TypeVar("R", bound=AbstractSCPResponse) diff --git a/spinnman/spalloc/session.py b/spinnman/spalloc/session.py index ab3601705..b58c7b01b 100644 --- a/spinnman/spalloc/session.py +++ b/spinnman/spalloc/session.py @@ -11,16 +11,20 @@ # 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. + from functools import wraps from logging import getLogger -import re -import requests from json.decoder import JSONDecodeError +import re from typing import Dict, Tuple, cast, Optional import websocket # type: ignore + +import requests + from spinn_utilities.log import FormatAdapter from spinn_utilities.typing.json import JsonObject from spinnman.exceptions import SpallocException + from .utils import clean_url logger = FormatAdapter(getLogger(__name__)) @@ -37,6 +41,7 @@ def pp_req(request: requests.PreparedRequest): """ print(">>>>>>>>>>>START>>>>>>>>>>>\n") print(f"{request.method} {request.url}") + # pylint: disable=consider-using-f-string print('\r\n'.join('{}: {}'.format(*kv) for kv in request.headers.items())) if request.body: @@ -46,6 +51,7 @@ def pp_resp(response: requests.Response): """ :param ~requests.Response response: """ + # pylint: disable=consider-using-f-string print('{}\n{}\r\n{}\r\n\r\n{}'.format( '<<<<<<<<<< str: + """ + Makes sure the url is the correct format. + + :param str url: original url + :rtype: str + """ parts = urlparse(url) if parts.scheme != 'https': parts = ParseResult("https", parts.netloc, parts.path, @@ -212,8 +220,11 @@ def create_job_rect( @overrides(AbstractSpallocClient.create_job_board) def create_job_board( - self, triad=None, physical=None, ip_address=None, - machine_name=None, keepalive=45) -> SpallocJob: + self, triad: Optional[Tuple[int, int, int]] = None, + physical: Optional[Tuple[int, int, int]] = None, + ip_address: Optional[str] = None, + machine_name: Optional[str] = None, + keepalive: int = 45) -> SpallocJob: board: JsonObject if triad: x, y, z = triad @@ -233,8 +244,13 @@ def create_job_board( @overrides(AbstractSpallocClient.create_job_rect_at_board) def create_job_rect_at_board( - self, width, height, triad=None, physical=None, ip_address=None, - machine_name=None, keepalive=45, max_dead_boards=0): + self, width: int, height: int, + triad: Optional[Tuple[int, int, int]] = None, + physical: Optional[Tuple[int, int, int]] = None, + ip_address: Optional[str] = None, + machine_name: Optional[str] = None, keepalive: int = 45, + max_dead_boards: int = 0) -> SpallocJob: + board: JsonObject if triad: x, y, z = triad board = {"x": int(x), "y": int(y), "z": int(z)} @@ -269,7 +285,7 @@ class _ProxyServiceError(IOError): """ -def _SpallocKeepalive(url, interval, term_queue, cookies, headers): +def _spalloc_keepalive(url, interval, term_queue, cookies, headers): """ Actual keepalive task implementation. Don't use directly. """ @@ -473,7 +489,7 @@ def dispatch_message(self, channel_id: int, msg: bytes): def unlisten(self, channel_id: int): """ - De-register a listener for a channel + Deregister a listener for a channel """ self.__handlers.pop(channel_id) @@ -510,14 +526,14 @@ def __init__(self, session: Session, job_handle: str): self.__proxy_ping: Optional[_ProxyPing] = None @overrides(SpallocJob.get_session_credentials_for_db) - def get_session_credentials_for_db(self): + def get_session_credentials_for_db(self) -> Mapping[Tuple[str, str], str]: config = {} config["SPALLOC", "service uri"] = self._service_url config["SPALLOC", "job uri"] = self._url cookies, headers = self._session_credentials if "Authorization" in headers: - # We never write the auth headers themselves; we just extend the - # session + # We never write the authorisation headers themselves; + # we just extend the session del headers["Authorization"] for k, v in cookies.items(): config["COOKIE", k] = v @@ -634,7 +650,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") -> None: + def destroy(self, reason: str = "finished"): if self.__keepalive_handle: self.__keepalive_handle.close() self.__keepalive_handle = None @@ -662,7 +678,7 @@ def launch_keepalive_task( if self.__keepalive_handle is not None: raise SpallocException("cannot keep job alive from two tasks") q: Queue = Queue(1) - p = Process(target=_SpallocKeepalive, args=( + p = Process(target=_spalloc_keepalive, args=( self._keepalive_url, 0 + period, q, *self._session_credentials), daemon=True) p.start() @@ -871,7 +887,7 @@ def __init__( super().__init__(ws, receiver) @overrides(_ProxiedConnection._open_connection) - def _open_connection(self): + def _open_connection(self) -> int: handle, = self._call( ProxyProtocol.OPEN, _open_req, _open_close_res, *self.__connect_args) @@ -879,10 +895,19 @@ def _open_connection(self): @overrides(Connection.is_connected) def is_connected(self) -> bool: + """ + Determines if the medium is connected at this point in time. + + :return: True if the medium is connected, False otherwise + :rtype: bool + """ return self._connected @overrides(Connection.close) - def close(self): + def close(self) -> None: + """ + Closes the connection. + """ self._close() @overrides(SpallocProxiedConnection.send) @@ -934,14 +959,23 @@ def _port(self) -> Optional[int]: @overrides(Connection.is_connected) def is_connected(self) -> bool: + """ + Determines if the medium is connected at this point in time. + + :return: True if the medium is connected, False otherwise + :rtype: bool + """ return self._connected @overrides(Connection.close) def close(self) -> None: + """ + Closes the connection. + """ self._close() @overrides(SpallocProxiedConnection.send) - def send(self, data: bytes) -> None: + def send(self, data: bytes): self._throw_if_closed() raise IOError("socket is not open for sending") diff --git a/spinnman/spalloc/spalloc_eieio_connection.py b/spinnman/spalloc/spalloc_eieio_connection.py index 613c7c7db..6cfbb063a 100644 --- a/spinnman/spalloc/spalloc_eieio_connection.py +++ b/spinnman/spalloc/spalloc_eieio_connection.py @@ -45,12 +45,20 @@ class SpallocEIEIOConnection( __slots__ = () @overrides(EIEIOConnection.send_eieio_message) - def send_eieio_message(self, eieio_message): + def send_eieio_message(self, eieio_message: AbstractEIEIOMessage): # 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): + """ + + :param AbstractEIEIOMessage eieio_message: + :param int x: + :param int y: + :param int p: + :rtype: None + """ sdp_message = SDPMessage( SDPHeader( flags=SDPFlag.REPLY_NOT_EXPECTED, tag=0, diff --git a/spinnman/spalloc/spalloc_eieio_listener.py b/spinnman/spalloc/spalloc_eieio_listener.py index 435fba604..9e7e2b94a 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): + def send(self, data: bytes): """ .. note:: This class does not allow sending. diff --git a/spinnman/spalloc/spalloc_job.py b/spinnman/spalloc/spalloc_job.py index 7cc8caac4..14f5ba429 100644 --- a/spinnman/spalloc/spalloc_job.py +++ b/spinnman/spalloc/spalloc_job.py @@ -34,7 +34,7 @@ class SpallocJob(object, metaclass=AbstractBase): __slots__ = () @abstractmethod - def get_state(self, wait_for_change=False) -> SpallocState: + def get_state(self, wait_for_change: bool = False) -> SpallocState: """ Get the current state of the machine. @@ -183,7 +183,7 @@ def destroy(self, reason: str = "finished"): raise NotImplementedError() @abstractmethod - def keepalive(self): + def keepalive(self) -> None: """ Signal the job that we want it to stay alive for a while longer. """ @@ -200,7 +200,7 @@ def launch_keepalive_task( :param int period: How often to send a keepalive message (in seconds) :return: - Some kind of closable task handle; closing it terminates the task. + Some kind of closeable task handle; closing it terminates the task. Destroying the job will also terminate the task. """ raise NotImplementedError() diff --git a/spinnman/spalloc/spalloc_scp_connection.py b/spinnman/spalloc/spalloc_scp_connection.py index a88c140fc..6b2bff7a0 100644 --- a/spinnman/spalloc/spalloc_scp_connection.py +++ b/spinnman/spalloc/spalloc_scp_connection.py @@ -55,19 +55,16 @@ def send_sdp_message(self, sdp_message: SDPMessage): self.send(_TWO_SKIP + sdp_message.bytestring) @overrides(SCAMPConnection.receive_scp_response) - def receive_scp_response( - self, timeout=1.0) -> Tuple[SCPResult, int, bytes, int]: + def receive_scp_response(self, timeout: Optional[float] = 1.0) -> Tuple[ + SCPResult, int, bytes, int]: data = self.receive(timeout) result, sequence = _TWO_SHORTS.unpack_from(data, 10) return SCPResult(result), sequence, data, 2 - @overrides(SCAMPConnection.send_scp_request) - def send_scp_request(self, scp_request: AbstractSCPRequest): - self.send(self.get_scp_data(scp_request)) - @overrides(SCAMPConnection.get_scp_data) def get_scp_data( - self, scp_request: AbstractSCPRequest, x=None, y=None) -> bytes: + self, scp_request: AbstractSCPRequest, + x: Optional[int] = None, y: Optional[int] = None) -> bytes: if x is None: x = self.chip_x if y is None: diff --git a/spinnman/transceiver/base_transceiver.py b/spinnman/transceiver/base_transceiver.py index 65e4139e6..fa0b83ad7 100644 --- a/spinnman/transceiver/base_transceiver.py +++ b/spinnman/transceiver/base_transceiver.py @@ -25,7 +25,7 @@ import time from typing import ( BinaryIO, Collection, Dict, FrozenSet, Iterable, Iterator, List, Optional, - Sequence, Tuple, TypeVar, Union, cast) + Sequence, Set, Tuple, TypeVar, Union, cast) from spinn_utilities.abstract_base import ( AbstractBase, abstractmethod) from spinn_utilities.config_holder import get_config_bool @@ -232,7 +232,7 @@ def bmp_selector(self) -> Optional[FixedConnectionSelector[BMPConnection]]: def scamp_connection_selector(self) -> MostDirectConnectionSelector: return self._scamp_connection_selector - def _where_is_xy(self, x: int, y: int): + def _where_is_xy(self, x: int, y: int) -> Optional[str]: """ Attempts to get where_is_x_y info from the machine @@ -256,7 +256,7 @@ def __identify_connections( ) -> MostDirectConnectionSelector: for conn in connections: - # locate the only boot send conn + # locate the only boot send connection if isinstance(conn, BootConnection): if self._boot_send_connection is not None: raise SpinnmanInvalidParameterException( @@ -266,7 +266,7 @@ def __identify_connections( # Locate any connections that talk to a BMP if isinstance(conn, BMPConnection): - # If it is a BMP conn, add it here + # If it is a BMP connection, add it here if self._bmp_connection is not None: raise NotImplementedError( "Only one BMP connection supported") @@ -276,7 +276,7 @@ def __identify_connections( elif isinstance(conn, SCAMPConnection): self._scamp_connections.append(conn) - # update the transceiver with the conn selectors. + # update the transceiver with the connection selectors. return MostDirectConnectionSelector(self._scamp_connections) def __check_bmp_connection(self) -> None: @@ -285,12 +285,11 @@ def __check_bmp_connection(self) -> None: :raise SpinnmanIOException: when a connection is not linked to a BMP """ - # check that the UDP BMP conn is actually connected to a BMP - # via the sver command + # check that the UDP BMP connection is actually connected to a BMP + # via the get_scamp_version command if self._bmp_connection is not None: conn = self._bmp_connection - # try to send a BMP sver to check if it responds as expected try: version_info = self._get_scamp_version( conn.chip_x, conn.chip_y, self._bmp_selector) @@ -422,7 +421,7 @@ def add_scamp_connections(self, connections: Dict[XY, str]): self._scamp_connections) @overrides(Transceiver.get_connections) - def get_connections(self): + def get_connections(self) -> Set[Connection]: return self._all_connections def _get_machine_dimensions(self) -> MachineDimensions: @@ -708,9 +707,8 @@ def get_cpu_infos( if core_subsets is None: core_subsets = CoreSubsets() for chip in SpiNNManDataView.get_machine().chips: - for processor in chip.processors: - core_subsets.add_processor( - chip.x, chip.y, processor.processor_id) + for p in chip.all_processor_ids: + core_subsets.add_processor(chip.x, chip.y, p) if states is None: process = GetCPUInfoProcess(self._scamp_connection_selector) @@ -731,11 +729,11 @@ def get_cpu_infos( @overrides(Transceiver.get_clock_drift) def get_clock_drift(self, x: int, y: int) -> float: - DRIFT_FP = 1 << 17 + drift_fp = 1 << 17 drift_b = self._get_sv_data(x, y, SystemVariableDefinition.clock_drift) drift = struct.unpack(" int: process = GetNCoresInStateProcess(self._scamp_connection_selector) - chip_xys = xys + chip_xys: Iterable[Tuple[int, int]] if xys is None: machine = SpiNNManDataView.get_machine() - chip_xys = [(ch.x, ch.y) - for ch in machine.ethernet_connected_chips] + chip_xys = machine.ethernet_connected_chips else: chip_xys = xys return process.get_n_cores_in_state(chip_xys, app_id, state) @@ -848,7 +844,7 @@ def execute_flood( if isinstance(executable, int): # No executable is 4 bytes long raise TypeError("executable may not be int") - # Lock against other executable's + # Lock against other executables with self.__flood_execute_lock(): # Flood fill the system with the binary n_bytes, chksum = self.write_memory( @@ -1018,7 +1014,7 @@ def __log_where_is_info(self, cpu_infos: Iterable[ """ xys = set() for cpu_info in cpu_infos: - # todo: Is it ever not a CPUInfo + # TODO: Is it ever not a CPUInfo if isinstance(cpu_info, CPUInfo): xys.add((cpu_info.x, cpu_info.y)) else: @@ -1232,7 +1228,7 @@ def get_tags(self, connection: Optional[SCAMPConnection] = None @overrides(Transceiver.malloc_sdram) def malloc_sdram( - self, x: int, y: int, size: int, app_id: int, tag=0) -> int: + self, x: int, y: int, size: int, app_id: int, tag: int = 0) -> int: try: process = MallocSDRAMProcess(self._scamp_connection_selector) process.malloc_sdram(x, y, size, app_id, tag) diff --git a/spinnman/transceiver/extendable_transceiver.py b/spinnman/transceiver/extendable_transceiver.py index e937f82bc..953ce9886 100644 --- a/spinnman/transceiver/extendable_transceiver.py +++ b/spinnman/transceiver/extendable_transceiver.py @@ -53,7 +53,7 @@ def __init__(self): @abstractmethod def bmp_selector(self) -> Optional[FixedConnectionSelector[BMPConnection]]: """ - Returns the bmp selector + Returns the BMP selector :rtype: AbstractMultiConnectionProcessConnectionSelector """ diff --git a/spinnman/transceiver/mockable_transceiver.py b/spinnman/transceiver/mockable_transceiver.py index 558cc7505..126ee9732 100644 --- a/spinnman/transceiver/mockable_transceiver.py +++ b/spinnman/transceiver/mockable_transceiver.py @@ -16,7 +16,7 @@ from typing import ( BinaryIO, Collection, Dict, FrozenSet, Iterable, - List, Optional, Tuple, Union) + List, Optional, Set, Tuple, Union) from spinn_utilities.overrides import overrides from spinn_utilities.progress_bar import ProgressBar from spinn_utilities.typing.coords import XY @@ -24,6 +24,7 @@ CoreSubsets, FixedRouteEntry, Machine, MulticastRoutingEntry) from spinn_machine.tags import AbstractTag, IPTag, ReverseIPTag from spinnman.data import SpiNNManDataView +from spinnman.connections.abstract_classes import Connection from spinnman.connections.udp_packet_connections import BMPConnection from spinnman.connections.udp_packet_connections import ( SCAMPConnection, SDPConnection) @@ -69,7 +70,7 @@ def get_machine_details(self) -> Machine: return SpiNNManDataView.get_machine() @overrides(Transceiver.get_connections) - def get_connections(self): + def get_connections(self) -> Set[Connection]: raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.get_cpu_infos) @@ -80,7 +81,7 @@ def get_cpu_infos( raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.get_clock_drift) - def get_clock_drift(self, x, y): + def get_clock_drift(self, x: int, y: int) -> float: raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.read_user) @@ -196,7 +197,7 @@ def get_tags(self, connection: Optional[SCAMPConnection] = None @overrides(Transceiver.malloc_sdram) def malloc_sdram( - self, x: int, y: int, size: int, app_id: int, tag=0) -> int: + self, x: int, y: int, size: int, app_id: int, tag: int = 0) -> int: raise NotImplementedError("Needs to be mocked") @overrides(Transceiver.load_multicast_routes) diff --git a/spinnman/transceiver/transceiver.py b/spinnman/transceiver/transceiver.py index faa361054..d33103274 100644 --- a/spinnman/transceiver/transceiver.py +++ b/spinnman/transceiver/transceiver.py @@ -16,13 +16,14 @@ from typing import ( BinaryIO, Collection, Dict, FrozenSet, Iterable, - List, Optional, Tuple, Union) + List, Optional, Set, Tuple, Union) from spinn_utilities.abstract_base import abstractmethod from spinn_utilities.progress_bar import ProgressBar from spinn_utilities.typing.coords import XY from spinn_machine import ( CoreSubsets, FixedRouteEntry, Machine, MulticastRoutingEntry) from spinn_machine.tags import AbstractTag, IPTag, ReverseIPTag +from spinnman.connections.abstract_classes import Connection from spinnman.connections.udp_packet_connections import ( SCAMPConnection, SDPConnection) from spinnman.messages.scp.enums import Signal @@ -111,7 +112,7 @@ def add_scamp_connections(self, connections: Dict[XY, str]): raise NotImplementedError("abstractmethod") @abstractmethod - def get_connections(self): + def get_connections(self) -> Set[Connection]: """ Get the currently known connections to the board, made up of those passed in to the transceiver and those that are discovered during @@ -732,7 +733,7 @@ def get_tags(self, connection: Optional[SCAMPConnection] = None @abstractmethod def malloc_sdram( - self, x: int, y: int, size: int, app_id: int, tag=0) -> int: + self, x: int, y: int, size: int, app_id: int, tag: int = 0) -> int: """ Allocates a chunk of SDRAM on a chip on the machine. diff --git a/spinnman/transceiver/transceiver_factory.py b/spinnman/transceiver/transceiver_factory.py index 5781d30a7..254f7d3b1 100644 --- a/spinnman/transceiver/transceiver_factory.py +++ b/spinnman/transceiver/transceiver_factory.py @@ -29,7 +29,7 @@ from spinnman.transceiver import Transceiver from spinnman.transceiver.version3transceiver import Version3Transceiver from spinnman.transceiver.version5transceiver import Version5Transceiver -from spinnman.transceiver.virtual5Transceiver import Virtual5Transceiver +from spinnman.transceiver.virtual5transceiver import Virtual5Transceiver from spinnman.constants import LOCAL_HOST logger = FormatAdapter(logging.getLogger(__name__)) diff --git a/spinnman/transceiver/virtual5Transceiver.py b/spinnman/transceiver/virtual5transceiver.py similarity index 100% rename from spinnman/transceiver/virtual5Transceiver.py rename to spinnman/transceiver/virtual5transceiver.py diff --git a/spinnman/utilities/locate_connected_machine_ip_address.py b/spinnman/utilities/locate_connected_machine_ip_address.py index 41896fce1..eaa734033 100644 --- a/spinnman/utilities/locate_connected_machine_ip_address.py +++ b/spinnman/utilities/locate_connected_machine_ip_address.py @@ -43,10 +43,8 @@ def locate_connected_machine(handler: Callable[[str, float], None]): if __name__ == "__main__": - def _ctrlc_handler(sig, frame): # @UnusedVariable + def _ctrlc_handler(sig, frame): """ - :param sig: - :param frame: :return: Never returns as it causes a sys.exit() """ # pylint: disable=unused-argument diff --git a/spinnman/utilities/utility_functions.py b/spinnman/utilities/utility_functions.py index 901b4cf9e..9fc4f86e3 100644 --- a/spinnman/utilities/utility_functions.py +++ b/spinnman/utilities/utility_functions.py @@ -99,7 +99,7 @@ def reprogram_tag(connection: SCAMPConnection, tag: int, strip: bool = True): connection.chip_x, connection.chip_y, [0, 0, 0, 0], 0, tag, strip=strip, use_sender=True) data = connection.get_scp_data(request) - exn = None + exception = None for _ in range(3): try: connection.send(data) @@ -107,9 +107,9 @@ def reprogram_tag(connection: SCAMPConnection, tag: int, strip: bool = True): request.get_scp_response().read_bytestring(response, offset) return except SpinnmanTimeoutException as e: - exn = e - # Should be impossible to get here with exn=None - raise exn or Exception + exception = e + # Should be impossible to get here with Exception is None + raise exception or Exception def reprogram_tag_to_listener( @@ -143,7 +143,7 @@ def reprogram_tag_to_listener( strip=strip, use_sender=True) request.sdp_header.update_for_send(x, y) send_data = b'\0\0' + request.bytestring - exn = None + exception = None for _ in range(3): try: connection.send_to(send_data, (ip_address, SCP_SCAMP_PORT)) @@ -152,6 +152,6 @@ def reprogram_tag_to_listener( connection.receive(), 2) return except SpinnmanTimeoutException as e: - exn = e - # Should be impossible to get here with exn=None - raise exn or Exception + exception = e + # Should be impossible to get here with exception is None + raise exception or Exception diff --git a/unittests/connection_tests/test_udp_connection.py b/unittests/connection_tests/test_udp_connection.py deleted file mode 100644 index a417d5330..000000000 --- a/unittests/connection_tests/test_udp_connection.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (c) 2014 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. - -import unittest -from spinnman.connections.udp_packet_connections import SCAMPConnection -from spinnman.config_setup import unittest_setup -from spinnman.constants import LOCAL_HOST -from spinnman.exceptions import SpinnmanTimeoutException -from spinnman.messages.scp.impl import GetVersion, ReadLink, ReadMemory -from spinnman.messages.scp.enums import SCPResult -from spinnman.messages.scp.impl.get_version_response import GetVersionResponse -from spinnman.board_test_configuration import BoardTestConfiguration - - -class TestUDPConnection(unittest.TestCase): - - def setUp(self): - unittest_setup() - self.board_config = BoardTestConfiguration() - - def test_scp_version_request_and_response_board(self): - self.board_config.set_up_remote_board(version=5) - connection = SCAMPConnection( - remote_host=self.board_config.remotehost) - scp_req = GetVersion(0, 0, 0) - scp_response = GetVersionResponse() - connection.send_scp_request(scp_req) - if self.board_config.remotehost == LOCAL_HOST: - raise unittest.SkipTest( - "Can not test the rest without a ral board") - _, _, data, offset = connection.receive_scp_response() - scp_response.read_bytestring(data, offset) - print(scp_response.version_info) - self.assertEqual( - scp_response._scp_response_header._result, SCPResult.RC_OK) - - def test_scp_read_link_request_and_response_board(self): - self.board_config.set_up_remote_board(version=5) - connection = SCAMPConnection( - remote_host=self.board_config.remotehost) - scp_link = ReadLink((0, 0, 0), 0, 0x70000000, 250) - connection.send_scp_request(scp_link) - if self.board_config.remotehost == LOCAL_HOST: - raise unittest.SkipTest( - "Can not test the rest without a ral board") - result, _, _, _ = connection.receive_scp_response() - self.assertEqual(result, SCPResult.RC_OK) - - def test_scp_read_memory_request_and_response_board(self): - self.board_config.set_up_remote_board(version=5) - connection = SCAMPConnection( - remote_host=self.board_config.remotehost) - scp_link = ReadMemory((0, 0, 0), 0x70000000, 256) - connection.send_scp_request(scp_link) - if self.board_config.remotehost == LOCAL_HOST: - raise unittest.SkipTest( - "Can not test the rest without a ral board") - result, _, _, _ = connection.receive_scp_response() - self.assertEqual(result, SCPResult.RC_OK) - - def test_send_scp_request_to_nonexistent_host(self): - # Microsoft invalid IP address. For more details see: - # https://answers.microsoft.com/en-us/windows/forum/windows_vista-networking/invalid-ip-address-169254xx/ce096728-e2b7-4d54-80cc-52a4ed342870 - _NOHOST = "169.254.254.254" - with self.assertRaises(SpinnmanTimeoutException): - connection = SCAMPConnection(remote_host=_NOHOST) - scp = ReadMemory((0, 0, 0), 0, 256) - connection.send_scp_request(scp) - _, _, _, _ = connection.receive_scp_response(2) - - -if __name__ == '__main__': - unittest.main() diff --git a/unittests/test_transceiver.py b/unittests/test_transceiver.py index 238c24453..d0584a830 100644 --- a/unittests/test_transceiver.py +++ b/unittests/test_transceiver.py @@ -32,6 +32,12 @@ class MockExtendedTransceiver(MockableTransceiver, ExtendedTransceiver): pass + def _where_is_xy(self, x: int, y: int) -> None: + return None + + def scamp_connection_selector(self): + raise NotImplementedError + class TestTransceiver(unittest.TestCase):