Feature/refactor settings (#507)

* fixed Default module
* fixed QByteArray parsing
* updated changelog
* refactored charts
pull/509/head
Holger Müller 2022-05-27 13:02:18 +02:00 zatwierdzone przez GitHub
rodzic 7b9d803b35
commit 01c83cd2f0
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 112 dodań i 39 usunięć

Wyświetl plik

@ -1,6 +1,15 @@
Changelog
=========
0.5.0 pre
---------
- Fix crash on open in use serial device
- Use a Defaults module for all settings -
ignores old .ini settings
- Refactoring and unifying Chart classes
- No more automatic update checks (more privacy)
0.4.0
-----

Wyświetl plik

@ -19,13 +19,15 @@
import dataclasses as DC
import logging
import json
from PyQt5.QtCore import QSettings
from ast import literal_eval
from PyQt5 import QtCore
from PyQt5.QtCore import QSettings, QByteArray
from PyQt5.QtGui import QColor
logger = logging.getLogger(__name__)
# pylint: disable=too-few-public-methods
# pylint: disable=too-many-instance-attributes
@DC.dataclass
@ -33,12 +35,22 @@ class GUI:
window_height: int = 950
window_width: int = 1433
font_size: int = 8
custom_colors: bool = False
dark_mode: bool = False
# TODO: implement QByteArray
splitter_sizes: bytearray = DC.field(default_factory=bytearray)
splitter_sizes: QByteArray = DC.field(default_factory=QByteArray)
markers_hidden: bool = False
@DC.dataclass
class ChartsSelected:
chart_00: str = 'S11 Smith Chart'
chart_01: str = 'S11 Return Loss'
chart_02: str = 'None'
chart_10: str = 'S21 Polar Plot'
chart_11: str = 'S21 Gain'
chart_12: str = 'None'
@DC.dataclass
class Chart:
point_size: int = 2
@ -50,16 +62,51 @@ class Chart:
marker_at_tip: bool = False
marker_size: int = 8
returnloss_is_positive: bool = False
show_bands: bool = False
vswr_lines: list = DC.field(default_factory=lambda: [])
@DC.dataclass
class ChartColors: # pylint: disable=too-many-instance-attributes
background: QColor = QColor(QtCore.Qt.white)
foreground: QColor = QColor(QtCore.Qt.lightGray)
reference: QColor = QColor(0, 0, 255, 64)
reference_secondary: QColor = QColor(0, 0, 192, 48)
sweep: QColor = QColor(QtCore.Qt.darkYellow)
sweep_secondary: QColor = QColor(QtCore.Qt.darkMagenta)
swr: QColor = QColor(255, 0, 0, 128)
text: QColor = QColor(QtCore.Qt.black)
bands: QColor = QColor(128, 128, 128, 48)
@DC.dataclass
class Markers:
active_labels: list = DC.field(default_factory=lambda: [
"actualfreq", "impedance", "serr", "serl", "serc", "parr", "parlc",
"vswr", "returnloss", "s11q", "s11phase", "s21gain", "s21phase",
])
colored_names: bool = True
color_0: QColor = QColor(QtCore.Qt.darkGray)
color_1: QColor = QColor(255, 0, 0)
color_2: QColor = QColor(0, 255, 0)
color_3: QColor = QColor(0, 0, 255)
color_4: QColor = QColor(0, 255, 255)
color_5: QColor = QColor(255, 0, 255)
color_6: QColor = QColor(255, 255, 0)
color_7: QColor = QColor(QtCore.Qt.lightGray)
@DC.dataclass
class CFG:
gui: object = GUI()
charts_selected: object = ChartsSelected()
chart: object = Chart()
chart_colors: object = ChartColors()
markers: object = Markers()
cfg = CFG()
def restore(settings: 'AppSettings') -> CFG:
result = CFG()
for field in DC.fields(result):
@ -70,15 +117,42 @@ def restore(settings: 'AppSettings') -> CFG:
return result
def store(settings: 'AppSettings', data: CFG) -> None:
def store(settings: 'AppSettings', data: CFG = None) -> None:
data = data or cfg
logger.debug("storing\n(\n%s\n)", data)
assert isinstance(data, CFG)
for field in DC.fields(data):
data_class = getattr(data, field.name)
data_class = getattr(data, field.name)
assert DC.is_dataclass(data_class)
settings.store_dataclass(field.name.upper(), data_class)
def from_type(data) -> str:
type_map = {
bytearray: lambda x: x.hex(),
QColor: lambda x: x.getRgb(),
QByteArray: lambda x: x.toHex(),
}
if type(data) in type_map:
return str(type_map[type(data)](data))
return str(data)
def to_type(data: object, data_type: type) -> object:
type_map = {
bool: lambda x: x.lower() == 'true',
bytearray: bytearray.fromhex,
list: literal_eval,
tuple: literal_eval,
QColor: lambda x: QColor.fromRgb(*literal_eval(x)),
QByteArray: lambda x: QByteArray.fromHex(literal_eval(x)),
}
if data_type in type_map:
return type_map[data_type](data)
return data_type(data)
# noinspection PyDataclass
class AppSettings(QSettings):
def store_dataclass(self, name: str, data: object) -> None:
assert DC.is_dataclass(data)
@ -87,16 +161,11 @@ class AppSettings(QSettings):
value = getattr(data, field.name)
try:
assert isinstance(value, field.type)
except AssertionError:
logger.error("%s: %s is not a %s", name, field.name,
field.type)
continue
if field.type not in (int, float, str, bool):
try:
value = json.dumps(value)
except TypeError:
value = field.type(value).hex()
self.setValue(field.name, value)
except AssertionError as exc:
logger.error("%s: %s of type %s is not a %s",
name, field.name, type(value), field.type)
raise TypeError from exc
self.setValue(field.name, from_type(value))
self.endGroup()
def restore_dataclass(self, name: str, data: object) -> object:
@ -105,21 +174,14 @@ class AppSettings(QSettings):
result = DC.replace(data)
self.beginGroup(name)
for field in DC.fields(data):
value = None
if field.type in (int, float, str, bool):
value = self.value(field.name,
type=field.type,
defaultValue=field.default)
else:
default = getattr(data, field.name)
try:
value = json.loads(
self.value(field.name, type=str,
defaultValue=json.dumps(default)))
except TypeError:
value = self.value(field.name)
value = bytes.fromhex(value) if value is str else default
setattr(result, field.name, field.type(value))
default = getattr(data, field.name)
value = self.value(field.name, type=str, defaultValue="")
if not value:
setattr(result, field.name, default)
continue
try:
setattr(result, field.name, to_type(value, field.type))
except TypeError:
setattr(result, field.name, default)
self.endGroup()
return result

Wyświetl plik

@ -17,6 +17,14 @@ points, and generally display and analyze the resulting data.
Latest Changes
--------------
### Changes in 0.5.0 pre
- Fix crash on open in use serial device
- Use a Defaults module for all settings -
ignores old .ini settings
- Refactoring and unifying Chart classes
- No more automatic update checks (more privacy)
### Changes in 0.4.0
- PA0JOZ Enhanced Response Correction
@ -36,12 +44,6 @@ Latest Changes
- Reference plane applied after calibration
- Calibration fixes by DiSlord
### Changes in v0.3.9
- TX Power on V2
- New analysis
- Magnitude Z Chart
- VSWR Chart improvements
Introduction
------------