diff --git a/src/NanoVNASaver/Analysis/BandPassAnalysis.py b/src/NanoVNASaver/Analysis/BandPassAnalysis.py
index dfb362e..2d304fa 100644
--- a/src/NanoVNASaver/Analysis/BandPassAnalysis.py
+++ b/src/NanoVNASaver/Analysis/BandPassAnalysis.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import logging
import math
-from typing import Dict, List
from PyQt6 import QtWidgets
@@ -158,13 +157,13 @@ class BandPassAnalysis(Analysis):
self.set_result(f"Analysis complete ({len(s21)} points)")
def derive_60dB(
- self, cutoff_pos: Dict[str, int], cutoff_freq: Dict[str, float]
+ self, cutoff_pos: dict[str, int], cutoff_freq: dict[str, float]
):
"""derive 60dB cutoff if needed an possible
Args:
- cutoff_pos (Dict[str, int])
- cutoff_freq (Dict[str, float])
+ cutoff_pos (dict[str, int])
+ cutoff_freq (dict[str, float])
"""
if (
math.isnan(cutoff_freq["60.0dB_l"])
@@ -191,7 +190,7 @@ class BandPassAnalysis(Analysis):
)
)
- def find_center(self, gains: List[float]) -> int:
+ def find_center(self, gains: list[float]) -> int:
marker = self.app.markers[0]
if marker.location <= 0 or marker.location >= len(gains) - 1:
logger.debug(
@@ -207,8 +206,8 @@ class BandPassAnalysis(Analysis):
return peak
def find_bounderies(
- self, gains: List[float], peak: int, peak_db: float
- ) -> Dict[str, int]:
+ self, gains: list[float], peak: int, peak_db: float
+ ) -> dict[str, int]:
cutoff_pos = {}
for attn in CUTOFF_VALS:
cutoff_pos[f"{attn:.1f}dB_l"] = at.cut_off_left(
diff --git a/src/NanoVNASaver/Analysis/BandStopAnalysis.py b/src/NanoVNASaver/Analysis/BandStopAnalysis.py
index da4395f..41ca94b 100644
--- a/src/NanoVNASaver/Analysis/BandStopAnalysis.py
+++ b/src/NanoVNASaver/Analysis/BandStopAnalysis.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import logging
-from typing import Dict, List
import NanoVNASaver.AnalyticTools as at
from NanoVNASaver.Analysis.Base import CUTOFF_VALS
@@ -31,12 +30,12 @@ class BandStopAnalysis(BandPassAnalysis):
super().__init__(app)
self.set_titel("Band stop filter analysis")
- def find_center(self, gains: List[float]) -> int:
+ def find_center(self, gains: list[float]) -> int:
return max(enumerate(gains), key=lambda i: i[1])[0]
def find_bounderies(
- self, gains: List[float], _: int, peak_db: float
- ) -> Dict[str, int]:
+ self, gains: list[float], _: int, peak_db: float
+ ) -> dict[str, int]:
cutoff_pos = {}
for attn in CUTOFF_VALS:
(
diff --git a/src/NanoVNASaver/Analysis/Base.py b/src/NanoVNASaver/Analysis/Base.py
index db7e77b..8da74cf 100644
--- a/src/NanoVNASaver/Analysis/Base.py
+++ b/src/NanoVNASaver/Analysis/Base.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import logging
-from typing import Dict
from PyQt6 import QtWidgets
logger = logging.getLogger(__name__)
@@ -34,7 +33,7 @@ class QHLine(QtWidgets.QFrame):
class Analysis:
def __init__(self, app: QtWidgets.QWidget):
self.app = app
- self.label: Dict[str, QtWidgets.QLabel] = {
+ self.label: dict[str, QtWidgets.QLabel] = {
"titel": QtWidgets.QLabel(),
"result": QtWidgets.QLabel(),
}
diff --git a/src/NanoVNASaver/Analysis/HighPassAnalysis.py b/src/NanoVNASaver/Analysis/HighPassAnalysis.py
index 4ae3c8a..fbe9711 100644
--- a/src/NanoVNASaver/Analysis/HighPassAnalysis.py
+++ b/src/NanoVNASaver/Analysis/HighPassAnalysis.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import logging
import math
-from typing import Dict, List
from PyQt6 import QtWidgets
@@ -109,7 +108,7 @@ class HighPassAnalysis(Analysis):
self.set_result(f"Analysis complete ({len(s21)}) points)")
- def find_level(self, gains: List[float]) -> int:
+ def find_level(self, gains: list[float]) -> int:
marker = self.app.markers[0]
logger.debug("Pass band location: %d", marker.location)
if marker.location < 0:
@@ -118,8 +117,8 @@ class HighPassAnalysis(Analysis):
return at.center_from_idx(gains, marker.location)
def find_cutoffs(
- self, gains: List[float], peak: int, peak_db: float
- ) -> Dict[str, int]:
+ self, gains: list[float], peak: int, peak_db: float
+ ) -> dict[str, int]:
return {
f"{attn:.1f}dB": at.cut_off_left(gains, peak, peak_db, attn)
for attn in CUTOFF_VALS
diff --git a/src/NanoVNASaver/Analysis/LowPassAnalysis.py b/src/NanoVNASaver/Analysis/LowPassAnalysis.py
index 764e791..a96e61c 100644
--- a/src/NanoVNASaver/Analysis/LowPassAnalysis.py
+++ b/src/NanoVNASaver/Analysis/LowPassAnalysis.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import logging
-from typing import Dict, List
import NanoVNASaver.AnalyticTools as at
from NanoVNASaver.Analysis.Base import CUTOFF_VALS
@@ -33,8 +32,8 @@ class LowPassAnalysis(HighPassAnalysis):
self.set_titel("Lowpass filter analysis")
def find_cutoffs(
- self, gains: List[float], peak: int, peak_db: float
- ) -> Dict[str, int]:
+ self, gains: list[float], peak: int, peak_db: float
+ ) -> dict[str, int]:
return {
f"{attn:.1f}dB": at.cut_off_right(gains, peak, peak_db, attn)
for attn in CUTOFF_VALS
diff --git a/src/NanoVNASaver/Analysis/ResonanceAnalysis.py b/src/NanoVNASaver/Analysis/ResonanceAnalysis.py
index 4a6068d..c65f28f 100644
--- a/src/NanoVNASaver/Analysis/ResonanceAnalysis.py
+++ b/src/NanoVNASaver/Analysis/ResonanceAnalysis.py
@@ -19,7 +19,6 @@
import os
import csv
import logging
-from typing import List
from PyQt6 import QtWidgets
@@ -44,7 +43,7 @@ def vswr_transformed(z, ratio=49) -> float:
class ResonanceAnalysis(Analysis):
def __init__(self, app):
super().__init__(app)
- self.crossings: List[int] = []
+ self.crossings: list[int] = []
self.filename = ""
self._widget = QtWidgets.QWidget()
self.layout = QtWidgets.QFormLayout()
diff --git a/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py b/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py
index 52bf25c..80e152b 100644
--- a/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py
+++ b/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import logging
-from typing import Callable, List, Tuple
+from typing import Callable
from PyQt6 import QtWidgets
import numpy as np
@@ -102,7 +102,7 @@ class SimplePeakSearchAnalysis(Analysis):
if self.button["move_marker"].isChecked() and self.app.markers:
self.app.markers[0].setFrequency(f"{s11[idx_peak].freq}")
- def data_and_format(self) -> Tuple[List[float], Callable]:
+ def data_and_format(self) -> tuple[list[float], Callable]:
s11 = self.app.data.s11
s21 = self.app.data.s21
diff --git a/src/NanoVNASaver/Analysis/VSWRAnalysis.py b/src/NanoVNASaver/Analysis/VSWRAnalysis.py
index 23769e4..2f6853f 100644
--- a/src/NanoVNASaver/Analysis/VSWRAnalysis.py
+++ b/src/NanoVNASaver/Analysis/VSWRAnalysis.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import logging
-from typing import List
from PyQt6 import QtWidgets
@@ -54,7 +53,7 @@ class VSWRAnalysis(Analysis):
self.results_label = QtWidgets.QLabel("Results")
self.layout.addRow(self.results_label)
- self.minimums: List[int] = []
+ self.minimums: list[int] = []
def runAnalysis(self):
if not self.app.data.s11:
diff --git a/src/NanoVNASaver/AnalyticTools.py b/src/NanoVNASaver/AnalyticTools.py
index c68b8b3..90ede24 100644
--- a/src/NanoVNASaver/AnalyticTools.py
+++ b/src/NanoVNASaver/AnalyticTools.py
@@ -18,7 +18,7 @@
# along with this program. If not, see .
import itertools as it
import math
-from typing import Callable, List, Tuple
+from typing import Callable
import numpy as np
@@ -28,14 +28,14 @@ from scipy.signal import find_peaks
from NanoVNASaver.RFTools import Datapoint
-def zero_crossings(data: List[float]) -> List[int]:
+def zero_crossings(data: list[float]) -> list[int]:
"""find zero crossings
Args:
- data (List[float]): data list execute
+ data (list[float]): data list execute
Returns:
- List[int]: sorted indices of zero crossing points
+ list[int]: sorted indices of zero crossing points
"""
if not data:
return []
@@ -54,27 +54,27 @@ def zero_crossings(data: List[float]) -> List[int]:
return sorted(real_zeros + crossings)
-def maxima(data: List[float], threshold: float = 0.0) -> List[int]:
+def maxima(data: list[float], threshold: float = 0.0) -> list[int]:
"""maxima
Args:
- data (List[float]): data list to execute
+ data (list[float]): data list to execute
Returns:
- List[int]: indices of maxima
+ list[int]: indices of maxima
"""
peaks = find_peaks(data, width=2, distance=3, prominence=1)[0].tolist()
return [i for i in peaks if data[i] > threshold] if threshold else peaks
-def minima(data: List[float], threshold: float = 0.0) -> List[int]:
+def minima(data: list[float], threshold: float = 0.0) -> list[int]:
"""minima
Args:
- data (List[float]): data list to execute
+ data (list[float]): data list to execute
Returns:
- List[int]: indices of minima
+ list[int]: indices of minima
"""
bottoms = find_peaks(-np.array(data), width=2, distance=3, prominence=1)[
0
@@ -83,18 +83,18 @@ def minima(data: List[float], threshold: float = 0.0) -> List[int]:
def take_from_idx(
- data: List[float], idx: int, predicate: Callable
-) -> List[int]:
+ data: list[float], idx: int, predicate: Callable
+) -> list[int]:
"""take_from_center
Args:
- data (List[float]): data list to execute
+ data (list[float]): data list to execute
idx (int): index of a start position
predicate (Callable): predicate on which elements to take
from center. (e.g. lambda i: i[1] < threshold)
Returns:
- List[int]: indices of element matching predicate left
+ list[int]: indices of element matching predicate left
and right from index
"""
lower = list(
@@ -111,11 +111,11 @@ def take_from_idx(
return lower + upper
-def center_from_idx(gains: List[float], idx: int, delta: float = 3.0) -> int:
+def center_from_idx(gains: list[float], idx: int, delta: float = 3.0) -> int:
"""find maximum from index postion of gains in a attn dB gain span
Args:
- gains (List[float]): gain values
+ gains (list[float]): gain values
idx (int): start position to search from
delta (float, optional): max gain delta from start. Defaults to 3.0.
@@ -128,13 +128,13 @@ def center_from_idx(gains: List[float], idx: int, delta: float = 3.0) -> int:
def cut_off_left(
- gains: List[float], idx: int, peak_gain: float, attn: float = 3.0
+ gains: list[float], idx: int, peak_gain: float, attn: float = 3.0
) -> int:
"""find first position in list where gain in attn lower then peak
left from index
Args:
- gains (List[float]): gain values
+ gains (list[float]): gain values
idx (int): start position to search from
peak_gain (float): reference gain value
attn (float, optional): attenuation to search position for.
@@ -149,13 +149,13 @@ def cut_off_left(
def cut_off_right(
- gains: List[float], idx: int, peak_gain: float, attn: float = 3.0
+ gains: list[float], idx: int, peak_gain: float, attn: float = 3.0
) -> int:
"""find first position in list where gain in attn lower then peak
right from index
Args:
- gains (List[float]): gain values
+ gains (list[float]): gain values
idx (int): start position to search from
peak_gain (float): reference gain value
attn (float, optional): attenuation to search position for.
@@ -171,15 +171,15 @@ def cut_off_right(
def dip_cut_offs(
- gains: List[float], peak_gain: float, attn: float = 3.0
-) -> Tuple[int, int]:
+ gains: list[float], peak_gain: float, attn: float = 3.0
+) -> tuple[int, int]:
rng = np.where(np.array(gains) < (peak_gain - attn))[0].tolist()
return (rng[0], rng[-1]) if rng else (math.nan, math.nan)
def calculate_rolloff(
- s21: List[Datapoint], idx_1: int, idx_2: int
-) -> Tuple[float, float]:
+ s21: list[Datapoint], idx_1: int, idx_2: int
+) -> tuple[float, float]:
if idx_1 == idx_2:
return (math.nan, math.nan)
freq_1, freq_2 = s21[idx_1].freq, s21[idx_2].freq
diff --git a/src/NanoVNASaver/Calibration.py b/src/NanoVNASaver/Calibration.py
index 2ab6979..377de55 100644
--- a/src/NanoVNASaver/Calibration.py
+++ b/src/NanoVNASaver/Calibration.py
@@ -23,7 +23,6 @@ import os
import re
from collections import defaultdict, UserDict
from dataclasses import dataclass
-from typing import List
from scipy.interpolate import interp1d
@@ -235,7 +234,7 @@ class CalDataSet(UserDict):
setattr(self.data[freq], name, (dp.z))
self.data[freq].freq = freq
- def frequencies(self) -> List[int]:
+ def frequencies(self) -> list[int]:
return sorted(self.data.keys())
def get(self, key: int, default: CalData = None) -> CalData:
@@ -276,7 +275,7 @@ class Calibration:
self.source = "Manual"
- def insert(self, name: str, data: List[Datapoint]):
+ def insert(self, name: str, data: list[Datapoint]):
for dp in data:
self.dataset.insert(name, dp)
diff --git a/src/NanoVNASaver/Charts/CLogMag.py b/src/NanoVNASaver/Charts/CLogMag.py
index 7db9a71..cde140e 100644
--- a/src/NanoVNASaver/Charts/CLogMag.py
+++ b/src/NanoVNASaver/Charts/CLogMag.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List
from PyQt6 import QtGui
@@ -33,11 +32,11 @@ class CombinedLogMagChart(LogMagChart):
def __init__(self, name=""):
super().__init__(name)
- self.data11: List[Datapoint] = []
- self.data21: List[Datapoint] = []
+ self.data11: list[Datapoint] = []
+ self.data21: list[Datapoint] = []
- self.reference11: List[Datapoint] = []
- self.reference21: List[Datapoint] = []
+ self.reference11: list[Datapoint] = []
+ self.reference21: list[Datapoint] = []
def setCombinedData(self, data11, data21):
self.data11 = data11
diff --git a/src/NanoVNASaver/Charts/Chart.py b/src/NanoVNASaver/Charts/Chart.py
index 6ab7a17..5ec26de 100644
--- a/src/NanoVNASaver/Charts/Chart.py
+++ b/src/NanoVNASaver/Charts/Chart.py
@@ -19,7 +19,7 @@
import logging
from dataclasses import dataclass, field, replace
-from typing import List, Set, Tuple, ClassVar, Any, Optional
+from typing import ClassVar, Any
from PyQt6 import QtWidgets, QtGui, QtCore
from PyQt6.QtCore import pyqtSignal, Qt
@@ -67,8 +67,8 @@ class ChartDimensions:
@dataclass
class ChartDragBox:
- pos: Tuple[int] = (-1, -1)
- pos_start: Tuple[int] = (0, 0)
+ pos: tuple[int] = (-1, -1)
+ pos_start: tuple[int] = (0, 0)
state: bool = False
move_x: int = -1
move_y: int = -1
@@ -128,11 +128,11 @@ class Chart(QtWidgets.QWidget):
self.draggedMarker = None
- self.data: List[Datapoint] = []
- self.reference: List[Datapoint] = []
+ self.data: list[Datapoint] = []
+ self.reference: list[Datapoint] = []
- self.markers: List[Marker] = []
- self.swrMarkers: Set[float] = set()
+ self.markers: list[Marker] = []
+ self.swrMarkers: set[float] = set()
self.action_popout = QAction("Popout chart")
self.action_popout.triggered.connect(
@@ -192,7 +192,7 @@ class Chart(QtWidgets.QWidget):
None,
)
- def getNearestMarker(self, x, y) -> Optional[Marker]:
+ def getNearestMarker(self, x, y) -> Marker | None:
if not self.data:
return None
shortest = 10**6
@@ -205,7 +205,7 @@ class Chart(QtWidgets.QWidget):
nearest = m
return nearest
- def getPosition(self, d: Datapoint) -> Tuple[int, int]:
+ def getPosition(self, d: Datapoint) -> tuple[int, int]:
return self.getXPosition(d), self.getYPosition(d)
def setDrawLines(self, draw_lines):
diff --git a/src/NanoVNASaver/Charts/Frequency.py b/src/NanoVNASaver/Charts/Frequency.py
index a5e467d..1599b3d 100644
--- a/src/NanoVNASaver/Charts/Frequency.py
+++ b/src/NanoVNASaver/Charts/Frequency.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List, Tuple
import numpy as np
from PyQt6 import QtWidgets, QtGui, QtCore
@@ -405,7 +404,7 @@ class FrequencyChart(Chart):
step = span / self.dim.width
return round(self.fstart + absx * step)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
"""
Returns the chart-specific value(s) at the specified Y-position
:param y: The Y position to calculate for.
@@ -493,7 +492,7 @@ class FrequencyChart(Chart):
self.drawDragbog(qp)
qp.end()
- def _data_oob(self, data: List[Datapoint]) -> bool:
+ def _data_oob(self, data: list[Datapoint]) -> bool:
return data[0].freq > self.fstop or self.data[-1].freq < self.fstart
def _check_frequency_boundaries(self, qp: QtGui.QPainter):
@@ -605,7 +604,7 @@ class FrequencyChart(Chart):
self.drawData(qp, self.reference, Chart.color.reference)
self.drawMarkers(qp)
- def _find_scaling(self) -> Tuple[float, float]:
+ def _find_scaling(self) -> tuple[float, float]:
min_value = self.minDisplayValue / 10e11
max_value = self.maxDisplayValue / 10e11
if self.fixedValues:
@@ -686,7 +685,7 @@ class FrequencyChart(Chart):
def drawData(
self,
qp: QtGui.QPainter,
- data: List[Datapoint],
+ data: list[Datapoint],
color: QtGui.QColor,
y_function=None,
):
diff --git a/src/NanoVNASaver/Charts/GroupDelay.py b/src/NanoVNASaver/Charts/GroupDelay.py
index dc30390..ed76908 100644
--- a/src/NanoVNASaver/Charts/GroupDelay.py
+++ b/src/NanoVNASaver/Charts/GroupDelay.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List
import numpy as np
@@ -74,7 +73,7 @@ class GroupDelayChart(FrequencyChart):
self.groupDelayReference = self.calc_data(self.reference)
self.update()
- def calc_data(self, data: List[Datapoint]):
+ def calc_data(self, data: list[Datapoint]):
data_len = len(data)
if data_len <= 1:
return []
@@ -172,8 +171,8 @@ class GroupDelayChart(FrequencyChart):
self,
qp: QtGui.QPainter,
color: QtGui.QColor,
- data: List[Datapoint],
- delay: List[Datapoint],
+ data: list[Datapoint],
+ delay: list[Datapoint],
):
pen = QtGui.QPen(color)
pen.setWidth(self.dim.point)
@@ -216,7 +215,7 @@ class GroupDelayChart(FrequencyChart):
(self.maxDelay - delay) / self.span * self.dim.height
)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
val = -1 * ((absy / self.dim.height * self.span) - self.maxDelay)
return [val]
diff --git a/src/NanoVNASaver/Charts/LogMag.py b/src/NanoVNASaver/Charts/LogMag.py
index c6736ba..d929c5b 100644
--- a/src/NanoVNASaver/Charts/LogMag.py
+++ b/src/NanoVNASaver/Charts/LogMag.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
import math
import logging
-from typing import List
from PyQt6 import QtGui
@@ -165,7 +164,7 @@ class LogMagChart(FrequencyChart):
(self.maxValue - logMag) / self.span * self.dim.height
)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
val = -1 * ((absy / self.dim.height * self.span) - self.maxValue)
return [val]
diff --git a/src/NanoVNASaver/Charts/Magnitude.py b/src/NanoVNASaver/Charts/Magnitude.py
index 0f7a912..dcff5f8 100644
--- a/src/NanoVNASaver/Charts/Magnitude.py
+++ b/src/NanoVNASaver/Charts/Magnitude.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List
from PyQt6 import QtGui
@@ -127,7 +126,7 @@ class MagnitudeChart(FrequencyChart):
(self.maxValue - mag) / self.span * self.dim.height
)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
val = -1 * ((absy / self.dim.height * self.span) - self.maxValue)
return [val]
diff --git a/src/NanoVNASaver/Charts/MagnitudeZ.py b/src/NanoVNASaver/Charts/MagnitudeZ.py
index 32cd2d6..b051a3d 100644
--- a/src/NanoVNASaver/Charts/MagnitudeZ.py
+++ b/src/NanoVNASaver/Charts/MagnitudeZ.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List
from PyQt6 import QtGui
@@ -129,7 +128,7 @@ class MagnitudeZChart(FrequencyChart):
)
return self.topMargin
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
if self.logarithmicY:
span = math.log(self.maxValue) - math.log(self.minValue)
diff --git a/src/NanoVNASaver/Charts/Permeability.py b/src/NanoVNASaver/Charts/Permeability.py
index aadda3e..8544d0e 100644
--- a/src/NanoVNASaver/Charts/Permeability.py
+++ b/src/NanoVNASaver/Charts/Permeability.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List
from PyQt6 import QtGui
@@ -325,7 +324,7 @@ class PermeabilityChart(FrequencyChart):
self.topMargin + (self.max - re) / self.span * self.dim.height
)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
if self.logarithmicY:
min_val = self.max - self.span
diff --git a/src/NanoVNASaver/Charts/Phase.py b/src/NanoVNASaver/Charts/Phase.py
index d743670..aad256b 100644
--- a/src/NanoVNASaver/Charts/Phase.py
+++ b/src/NanoVNASaver/Charts/Phase.py
@@ -19,7 +19,6 @@
import math
import logging
-from typing import List
import numpy as np
from PyQt6.QtGui import QAction, QPainter, QPen
@@ -151,7 +150,7 @@ class PhaseChart(FrequencyChart):
(self.maxAngle - angle) / self.span * self.dim.height
)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
val = -1 * ((absy / self.dim.height * self.span) - self.maxAngle)
return [val]
diff --git a/src/NanoVNASaver/Charts/QFactor.py b/src/NanoVNASaver/Charts/QFactor.py
index 3986a96..df5aa89 100644
--- a/src/NanoVNASaver/Charts/QFactor.py
+++ b/src/NanoVNASaver/Charts/QFactor.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List
from PyQt6 import QtGui
@@ -127,7 +126,7 @@ class QualityFactorChart(FrequencyChart):
(self.maxQ - Q) / self.span * self.dim.height
)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
val = -1 * ((absy / self.dim.height * self.span) - self.maxQ)
return [val]
diff --git a/src/NanoVNASaver/Charts/RI.py b/src/NanoVNASaver/Charts/RI.py
index a64fda0..2690e22 100644
--- a/src/NanoVNASaver/Charts/RI.py
+++ b/src/NanoVNASaver/Charts/RI.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List, Optional
from PyQt6 import QtWidgets, QtGui
@@ -381,7 +380,7 @@ class RealImaginaryChart(FrequencyChart):
else self.topMargin
)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
valRe = -1 * ((absy / self.dim.height * self.span_real) - self.max_real)
valIm = -1 * ((absy / self.dim.height * self.span_imag) - self.max_imag)
@@ -408,7 +407,7 @@ class RealImaginaryChart(FrequencyChart):
self.update()
- def getNearestMarker(self, x, y) -> Optional[Marker]:
+ def getNearestMarker(self, x, y) -> Marker | None:
if not self.data:
return None
shortest = 10e6
diff --git a/src/NanoVNASaver/Charts/RIZ.py b/src/NanoVNASaver/Charts/RIZ.py
index 5e97489..f1a810e 100644
--- a/src/NanoVNASaver/Charts/RIZ.py
+++ b/src/NanoVNASaver/Charts/RIZ.py
@@ -18,7 +18,7 @@
# along with this program. If not, see .
import logging
-from PyQt6 import QtWidgets, QtGui
+from PyQt6 import QtGui
from NanoVNASaver.Formatting import format_frequency_chart
from NanoVNASaver.RFTools import Datapoint
diff --git a/src/NanoVNASaver/Charts/SParam.py b/src/NanoVNASaver/Charts/SParam.py
index 09f6cb9..4d1e8e8 100644
--- a/src/NanoVNASaver/Charts/SParam.py
+++ b/src/NanoVNASaver/Charts/SParam.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import logging
-from typing import List
from PyQt6 import QtGui
@@ -142,7 +141,7 @@ class SParameterChart(FrequencyChart):
+ (self.maxValue - d.im) / self.span * self.dim.height
)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
val = -1 * ((absy / self.dim.height * self.span) - self.maxValue)
return [val]
diff --git a/src/NanoVNASaver/Charts/Square.py b/src/NanoVNASaver/Charts/Square.py
index dd5ab16..ff66db8 100644
--- a/src/NanoVNASaver/Charts/Square.py
+++ b/src/NanoVNASaver/Charts/Square.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import logging
import math
-from typing import List
from PyQt6 import QtGui, QtCore, QtWidgets
@@ -58,7 +57,7 @@ class SquareChart(Chart):
self,
qp: QtGui.QPainter,
color: QtGui.QColor,
- data: List[Datapoint],
+ data: list[Datapoint],
fstart: int = 0,
fstop: int = 0,
):
diff --git a/src/NanoVNASaver/Charts/VSWR.py b/src/NanoVNASaver/Charts/VSWR.py
index f0efe18..73d8a28 100644
--- a/src/NanoVNASaver/Charts/VSWR.py
+++ b/src/NanoVNASaver/Charts/VSWR.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
import logging
-from typing import List
from PyQt6 import QtGui
@@ -166,7 +165,7 @@ class VSWRChart(FrequencyChart):
def getYPosition(self, d: Datapoint) -> int:
return self.getYPositionFromValue(d.vswr)
- def valueAtPosition(self, y) -> List[float]:
+ def valueAtPosition(self, y) -> list[float]:
absy = y - self.topMargin
if self.logarithmicY:
min_val = self.maxVSWR - self.span
diff --git a/src/NanoVNASaver/Defaults.py b/src/NanoVNASaver/Defaults.py
index e7c32ec..0a29481 100644
--- a/src/NanoVNASaver/Defaults.py
+++ b/src/NanoVNASaver/Defaults.py
@@ -62,7 +62,7 @@ class Chart:
marker_size: int = 8
returnloss_is_positive: bool = False
show_bands: bool = False
- vswr_lines: list = DC.field(default_factory=lambda: [])
+ vswr_lines: list = DC.field(default_factory=list)
@DC.dataclass
@@ -126,11 +126,11 @@ class Markers:
@DC.dataclass
class CFG:
- gui: object = DC.field(default_factory=lambda: GUI())
- charts_selected: object = DC.field(default_factory=lambda: ChartsSelected())
- chart: object = DC.field(default_factory=lambda: Chart())
- chart_colors: object = DC.field(default_factory=lambda: ChartColors())
- markers: object = DC.field(default_factory=lambda: Markers())
+ gui: object = DC.field(default_factory=GUI)
+ charts_selected: object = DC.field(default_factory=ChartsSelected)
+ chart: object = DC.field(default_factory=Chart)
+ chart_colors: object = DC.field(default_factory=ChartColors)
+ markers: object = DC.field(default_factory=Markers)
cfg = CFG()
@@ -159,9 +159,9 @@ def store(settings: "AppSettings", data: CFG = None) -> None:
def from_type(data) -> str:
type_map = {
- bytearray: lambda x: x.hex(),
- QColor: lambda x: x.getRgb(),
- QByteArray: lambda x: x.toHex(),
+ bytearray: bytearray.hex,
+ QColor: QColor.getRgb,
+ QByteArray: QByteArray.toHex,
}
return (
f"{type_map[type(data)](data)}" if type(data) in type_map else f"{data}"
diff --git a/src/NanoVNASaver/Formatting.py b/src/NanoVNASaver/Formatting.py
index 6a1093a..cbdab27 100644
--- a/src/NanoVNASaver/Formatting.py
+++ b/src/NanoVNASaver/Formatting.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import math
from numbers import Number
-from typing import Union
from NanoVNASaver import SITools
@@ -55,7 +54,7 @@ def format_frequency(freq: Number) -> str:
return str(SITools.Value(freq, "Hz", FMT_FREQ))
-def format_frequency_inputs(freq: Union[Number, str]) -> str:
+def format_frequency_inputs(freq: Number | str) -> str:
return str(SITools.Value(freq, "Hz", FMT_FREQ_INPUTS))
diff --git a/src/NanoVNASaver/Hardware/Hardware.py b/src/NanoVNASaver/Hardware/Hardware.py
index faa352a..b63f5f3 100644
--- a/src/NanoVNASaver/Hardware/Hardware.py
+++ b/src/NanoVNASaver/Hardware/Hardware.py
@@ -20,7 +20,6 @@ import logging
import platform
from collections import namedtuple
from time import sleep
-from typing import List
import serial
from serial.tools import list_ports
@@ -91,7 +90,7 @@ def usb_typename(device: ListPortInfo) -> str:
# Get list of interfaces with VNAs connected
-def get_interfaces() -> List[Interface]:
+def get_interfaces() -> list[Interface]:
interfaces = []
# serial like usb interfaces
for d in list_ports.comports():
@@ -117,7 +116,7 @@ def get_interfaces() -> List[Interface]:
return interfaces
-def get_portinfos() -> List[str]:
+def get_portinfos() -> list[str]:
portinfos = []
# serial like usb interfaces
for d in list_ports.comports():
diff --git a/src/NanoVNASaver/Hardware/NanoVNA.py b/src/NanoVNASaver/Hardware/NanoVNA.py
index d836341..1fd2250 100644
--- a/src/NanoVNASaver/Hardware/NanoVNA.py
+++ b/src/NanoVNASaver/Hardware/NanoVNA.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import logging
import struct
-from typing import List
import serial
import numpy as np
@@ -123,7 +122,7 @@ class NanoVNA(VNA):
self.features.add("Scan command")
self.sweep_method = "scan"
- def readFrequencies(self) -> List[int]:
+ def readFrequencies(self) -> list[int]:
logger.debug("readFrequencies: %s", self.sweep_method)
if self.sweep_method != "scan_mask":
return super().readFrequencies()
@@ -134,7 +133,7 @@ class NanoVNA(VNA):
)
]
- def readValues(self, value) -> List[str]:
+ def readValues(self, value) -> list[str]:
if self.sweep_method != "scan_mask":
return super().readValues(value)
logger.debug("readValue with scan mask (%s)", value)
diff --git a/src/NanoVNASaver/Hardware/NanoVNA_V2.py b/src/NanoVNASaver/Hardware/NanoVNA_V2.py
index d49364b..d9b8c1b 100644
--- a/src/NanoVNASaver/Hardware/NanoVNA_V2.py
+++ b/src/NanoVNASaver/Hardware/NanoVNA_V2.py
@@ -20,7 +20,6 @@ import logging
import platform
from struct import pack, unpack_from
from time import sleep
-from typing import List
from NanoVNASaver.Hardware.Serial import Interface
from NanoVNASaver.Hardware.VNA import VNA
@@ -131,7 +130,7 @@ class NanoVNA_V2(VNA):
logger.debug("readFirmware: %s", result)
return result
- def readFrequencies(self) -> List[int]:
+ def readFrequencies(self) -> list[int]:
return [
int(self.sweepStartHz + i * self.sweepStepHz)
for i in range(self.datapoints)
@@ -159,7 +158,7 @@ class NanoVNA_V2(VNA):
logger.debug("Freq index to: %i", freq_index)
- def readValues(self, value) -> List[str]:
+ def readValues(self, value) -> list[str]:
# Actually grab the data only when requesting channel 0.
# The hardware will return all channels which we will store.
if value == "data 0":
diff --git a/src/NanoVNASaver/Hardware/TinySA.py b/src/NanoVNASaver/Hardware/TinySA.py
index cc741d5..09a4ed9 100644
--- a/src/NanoVNASaver/Hardware/TinySA.py
+++ b/src/NanoVNASaver/Hardware/TinySA.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import logging
import struct
-from typing import List
import serial
import numpy as np
@@ -109,11 +108,11 @@ class TinySA(VNA):
list(self.exec_command(f"sweep {start} {stop} {self.datapoints}"))
list(self.exec_command("trigger auto"))
- def readFrequencies(self) -> List[int]:
+ def readFrequencies(self) -> list[int]:
logger.debug("readFrequencies")
return [int(line) for line in self.exec_command("frequencies")]
- def readValues(self, value) -> List[str]:
+ def readValues(self, value) -> list[str]:
def conv2float(data: str) -> float:
try:
return 10 ** (float(data.strip()) / 20)
diff --git a/src/NanoVNASaver/Hardware/VNA.py b/src/NanoVNASaver/Hardware/VNA.py
index a429ebd..361efca 100644
--- a/src/NanoVNASaver/Hardware/VNA.py
+++ b/src/NanoVNASaver/Hardware/VNA.py
@@ -18,7 +18,7 @@
# along with this program. If not, see .
import logging
from time import sleep
-from typing import List, Iterator, Set
+from typing import Iterator
from PyQt6 import QtGui
@@ -131,7 +131,7 @@ class VNA:
if len(self.valid_datapoints) > 1:
self.features.add("Customizable data points")
- def get_bandwidths(self) -> List[int]:
+ def get_bandwidths(self) -> list[int]:
logger.debug("get bandwidths")
if self.bw_method == "dislord":
return list(DISLORD_BW.keys())
@@ -153,7 +153,7 @@ class VNA:
raise IOError(f"set_bandwith({bandwidth}: {result}")
self.bandwidth = bandwidth
- def readFrequencies(self) -> List[int]:
+ def readFrequencies(self) -> list[int]:
return [int(f) for f in self.readValues("frequencies")]
def resetSweep(self, start: int, stop: int):
@@ -170,7 +170,7 @@ class VNA:
def connected(self) -> bool:
return self.serial.is_open
- def getFeatures(self) -> Set[str]:
+ def getFeatures(self) -> set[str]:
return self.features
def getCalibration(self) -> str:
@@ -194,7 +194,7 @@ class VNA:
logger.debug("result:\n%s", result)
return result
- def readValues(self, value) -> List[str]:
+ def readValues(self, value) -> list[str]:
logger.debug("VNA reading %s", value)
result = list(self.exec_command(value))
logger.debug("VNA done reading %s (%d values)", value, len(result))
diff --git a/src/NanoVNASaver/Marker/Values.py b/src/NanoVNASaver/Marker/Values.py
index 97b0a81..be9d33a 100644
--- a/src/NanoVNASaver/Marker/Values.py
+++ b/src/NanoVNASaver/Marker/Values.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-from typing import List, NamedTuple
+from typing import NamedTuple
from NanoVNASaver.RFTools import Datapoint
@@ -71,16 +71,13 @@ class Value:
"""Contains the data area to calculate marker values from"""
def __init__(
- self,
- freq: int = 0,
- s11: List[Datapoint] = None,
- s21: List[Datapoint] = None,
+ self,
):
- self.freq = freq
- self.s11 = [] if s11 is None else s11[:]
- self.s21 = [] if s21 is None else s21[:]
+ self.freq: int = 0
+ self.s11: list[Datapoint] = []
+ self.s21: list[Datapoint] = []
- def store(self, index: int, s11: List[Datapoint], s21: List[Datapoint]):
+ def store(self, index: int, s11: list[Datapoint], s21: list[Datapoint]):
# handle boundaries
if index == 0:
index = 1
diff --git a/src/NanoVNASaver/Marker/Widget.py b/src/NanoVNASaver/Marker/Widget.py
index 44a0696..df41495 100644
--- a/src/NanoVNASaver/Marker/Widget.py
+++ b/src/NanoVNASaver/Marker/Widget.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import math
-from typing import List
from PyQt6 import QtGui, QtWidgets, QtCore
from PyQt6.QtCore import pyqtSignal
@@ -253,7 +252,7 @@ class Marker(QtCore.QObject, Value):
def getRow(self):
return QtWidgets.QLabel(self.name), self.layout
- def findLocation(self, data: List[RFTools.Datapoint]):
+ def findLocation(self, data: list[RFTools.Datapoint]):
self.location = -1
self.frequencyInput.nextFrequency = -1
self.frequencyInput.previousFrequency = -1
@@ -298,7 +297,7 @@ class Marker(QtCore.QObject, Value):
v.setText("")
def updateLabels(
- self, s11: List[RFTools.Datapoint], s21: List[RFTools.Datapoint]
+ self, s11: list[RFTools.Datapoint], s21: list[RFTools.Datapoint]
):
if not s11:
return
diff --git a/src/NanoVNASaver/RFTools.py b/src/NanoVNASaver/RFTools.py
index 7948384..3a25387 100644
--- a/src/NanoVNASaver/RFTools.py
+++ b/src/NanoVNASaver/RFTools.py
@@ -18,7 +18,7 @@
# along with this program. If not, see .
import math
import cmath
-from typing import List, NamedTuple
+from typing import NamedTuple
from NanoVNASaver.SITools import Format, clamp_value
@@ -92,7 +92,7 @@ def gamma_to_impedance(gamma: complex, ref_impedance: float = 50) -> complex:
return math.inf
-def groupDelay(data: List[Datapoint], index: int) -> float:
+def groupDelay(data: list[Datapoint], index: int) -> float:
idx0 = clamp_value(index - 1, 0, len(data) - 1)
idx1 = clamp_value(index + 1, 0, len(data) - 1)
delta_angle = data[idx1].phase - data[idx0].phase
@@ -147,7 +147,7 @@ def serial_to_parallel(z: complex) -> complex:
return complex(z_sq_sum / z.real, z_sq_sum / z.imag)
-def corr_att_data(data: List[Datapoint], att: float) -> List[Datapoint]:
+def corr_att_data(data: list[Datapoint], att: float) -> list[Datapoint]:
"""Correct the ratio for a given attenuation on s21 input"""
if att <= 0:
return data
diff --git a/src/NanoVNASaver/Settings/Sweep.py b/src/NanoVNASaver/Settings/Sweep.py
index 57509a2..d5aef9e 100644
--- a/src/NanoVNASaver/Settings/Sweep.py
+++ b/src/NanoVNASaver/Settings/Sweep.py
@@ -17,10 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import logging
+from dataclasses import dataclass, replace
from enum import Enum
from math import log
from threading import Lock
-from typing import Iterator, Tuple
+from typing import Iterator, NamedTuple
logger = logging.getLogger(__name__)
@@ -31,63 +32,28 @@ class SweepMode(Enum):
AVERAGE = 2
-class Properties:
- def __init__(
- self,
- name: str = "",
- mode: "SweepMode" = SweepMode.SINGLE,
- averages: Tuple[int, int] = (3, 0),
- logarithmic: bool = False,
- ):
- self.name = name
- self.mode = mode
- self.averages = averages
- self.logarithmic = logarithmic
-
- def __repr__(self):
- return (
- f"Properties('{self.name}', {self.mode}, {self.averages},"
- f" {self.logarithmic})"
- )
+class Properties(NamedTuple):
+ name: str = ""
+ mode: "SweepMode" = SweepMode.SINGLE
+ averages: tuple[int, int] = (3, 0)
+ logarithmic: bool = False
+@dataclass
class Sweep:
- def __init__(
- self,
- start: int = 3600000,
- end: int = 30000000,
- points: int = 101,
- segments: int = 1,
- properties: "Properties" = Properties(),
- ):
- self.start = start
- self.end = end
- self.points = points
- self.segments = segments
- self.properties = properties
+ start: int = 3600000
+ end: int = 30000000
+ points: int = 101
+ segments: int = 1
+ properties: "Properties" = Properties()
+
+ def __post_init__(self):
self.lock = Lock()
self.check()
logger.debug("%s", self)
- def __repr__(self) -> str:
- return (
- f"Sweep({self.start}, {self.end}, {self.points}, {self.segments},"
- f" {self.properties})"
- )
-
- def __eq__(self, other) -> bool:
- return (
- self.start == other.start
- and self.end == other.end
- and self.points == other.points
- and self.segments == other.segments
- and self.properties == other.properties
- )
-
def copy(self) -> "Sweep":
- return Sweep(
- self.start, self.end, self.points, self.segments, self.properties
- )
+ return replace(self)
@property
def span(self) -> int:
@@ -110,7 +76,7 @@ class Sweep:
def _exp_factor(self, index: int) -> float:
return 1 - log(self.segments + 1 - index) / log(self.segments + 1)
- def get_index_range(self, index: int) -> Tuple[int, int]:
+ def get_index_range(self, index: int) -> tuple[int, int]:
if not self.properties.logarithmic:
start = self.start + index * self.points * self.stepsize
end = start + (self.points - 1) * self.stepsize
diff --git a/src/NanoVNASaver/SweepWorker.py b/src/NanoVNASaver/SweepWorker.py
index f384682..3cae9bc 100644
--- a/src/NanoVNASaver/SweepWorker.py
+++ b/src/NanoVNASaver/SweepWorker.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
import logging
from time import sleep
-from typing import List, Tuple
import numpy as np
from PyQt6 import QtCore, QtWidgets
@@ -31,7 +30,7 @@ from NanoVNASaver.Settings.Sweep import Sweep, SweepMode
logger = logging.getLogger(__name__)
-def truncate(values: List[List[Tuple]], count: int) -> List[List[Tuple]]:
+def truncate(values: list[list[tuple]], count: int) -> list[list[tuple]]:
"""truncate drops extrema from data list if averaging is active"""
keep = len(values) - count
logger.debug("Truncating from %d values to %d", len(values), keep)
@@ -62,10 +61,10 @@ class SweepWorker(QtCore.QRunnable):
self.sweep = Sweep()
self.setAutoDelete(False)
self.percentage = 0
- self.data11: List[Datapoint] = []
- self.data21: List[Datapoint] = []
- self.rawData11: List[Datapoint] = []
- self.rawData21: List[Datapoint] = []
+ self.data11: list[Datapoint] = []
+ self.data21: list[Datapoint] = []
+ self.rawData11: list[Datapoint] = []
+ self.rawData21: list[Datapoint] = []
self.init_data()
self.stopped = False
self.running = False
@@ -187,10 +186,10 @@ class SweepWorker(QtCore.QRunnable):
self.signals.updated.emit()
def applyCalibration(
- self, raw_data11: List[Datapoint], raw_data21: List[Datapoint]
- ) -> Tuple[List[Datapoint], List[Datapoint]]:
- data11: List[Datapoint] = []
- data21: List[Datapoint] = []
+ self, raw_data11: list[Datapoint], raw_data21: list[Datapoint]
+ ) -> tuple[list[Datapoint], list[Datapoint]]:
+ data11: list[Datapoint] = []
+ data21: list[Datapoint] = []
if not self.app.calibration.isCalculated:
data11 = raw_data11.copy()
diff --git a/src/NanoVNASaver/Touchstone.py b/src/NanoVNASaver/Touchstone.py
index 2a9a7f9..4e09814 100644
--- a/src/NanoVNASaver/Touchstone.py
+++ b/src/NanoVNASaver/Touchstone.py
@@ -22,8 +22,6 @@ import cmath
import io
from operator import attrgetter
-from typing import List
-
from scipy.interpolate import interp1d
from NanoVNASaver.RFTools import Datapoint
@@ -108,42 +106,42 @@ class Touchstone:
self._interp = {}
@property
- def s11(self) -> List[Datapoint]:
+ def s11(self) -> list[Datapoint]:
return self.s("11")
@s11.setter
- def s11(self, value: List[Datapoint]):
+ def s11(self, value: list[Datapoint]):
self.sdata[0] = value
@property
- def s12(self) -> List[Datapoint]:
+ def s12(self) -> list[Datapoint]:
return self.s("12")
@s12.setter
- def s12(self, value: List[Datapoint]):
+ def s12(self, value: list[Datapoint]):
self.sdata[2] = value
@property
- def s21(self) -> List[Datapoint]:
+ def s21(self) -> list[Datapoint]:
return self.s("21")
@s21.setter
- def s21(self, value: List[Datapoint]):
+ def s21(self, value: list[Datapoint]):
self.sdata[1] = value
@property
- def s22(self) -> List[Datapoint]:
+ def s22(self) -> list[Datapoint]:
return self.s("22")
@s22.setter
- def s22(self, value: List[Datapoint]):
+ def s22(self, value: list[Datapoint]):
self.sdata[3] = value
@property
def r(self) -> int:
return self.opts.resistance
- def s(self, name: str) -> List[Datapoint]:
+ def s(self, name: str) -> list[Datapoint]:
return self.sdata[Touchstone.FIELD_ORDER.index(name)]
def s_freq(self, name: str, freq: int) -> Datapoint:
diff --git a/src/NanoVNASaver/Version.py b/src/NanoVNASaver/Version.py
index f6bf3e2..f103d56 100644
--- a/src/NanoVNASaver/Version.py
+++ b/src/NanoVNASaver/Version.py
@@ -17,12 +17,12 @@
# along with this program. If not, see .
import logging
import re
+import typing
logger = logging.getLogger(__name__)
-class Version:
- RXP = re.compile(
+_RXP = re.compile(
r"""^
\D*
(?P\d+)\.
@@ -33,61 +33,26 @@ class Version:
re.VERBOSE,
)
- def __init__(self, vstring: str = "0.0.0"):
- self.data = {
- "major": 0,
- "minor": 0,
- "revision": 0,
- "note": "",
- }
- try:
- self.data = Version.RXP.search(vstring).groupdict()
- for name in ("major", "minor", "revision"):
- self.data[name] = int(self.data[name])
- except TypeError:
- self.data["revision"] = 0
- except AttributeError:
- logger.error("Unable to parse version: %s", vstring)
- def __gt__(self, other: "Version") -> bool:
- left, right = self.data, other.data
- for name in ("major", "minor", "revision"):
- if left[name] > right[name]:
- return True
- if left[name] < right[name]:
- return False
- return False
-
- def __lt__(self, other: "Version") -> bool:
- return other.__gt__(self)
-
- def __ge__(self, other: "Version") -> bool:
- return self.__gt__(other) or self.__eq__(other)
-
- def __le__(self, other: "Version") -> bool:
- return other.__gt__(self) or self.__eq__(other)
-
- def __eq__(self, other: "Version") -> bool:
- return self.data == other.data
+class _Version(typing.NamedTuple):
+ major: int
+ minor: int
+ revision: int
+ note: str
def __str__(self) -> str:
return (
- f'{self.data["major"]}.{self.data["minor"]}'
- f'.{self.data["revision"]}{self.data["note"]}'
+ f'{self.major}.{self.minor}'
+ f'.{self.revision}{self.note}'
)
- @property
- def major(self) -> int:
- return self.data["major"]
- @property
- def minor(self) -> int:
- return self.data["minor"]
+def Version(vstring: str = "0.0.0") -> '_Version':
+ if (match := _RXP.search(vstring)) is None:
+ logger.error("Unable to parse version: %s", vstring)
+ return _Version(0, 0, 0, '')
- @property
- def revision(self) -> int:
- return self.data["revision"]
-
- @property
- def note(self) -> str:
- return self.data["note"]
+ return _Version(int(match.group('major')),
+ int(match.group('minor')),
+ int(match.group('revision') or '0'),
+ match.group('note'))
diff --git a/src/NanoVNASaver/Windows/DisplaySettings.py b/src/NanoVNASaver/Windows/DisplaySettings.py
index 51f4f52..908d430 100644
--- a/src/NanoVNASaver/Windows/DisplaySettings.py
+++ b/src/NanoVNASaver/Windows/DisplaySettings.py
@@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import logging
-from typing import List
from PyQt6 import QtWidgets, QtCore
from PyQt6.QtGui import QColor, QColorConstants, QPalette, QShortcut
@@ -210,7 +209,7 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
vswr_marker_box = QtWidgets.QGroupBox("VSWR Markers")
vswr_marker_layout = QtWidgets.QFormLayout(vswr_marker_box)
- self.vswrMarkers: List[float] = self.app.settings.value(
+ self.vswrMarkers: list[float] = self.app.settings.value(
"VSWRMarkers", [], float
)
diff --git a/src/NanoVNASaver/__init__.py b/src/NanoVNASaver/__init__.py
index 8c289c0..e8935d1 100644
--- a/src/NanoVNASaver/__init__.py
+++ b/src/NanoVNASaver/__init__.py
@@ -1,13 +1,7 @@
-from importlib.metadata import (
- PackageNotFoundError,
- version,
-)
+import importlib.metadata
try:
# Change here if project is renamed and does not equal the package name
- dist_name = "nanovna-saver"
- __version__ = version(dist_name)
-except PackageNotFoundError: # pragma: no cover
+ __version__ = importlib.metadata.version(distribution_name="nanovna-saver")
+except importlib.metadata.PackageNotFoundError: # pragma: no cover
__version__ = "unknown"
-finally:
- del version, PackageNotFoundError
diff --git a/tests/test_sweep.py b/tests/test_sweep.py
index e4733bb..b6a484c 100644
--- a/tests/test_sweep.py
+++ b/tests/test_sweep.py
@@ -27,8 +27,10 @@ class TestCases(unittest.TestCase):
def test_sweep(self):
sweep = Sweep()
self.assertEqual(str(sweep),
- "Sweep(3600000, 30000000, 101, 1, Properties('',"
- " SweepMode.SINGLE, (3, 0), False))")
+ "Sweep(start=3600000, end=30000000, points=101,"
+ " segments=1, properties=Properties(name='',"
+ " mode=, averages=(3, 0),"
+ " logarithmic=False))")
self.assertTrue(Sweep(3600000) == sweep)
self.assertFalse(Sweep(3600001) == sweep)
self.assertRaises(ValueError, Sweep, -1)