Trivial style changes (#625)

* Style: update type annotations

* Style: simplify extraction of version from metadata

* Style: replace some handwritten classes with namedtuples or dataclasses

* RIZ.py: remove unused import

* Style: remove some redundant lambda constructs

* Marker/Values: remove __init__ parameters

Mutable default values imply some complexity. In this case, the
constructor is always called without arguments.
pull/629/head
Name 2023-03-22 15:56:59 +01:00 zatwierdzone przez GitHub
rodzic d89c9f9d94
commit 6eb24f2315
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
42 zmienionych plików z 172 dodań i 279 usunięć

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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(

Wyświetl plik

@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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:
(

Wyświetl plik

@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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(),
}

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -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()

Wyświetl plik

@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import logging
from typing import List
from PyQt6 import QtWidgets
@ -54,7 +53,7 @@ class VSWRAnalysis(Analysis):
self.results_label = QtWidgets.QLabel("<b>Results</b>")
self.layout.addRow(self.results_label)
self.minimums: List[int] = []
self.minimums: list[int] = []
def runAnalysis(self):
if not self.app.data.s11:

Wyświetl plik

@ -18,7 +18,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -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)

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -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):

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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,
):

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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]

Wyświetl plik

@ -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]

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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]

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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)

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -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]

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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]

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -18,7 +18,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import logging
from PyQt6 import QtWidgets, QtGui
from PyQt6 import QtGui
from NanoVNASaver.Formatting import format_frequency_chart
from NanoVNASaver.RFTools import Datapoint

Wyświetl plik

@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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]

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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,
):

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -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}"

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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))

Wyświetl plik

@ -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():

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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)

Wyświetl plik

@ -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":

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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)

Wyświetl plik

@ -18,7 +18,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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))

Wyświetl plik

@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -18,7 +18,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -17,10 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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

Wyświetl plik

@ -18,7 +18,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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()

Wyświetl plik

@ -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:

Wyświetl plik

@ -17,12 +17,12 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import logging
import re
import typing
logger = logging.getLogger(__name__)
class Version:
RXP = re.compile(
_RXP = re.compile(
r"""^
\D*
(?P<major>\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'))

Wyświetl plik

@ -17,7 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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
)

Wyświetl plik

@ -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

Wyświetl plik

@ -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=<SweepMode.SINGLE: 0>, averages=(3, 0),"
" logarithmic=False))")
self.assertTrue(Sweep(3600000) == sweep)
self.assertFalse(Sweep(3600001) == sweep)
self.assertRaises(ValueError, Sweep, -1)