# -*- 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()