From e87b95ba3a681ae6bdf61fd823fd82fb8beb6d06 Mon Sep 17 00:00:00 2001 From: flandre Date: Sun, 11 May 2025 17:35:37 +0800 Subject: [PATCH] clear config and launcher --- flandre/__init__.py | 173 ++++++++++++++++++++++++++-------- flandre/beamformer/dist.py | 5 +- flandre/config.py | 133 -------------------------- flandre/kde_pyqt6_mainui.py | 25 ++--- flandre/launcher.py | 58 +++++++++--- flandre/nodes/Beamformer.py | 2 +- flandre/nodes/Device.py | 2 +- flandre/nodes/ImageCV.py | 2 +- flandre/nodes/ImageFFMPEG.py | 2 +- flandre/nodes/ImageQt.py | 2 +- flandre/nodes/Loader.py | 5 +- flandre/nodes/MainUI.py | 11 +-- flandre/nodes/Mi.py | 2 +- flandre/nodes/Monitor.py | 2 +- flandre/nodes/Muxer.py | 2 +- flandre/nodes/Node.py | 3 + flandre/nodes/Recorder.py | 2 +- flandre/nodes/VideoQt.py | 2 +- flandre/pathconfig.py | 0 flandre/utils/Config.py | 6 +- flandre/utils/mi.py | 2 +- pyproject.toml | 2 +- test/legacy/driver_pull.py | 2 +- test/legacy/testdevicegui.py | 2 +- test/legacy/testdevicerecv.py | 2 +- test/multiprocess_config.py | 27 ++++++ test/platformdirs_test.py | 5 + 27 files changed, 254 insertions(+), 227 deletions(-) delete mode 100644 flandre/config.py delete mode 100644 flandre/pathconfig.py create mode 100644 test/multiprocess_config.py create mode 100644 test/platformdirs_test.py diff --git a/flandre/__init__.py b/flandre/__init__.py index d547158..25bd3d7 100644 --- a/flandre/__init__.py +++ b/flandre/__init__.py @@ -1,47 +1,146 @@ -import shutil -import subprocess +import dataclasses +import json import sys from pathlib import Path -import click import platformdirs MODULE_FOLDER = Path(__file__).parent -ASSETS = MODULE_FOLDER / 'assets' -PYQT = MODULE_FOLDER / 'pyqt' -DEV_PROJECT_FOLDER = MODULE_FOLDER.parent -@click.command() -@click.option('--data_folder', default=None) -@click.option('--generate_pyqt', default=True) -@click.option('--dev/--no-dev', default=True) -@click.option('-p', '--path', type=str, - default=platformdirs.user_config_path('Flandre', 'Scarlet') / 'launch.toml', - help='Path to launch.toml' - ) -def entrypoint(data_folder, generate_pyqt, dev, path): - from flandre.config import C - from flandre.launcher import launch_from_file - if dev and '--dev' not in sys.argv: - sys.argv.append('--dev') - - if (pyuic6 := shutil.which('pyuic6')) is None: - print('pyuic6 is not installed') - return - if generate_pyqt: - subprocess.run([pyuic6, '-o', PYQT / 'Main.py', PYQT / 'Main.ui']) - subprocess.run([pyuic6, '-o', PYQT / 'Image.py', PYQT / 'Image.ui']) - if data_folder is not None: - C.data_folder = Path(data_folder) - - path = Path(path) - if not path.exists(): - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text('[MainUI]\n') - print('Use launch config', path) - launch_from_file(path) +class P: + ASSETS = MODULE_FOLDER / 'assets' + PYQT = MODULE_FOLDER / 'pyqt' + DEV_PROJECT_FOLDER = MODULE_FOLDER.parent -if __name__ == '__main__': - entrypoint() +@dataclasses.dataclass +class SoftwareConfig: + def s(self, host, port, proto='tcp'): + return f'{proto}://{host}:{port}' + + data_folder_: Path = platformdirs.user_data_path('Flandre', 'Scarlet') / 'record' + config_folder: Path = platformdirs.user_config_path('Flandre', 'Scarlet') + + @property + def software_config_file(self): + return self.config_folder / 'software.json' + + @property + def data_folder(self): + self.data_folder_.mkdir(exist_ok=True, parents=True) + return self.data_folder_ + + @data_folder.setter + def data_folder(self, value): + self.data_folder_ = value + + @property + def imaging_config_folder(self): + p = self.config_folder / 'imaging' + p.mkdir(exist_ok=True, parents=True) + return p + + @property + def device_config_folder(self): + p = self.config_folder / 'device' + p.mkdir(exist_ok=True, parents=True) + return p + + video_height: int = 1080 + video_width: int = 960 + + live_ip: str = '11.6.1.71' + live_push_port: int = 5555 + live_rep_port: int = 5556 + device_py_rep_port: int = 5558 + + @property + def live_push_socket(self): + return f'tcp://{self.live_ip}:{self.live_push_port}' + + @property + def live_rep_socket(self): + return f'tcp://{self.live_ip}:{self.live_rep_port}' + + @property + def live_rep_socket_http(self): + return f'http://{self.live_ip}:{self.live_rep_port}' + + @property + def device_py_rep_socket(self): + return f'tcp://{self.live_ip}:{self.device_py_rep_port}' + + playback_port: int = 5003 + + @property + def playback_socket(self): + return f'tcp://127.0.0.1:{self.playback_port}' + + local_ip: str = '127.0.0.1' + mi_rep_port: int = 5557 + muxer_rep_port: int = 5560 + driver_rep_port: int = 5561 + + @property + def mi_rep_socket(self): + return self.s(self.local_ip, self.device_py_rep_port) + + @property + def muxer_rep_socket(self): + return self.s(self.local_ip, self.muxer_rep_port) + + @property + def driver_rep_socket(self): + return self.s(self.local_ip, self.driver_rep_port) + + switch1_ip: str = 'c1' + switch1_token: str = '7ad51e0016e7a9d22f753d5110f76c7d' + switch2_ip: str = 'c2' + switch2_token: str = 'bf5a7b77a1ba3761ea63fafd8427b7d6' + + @staticmethod + def read_config(path: Path): + return SoftwareConfig.read_config_text(path.read_text(encoding='utf-8')) + + @staticmethod + def read_config_text(text: str): + j = json.loads(text) + arg_d = dict() + for field in dataclasses.fields(SoftwareConfig): + try: + v = j[field.name] + match field.type.__name__: + case 'Path': + arg_d[field.name] = Path(v) + case _: + arg_d[field.name] = v + except KeyError: + pass + sc = SoftwareConfig(**arg_d) + return sc + + @property + def json_text(self): + arg_d = dict() + for field in dataclasses.fields(SoftwareConfig): + v = self.__getattribute__(field.name) + match field.type.__name__: + case 'Path': + arg_d[field.name] = str(v) + case _: + arg_d[field.name] = v + return json.dumps(arg_d, indent=4) + + def write_config(self, config_file=None): + if config_file is None: + config_file = self.software_config_file + config_file.parent.mkdir(exist_ok=True, parents=True) + config_file.write_text(self.json_text, encoding='utf-8') + + def copy_form(self, arg: 'SoftwareConfig'): + for field in dataclasses.fields(SoftwareConfig): + self.__setattr__(field.name, arg.__getattribute__(field.name)) + + +C = SoftwareConfig() diff --git a/flandre/beamformer/dist.py b/flandre/beamformer/dist.py index d320111..bd58d9c 100644 --- a/flandre/beamformer/dist.py +++ b/flandre/beamformer/dist.py @@ -5,9 +5,12 @@ where f(y,x) is the pixel distance in echo pulse RF signal between point(0,0) an import numpy as np from scipy.optimize import fsolve -from flandre.config import DS from flandre.utils.Config import DeviceConfig +# from flandre.config import DS + +DS = None + def refraction_dist(dev_cfg=DeviceConfig()): v1 = dev_cfg.v1 diff --git a/flandre/config.py b/flandre/config.py deleted file mode 100644 index e8b543c..0000000 --- a/flandre/config.py +++ /dev/null @@ -1,133 +0,0 @@ -import dataclasses -import json -import sys -from pathlib import Path - -import platformdirs - -from flandre import DEV_PROJECT_FOLDER - -ISDEV = False -if '--dev' in sys.argv: - ISDEV = True - -CONFIG_FOLDER = platformdirs.user_config_path('Flandre', 'Scarlet') - -if ISDEV: - CONFIG_FOLDER = DEV_PROJECT_FOLDER / 'config' - -DS = DEV_PROJECT_FOLDER / '@DS' -DS.mkdir(exist_ok=True, parents=True) - -SOFTWARE_CONFIG_PATH = CONFIG_FOLDER / 'software.json' - - -@dataclasses.dataclass -class SoftwareConfig: - def s(self, host, port, proto='tcp'): - return f'{proto}://{host}:{port}' - - data_folder: Path = DS - - @property - def imaging_config_folder(self): - p = CONFIG_FOLDER / 'imaging' - p.mkdir(exist_ok=True, parents=True) - return p - - @property - def device_config_folder(self): - p = CONFIG_FOLDER / 'device' - p.mkdir(exist_ok=True, parents=True) - return p - - video_height: int = 1080 - video_width: int = 960 - - live_ip: str = '11.6.1.71' - live_push_port: int = 5555 - live_rep_port: int = 5556 - device_py_rep_port: int = 5558 - - @property - def live_push_socket(self): - return f'tcp://{self.live_ip}:{self.live_push_port}' - - @property - def live_rep_socket(self): - return f'tcp://{self.live_ip}:{self.live_rep_port}' - - @property - def live_rep_socket_http(self): - return f'http://{self.live_ip}:{self.live_rep_port}' - - @property - def device_py_rep_socket(self): - return f'tcp://{self.live_ip}:{self.device_py_rep_port}' - - playback_port: int = 5003 - - @property - def playback_socket(self): - return f'tcp://127.0.0.1:{self.playback_port}' - - local_ip: str = '127.0.0.1' - mi_rep_port: int = 5557 - muxer_rep_port: int = 5560 - driver_rep_port: int = 5561 - - - @property - def mi_rep_socket(self): - return self.s(self.local_ip, self.device_py_rep_port) - - @property - def muxer_rep_socket(self): - return self.s(self.local_ip, self.muxer_rep_port) - - @property - def driver_rep_socket(self): - return self.s(self.local_ip, self.driver_rep_port) - - switch1_ip: str = 'c1' - switch1_token: str = '7ad51e0016e7a9d22f753d5110f76c7d' - switch2_ip: str = 'c2' - switch2_token: str = 'bf5a7b77a1ba3761ea63fafd8427b7d6' - - @staticmethod - def read_config(path: Path): - j = json.loads(path.read_text(encoding='utf-8')) - arg_d = dict() - for field in dataclasses.fields(SoftwareConfig): - try: - v = j[field.name] - match field.type: - case Path(): - arg_d[field.name] = Path(v) - case _: - arg_d[field.name] = v - except KeyError: - pass - sc = SoftwareConfig(**arg_d) - return sc - - def write_config(self): - arg_d = dict() - for field in dataclasses.fields(SoftwareConfig): - v = self.__getattribute__(field.name) - match v: - case Path(): - arg_d[field.name] = str(v) - case _: - arg_d[field.name] = v - SOFTWARE_CONFIG_PATH.parent.mkdir(exist_ok=True, parents=True) - SOFTWARE_CONFIG_PATH.write_text(json.dumps(arg_d, indent=4), encoding='utf-8') - - -C = SoftwareConfig() - -if SOFTWARE_CONFIG_PATH.exists() and not ISDEV: - C = SoftwareConfig.read_config(SOFTWARE_CONFIG_PATH) - -if __name__ == '__main__': - print(C) diff --git a/flandre/kde_pyqt6_mainui.py b/flandre/kde_pyqt6_mainui.py index 755ae2b..aa99c98 100644 --- a/flandre/kde_pyqt6_mainui.py +++ b/flandre/kde_pyqt6_mainui.py @@ -1,33 +1,24 @@ import logging import os import subprocess -import sys -from pathlib import Path - -from PyQt6 import QtWidgets import flandre -from flandre.config import C +from flandre import C from flandre.nodes.MainUI import MainUI -def kde_pyqt6_mainui(): - subprocess.run(['python', __file__, *sys.argv[1:]], +def kde_pyqt6_mainui(software_config): + flandre.C.write_config() + subprocess.run(['python', __file__], env=dict(XDG_CURRENT_DESKTOP="KDE", XDG_RUNTIME_DIR="/run/user/1000", XDG_SESSION_TYPE="wayland", - PYTHONPATH=os.environ.get('PYTHONPATH', flandre.MODULE_FOLDER.parent)) + PYTHONPATH=os.environ.get('PYTHONPATH', flandre.MODULE_FOLDER.parent), + FLANDRE_CONFIG=software_config.json_text, + ) ) if __name__ == '__main__': - if '--dev' in sys.argv: - print('qt styles:', QtWidgets.QStyleFactory.keys()) - try: - idx = sys.argv.index('--data_folder') - C.data_folder = Path(sys.argv[idx + 1]) - except ValueError: - pass - logging.basicConfig(level=logging.INFO) - MainUI()() + MainUI()(software_config=C.read_config_text(os.environ['FLANDRE_CONFIG'])) diff --git a/flandre/launcher.py b/flandre/launcher.py index e437151..9cac120 100644 --- a/flandre/launcher.py +++ b/flandre/launcher.py @@ -1,30 +1,35 @@ import logging import multiprocessing import os -import time +import shutil +import subprocess import tomllib from enum import Enum from pathlib import Path +import click +import platformdirs + +from flandre import C +from flandre import P from flandre.BusClient import BusClient from flandre.kde_pyqt6_mainui import kde_pyqt6_mainui from flandre.nodes.Beamformer import Beamformer from flandre.nodes.Broker import Broker from flandre.nodes.Device import Device from flandre.nodes.ImageCV import ImageCV -from flandre.nodes.Loader import Loader -from flandre.nodes.MainUI import MainUI -from flandre.nodes.Muxer import Muxer -from flandre.nodes.Robot import Robot from flandre.nodes.ImageFFMPEG import ImageFFMPEG from flandre.nodes.ImageQt import ImageQt -from flandre.nodes.Midi import Midi +from flandre.nodes.Loader import Loader +from flandre.nodes.MainUI import MainUI from flandre.nodes.Mi import Mi +from flandre.nodes.Midi import Midi +from flandre.nodes.Muxer import Muxer from flandre.nodes.Recorder import Recorder -from flandre.nodes.Web import Web +from flandre.nodes.Robot import Robot from flandre.nodes.VideoQt import VideoQt +from flandre.nodes.Web import Web from flandre.utils.Msg import KillMsg, NodeOnlineMsg, Msg1, Msg2 -from flandre.config import CONFIG_FOLDER class LaunchComponent(Enum): @@ -47,7 +52,7 @@ class LaunchComponent(Enum): def launch(arg: dict[LaunchComponent, dict]): logging.basicConfig(level=logging.INFO) multiprocessing.set_start_method('spawn') - bp = multiprocessing.Process(target=Broker(broker=True)) + bp = multiprocessing.Process(target=Broker(broker=True), kwargs=dict(software_config=C)) bp.start() ps = [] for k, v in arg.items(): @@ -58,7 +63,7 @@ def launch(arg: dict[LaunchComponent, dict]): pps = [] for p in ps: - pps.append(multiprocessing.Process(target=p)) + pps.append(multiprocessing.Process(target=p, kwargs=dict(software_config=C))) for p in pps: p.start() @@ -100,5 +105,36 @@ def launch_from_file(file: Path): launch(arg_d) +@click.command() +@click.option('--data_folder', default=None) +@click.option('--generate_pyqt', default=True) +@click.option('--dev/--no-dev', default=True) +@click.option('-p', '--path', type=str, + default=platformdirs.user_config_path('Flandre', 'Scarlet') / 'launch.toml', + help='Path to launch.toml' + ) +def entrypoint(data_folder, generate_pyqt, dev, path): + if dev: + C.config_folder = P.DEV_PROJECT_FOLDER / 'config' + else: + C.read_config(C.software_config_file) + + if (pyuic6 := shutil.which('pyuic6')) is None: + print('pyuic6 is not installed') + return + if generate_pyqt: + subprocess.run([pyuic6, '-o', P.PYQT / 'Main.py', P.PYQT / 'Main.ui']) + subprocess.run([pyuic6, '-o', P.PYQT / 'Image.py', P.PYQT / 'Image.ui']) + if data_folder is not None: + C.data_folder = Path(data_folder) + + path = Path(path) + if not path.exists(): + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text('[MainUI]\n') + print('Use launch config', path) + launch_from_file(path) + + if __name__ == '__main__': - launch_from_file(CONFIG_FOLDER / 'gui.toml') + entrypoint() diff --git a/flandre/nodes/Beamformer.py b/flandre/nodes/Beamformer.py index 7376aef..9d584fb 100644 --- a/flandre/nodes/Beamformer.py +++ b/flandre/nodes/Beamformer.py @@ -8,7 +8,7 @@ import zmq from flandre.beamformer.das import gen_pwi, TFM from flandre.beamformer.dist import direct_dist from flandre.beamformer.kernels import dist_mat_to_yids -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node from flandre.utils.Config import DeviceConfig from flandre.utils.Msg import ImageArgMsg, Msg, BeamformerMsg, RfMatMsg, RfFrameMsg, MaxMsg diff --git a/flandre/nodes/Device.py b/flandre/nodes/Device.py index 3c9b6d7..eb41979 100644 --- a/flandre/nodes/Device.py +++ b/flandre/nodes/Device.py @@ -7,7 +7,7 @@ from threading import Thread import zmq -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node from flandre.utils.Msg import ImageArgMsg, KillMsg, SetDeviceConnectedMsg, SetDeviceEnabledMsg, DeviceEnabledMsg, \ DeviceConnectedMsg, SetDeviceConfigMsg, DeviceOnlineMsg, DeviceConfigListMsg, RequestRfFrameMsg, \ diff --git a/flandre/nodes/ImageCV.py b/flandre/nodes/ImageCV.py index 7343b7a..106ff04 100644 --- a/flandre/nodes/ImageCV.py +++ b/flandre/nodes/ImageCV.py @@ -4,7 +4,7 @@ import cv2 import numpy as np import zmq -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node from flandre.utils.Msg import BMMsg, SetWindowVisibleMsg, RfMatMsg from flandre.utils.RfMat import RfMat diff --git a/flandre/nodes/ImageFFMPEG.py b/flandre/nodes/ImageFFMPEG.py index 503817e..f9d06e4 100644 --- a/flandre/nodes/ImageFFMPEG.py +++ b/flandre/nodes/ImageFFMPEG.py @@ -6,7 +6,7 @@ import cv2 import numpy as np from flandre.BusClient import BusClient -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node from flandre.utils.Msg import Msg, RfMatMsg from flandre.utils.RfMat import RfMat diff --git a/flandre/nodes/ImageQt.py b/flandre/nodes/ImageQt.py index 0c8ab70..28b1cd3 100644 --- a/flandre/nodes/ImageQt.py +++ b/flandre/nodes/ImageQt.py @@ -7,7 +7,7 @@ from PyQt6.QtCore import QByteArray, Qt from PyQt6.QtGui import QImage, QPixmap, QKeyEvent, QWheelEvent from PyQt6.QtWidgets import QMainWindow, QApplication, QGraphicsPixmapItem, QGraphicsScene -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node from flandre.pyqt.Image import Ui_MainWindow from flandre.pyqt.ZMQReceiver import ZMQReceiver diff --git a/flandre/nodes/Loader.py b/flandre/nodes/Loader.py index 061b5b5..2810199 100644 --- a/flandre/nodes/Loader.py +++ b/flandre/nodes/Loader.py @@ -3,7 +3,7 @@ from pathlib import Path import zmq -from flandre.config import C, ISDEV +from flandre import C from flandre.nodes.Node import Node from flandre.utils.Msg import MoveAxisMsg, KillMsg, SetSeqMetaMsg, SeqIdMinMax, SetBaseMsg, PlaybackSeqListMsg, \ SeqIdList, SetSidMsg, RfFrameMsg, RobotRtsiMsg @@ -49,8 +49,7 @@ class Loader(Node): logger.warning(f'No sequences found in {base}') else: C.data_folder = base - if not ISDEV: - C.write_config() + C.write_config() self.send(PlaybackSeqListMsg(seq_list)) elif isinstance(msg, KillMsg): if msg.name == '': diff --git a/flandre/nodes/MainUI.py b/flandre/nodes/MainUI.py index 8d3ea50..cd007f2 100644 --- a/flandre/nodes/MainUI.py +++ b/flandre/nodes/MainUI.py @@ -11,8 +11,8 @@ from PyQt6 import QtWidgets, QtGui from PyQt6.QtCore import QByteArray, pyqtSlot from PyQt6.QtWidgets import QMainWindow, QApplication, QFrame, QMessageBox, QFileDialog, QLineEdit -from flandre import ASSETS -from flandre.config import DS, C +from flandre import P +from flandre import C from flandre.nodes.Node import Node from flandre.pyqt.Main import Ui_MainWindow from flandre.pyqt.ZMQReceiver import ZMQReceiver @@ -73,12 +73,12 @@ class Adv(QMainWindow, Ui_MainWindow): self.device_switch_state: LinkStatus = LinkStatus.RED icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(str(ASSETS / 'switch_button.png'))) + icon.addPixmap(QtGui.QPixmap(str(P.ASSETS / 'switch_button.png'))) self.b_probe_head_switch.setIcon(icon) self.b_us_switch.setIcon(icon) self.b_cobot_switch.setIcon(icon) icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(str(ASSETS / 'refresh_button.png'))) + icon.addPixmap(QtGui.QPixmap(str(P.ASSETS / 'refresh_button.png'))) self.b_us_refresh.setIcon(icon) zmq_receiver = ZMQReceiver(self) zmq_receiver.zmq_event.connect(self.on_zmq_event) @@ -335,11 +335,9 @@ class Adv(QMainWindow, Ui_MainWindow): self.s_t_start.setMaximum(m) self.s_t_end.setMaximum(m) - self.sp_crop_center.setMaximum(m) self.sp_crop_width.setMaximum(m) - def update_max(self, m): self.s_f_rows.setMaximum(m) self.sp_f_rows.setMaximum(m) @@ -349,6 +347,7 @@ class Adv(QMainWindow, Ui_MainWindow): self.sp_dct_center.setMaximum(m) self.sp_dct_bandwidth.setMaximum(m) + def on_zmq_event(self, msg: QByteArray): try: msg = Msg.decode_msg(msg.data()) diff --git a/flandre/nodes/Mi.py b/flandre/nodes/Mi.py index 3ab96b2..b1b64fa 100644 --- a/flandre/nodes/Mi.py +++ b/flandre/nodes/Mi.py @@ -4,7 +4,7 @@ from threading import Thread import zmq -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node from flandre.utils.Msg import KillMsg, SetDeviceSwitchMsg, DeviceSwitchMsg, RefreshDeviceMsg, InterruptMsg from flandre.utils.mi import c1_connect, c1_connected, c1_disconnect diff --git a/flandre/nodes/Monitor.py b/flandre/nodes/Monitor.py index 884940e..116e7ba 100644 --- a/flandre/nodes/Monitor.py +++ b/flandre/nodes/Monitor.py @@ -3,7 +3,7 @@ import logging import zmq from flandre.BusClient import BusClient -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node logger = logging.getLogger(__name__) diff --git a/flandre/nodes/Muxer.py b/flandre/nodes/Muxer.py index 9428502..d20d5f5 100644 --- a/flandre/nodes/Muxer.py +++ b/flandre/nodes/Muxer.py @@ -6,7 +6,7 @@ from threading import Thread import zmq -from flandre.config import C +from flandre import C from flandre.nodes.Device import Device, DeviceCmd from flandre.nodes.Node import Node from flandre.utils.Msg import ImageArgMsg, KillMsg, SetSeqMetaMsg, SetPlayMode, SetDeviceConfigMsg, \ diff --git a/flandre/nodes/Node.py b/flandre/nodes/Node.py index ab4412f..3537da8 100644 --- a/flandre/nodes/Node.py +++ b/flandre/nodes/Node.py @@ -4,6 +4,7 @@ from abc import abstractmethod import zmq from flandre.BusClient import BusClient +import flandre from flandre.utils.Msg import Msg, KillMsg, NodeOnlineMsg, Msg1, Msg2 @@ -62,6 +63,8 @@ class Node: poller=True, conflare=self.conflare, req_socket_str=self.req) def __call__(self, *args, **kwargs): + assert 'software_config' in kwargs, self.__class__ + flandre.C.copy_form(kwargs['software_config']) self.setup() if not self.broker: while True: diff --git a/flandre/nodes/Recorder.py b/flandre/nodes/Recorder.py index 69b55ee..e92c58f 100644 --- a/flandre/nodes/Recorder.py +++ b/flandre/nodes/Recorder.py @@ -6,7 +6,7 @@ from pathlib import Path import numpy as np import zmq -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node from flandre.utils.Msg import ImageArgMsg, KillMsg, SetSeqMetaMsg, SetPlayMode, SetDeviceConfigMsg, SetRecordMsg, \ RequestRfFrameMsg, RecordFrameMsg, RobotRtsiMsg, SeqMetaMsg diff --git a/flandre/nodes/VideoQt.py b/flandre/nodes/VideoQt.py index 69b927e..939a2f7 100644 --- a/flandre/nodes/VideoQt.py +++ b/flandre/nodes/VideoQt.py @@ -7,7 +7,7 @@ from PyQt6.QtCore import QByteArray, Qt from PyQt6.QtGui import QImage, QPixmap, QKeyEvent, QWheelEvent from PyQt6.QtWidgets import QMainWindow, QApplication, QGraphicsPixmapItem, QGraphicsScene -from flandre.config import C +from flandre import C from flandre.nodes.Node import Node from flandre.pyqt.FFmpegReceiver import FFmpegReceiver from flandre.pyqt.Image import Ui_MainWindow diff --git a/flandre/pathconfig.py b/flandre/pathconfig.py deleted file mode 100644 index e69de29..0000000 diff --git a/flandre/utils/Config.py b/flandre/utils/Config.py index a79ad0d..e249a8f 100644 --- a/flandre/utils/Config.py +++ b/flandre/utils/Config.py @@ -1,8 +1,6 @@ import dataclasses import json -from flandre.config import CONFIG_FOLDER - @dataclasses.dataclass class ImagingConfig: @@ -31,13 +29,13 @@ class ImagingConfig: changed_field_orig_value: str | int = None @staticmethod - def from_file(input_format, focus_mode, folder=CONFIG_FOLDER): + def from_file(input_format, focus_mode, folder=None): try: return ImagingConfig(**json.load((folder / f'icfg_{input_format}_{focus_mode}.json').open())) except Exception as e: return ImagingConfig() - def save(self, input_format: str, focus_mode: str, folder=CONFIG_FOLDER): + def save(self, input_format: str, focus_mode: str, folder=None): json.dump(self.__dict__, (folder / f'icfg_{input_format}_{focus_mode}.json').open('w')) diff --git a/flandre/utils/mi.py b/flandre/utils/mi.py index db1ff79..13ae642 100644 --- a/flandre/utils/mi.py +++ b/flandre/utils/mi.py @@ -1,7 +1,7 @@ import click from miio.miioprotocol import MiIOProtocol -from flandre.config import C +from flandre import C def c1(): diff --git a/pyproject.toml b/pyproject.toml index 2874962..31d876a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,4 +32,4 @@ packages = { find = { where = ["."], include = ["flandre", "flandre.*"] } } package-data = { "flandre.assets" = ["*.svg", "*.png"], "flandre.pyqt" = ["*.ui"] } [project.scripts] -flandre = "flandre:entrypoint" +flandre = "flandre.launcher:entrypoint" diff --git a/test/legacy/driver_pull.py b/test/legacy/driver_pull.py index 57080d6..78df05c 100644 --- a/test/legacy/driver_pull.py +++ b/test/legacy/driver_pull.py @@ -1,6 +1,6 @@ import zmq -from flandre.config import C +from flandre import C from flandre.utils.RfFrame import b2t if __name__ == '__main__': diff --git a/test/legacy/testdevicegui.py b/test/legacy/testdevicegui.py index c98a07d..43a0585 100644 --- a/test/legacy/testdevicegui.py +++ b/test/legacy/testdevicegui.py @@ -5,7 +5,7 @@ import cv2 import numpy as np import zmq -from flandre.config import C +from flandre import C from flandre.nodes.Device import Device, DeviceCmd from flandre.nodes.Mi import Mi diff --git a/test/legacy/testdevicerecv.py b/test/legacy/testdevicerecv.py index c6c0a8f..21ce1b3 100644 --- a/test/legacy/testdevicerecv.py +++ b/test/legacy/testdevicerecv.py @@ -5,7 +5,7 @@ import cv2 import numpy as np import zmq -from flandre.config import C +from flandre import C from flandre.nodes.Device import Device, DeviceCmd from flandre.nodes.Mi import Mi diff --git a/test/multiprocess_config.py b/test/multiprocess_config.py new file mode 100644 index 0000000..7b5be55 --- /dev/null +++ b/test/multiprocess_config.py @@ -0,0 +1,27 @@ +import dataclasses +import multiprocessing + + +@dataclasses.dataclass +class Config: + arg: int = 1 + + +global_config = Config(arg=2) + + +def process1(): + print('Process1 arg=', global_config.arg) + + +def main(): + global_config.arg = 3 + multiprocessing.set_start_method("spawn") + p1 = multiprocessing.Process(target=process1) + p1.start() + p1.join() + print('main arg=', global_config.arg) + + +if __name__ == '__main__': + main() diff --git a/test/platformdirs_test.py b/test/platformdirs_test.py new file mode 100644 index 0000000..45a2dfc --- /dev/null +++ b/test/platformdirs_test.py @@ -0,0 +1,5 @@ +import platformdirs + +if __name__ == '__main__': + print(platformdirs.user_data_dir('Flandre', 'Scarlet')) + print(platformdirs.user_data_dir('Flandre'))