Skip to content
19 changes: 14 additions & 5 deletions rig/machine_control/boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
"""
from . import struct_file, consts
import enum
import pkg_resources
import socket
import struct
import time
import os

import rig
from rig.utils.docstrings import add_int_enums_to_docstring

# Specifies the size of packets that should be sent to SpiNNaker to boot the
Expand Down Expand Up @@ -102,10 +103,18 @@ def boot(hostname, boot_port=consts.BOOT_PORT,
Layout of structs in memory.
"""
# Get the boot data if not specified.
scamp_binary = (scamp_binary if scamp_binary is not None else
pkg_resources.resource_filename("rig", "boot/scamp.boot"))
sark_struct = (sark_struct if sark_struct is not None else
pkg_resources.resource_filename("rig", "boot/sark.struct"))
if scamp_binary is None: # pragma: no branch
scamp_binary = os.path.join(
os.path.dirname(rig.__file__),
"boot",
"scamp.boot",
)
if sark_struct is None: # pragma: no branch
sark_struct = os.path.join(
os.path.dirname(rig.__file__),
"boot",
"sark.struct",
)
with open(scamp_binary, "rb") as f:
boot_data = f.read()

Expand Down
16 changes: 12 additions & 4 deletions rig/machine_control/machine_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import socket
import struct
import time
import pkg_resources
import warnings
from six.moves.collections_abc import Iterable

import rig

from rig.machine_control.consts import \
SCPCommands, NNCommands, NNConstants, AppFlags, LEDAction
Expand Down Expand Up @@ -118,8 +120,14 @@ def __init__(self, initial_host, scp_port=consts.SCP_PORT,
# Load default structs if none provided
self.structs = structs
if self.structs is None:
struct_data = pkg_resources.resource_string("rig",
"boot/sark.struct")
struct_data = open(
os.path.join(
os.path.dirname(rig.__file__),
"boot",
"sark.struct",
),
"rb",
).read()
self.structs = struct_file.read_struct_file(struct_data)

# This dictionary contains a lookup from chip (x, y) to the
Expand Down Expand Up @@ -1550,7 +1558,7 @@ def count_cores_in_state(self, state, app_id):
an iterable of these, in which case the total count will be
returned.
"""
if (isinstance(state, collections.Iterable) and
if (isinstance(state, Iterable) and
not isinstance(state, str)):
# If the state is iterable then call for each state and return the
# sum.
Expand Down
2 changes: 1 addition & 1 deletion rig/place_and_route/place/rand.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def place(vertices_resources, nets, machine, constraints,
movable_vertices = [v for v in vertices_resources
if v not in placements]

locations = set(machine)
locations = list(machine)

for vertex in movable_vertices:
# Keep choosing random chips until we find one where the vertex fits.
Expand Down
6 changes: 2 additions & 4 deletions rig/place_and_route/place/sa/c_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@

from six import iteritems

import pkg_resources

# An optional Rig dependency.
from rig_c_sa import ffi
import rig_c_sa


# Make sure installed rig_c_sa version is compatible.
pkg_resources.require("rig_c_sa>=0.3.1,<1.0.0")
rig_c_sa_version = tuple(map(int, rig_c_sa.__version__.split(".")))
assert (0, 3, 1) <= rig_c_sa_version < (1, 0, 0)


class CKernel(object):
Expand Down
4 changes: 2 additions & 2 deletions rig/type_casts.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,13 +380,13 @@ class NumpyFixToFloatConverter(object):
This will produced signed and unsigned values depending on the `dtype` of
the original array.

>>> signed = np.array([0xf0], dtype=np.int8)
>>> signed = np.array(np.array([0xf0]), dtype=np.int8)
>>> kbits(signed)
array([-1.])

>>> unsigned = np.array([0xf0], dtype=np.uint8)
>>> kbits(unsigned)[0]
15.0
np.float64(15.0)
"""
def __init__(self, n_frac):
"""Create a new converter from fix-point to floating point
Expand Down
17 changes: 16 additions & 1 deletion rig/utils/contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,22 @@ def f(self, **kwargs):
def decorator(f):
# Extract any positional and positional-and-key-word arguments
# which may be set.
arg_names, varargs, keywords, defaults = inspect.getargspec(f)
if hasattr(inspect, "getfullargspec"): # pragma: no cover
# Python 3
(
arg_names,
varargs,
keywords, # Actually varkw
defaults,
# Unused for consistency with Python 2 behaviour, whilst
# Python 2 support remains.
_kwonlyargs,
_kwonlydefaults,
_anotations,
) = inspect.getfullargspec(f)
else: # pragma: no cover
# Python 2
arg_names, varargs, keywords, defaults = inspect.getargspec(f)

# Sanity check: non-keyword-only arguments should't be present in
# the keyword-only-arguments list.
Expand Down
17 changes: 16 additions & 1 deletion rig/utils/docstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,22 @@ def f(*args, kw_only_arg=123)
"""

def decorate(f_wrapper):
args, varargs, keywords, defaults = inspect.getargspec(f)
if hasattr(inspect, "getfullargspec"): # pragma: no cover
# Python 3
(
args,
varargs,
keywords, # Actually varkw
defaults,
# Unused for consistency with Python 2 behaviour, whilst
# Python 2 support remains.
_kwonlyargs,
_kwonlydefaults,
_anotations,
) = inspect.getfullargspec(f)
else: # pragma: no cover
# Python 2
args, varargs, keywords, defaults = inspect.getargspec(f)

# Simplifies later logic
if defaults is None:
Expand Down
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ def pytest_addoption(parser):
"Specify the IP address or hostname of "
"the BMP to use.")

