Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into replace-quantities-…
Browse files Browse the repository at this point in the history
…with-pint
  • Loading branch information
scasagrande committed Oct 15, 2020
2 parents 76eabc3 + 760deb3 commit 2dea5ed
Show file tree
Hide file tree
Showing 7 changed files with 504 additions and 21 deletions.
10 changes: 5 additions & 5 deletions instruments/abstract_instruments/comm/visa_communicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import io

import visa
import pyvisa

from instruments.abstract_instruments.comm import AbstractCommunicator
from instruments.util_fns import assume_units
Expand All @@ -29,13 +29,13 @@ class VisaCommunicator(io.IOBase, AbstractCommunicator):
def __init__(self, conn):
super(VisaCommunicator, self).__init__(self)

if visa is None:
if pyvisa is None:
raise ImportError("PyVISA required for accessing VISA instruments.")

version = int(visa.__version__.replace(".", "").ljust(3, "0"))
version = int(pyvisa.__version__.replace(".", "").ljust(3, "0"))
# pylint: disable=no-member
if (version < 160 and isinstance(conn, visa.Instrument)) or \
(version >= 160 and isinstance(conn, visa.Resource)):
if (version < 160 and isinstance(conn, pyvisa.Instrument)) or \
(version >= 160 and isinstance(conn, pyvisa.Resource)):
self._conn = conn
self._terminator = "\n"
else:
Expand Down
10 changes: 5 additions & 5 deletions instruments/abstract_instruments/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from serial import SerialException
from serial.tools.list_ports import comports
import numpy as np
import visa
import pyvisa
import usb
import usb.core
import usb.util
Expand Down Expand Up @@ -581,16 +581,16 @@ def open_visa(cls, resource_name):
.. _PyVISA: http://pyvisa.sourceforge.net/
"""
if visa is None:
if pyvisa is None:
raise ImportError("PyVISA is required for loading VISA "
"instruments.")
version = list(map(int, visa.__version__.split(".")))
version = list(map(int, pyvisa.__version__.split(".")))
while len(version) < 3:
version += [0]
if version[0] >= 1 and version[1] >= 6:
ins = visa.ResourceManager().open_resource(resource_name)
ins = pyvisa.ResourceManager().open_resource(resource_name)
else:
ins = visa.instrument(resource_name) #pylint: disable=no-member
ins = pyvisa.instrument(resource_name) #pylint: disable=no-member
return cls(VisaCommunicator(ins))

@classmethod
Expand Down
6 changes: 3 additions & 3 deletions instruments/tests/test_base_instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,14 +272,14 @@ def test_instrument_open_gpibusb(mock_serial_manager, mock_gpib_comm):
)


@mock.patch("instruments.abstract_instruments.instrument.visa", new=None)
@mock.patch("instruments.abstract_instruments.instrument.pyvisa", new=None)
def test_instrument_open_visa_import_error():
with pytest.raises(ImportError):
_ = ik.Instrument.open_visa("abc123")


@mock.patch("instruments.abstract_instruments.instrument.VisaCommunicator")
@mock.patch("instruments.abstract_instruments.instrument.visa")
@mock.patch("instruments.abstract_instruments.instrument.pyvisa")
def test_instrument_open_visa_new_version(mock_visa, mock_visa_comm):
mock_visa_comm.return_value.__class__ = VisaCommunicator
mock_visa.__version__ = "1.8"
Expand All @@ -294,7 +294,7 @@ def test_instrument_open_visa_new_version(mock_visa, mock_visa_comm):


@mock.patch("instruments.abstract_instruments.instrument.VisaCommunicator")
@mock.patch("instruments.abstract_instruments.instrument.visa")
@mock.patch("instruments.abstract_instruments.instrument.pyvisa")
def test_instrument_open_visa_old_version(mock_visa, mock_visa_comm):
mock_visa_comm.return_value.__class__ = VisaCommunicator
mock_visa.__version__ = "1.5"
Expand Down
186 changes: 186 additions & 0 deletions instruments/tests/test_thorlabs/test_abstract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Module containing tests for the abstract ThorlabsInstrument class.
"""

# IMPORTS ####################################################################


import struct
import time

import pytest

