523 lines
18 KiB
Python
523 lines
18 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Test test the resource name parsing.
|
|
|
|
"""
|
|
import logging
|
|
from dataclasses import dataclass
|
|
|
|
import pytest
|
|
from typing_extensions import ClassVar
|
|
|
|
from pyvisa import constants, errors, rname
|
|
from pyvisa.testsuite import BaseTestCase
|
|
|
|
|
|
class TestInvalidResourceName(BaseTestCase):
|
|
"""Test the creation of InvalidResourceName errors."""
|
|
|
|
def test_bad_syntax(self):
|
|
"""Test creating a bad syntax error."""
|
|
e = rname.InvalidResourceName.bad_syntax("syntax", "resource")
|
|
assert str(e) == "Could not parse 'resource'. The syntax is 'syntax'."
|
|
|
|
e = rname.InvalidResourceName.bad_syntax("syntax", "resource", "ex")
|
|
assert str(e) == "Could not parse 'resource'. The syntax is 'syntax' (ex)."
|
|
|
|
def test_subclass_notfound(self):
|
|
"""Test creating a subclass not found error"""
|
|
e = rname.InvalidResourceName.subclass_notfound("inter")
|
|
assert str(e) == "Parser not found for: inter."
|
|
|
|
e = rname.InvalidResourceName.subclass_notfound("inter", "resource")
|
|
assert str(e) == "Could not parse 'resource'. Parser not found for: inter."
|
|
|
|
def test_rc_notfound(self):
|
|
"""Test creating a resource not found error."""
|
|
e = rname.InvalidResourceName.rc_notfound("inter")
|
|
assert str(e) == "Resource class for inter not provided and default not found."
|
|
|
|
e = rname.InvalidResourceName.rc_notfound("inter", "resource")
|
|
assert str(e) == (
|
|
"Could not parse 'resource'. "
|
|
"Resource class for inter not provided and default not found."
|
|
)
|
|
|
|
|
|
class TestRegisteringSubclass(BaseTestCase):
|
|
"""Test the validation of ResourceName subclass during registration."""
|
|
|
|
def test_handling_duplicate(self):
|
|
"""Test we reject class for existing interface_type and resource class."""
|
|
with pytest.raises(ValueError) as e:
|
|
rname.register_subclass(rname.GPIBInstr)
|
|
assert "Class already registered for" in e.exconly()
|
|
|
|
def test_handling_duplicate_default(self):
|
|
"""Test we enforce the unicity of default resource class per interface."""
|
|
with pytest.raises(ValueError) as e:
|
|
|
|
@dataclass
|
|
class R(rname.ResourceName):
|
|
interface_type: ClassVar[str] = "TCPIP"
|
|
resource_class: ClassVar[str] = "HISLIP"
|
|
is_rc_optional: ClassVar[bool] = True
|
|
|
|
rname.register_subclass(R)
|
|
assert "Default already specified for" in e.exconly()
|
|
|
|
|
|
class TestResourceName(BaseTestCase):
|
|
"""Test error handling in ResourceName.
|
|
|
|
This exercise creating a resource name from parts too which is hence not
|
|
tested explicitely.
|
|
|
|
"""
|
|
|
|
def test_creation_from_string(self):
|
|
"""Test error handling when creating a name from a string."""
|
|
# No interface class registered
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_string("RJ45::1")
|
|
assert "unknown interface type" in e.exconly()
|
|
|
|
# No default resource class registered
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_string("PXI::1")
|
|
assert "not provided and default not found" in e.exconly()
|
|
|
|
# No resource class registered, this cannot really happen...
|
|
try:
|
|
rname._RESOURCE_CLASSES["GPIB"].add("RAW")
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_string("GPIB::1::RAW")
|
|
assert "Parser not found for:" in e.exconly()
|
|
finally:
|
|
rname._RESOURCE_CLASSES["GPIB"].remove("RAW")
|
|
|
|
# Test handling less than required parts
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_string("GPIB")
|
|
assert "not enough parts" in e.exconly()
|
|
|
|
# Test handling more than possible parts
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_string("GPIB1::1::1::1::INSTR")
|
|
assert "too many parts" in e.exconly()
|
|
|
|
# Test handling missing mandatory part
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_string("GPIB::::INSTR")
|
|
assert "The syntax is" in e.exconly()
|
|
|
|
# Test handling no part situation
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_string("ASRL")
|
|
assert "The syntax is" in e.exconly()
|
|
|
|
def test_creation_from_kwargs(self):
|
|
"""Test error handling when creating a name from a kwargs."""
|
|
# No interface class registered
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_kwargs(interface_type="RJ45")
|
|
assert "Unknown interface type:" in e.exconly()
|
|
|
|
# No default resource class registered
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_kwargs(interface_type="PXI", chassis_number="1")
|
|
assert "not provided and default not found" in e.exconly()
|
|
|
|
# No resource class registered
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_kwargs(
|
|
interface_type="GPIB", address=1, resource_class="RAW"
|
|
)
|
|
assert "Parser not found for:" in e.exconly()
|
|
|
|
# Test bad resource from kwargs
|
|
with pytest.raises(rname.InvalidResourceName) as e:
|
|
rname.ResourceName.from_kwargs(
|
|
interface_type="GPIB", resource_class="INSTR"
|
|
)
|
|
assert "required parameter" in e.exconly()
|
|
|
|
# Test assembling from kwargs
|
|
rn = rname.ResourceName.from_kwargs(interface_type="GPIB", primary_address="1")
|
|
assert str(rn) == rname.to_canonical_name("GPIB::1")
|
|
|
|
def test_accessing_interface_type(self):
|
|
"""Test converting the interface to a VISA constant"""
|
|
types = constants.InterfaceType
|
|
for it, itc in zip(
|
|
("ASRL", "USB", "GPIB", "TCPIP", "PXI", "VXI"),
|
|
(types.asrl, types.usb, types.gpib, types.tcpip, types.pxi, types.vxi),
|
|
):
|
|
rn = rname.ResourceName()
|
|
rn.interface_type = it
|
|
assert rn.interface_type_const == itc
|
|
|
|
rn = rname.ResourceName()
|
|
rn.interface_type = "none"
|
|
assert rn.interface_type_const == constants.InterfaceType.unknown
|
|
|
|
|
|
class TestParsers(BaseTestCase):
|
|
def _parse_test(self, rn, **kwargs):
|
|
p = rname.ResourceName.from_string(rn)
|
|
r = dict(
|
|
(k, getattr(p, k)) for k in p._fields + ("interface_type", "resource_class")
|
|
)
|
|
r["canonical_resource_name"] = rname.assemble_canonical_name(**r)
|
|
assert r == kwargs, rn
|
|
|
|
# @unittest.expectedFailure
|
|
# def test_asrl_ethernet(self):
|
|
# self._parse_test('ASRL::1.2.3.4::2::INSTR',
|
|
# interface_type='ASRL',
|
|
# resource_class='INSTR',
|
|
# port='2',
|
|
# address='1.2.3.4')
|
|
|
|
def test_asrl(self):
|
|
self._parse_test(
|
|
"ASRL1::INSTR",
|
|
interface_type="ASRL",
|
|
resource_class="INSTR",
|
|
board="1",
|
|
canonical_resource_name="ASRL1::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"ASRL1",
|
|
interface_type="ASRL",
|
|
resource_class="INSTR",
|
|
board="1",
|
|
canonical_resource_name="ASRL1::INSTR",
|
|
)
|
|
|
|
def test_gpib_instr(self):
|
|
self._parse_test(
|
|
"GPIB::1::1::INSTR",
|
|
interface_type="GPIB",
|
|
resource_class="INSTR",
|
|
board="0",
|
|
primary_address="1",
|
|
secondary_address="1",
|
|
canonical_resource_name="GPIB0::1::1::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"GPIB::1::INSTR",
|
|
interface_type="GPIB",
|
|
resource_class="INSTR",
|
|
board="0",
|
|
primary_address="1",
|
|
secondary_address=None,
|
|
canonical_resource_name="GPIB0::1::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"GPIB1::1::INSTR",
|
|
interface_type="GPIB",
|
|
resource_class="INSTR",
|
|
board="1",
|
|
primary_address="1",
|
|
secondary_address=None,
|
|
canonical_resource_name="GPIB1::1::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"GPIB1::1",
|
|
interface_type="GPIB",
|
|
resource_class="INSTR",
|
|
board="1",
|
|
primary_address="1",
|
|
secondary_address=None,
|
|
canonical_resource_name="GPIB1::1::INSTR",
|
|
)
|
|
|
|
def test_gpib_intf(self):
|
|
self._parse_test(
|
|
"GPIB::INTFC",
|
|
interface_type="GPIB",
|
|
resource_class="INTFC",
|
|
board="0",
|
|
canonical_resource_name="GPIB0::INTFC",
|
|
)
|
|
|
|
self._parse_test(
|
|
"GPIB3::INTFC",
|
|
interface_type="GPIB",
|
|
resource_class="INTFC",
|
|
board="3",
|
|
canonical_resource_name="GPIB3::INTFC",
|
|
)
|
|
|
|
def test_tcpip_intr(self):
|
|
|
|
self._parse_test(
|
|
"TCPIP::192.168.134.102",
|
|
interface_type="TCPIP",
|
|
resource_class="INSTR",
|
|
host_address="192.168.134.102",
|
|
board="0",
|
|
lan_device_name="inst0",
|
|
canonical_resource_name="TCPIP0::192.168.134.102::inst0::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"TCPIP::dev.company.com::INSTR",
|
|
interface_type="TCPIP",
|
|
resource_class="INSTR",
|
|
host_address="dev.company.com",
|
|
board="0",
|
|
lan_device_name="inst0",
|
|
canonical_resource_name="TCPIP0::dev.company.com::inst0::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"TCPIP3::dev.company.com::inst3::INSTR",
|
|
interface_type="TCPIP",
|
|
resource_class="INSTR",
|
|
host_address="dev.company.com",
|
|
board="3",
|
|
lan_device_name="inst3",
|
|
canonical_resource_name="TCPIP3::dev.company.com::inst3::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"TCPIP3::1.2.3.4::inst3::INSTR",
|
|
interface_type="TCPIP",
|
|
resource_class="INSTR",
|
|
host_address="1.2.3.4",
|
|
board="3",
|
|
lan_device_name="inst3",
|
|
canonical_resource_name="TCPIP3::1.2.3.4::inst3::INSTR",
|
|
)
|
|
|
|
def test_tcpip_socket(self):
|
|
self._parse_test(
|
|
"TCPIP::1.2.3.4::999::SOCKET",
|
|
interface_type="TCPIP",
|
|
resource_class="SOCKET",
|
|
host_address="1.2.3.4",
|
|
board="0",
|
|
port="999",
|
|
canonical_resource_name="TCPIP0::1.2.3.4::999::SOCKET",
|
|
)
|
|
|
|
self._parse_test(
|
|
"TCPIP2::1.2.3.4::999::SOCKET",
|
|
interface_type="TCPIP",
|
|
resource_class="SOCKET",
|
|
host_address="1.2.3.4",
|
|
board="2",
|
|
port="999",
|
|
canonical_resource_name="TCPIP2::1.2.3.4::999::SOCKET",
|
|
)
|
|
|
|
def test_usb_instr(self):
|
|
self._parse_test(
|
|
"USB::0x1234::125::A22-5::INSTR",
|
|
interface_type="USB",
|
|
resource_class="INSTR",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="0",
|
|
usb_interface_number="0",
|
|
canonical_resource_name="USB0::0x1234::125::A22-5::0::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"USB2::0x1234::125::A22-5::INSTR",
|
|
interface_type="USB",
|
|
resource_class="INSTR",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="2",
|
|
usb_interface_number="0",
|
|
canonical_resource_name="USB2::0x1234::125::A22-5::0::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"USB::0x1234::125::A22-5",
|
|
interface_type="USB",
|
|
resource_class="INSTR",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="0",
|
|
usb_interface_number="0",
|
|
canonical_resource_name="USB0::0x1234::125::A22-5::0::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"USB::0x1234::125::A22-5::3::INSTR",
|
|
interface_type="USB",
|
|
resource_class="INSTR",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="0",
|
|
usb_interface_number="3",
|
|
canonical_resource_name="USB0::0x1234::125::A22-5::3::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"USB2::0x1234::125::A22-5::3::INSTR",
|
|
interface_type="USB",
|
|
resource_class="INSTR",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="2",
|
|
usb_interface_number="3",
|
|
canonical_resource_name="USB2::0x1234::125::A22-5::3::INSTR",
|
|
)
|
|
|
|
self._parse_test(
|
|
"USB1::0x1234::125::A22-5::3",
|
|
interface_type="USB",
|
|
resource_class="INSTR",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="1",
|
|
usb_interface_number="3",
|
|
canonical_resource_name="USB1::0x1234::125::A22-5::3::INSTR",
|
|
)
|
|
|
|
def test_usb_raw(self):
|
|
self._parse_test(
|
|
"USB::0x1234::125::A22-5::RAW",
|
|
interface_type="USB",
|
|
resource_class="RAW",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="0",
|
|
usb_interface_number="0",
|
|
canonical_resource_name="USB0::0x1234::125::A22-5::0::RAW",
|
|
)
|
|
|
|
self._parse_test(
|
|
"USB2::0x1234::125::A22-5::RAW",
|
|
interface_type="USB",
|
|
resource_class="RAW",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="2",
|
|
usb_interface_number="0",
|
|
canonical_resource_name="USB2::0x1234::125::A22-5::0::RAW",
|
|
)
|
|
|
|
self._parse_test(
|
|
"USB2::0x1234::125::A22-5::3::RAW",
|
|
interface_type="USB",
|
|
resource_class="RAW",
|
|
manufacturer_id="0x1234",
|
|
model_code="125",
|
|
serial_number="A22-5",
|
|
board="2",
|
|
usb_interface_number="3",
|
|
canonical_resource_name="USB2::0x1234::125::A22-5::3::RAW",
|
|
)
|
|
|
|
|
|
class TestFilters(BaseTestCase):
|
|
|
|
CHECK_NO_WARNING = False
|
|
|
|
run_list = (
|
|
"GPIB0::8::INSTR",
|
|
"TCPIP0::localhost:1111::inst0::INSTR",
|
|
"ASRL1::INSTR",
|
|
"USB1::0x1111::0x2222::0x4445::0::RAW",
|
|
"USB0::0x1112::0x2223::0x1234::0::INSTR",
|
|
"TCPIP0::192.168.0.1::inst1::INSTR",
|
|
"TCPIP0::localhost::10001::SOCKET",
|
|
"GPIB9::7::1::INSTR",
|
|
"ASRL11::INSTR",
|
|
"ASRL2::INSTR",
|
|
"GPIB::INTFC",
|
|
"PXI::1::BACKPLANE",
|
|
"PXI::MEMACC",
|
|
"VXI::1::BACKPLANE", # should work without the one
|
|
"VXI::1::INSTR",
|
|
"VXI::SERVANT",
|
|
)
|
|
|
|
def _test_filter(self, expr, *correct):
|
|
ok = tuple(self.run_list[n] for n in correct)
|
|
assert rname.filter(self.run_list, expr) == ok
|
|
|
|
def _test_filter2(self, expr, *correct):
|
|
class MockedResource(object):
|
|
def get_visa_attribute(self, attr):
|
|
if attr == "VI_test":
|
|
return 1
|
|
else:
|
|
raise ValueError()
|
|
|
|
def close(self):
|
|
pass
|
|
|
|
ok = tuple(self.run_list[n] for n in correct)
|
|
filtered = rname.filter2(self.run_list, expr, lambda x: MockedResource())
|
|
assert filtered == ok
|
|
|
|
def test_filter(self, caplog):
|
|
self._test_filter("?*::INSTR", 0, 1, 2, 4, 5, 7, 8, 9, 14)
|
|
self._test_filter("GPIB?+INSTR", 0, 7)
|
|
self._test_filter("GPIB[0-8]*::?*INSTR", 0)
|
|
self._test_filter("GPIB[^0]::?*INSTR", 7)
|
|
self._test_filter("ASRL1+::INSTR", 2, 8)
|
|
self._test_filter("(GPIB|VXI)?*INSTR", 0, 7, 14)
|
|
with caplog.at_level(logging.DEBUG):
|
|
self._test_filter("?*{}", *tuple(range(len(self.run_list))))
|
|
assert (
|
|
"optional part of the query expression not supported."
|
|
in caplog.records[0].message
|
|
)
|
|
# Not sure why this is needed
|
|
self._test_handler = None
|
|
|
|
def test_filter2_no_optional_clause(self):
|
|
self._test_filter2("?*::INSTR", 0, 1, 2, 4, 5, 7, 8, 9, 14)
|
|
self._test_filter2("GPIB?+INSTR", 0, 7)
|
|
self._test_filter2("GPIB[0-8]*::?*INSTR", 0)
|
|
self._test_filter2("GPIB[^0]::?*INSTR", 7)
|
|
self._test_filter2("ASRL1+::INSTR", 2, 8)
|
|
self._test_filter2("(GPIB|VXI)?*INSTR", 0, 7, 14)
|
|
|
|
def test_filter2_optional_clause_no_connection(self):
|
|
self._test_filter2("?*::INSTR{!(VI_ATTR_INTF_NUM == 0)}", 2, 7, 8, 9)
|
|
self._test_filter2('?*{VI_ATTR_MANF_ID == "0x1111"}', 3)
|
|
self._test_filter2('?*{VI_ATTR_MODEL_CODE == "0x2223"}', 4)
|
|
self._test_filter2('?*{VI_ATTR_USB_SERIAL_NUM == "0x1234"}', 4)
|
|
self._test_filter2("?*{VI_ATTR_USB_INTFC_NUM == 0}", 4)
|
|
self._test_filter2('?*{VI_ATTR_TCPIP_ADDR == "localhost"}', 6)
|
|
self._test_filter2('?*{VI_ATTR_TCPIP_DEVICE_NAME == "inst1"}', 5)
|
|
self._test_filter2("?*{VI_ATTR_TCPIP_PORT == 10001}", 6)
|
|
self._test_filter2("?*{VI_ATTR_GPIB_PRIMARY_ADDR == 8}", 0)
|
|
self._test_filter2("?*{VI_ATTR_GPIB_SECONDARY_ADDR == 1}", 7)
|
|
self._test_filter2(
|
|
"?*{VI_ATTR_GPIB_SECONDARY_ADDR == %d}" % constants.VI_NO_SEC_ADDR, 0
|
|
)
|
|
self._test_filter2("?*{VI_ATTR_PXI_CHASSIS == 1}", 11)
|
|
self._test_filter2("?*{VI_ATTR_MAINFRAME_LA == 1}", 13, 14)
|
|
self._test_filter2("?*{VI_ATTR_MAINFRAME_LA == 1 && VI_test == 1}", 13, 14)
|
|
|
|
def test_bad_filter(self):
|
|
with pytest.raises(errors.VisaIOError) as e:
|
|
rname.filter([], "?*(")
|
|
assert "VI_ERROR_INV_EXPR" in e.exconly()
|
|
|
|
def test_bad_filter2(self):
|
|
with pytest.raises(errors.VisaIOError) as e:
|
|
rname.filter2([], "?*{", lambda x: None)
|
|
assert "VI_ERROR_INV_EXPR" in e.exconly()
|