def pytest_configure(config):
config.addinivalue_line("markers", "order_before")
config.addinivalue_line("markers", "order_after")
config.addinivalue_line("markers", "order_id")
config.addinivalue_line("markers", "incremental")
config.addinivalue_line("markers", "no_boot")


# From pytest.org
def pytest_runtest_makereport(item, call): # pragma: no cover
Expand Down
48 changes: 28 additions & 20 deletions tests/machine_control/test_machine_controller.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import mock
import pkg_resources
import pytest
import six
from six import iteritems, itervalues
Expand All @@ -10,6 +9,7 @@
import itertools
import warnings

import rig
from rig.machine_control.consts import (
SCPCommands, LEDAction, NNCommands, NNConstants)
from rig.machine_control.machine_controller import (
Expand All @@ -27,6 +27,22 @@
from rig.routing_table import RoutingTableEntry, Routes


sark_struct_data = open(
os.path.join(
os.path.dirname(rig.__file__),
"boot",
"sark.struct",
),
"rb",
).read()

test_aplx_file = os.path.join(
os.path.dirname(rig.__file__),
"binaries",
"test.aplx",
)


@pytest.fixture(scope="module")
def controller(spinnaker_ip):
return MachineController(spinnaker_ip)
Expand Down Expand Up @@ -258,7 +274,7 @@ def test_load_application(self, controller, targets):
assert len(controller.structs) > 0, \
"Controller has no structs, check test fixture."
controller.load_application(
pkg_resources.resource_filename("rig", "binaries/test.aplx"),
test_aplx_file,
targets, use_count=False
)

Expand Down Expand Up @@ -314,8 +330,7 @@ def test_stop_signal(self, controller):
controller.get_chip_info(0, 1).core_states[10] ==
consts.AppState.idle)
controller.load_application(
pkg_resources.resource_filename("rig",
"binaries/test.aplx"),
test_aplx_file,
{(0, 1): set([10])},
wait=True
)
Expand Down Expand Up @@ -1389,8 +1404,7 @@ def test_read_struct_field(self, x, y, p, which_struct_ascii, field_ascii,
field = six.b(field_ascii)

# Open the struct file
struct_data = pkg_resources.resource_string("rig", "boot/sark.struct")
structs = struct_file.read_struct_file(struct_data)
structs = struct_file.read_struct_file(sark_struct_data)
assert (which_struct in structs and
field in structs[which_struct]), "Test is broken"

Expand Down Expand Up @@ -1423,8 +1437,7 @@ def test_read_struct_field(self, x, y, p, which_struct_ascii, field_ascii,
])
def test_write_struct_field(self, x, y, p, which_struct, field, value):
# Open the struct file
struct_data = pkg_resources.resource_string("rig", "boot/sark.struct")
structs = struct_file.read_struct_file(struct_data)
structs = struct_file.read_struct_file(sark_struct_data)
assert (six.b(which_struct) in structs and
six.b(field) in structs[six.b(which_struct)]), "Test is broken"

Expand Down Expand Up @@ -1466,8 +1479,7 @@ def test_write_struct_field(self, x, y, p, which_struct, field, value):
)
def test_read_vcpu_struct(self, x, y, p, vcpu_base, field, data,
converted):
struct_data = pkg_resources.resource_string("rig", "boot/sark.struct")
structs = struct_file.read_struct_file(struct_data)
structs = struct_file.read_struct_file(sark_struct_data)
vcpu_struct = structs[b"vcpu"]
assert six.b(field) in vcpu_struct, "Test is broken"
field_ = vcpu_struct[six.b(field)]
Expand Down Expand Up @@ -1503,8 +1515,7 @@ def mock_read_struct_field(struct_name, field, x, y, p=0):
("rt_code", 8, b"\x08")]
)
def test_write_vcpu_struct(self, x, y, p, vcpu_base, field, value, data):
struct_data = pkg_resources.resource_string("rig", "boot/sark.struct")
structs = struct_file.read_struct_file(struct_data)
structs = struct_file.read_struct_file(sark_struct_data)
vcpu_struct = structs[b"vcpu"]
assert six.b(field) in vcpu_struct, "Test is broken"
field_ = vcpu_struct[six.b(field)]
Expand Down Expand Up @@ -1532,8 +1543,7 @@ def mock_read_struct_field(struct_name, field, x, y, p=0):
@pytest.mark.parametrize("x, y, p, vcpu_base", [(0, 1, 11, 0x67801234),
(1, 4, 17, 0x33331110)])
def test_get_processor_status(self, x, y, p, vcpu_base):
struct_data = pkg_resources.resource_string("rig", "boot/sark.struct")
structs = struct_file.read_struct_file(struct_data)
structs = struct_file.read_struct_file(sark_struct_data)
vcpu_struct = structs[b"vcpu"]

