From 544b01fe3e205b8a9cd690e2c1bd3e98af4bc514 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 4 Sep 2024 15:25:46 -0700 Subject: [PATCH 1/4] csv: Allow quoted header names Some software that spits out CSV may just quote everything, even when not needed. Doing that prevents us from recognizing the header and thus makes us think a file isn't in a known format. Fixes: #11519 --- chirp/drivers/generic_csv.py | 4 +++- tests/unit/test_csv.py | 29 ++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/chirp/drivers/generic_csv.py b/chirp/drivers/generic_csv.py index 827506529..c23421778 100644 --- a/chirp/drivers/generic_csv.py +++ b/chirp/drivers/generic_csv.py @@ -348,7 +348,9 @@ def find_csv_header(filedata): filedata = filedata[1:] while filedata.startswith('#'): filedata = filedata[filedata.find('\n') + 1:] - return filedata.startswith('Location,') + delims = ['', '"', "'"] + return any([filedata.startswith('%sLocation%s,' % (d, d)) + for d in delims]) @directory.register diff --git a/tests/unit/test_csv.py b/tests/unit/test_csv.py index 4f1980ba1..60ee8cc56 100644 --- a/tests/unit/test_csv.py +++ b/tests/unit/test_csv.py @@ -23,6 +23,11 @@ 0,Nat Simplex,146.520000,,0.600000,TSQL,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,This is the national calling frequency on 2m,,,, 1,National Simp,446.000000,-,5.000000,DTCS,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,5.0W,This is NOT the UHF calling frequency,,,, """) # noqa +CHIRP_CSV_MODERN_QUOTED_HEADER = ( + """"Location","Name","Frequency","Duplex","Offset","Tone","rToneFreq","cToneFreq","DtcsCode","DtcsPolarity","RxDtcsCode","CrossMode","Mode","TStep","Skip","Power","Comment","URCALL","RPT1CALL","RPT2CALL","DVCODE" +0,Nat Simplex,146.520000,,0.600000,TSQL,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,This is the national calling frequency on 2m,,,, +1,"National Simp",446.000000,-,5.000000,DTCS,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,5.0W,This is NOT the UHF calling frequency,,,, +""") # noqa class TestCSV(unittest.TestCase): @@ -55,9 +60,9 @@ def test_parse_legacy(self): self.assertEqual('NFM', mem.mode) self.assertEqual(12.5, mem.tuning_step) - def test_parse_modern(self, output_encoding='utf-8'): + def test_parse_modern(self, output_encoding='utf-8', data=None): with open(self.testfn, 'w', encoding=output_encoding) as f: - f.write(CHIRP_CSV_MODERN) + f.write(data or CHIRP_CSV_MODERN) # Make sure we detect the file with open(self.testfn, 'rb') as f: self.assertTrue(generic_csv.CSVRadio.match_model( @@ -79,8 +84,8 @@ def test_parse_modern(self, output_encoding='utf-8'): self.assertEqual('5.0W', str(mem.power)) self.assertIn('UHF calling', mem.comment) - def test_csv_with_comments(self, output_encoding='utf-8'): - lines = list(CHIRP_CSV_MODERN.strip().split('\n')) + def _test_csv_with_comments(self, data, output_encoding='utf-8'): + lines = list(data.strip().split('\n')) lines.insert(0, '# This is a comment') lines.insert(0, '# Test file with comments') lines.insert(4, '# Test comment in the middle') @@ -99,7 +104,21 @@ def test_csv_with_comments(self, output_encoding='utf-8'): csv.save(self.testfn) with open(self.testfn, 'r') as f: read_lines = [x.strip() for x in f.readlines()] - self.assertEqual(lines, read_lines) + # Ignore quotes + self.assertEqual([x.replace('"', '') for x in lines], read_lines) + + def test_csv_with_comments(self): + self._test_csv_with_comments(CHIRP_CSV_MODERN) + + def test_csv_with_comments_quoted_header(self): + self._test_csv_with_comments(CHIRP_CSV_MODERN_QUOTED_HEADER) + + def test_parse_modern_quoted_header(self): + self.test_parse_modern(data=CHIRP_CSV_MODERN_QUOTED_HEADER) + + def test_parse_modern_quoted_header_bom(self): + self.test_parse_modern(output_encoding='utf-8-sig', + data=CHIRP_CSV_MODERN_QUOTED_HEADER) def test_parse_modern_bom(self): self.test_parse_modern(output_encoding='utf-8-sig') From e993b4924bb21e25058a7418ba924019ab2b9627 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 4 Sep 2024 15:27:28 -0700 Subject: [PATCH 2/4] csv: Fall back to GenericCSV for csv files with no match If we fail to find a matching driver and the file appears to be a ".csv" file, return GenericCSV as a match. This will make us try to open the file with the generic driver and thus capture loading error messages and show them to the user. Otherwise we would just fail to match a driver, and report the format is unsupported, which is confusing to a user. Related to #11519 --- chirp/directory.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chirp/directory.py b/chirp/directory.py index 2e0695fe7..0c029ee9e 100644 --- a/chirp/directory.py +++ b/chirp/directory.py @@ -193,6 +193,12 @@ def __repr__(self): ex.metadata = metadata raise ex else: + # If we don't find anything else and the file appears to be a CSV + # file, then explicitly open it with the generic driver so we can + # get relevant errors instead of just "Unknown file format". + if image_file.lower().endswith('.csv'): + rclass = get_radio('Generic_CSV') + return rclass(image_file) raise errors.ImageDetectFailed("Unknown file format") From 872227c122990def4ba16ca0c0e34d53507d06dd Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 4 Sep 2024 15:29:29 -0700 Subject: [PATCH 3/4] csv: Report unknown header fields In order to help make more sense of why a CSV file isn't open-able, we should log any headers we don't recognize so the user will see them. Note that the test csv file in tests/images is from a billion years ago, when we apparently had bank info as a column. With this, the test that asserts we load CSV files with no errors fails on our own sample file (!). Related to #11519 --- chirp/drivers/generic_csv.py | 4 + tests/images/Generic_CSV.csv | 200 +++++++++++++++++------------------ 2 files changed, 100 insertions(+), 104 deletions(-) diff --git a/chirp/drivers/generic_csv.py b/chirp/drivers/generic_csv.py index c23421778..e19e4f865 100644 --- a/chirp/drivers/generic_csv.py +++ b/chirp/drivers/generic_csv.py @@ -218,6 +218,10 @@ def _load(self, f): lineno += 1 if lineno == 1: header = line + for field in header: + # Log unknown header names for the UI to capture and expose + if field not in chirp_common.Memory.CSV_FORMAT: + LOG.error('Header line has unknown field %r' % field) self.file_has_rTone = "rToneFreq" in header self.file_has_cTone = "cToneFreq" in header continue diff --git a/tests/images/Generic_CSV.csv b/tests/images/Generic_CSV.csv index e50f849e8..a595c0689 100644 --- a/tests/images/Generic_CSV.csv +++ b/tests/images/Generic_CSV.csv @@ -1,104 +1,96 @@ -Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Bank,Bank Index,URCALL,RPT1CALL,RPT2CALL -25,H-TAC1,443.100000,+,5.000000,DTCS,88.5,88.5,032,NN,FM,5.00,,,-1,,,, -26,H-TAC2,147.380000,+,0.600000,Tone,100.0,100.0,023,NN,FM,5.00,,,-1,,,, -27,H-TAC3,147.440000,,0.600000,Tone,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -28,H-TAC4,441.550000,+,5.000000,Tone,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -29,H-TAC5,442.925000,+,5.000000,Tone,107.2,107.2,023,NN,FM,5.00,,,-1,,,, -30,H-TAC6,443.350000,+,5.000000,Tone,156.7,156.7,023,NN,FM,5.00,,,-1,,,, -31,H-TAC7,442.825000,+,5.000000,,110.9,110.9,023,NN,FM,5.00,,,-1,,,, -50,ARESD1,147.320000,+,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -51,WAPRIR,146.900000,-,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -52,WAPRIS,147.400000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -53,WASECR,440.350000,+,5.000000,TSQL,127.3,127.3,023,NN,FM,5.00,,,-1,,,, -54,OEMNCS,145.330000,-,0.600000,Tone,186.2,186.2,023,NN,FM,5.00,,,-1,,,, -55,HEARTN,145.230000,-,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -56,CLACK,147.120000,+,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -57,CLATSP,146.660000,-,0.600000,Tone,118.8,118.8,023,NN,FM,5.00,,,-1,,,, -58,COLUMB,146.880000,-,0.600000,Tone,114.8,114.8,023,NN,FM,5.00,,,-1,,,, -59,TMOOK1,147.220000,+,0.600000,Tone,100.0,100.0,023,NN,FM,5.00,,,-1,,,, -60,TMOOK2,147.160000,+,0.600000,Tone,118.8,118.8,023,NN,FM,5.00,,,-1,,,, -61,TMOOK3,440.175000,+,5.000000,Tone,100.0,100.0,023,NN,FM,5.00,,,-1,,,, -62,TMOOK4,441.250000,+,5.000000,Tone,118.8,118.8,023,NN,FM,5.00,,,-1,,,, -63,MULTNM,146.840000,-,0.600000,Tone,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -64,CLARK,147.240000,+,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -65,ARC,146.980000,-,0.600000,Tone,123.0,123.0,023,NN,FM,5.00,,,-1,,,, -66,VERNIA,145.250000,-,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -80,WX1,162.400000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -81,WX2,162.425000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -82,WX3,162.450000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -83,WX4,162.475000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -84,WX5,162.500000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -85,WX6,162.525000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -86,WX7,162.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -88,CTAF,119.300000,,0.600000,,88.5,88.5,023,NN,AM,5.00,,,-1,,,, -89,ATIS,127.650000,,0.600000,,88.5,88.5,023,NN,AM,5.00,,,-1,,,, -90,GROUND,121.700000,,0.600000,,88.5,88.5,023,NN,AM,5.00,,,-1,,,, -91,TOWER,119.300000,,0.600000,,88.5,88.5,023,NN,AM,5.00,,,-1,,,, -92,UNICOM,122.950000,,0.600000,,88.5,88.5,023,NN,AM,5.00,,,-1,,,, -93,ACARS,131.550000,,0.600000,,88.5,88.5,023,NN,AM,5.00,,,-1,,,, -100,ICALL,851.012500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -101,ITAC1,851.512500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -102,ITAC2,852.012500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -103,ITAC3,852.512500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -104,ITAC4,853.012500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -105,OROPS1,851.325000,,0.600000,TSQL,88.5,156.7,023,NN,FM,10.00,,,-1,,,, -106,OROPS2,851.387500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -107,OROPS3,851.750000,,0.600000,TSQL,88.5,156.7,023,NN,FM,10.00,,,-1,,,, -108,OROPS4,851.775000,,0.600000,TSQL,88.5,156.7,023,NN,FM,10.00,,,-1,,,, -109,OROPS5,851.800000,,0.600000,TSQL,88.5,156.7,023,NN,FM,10.00,,,-1,,,, -110,WAOPS1,852.537500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -111,WAOPS2,852.562500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -112,WAOPS3,852.587500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -113,WAOPS4,852.612500,,0.600000,TSQL,88.5,156.7,023,NN,FM,10.00,,,-1,,,, -114,WAOPS5,852.637500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -115,UCAL40,453.212500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -116,UTAC41,453.462500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -117,UTAC42,453.712500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -118,UTAC43,453.862500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -119,ISIMP1,853.437500,,0.600000,DTCS,88.5,88.5,074,NN,FM,12.50,,,-1,,,, -120,ISIMP2,851.037500,,0.600000,DTCS,88.5,88.5,114,NN,FM,12.50,,,-1,,,, -121,ISIMP3,851.950000,,0.600000,DTCS,88.5,88.5,131,NN,FM,10.00,,,-1,,,, -122,ISIMP4,851.175000,,0.600000,DTCS,88.5,88.5,023,NN,FM,10.00,,,-1,,,, -123,MAYDAY,853.387500,,0.600000,DTCS,88.5,88.5,025,NN,FM,12.50,,,-1,,,, -124,VCALL,155.750000,,0.600000,TSQL,88.5,156.7,023,NN,FM,5.00,,,-1,,,, -125,VTAC11,151.137500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -126,VTAC12,154.452500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -127,VTAC13,158.737500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -128,VTAC14,159.472500,,0.600000,TSQL,88.5,156.7,023,NN,FM,12.50,,,-1,,,, -129,WCCCA1,860.737500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -130,WCCCA2,860.237500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -131,WCCCA3,859.737500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -132,WCCCA4,859.737500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -133,WCCCA5,858.237500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -134,WCCCA6,857.237500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -135,WCCCA7,856.237500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -136,WCCCA8,855.962500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -137,WCCCA9,855.237500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -138,WCCCA0,854.987500,,0.600000,,88.5,88.5,023,NN,FM,12.50,,,-1,,,, -139,OR SAR,155.805000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -140,OPEN,155.475000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -141,OSPTAC,156.030000,,0.600000,TSQL,88.5,156.7,023,NN,FM,5.00,,,-1,,,, -142,OSPD1A,154.935000,,0.600000,TSQL,88.5,179.9,023,NN,FM,5.00,,,-1,,,, -143,OSPD1B,156.225000,,0.600000,TSQL,88.5,179.9,023,NN,FM,5.00,,,-1,,,, -144,OSPD1C,154.905000,,0.600000,TSQL,88.5,179.9,023,NN,FM,5.00,,,-1,,,, -145,OSPD1D,156.150000,,0.600000,TSQL,88.5,179.9,023,NN,FM,5.00,,,-1,,,, -146,OSPD6A,153.935000,,0.600000,TSQL,88.5,156.7,023,NN,FM,5.00,,,-1,,,, -147,OSPD6B,154.785000,,0.600000,TSQL,88.5,156.7,023,NN,FM,5.00,,,-1,,,, -148,OSPD6C,154.860000,,0.600000,TSQL,88.5,131.8,023,NN,FM,5.00,,,-1,,,, -149,OSPD6D,155.910000,,0.600000,TSQL,88.5,131.8,023,NN,FM,5.00,,,-1,,,, -150,WASP,155.370000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -151,CHP,156.075000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -152,ODFW,158.895000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -153,SARINTOP,158.905000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -160,H-DS1,147.550000,,0.600000,,88.5,88.5,023,NN,DV,5.00,,,-1,CQCQCQ,,,0 -161,H-DS2,147.580000,,0.600000,,88.5,88.5,023,NN,DV,5.00,,,-1,CQCQCQ,,,0 -162,H-DS3,446.300000,,5.000000,,88.5,88.5,023,NN,DV,5.00,,,-1,CQCQCQ,,,0 -163,H-DS4,446.400000,,5.000000,,88.5,88.5,023,NN,DV,5.00,,,-1,CQCQCQ,,,0 -164,H-DS5,1294.100000,,0.600000,,88.5,88.5,023,NN,DV,5.00,,,-1,CQCQCQ,,,0 -165,H-DS6,441.637500,+,5.000000,,88.5,88.5,023,NN,DV,12.50,,,-1,CQCQCQ,,,0 -166,H-DS7,440.550000,+,5.000000,,88.5,88.5,023,NN,DV,5.00,,,-1,CQCQCQ,,,0 -167,H-DS8,444.262500,+,5.000000,,88.5,88.5,023,NN,DV,12.50,,,-1,CQCQCQ,,,0 -168,HPAGE,145.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -169,APRS,144.390000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -170,H-DAT1,145.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, -171,H-DAT2,145.070000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,-1,,,, +Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,RxDtcsCode,CrossMode,Mode,TStep,Skip,Power,Comment,URCALL,RPT1CALL,RPT2CALL,DVCODE +25,H-TAC1,443.100000,+,5.000000,DTCS,88.5,88.5,032,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +26,H-TAC2,147.380000,+,0.600000,Tone,100.0,100.0,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +27,H-TAC3,147.440000,,0.600000,Tone,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +28,H-TAC4,441.550000,+,5.000000,Tone,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +29,H-TAC5,442.925000,+,5.000000,Tone,107.2,107.2,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +30,H-TAC6,443.350000,+,5.000000,Tone,156.7,156.7,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +31,H-TAC7,442.825000,+,5.000000,,110.9,110.9,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +50,ARESD1,147.320000,+,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +51,WAPRIR,146.900000,-,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +52,WAPRIS,147.400000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +53,WASECR,440.350000,+,5.000000,TSQL,127.3,127.3,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +54,OEMNCS,145.330000,-,0.600000,Tone,186.2,186.2,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +55,HEARTN,145.230000,-,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +56,CLACK,147.120000,+,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +57,CLATSP,146.660000,-,0.600000,Tone,118.8,118.8,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +58,COLUMB,146.880000,-,0.600000,Tone,114.8,114.8,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +59,TMOOK1,147.220000,+,0.600000,Tone,100.0,100.0,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +60,TMOOK2,147.160000,+,0.600000,Tone,118.8,118.8,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +61,TMOOK3,440.175000,+,5.000000,Tone,100.0,100.0,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +62,TMOOK4,441.250000,+,5.000000,Tone,118.8,118.8,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +63,MULTNM,146.840000,-,0.600000,Tone,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +64,CLARK,147.240000,+,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +65,ARC,146.980000,-,0.600000,Tone,123.0,123.0,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +66,VERNIA,145.250000,-,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +80,WX1,162.400000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +81,WX2,162.425000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +82,WX3,162.450000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +83,WX4,162.475000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +84,WX5,162.500000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +85,WX6,162.525000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +86,WX7,162.550000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +88,CTAF,119.300000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,AM,5.00,,50W,,,,, +89,ATIS,127.650000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,AM,5.00,,50W,,,,, +90,GROUND,121.700000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,AM,5.00,,50W,,,,, +91,TOWER,119.300000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,AM,5.00,,50W,,,,, +92,UNICOM,122.950000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,AM,5.00,,50W,,,,, +93,ACARS,131.550000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,AM,5.00,,50W,,,,, +100,ICALL,851.012500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +101,ITAC1,851.512500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +102,ITAC2,852.012500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +103,ITAC3,852.512500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +104,ITAC4,853.012500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +105,OROPS1,851.325000,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,10.00,,50W,,,,, +106,OROPS2,851.387500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +107,OROPS3,851.750000,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,10.00,,50W,,,,, +108,OROPS4,851.775000,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,10.00,,50W,,,,, +109,OROPS5,851.800000,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,10.00,,50W,,,,, +110,WAOPS1,852.537500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +111,WAOPS2,852.562500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +112,WAOPS3,852.587500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +113,WAOPS4,852.612500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,10.00,,50W,,,,, +114,WAOPS5,852.637500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +115,UCAL40,453.212500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +116,UTAC41,453.462500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +117,UTAC42,453.712500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +118,UTAC43,453.862500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +119,ISIMP1,853.437500,,0.600000,DTCS,88.5,88.5,074,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +120,ISIMP2,851.037500,,0.600000,DTCS,88.5,88.5,114,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +121,ISIMP3,851.950000,,0.600000,DTCS,88.5,88.5,131,NN,023,Tone->Tone,FM,10.00,,50W,,,,, +122,ISIMP4,851.175000,,0.600000,DTCS,88.5,88.5,023,NN,023,Tone->Tone,FM,10.00,,50W,,,,, +123,MAYDAY,853.387500,,0.600000,DTCS,88.5,88.5,025,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +124,VCALL,155.750000,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +125,VTAC11,151.137500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +126,VTAC12,154.452500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +127,VTAC13,158.737500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +128,VTAC14,159.472500,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +129,WCCCA1,860.737500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +130,WCCCA2,860.237500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +131,WCCCA3,859.737500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +132,WCCCA4,859.737500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +133,WCCCA5,858.237500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +134,WCCCA6,857.237500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +135,WCCCA7,856.237500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +136,WCCCA8,855.962500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +137,WCCCA9,855.237500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +138,WCCCA0,854.987500,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,12.50,,50W,,,,, +139,OR SAR,155.805000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +140,OPEN,155.475000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +141,OSPTAC,156.030000,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +142,OSPD1A,154.935000,,0.600000,TSQL,88.5,179.9,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +143,OSPD1B,156.225000,,0.600000,TSQL,88.5,179.9,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +144,OSPD1C,154.905000,,0.600000,TSQL,88.5,179.9,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +145,OSPD1D,156.150000,,0.600000,TSQL,88.5,179.9,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +146,OSPD6A,153.935000,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +147,OSPD6B,154.785000,,0.600000,TSQL,88.5,156.7,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +148,OSPD6C,154.860000,,0.600000,TSQL,88.5,131.8,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +149,OSPD6D,155.910000,,0.600000,TSQL,88.5,131.8,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +150,WASP,155.370000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +151,CHP,156.075000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +152,ODFW,158.895000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +153,SARINTOP,158.905000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +168,HPAGE,145.550000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +169,APRS,144.390000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +170,H-DAT1,145.550000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, +171,H-DAT2,145.070000,,0.600000,,88.5,88.5,023,NN,023,Tone->Tone,FM,5.00,,50W,,,,, From 4884faed4ebdcc311c77a6c48e88392a9fa64391 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 4 Sep 2024 15:31:11 -0700 Subject: [PATCH 4/4] Improve "driver messages" dialog Jamming a hundred errors into a MessageBox is not scalable and looks pretty dumb after a few. This makes it into a proper dialog that shows the first line of each and lets the user select each for better readability. Related to #11519 --- chirp/wxui/common.py | 54 ++++++++++++++++++++++++++++++++++++++------ chirp/wxui/main.py | 5 ++-- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/chirp/wxui/common.py b/chirp/wxui/common.py index 33cce0eec..e735a5612 100644 --- a/chirp/wxui/common.py +++ b/chirp/wxui/common.py @@ -22,7 +22,6 @@ import platform import shutil import tempfile -import textwrap import threading import wx @@ -711,8 +710,51 @@ def temporary_debug_log(): return dst +class MultiErrorDialog(wx.Dialog): + def __init__(self, *args, **kw): + super().__init__(*args, **kw) + vbox = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(vbox) + + self.choices = [] + self.choice_box = wx.ListBox(self) + vbox.Add(self.choice_box, border=10, proportion=0, + flag=wx.EXPAND | wx.ALL) + + self.message = wx.TextCtrl(self) + self.message.SetEditable(False) + vbox.Add(self.message, border=10, proportion=1, + flag=wx.EXPAND | wx.ALL) + + buttons = self.CreateButtonSizer(wx.OK) + vbox.Add(buttons, border=10, flag=wx.ALL) + + self.Bind(wx.EVT_BUTTON, self._button) + self.choice_box.Bind(wx.EVT_LISTBOX, self._selected) + + self.SetMinSize((600, 400)) + self.Fit() + self.Center() + + def _button(self, event): + self.EndModal(wx.ID_OK) + + def select(self, index): + error = self.choices[index] + self.message.SetValue('%s in %s:\n%s' % ( + error.levelname, error.module, error.getMessage())) + + def _selected(self, event): + self.select(event.GetInt()) + + def set_errors(self, errors): + self.choices = errors + self.choice_box.Set([x.getMessage() for x in self.choices]) + self.select(0) + + @contextlib.contextmanager -def expose_logs(level, root, label, maxlen=128): +def expose_logs(level, root, label, maxlen=128, parent=None): if not isinstance(root, tuple): root = (root,) @@ -725,9 +767,7 @@ def expose_logs(level, root, label, maxlen=128): lines = list(itertools.chain.from_iterable(x.get_history() for x in histories)) if lines: - msg = os.linesep.join(textwrap.shorten(x.getMessage(), maxlen) - for x in lines) - d = wx.MessageDialog( - None, str(msg), label, - style=wx.OK | wx.ICON_INFORMATION) + d = MultiErrorDialog(parent) + d.SetTitle(label) + d.set_errors(lines) d.ShowModal() diff --git a/chirp/wxui/main.py b/chirp/wxui/main.py index 81b481fa3..54bb91a4f 100644 --- a/chirp/wxui/main.py +++ b/chirp/wxui/main.py @@ -551,7 +551,8 @@ def open_file(self, filename, exists=True, select=True, rclass=None): self.enable_bugreport() CSVRadio = directory.get_radio('Generic_CSV') label = _('Driver messages') - with common.expose_logs(logging.WARNING, 'chirp.drivers', label): + with common.expose_logs(logging.WARNING, 'chirp.drivers', label, + parent=self): if exists: if not os.path.exists(filename): raise FileNotFoundError( @@ -1356,7 +1357,7 @@ def _menu_import(self, event): r = d.ShowModal() if r == wx.ID_YES: with common.expose_logs(logging.WARNING, 'chirp.drivers', - _('Import messages')): + _('Import messages'), parent=self): radio = directory.get_radio_by_image(filename) self.current_editorset.current_editor.memedit_import_all(radio) elif r == wx.ID_NO: