Skip to content

Commit

Permalink
Fix up port sorting for strange windows ports
Browse files Browse the repository at this point in the history
After the previous change, if any  port string ends up without a COMn
port label we would compare an int to a str while sorting and break.
Fix this up by sorting the devices themselves so we can do a better
job and then format the label after.

Also log all the ports we get from the manifest for better forensics.

Fixes #11032
  • Loading branch information
kk7ds committed Dec 22, 2023
1 parent f83662b commit f4e468c
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 8 deletions.
21 changes: 13 additions & 8 deletions chirp/wxui/clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,16 @@ def port_label(port):


def port_sort_key(port):
_dev, label = port
m = re.match('^COM([0-9]+):.*', label)
if m:
return int(m.group(1))
else:
return label
key = port.device
if platform.system() == 'Windows':
try:
m = re.match('^COM([0-9]+)$', port.device)
if m:
key = 'COM%08i' % int(m.group(1))
except Exception as e:
LOG.warning('Failed to stable format %s: %s', port.device, e)

return key


# Make this global so it sticks for a session
Expand Down Expand Up @@ -322,10 +326,11 @@ def set_ports(self, system_ports=None, select=None):
'/dev/cu.Bluetooth-Incoming-Port',
]

LOG.debug('All system ports: %s', [x.__dict__ for x in system_ports])
self.ports = [(port.device, port_label(port))
for port in system_ports
for port in sorted(system_ports,
key=port_sort_key)
if port.device not in filter_ports]
self.ports.sort(key=port_sort_key)

favorite_ports = CONF.get('favorite_ports', 'state') or ''
for port in favorite_ports.split(','):
Expand Down
46 changes: 46 additions & 0 deletions tests/unit/test_wxui_radiothread.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
from unittest import mock

sys.modules['wx'] = wx = mock.MagicMock()
sys.modules['wx.lib'] = mock.MagicMock()
sys.modules['wx.lib.scrolledpanel'] = mock.MagicMock()
sys.modules['wx.lib.sized_controls'] = mock.MagicMock()
sys.modules['wx.richtext'] = mock.MagicMock()
wx.lib.newevent.NewCommandEvent.return_value = None, None
sys.modules['chirp.wxui.developer'] = mock.MagicMock()

# These need to be imported after the above mock so that we don't require
# wx to be present for these tests
from tests.unit import base # noqa
from chirp.wxui import clone # noqa
from chirp.wxui import radiothread # noqa


Expand Down Expand Up @@ -105,3 +112,42 @@ def test_thread_abort_priority(self):
radio.set_memory.assert_not_called()
radio.get_features.assert_not_called()
wx.PostEvent.assert_not_called()


class TestClone(base.BaseTest):
@mock.patch('platform.system', return_value='Linux')
def test_sort_ports_unix(self, system):
ports = [
mock.MagicMock(device='/dev/cu.zed',
description='My Zed'),
mock.MagicMock(device='/dev/cu.abc',
description='Some device'),
mock.MagicMock(device='/dev/cu.serial',
description='')
]
self.assertEqual(
['Some device (cu.abc)',
'cu.serial',
'My Zed (cu.zed)'],
[clone.port_label(p)
for p in sorted(ports, key=clone.port_sort_key)])

@mock.patch('platform.system', return_value='Windows')
def test_sort_ports_windows(self, system):
ports = [
mock.MagicMock(device='COM7',
description='Some serial device'),
mock.MagicMock(device='COM17',
description='Some other device'),
mock.MagicMock(device='CNC0',
description='Some weird device'),
mock.MagicMock(device='COM4',
description=''),
]
self.assertEqual(
['CNC0: Some weird device',
'COM4',
'COM7: Some serial device',
'COM17: Some other device'],
[clone.port_label(p)
for p in sorted(ports, key=clone.port_sort_key)])

0 comments on commit f4e468c

Please sign in to comment.