# Create a mock SV struct reader
Expand Down Expand Up @@ -1989,11 +1999,10 @@ def read_struct_field(fn, x, y, p):

assert "(0, 1, 4)" in str(excinfo.value)

@pytest.mark.parametrize("signal", ["non-existant",
consts.AppDiagnosticSignal.AND])
@pytest.mark.parametrize("signal", ["non-existant", -1])
def test_send_signal_fails(self, signal):
# Make sure that the send_signal function rejects bad signal
# identifiers (or ones that require special treatment)
# identifiers
cn = MachineController("localhost")
with pytest.raises(ValueError):
cn.send_signal(signal)
Expand Down Expand Up @@ -2084,11 +2093,10 @@ def test_count_cores_in_state_iterable_of_states(self, states, exp):
# Check the correct number of packets were sent
assert cn._send_scp.call_count == len(states)

@pytest.mark.parametrize("state", ["non-existant",
consts.AppDiagnosticSignal.AND])
@pytest.mark.parametrize("state", ["non-existant", -1])
def test_count_cores_in_state_fails(self, state):
# Make sure that the count_cores_in_state function rejects bad state
# identifiers (or ones that require special treatment)
# identifiers
cn = MachineController("localhost")
with pytest.raises(ValueError):
cn.count_cores_in_state(state)
Expand Down
3 changes: 2 additions & 1 deletion tests/machine_control/test_scp_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
import struct
import time
from six.moves.collections_abc import Callable

from rig.machine_control.consts import \
SCPCommands, DataType, SDP_HEADER_LENGTH, RETRYABLE_SCP_RETURN_CODES, \
Expand Down Expand Up @@ -58,7 +59,7 @@ def test_scpcall():
assert call.arg1 == call.arg2 == call.arg3 == 0
assert call.data == b''
assert call.timeout == 0.0
assert isinstance(call.callback, collections.Callable)
assert isinstance(call.callback, Callable)


def test_single_scp_packet(mock_conn):
Expand Down
4 changes: 2 additions & 2 deletions tests/machine_control/test_unbooted_ping.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ def test_listen(should_fail, monkeypatch):
assert retval == "127.0.0.1"

# Make sure parameters were obayed
assert mock_socket.settimeout.called_once_with(12.0)
assert mock_socket.bind.called_once_with('0.0.0.0', 12345)
mock_socket.settimeout.assert_called_once_with(12.0)
mock_socket.bind.assert_called_once_with(('0.0.0.0', 12345))
5 changes: 3 additions & 2 deletions tests/place_and_route/place/test_generic_place.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@
(sa_place, {}),
# Test using other kernels (when available)
(sa_place, {"kernel": PythonKernel}),
pytest.mark.skipif("CKernel is None")(
(sa_place, {"kernel": CKernel})),
pytest.param(sa_place,
{"kernel": CKernel},
marks=pytest.mark.skipif("CKernel is None")),
# Testing with effort = 0 tests the initial (random)
# placement solutions of the SA placer.
(sa_place, {"effort": 0.0}),
Expand Down
6 changes: 3 additions & 3 deletions tests/routing_table/test_routing_table_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,9 @@ def test_routing_tree_to_tables_repeated_key_mask_fork_not_allowed():
with pytest.raises(MultisourceRouteError) as err:
routing_tree_to_tables(routes, net_keys)

assert "(1, 1)" in str(err) # Co-ordinate of the fork
assert "0x00000000" in str(err) # Key that causes the problem
assert "0x0000000f" in str(err) # Mask that causes the problem
assert "(1, 1)" in str(err.value) # Co-ordinate of the fork
assert "0x00000000" in str(err.value) # Key that causes the problem
assert "0x0000000f" in str(err.value) # Mask that causes the problem


def test_build_routing_table_target_lengths():
Expand Down
2 changes: 1 addition & 1 deletion tests/scripts/test_rig_discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ def test_rig_discover(args, should_work, timeout, monkeypatch, capsys):
else:
assert out == ""

assert mock_listen.called_once_with(timeout)
mock_listen.assert_called_once_with(timeout=timeout)
2 changes: 1 addition & 1 deletion tests/test_type_casts.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ class TestNumpyFixToFloat(object):
]
)
def test_standard(self, values, dtype, n_frac, expected_values):
input_array = np.array(values, dtype=dtype)
input_array = np.array(np.array(values), dtype=dtype)

fpf = NumpyFixToFloatConverter(n_frac)
output_array = fpf(input_array)
Expand Down