import instruments as ik
from instruments.thorlabs import _packets
from instruments.tests import expected_protocol


# TESTS ######################################################################


example_packet = _packets.ThorLabsPacket(
message_id=0x0000,
param1=0x00,
param2=0x00,
dest=0x50,
source=0x01,
data=None
)


example_packet_with_data = _packets.ThorLabsPacket(
message_id=0x0000,
param1=None,
param2=None,
dest=0x50,
source=0x01,
data=struct.pack('<HH', 0, 1)
)


# pylint: disable=protected-access


def test_init():
"""Initialize the instrument and set terminator."""
with expected_protocol(
ik.thorlabs._abstract.ThorLabsInstrument,
[
],
[
],
sep=""
) as inst:
assert inst.terminator == ""


def test_send_packet():
"""Send a packet using write_raw."""
with expected_protocol(
ik.thorlabs._abstract.ThorLabsInstrument,
[
example_packet.pack()
],
[
],
sep=""
) as inst:
inst.sendpacket(example_packet)


def test_query_packet(mocker):
"""Query the simple example packet without data.
For simplicity, the query and response packet are the same.
"""
with expected_protocol(
ik.thorlabs._abstract.ThorLabsInstrument,
[
example_packet.pack()
],
[
example_packet.pack()
],
sep=""
) as inst:
read_raw_spy = mocker.spy(inst._file, 'read_raw')
packet_return = inst.querypacket(example_packet)
assert packet_return.message_id == example_packet.message_id
assert packet_return.parameters == example_packet.parameters
assert packet_return.destination == example_packet.destination
assert packet_return.source == example_packet.source
assert packet_return.data == example_packet.data
# assert read_raw is called with proper length
read_raw_spy.assert_called_with(6)


def test_query_packet_with_data(mocker):
"""Query the simple example packet with data."""
data_length = 4
with expected_protocol(
ik.thorlabs._abstract.ThorLabsInstrument,
[
example_packet.pack()
],
[
example_packet_with_data.pack()
],
sep=""
) as inst:
read_raw_spy = mocker.spy(inst._file, 'read_raw')
packet_return = inst.querypacket(example_packet,
expect_data_len=data_length)
assert packet_return.data == example_packet_with_data.data
# assert read_raw is called with proper length
read_raw_spy.assert_called_with(data_length + 6)


def test_query_packet_expect_none_no_respnse():
"""Query a packet but no response, none expected."""
with expected_protocol(
ik.thorlabs._abstract.ThorLabsInstrument,
[
example_packet.pack()
],
[
],
sep=""
) as inst:
assert inst.querypacket(example_packet, expect=None) is None


def test_query_packet_expect_but_no_respnse():
"""Raise IO error when expecting a package but none returned."""
expect = 0x0000
with expected_protocol(
ik.thorlabs._abstract.ThorLabsInstrument,
[
example_packet.pack()
],
[
],
sep=""
) as inst:
with pytest.raises(IOError) as err_info:
inst.querypacket(example_packet, expect=expect)
err_msg = err_info.value.args[0]
assert err_msg == f"Expected packet {expect}, got nothing instead."


def test_query_packet_wrong_package_received():
"""Raise IOError if an unexpected package is received."""
expect = 0x002A
with expected_protocol(
ik.thorlabs._abstract.ThorLabsInstrument,
[
example_packet.pack()
],
[
example_packet.pack()
],
sep=""
) as inst:
with pytest.raises(IOError) as err_info:
inst.querypacket(example_packet, expect=expect)
err_msg = err_info.value.args[0]
assert err_msg == f"APT returned message ID " \
f"{example_packet.message_id}, expected {expect}"


def test_query_packet_no_response_with_timeout(mocker):
"""Query a packet but no response, timeout is set."""
with expected_protocol(
ik.thorlabs._abstract.ThorLabsInstrument,
[
example_packet.pack()
],
[
],
sep=""
) as inst:
time_spy = mocker.spy(time, 'time')
assert inst.querypacket(example_packet, timeout=0) is None
# timeout set to zero, assert `time.time()` called twice
assert time_spy.call_count == 2
Loading

0 comments on commit 2dea5ed

Please sign in to comment.