pyvisa/pyvisa-py

list_resources fails when avahi-daemon and zeroconf are both installed

eliotb opened this issue · 2 comments

ResourceManager.list_resources() fails with an unhandled exception when avahi-daemon and zeroconf are both installed.

avahi-daemon is part of the OS install that provides mDNS services for e.g. network printer discovery.
pip installed zeroconf is required for hislip instrument discovery.

Here is a small example showing the traceback and error. This is executed in a venv with pyvisa, pyvisa-py, and zeroconf installed.

python -c "import pyvisa; rm=pyvisa.ResourceManager('@py'); rl=rm.list_resources()"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/eliot/tmp/.venv/lib/python3.10/site-packages/pyvisa/highlevel.py", line 3129, in list_resources
    return self.visalib.list_resources(self.session, query)
  File "/home/eliot/tmp/.venv/lib/python3.10/site-packages/pyvisa_py/highlevel.py", line 486, in list_resources
    resources += st.list_resources()
  File "/home/eliot/tmp/.venv/lib/python3.10/site-packages/pyvisa_py/tcpip.py", line 89, in list_resources
    return TCPIPInstrVxi11.list_resources() + TCPIPInstrHiSLIP.list_resources()
  File "/home/eliot/tmp/.venv/lib/python3.10/site-packages/pyvisa_py/tcpip.py", line 118, in list_resources
    for host in get_services("_hislip._tcp.local.", wait_time=wait_time):
  File "/home/eliot/tmp/.venv/lib/python3.10/site-packages/pyvisa_py/tcpip.py", line 1426, in get_services
    zero_conf = zeroconf.Zeroconf()
  File "/home/eliot/tmp/.venv/lib/python3.10/site-packages/zeroconf/_core.py", line 492, in __init__
    listen_socket, respond_sockets = create_sockets(interfaces, unicast, ip_version, apple_p2p=apple_p2p)
  File "/home/eliot/tmp/.venv/lib/python3.10/site-packages/zeroconf/_utils/net.py", line 358, in create_sockets
    listen_socket = new_socket(ip_version=ip_version, apple_p2p=apple_p2p, bind_addr=('',))
  File "/home/eliot/tmp/.venv/lib/python3.10/site-packages/zeroconf/_utils/net.py", line 248, in new_socket
    s.bind(bind_tup)
OSError: [Errno 98] Address already in use

Workarounds

? Potentially a FAQ entry ?

  1. Do not install zeroconf. This will result in a warning, but no exception. ?not an option if you need hislip discovery using zeroconf?
❯ python -c "import pyvisa; rm=pyvisa.ResourceManager('@py'); rl=rm.list_resources()"
/home/eliot/tmp/.venv/lib/python3.10/site-packages/pyvisa_py/tcpip.py:121: UserWarning: TCPIP::hislip resource discovery requires the zeroconf package to be installed... try 'pip install zeroconf'
  warnings.warn(
  1. Change the configuration of avahi-daemon to allow coexistence with python zeroconf

Edit /etc/avahi/avahi-daemon.conf and add/uncomment line

disallow-other-stacks=no

then restart the daemon: systemctl restart avahi-daemon.service

This comes with a warning in the manpage:

disallow-other-stacks= Takes a boolean value ("yes" or "no"). If set to "yes" no other process is allowed to bind to UDP port 5353. This effectively impedes other mDNS stacks from running on the host. Use this as a security measure to make sure that only Avahi is responsible for mDNS traffic. Please note that we do not recommend running multiple mDNS stacks on the same host simultaneously. This hampers reliability and is a waste of resources. However, to not annoy people this option defaults to "no".
(? Ubuntu sets this to yes ?)

  1. In future? : Use the avahi-daemon instead of requiring the python zeroconf module for device discovery

Output of pyvisa-info

Machine Details:
   Platform ID:    Linux-5.19.0-1025-lowlatency-x86_64-with-glibc2.35
   Processor:      x86_64

Python:
   Implementation: CPython
   Executable:     /home/eliot/tmp/.venv/bin/python
   Version:        3.10.6
   Compiler:       GCC 11.3.0
   Bits:           64bit
   Build:          Mar 10 2023 10:55:28 (#main)
   Unicode:        UCS4

PyVISA Version: 1.13.0

Backends:
   ivi:
      Version: 1.13.0 (bundled with PyVISA)
      Binary library: Not found
   py:
      Version: 0.7.0
      ASRL INSTR: Available via PySerial (3.5)
      USB INSTR: Available via PyUSB (1.2.1). Backend: libusb1
      USB RAW: Available via PyUSB (1.2.1). Backend: libusb1
      TCPIP INSTR: Available 
         Resource discovery:
         - VXI-11: ok
         - hislip: ok
      TCPIP SOCKET: Available 
      VICP INSTR:
         Please install PyVICP to use this resource type.
      GPIB INSTR:
         Please install linux-gpib (Linux) or gpib-ctypes (Windows, Linux) to use this resource type. Note that installing gpib-ctypes will give you access to a broader range of functionalities.
         No module named 'gpib'
      GPIB INTFC:
         Please install linux-gpib (Linux) or gpib-ctypes (Windows, Linux) to use this resource type. Note that installing gpib-ctypes will give you access to a broader range of functionalities.
         No module named 'gpib'

In future? : Use the avahi-daemon instead of requiring the python zeroconf module for device discovery

This is not a portable solution. Aside from that, it'd likely require using their dbus API, which I am not looking forward to.

(? Ubuntu sets this to yes ?)

Correct, since 2007. I can't conveniently check the actual config that ships with e.g. arch or fedora, but I don't see them changing it in this area.

FWIW reading python-zeroconf/python-zeroconf#967 I noticed we might be failing to bind (and just silently moving on) in some cases already — e.g. on macos. I will try to remember and verify this next week.

So far, I think this might warrant a note in the FAQ to fix avahi config, but nothing beyond that.

As well as a FAQ entry, I think the OSError should be caught and a warning logged instead of crashing.
In my case I only had a USB device connected but I couldn't list_resources to start working with it.