Skip to content

Commit 38338ae

Browse files
committed
Checkout dialout membership before udev rule
1 parent cb723a8 commit 38338ae

File tree

4 files changed

+26
-16
lines changed

4 files changed

+26
-16
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pslab-python can be installed from PyPI:
2525

2626
$ pip install pslab
2727

28-
**Note**: Linux users must additionally install a udev rules file for pslab-python to be able to communicate with the PSLab device. The file [99-pslab.rules](https://github.com/fossasia/pslab-python/blob/development/99-pslab.rules) should be copied to /etc/udev/rules.d/.
28+
**Note**: Linux users must either install a udev rule by running 'pslab install' as root, or be part of the 'dialout' group in order for pslab-python to be able to communicate with the PSLab device.
2929

3030
**Note**: If you are only interested in using PSLab as an acquisition device without a display/GUI, only pslab-python needs to be installed. If you would like a GUI, install the [pslab-desktop app](https://github.com/fossasia/pslab-desktop) and follow the instructions of the Readme in that repo.
3131

pslab/cli.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ def install(args: argparse.Namespace):
481481
return
482482
else:
483483
try:
484-
SerialHandler.check_udev()
484+
SerialHandler.check_serial_access_permission()
485485
except OSError:
486486
_install()
487487
return
@@ -490,7 +490,7 @@ def install(args: argparse.Namespace):
490490
_install()
491491
return
492492

493-
print("udev rule already installed.")
493+
print("User is in dialout group or udev rule is already installed.")
494494

495495

496496
def _install():
@@ -514,5 +514,5 @@ def add_install_args(subparser: argparse._SubParsersAction):
514514
"--force",
515515
action="store_true",
516516
default=False,
517-
help="Overwrite existing udev rules.",
517+
help="Overwrite existing udev rule.",
518518
)

pslab/serial_handler.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
>>> version = device.get_version()
88
>>> device.disconnect()
99
"""
10+
import grp
1011
import logging
11-
import os.path
12+
import os
1213
import platform
1314
import struct
1415
import time
@@ -80,7 +81,7 @@ def __init__(
8081
baudrate: int = 1000000,
8182
timeout: float = 1.0,
8283
):
83-
self.check_udev()
84+
self.check_serial_access_permission()
8485
self.version = ""
8586
self._log = b""
8687
self._logging = False
@@ -99,9 +100,13 @@ def __init__(
99100
self.connected = self.interface.is_open
100101

101102
@staticmethod
102-
def check_udev():
103-
"""Check if udev rule is installed on Linux."""
103+
def check_serial_access_permission():
104+
"""Check that we have permission to use the tty on Linux."""
104105
if platform.system() == "Linux":
106+
for group in os.getgroups():
107+
if grp.getgrgid(group).gr_name == "dialout":
108+
return
109+
105110
udev_paths = [
106111
"/run/udev/rules.d/",
107112
"/etc/udev/rules.d/",
@@ -113,8 +118,13 @@ def check_udev():
113118
break
114119
else:
115120
raise OSError(
116-
"A udev rule must be installed to access the PSLab. "
117-
"Please run 'pslab install' as root, or copy "
121+
"You are not a member of the dialout group and therefore "
122+
"do not have permission to talk to serial devices. Please "
123+
"add the current user to the dialout group. After logging "
124+
"out and then logging back in you will be able to access "
125+
"the PSLab.\n"
126+
"Alternativelly, a udev rule can be installed by running "
127+
"'pslab install' as root, or by copying "
118128
f"{pslab.__path__[0]}/99-pslab.rules to {udev_paths[1]}."
119129
)
120130

@@ -403,8 +413,8 @@ def __init__(
403413
super().__init__(port, baudrate, timeout)
404414

405415
@staticmethod
406-
def check_udev():
407-
"""See :meth:`SerialHandler.check_udev`."""
416+
def check_serial_access_permission():
417+
"""See :meth:`SerialHandler.check_serial_access_permission`."""
408418
pass
409419

410420
def connect(

tests/test_serial_handler.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def mock_serial(mocker):
3030

3131
@pytest.fixture
3232
def mock_handler(mocker, mock_serial, mock_list_ports):
33-
mocker.patch("pslab.serial_handler.SerialHandler.check_udev")
33+
mocker.patch("pslab.serial_handler.SerialHandler.check_serial_access_permission")
3434
mock_list_ports.grep.return_value = mock_ListPortInfo()
3535
return SerialHandler()
3636

@@ -47,21 +47,21 @@ def test_detect(mocker, mock_serial, mock_list_ports):
4747

4848
def test_connect_scan_port(mocker, mock_serial, mock_list_ports):
4949
mock_list_ports.grep.return_value = mock_ListPortInfo()
50-
mocker.patch("pslab.serial_handler.SerialHandler.check_udev")
50+
mocker.patch("pslab.serial_handler.SerialHandler.check_serial_access_permission")
5151
SerialHandler()
5252
mock_serial().open.assert_called()
5353

5454

5555
def test_connect_scan_failure(mocker, mock_serial, mock_list_ports):
5656
mock_list_ports.grep.return_value = mock_ListPortInfo(found=False)
57-
mocker.patch("pslab.serial_handler.SerialHandler.check_udev")
57+
mocker.patch("pslab.serial_handler.SerialHandler.check_serial_access_permission")
5858
with pytest.raises(SerialException):
5959
SerialHandler()
6060

6161

6262
def test_connect_multiple_connected(mocker, mock_serial, mock_list_ports):
6363
mock_list_ports.grep.return_value = mock_ListPortInfo(multiple=True)
64-
mocker.patch("pslab.serial_handler.SerialHandler.check_udev")
64+
mocker.patch("pslab.serial_handler.SerialHandler.check_serial_access_permission")
6565
with pytest.raises(RuntimeError):
6666
SerialHandler()
6767

0 commit comments

Comments
 (0)