Package: dvg-pyqt-filelogger
DvG_PyQt_FileLoggerPyQt/PySide interface to handle logging data to file particularly well suited
for multithreaded programs.Supports PyQt5, PyQt6, PySide2 and PySide6.Github:https://github.com/Dennis-van-Gils/python-dvg-pyqt-fileloggerPyPI:https://pypi.org/project/dvg-pyqt-fileloggerInstallation:pip install dvg-pyqt-fileloggerAPIclass FileLogger(write_header_function: Callable = None, write_data_function: Callable = None)Bases:PyQt5.QtCore.QObjectHandles logging data to a file particularly well suited for multithreaded
programs where one thread is writing data to the log and the other thread
(the main/GUI thread) requests starting and stopping of the log, e.g.,
by the user pressing a button.The methodsstart_recording(),stop_recording()andrecord(bool)can be directly called from the main/GUI thread.In the logging thread you repeatedly need to callupdate(). This method
takes cares of the state machine behindFileLoggerand will perform the
appropiate action, such as creating a file on disk, creating the header or
writing new data to the log.Args:write_header_function (Callable, optional):Reference to a function that contains your specific code to write a
header to the log file. This will get called duringupdate().Default:Nonewrite_data_function (Callable, optional):Reference to a function that contains your specific code to write
new data to the log file. This will get called duringupdate().Default:NoneBoth of the above functions can contain calls to the following class
members:FileLogger.write()FileLogger.elapsed()NOTE:This class lacks a mutex and is hence not threadsafe from the get-go.
As long asupdate()is being called from inside another mutex, such
as a data-acquisition mutex for instance, it is safe.NOTE:By design the code in this class will continue on when exceptions occur.
They are reported to the command line.Signals:signal_recording_started (str):Emitted whenever a new recording has started. Useful for, e.g.,
updating text of a record button.Returns:The filepath asstrof the newly created log file.Type:PyQt5.QtCore.pyqtSignal()signal_recording_stopped (pathlib.Path):Emitted whenever the recording has stopped. Useful for, e.g., updating
text of a record button.Returns:The filepath aspathlib.Path()of the newly created log file.
You could use this to, e.g., automatically navigate to the log in
the file explorer or ask the user for a ‘save to’ destination.Type:PyQt5.QtCore.pyqtSignal()Example usage:fromPyQt5importQtWidgetsasQtWidfromdvg_pyqt_fileloggerimportFileLogger#  When using a PyQt5 GUI put this inside your ``MainWindow()`` definition:# ----self.qpbt_record=QtWid.QPushButton(text="Click to start recording to file",checkable=True)self.qpbt_record.clicked.connect(lambdastate:log.record(state))#  Initialize FileLogger at __main__# ----window=MainWindow()log=FileLogger(write_header_function=write_header_to_log,write_data_function=write_data_to_log)log.signal_recording_started.connect(lambdafilepath:window.qpbt_record.setText("Recording to file:%s"%filepath))log.signal_recording_stopped.connect(lambda:window.qpbt_record.setText("Click to start recording to file"))#  Define these functions in your main module:# ----defwrite_header_to_log():log.write("elapsed [s]\treading_1\n")defwrite_data_to_log():log.write("%.3f\t%.4f\n"%(log.elapsed(),state.reading_1))#  Lastly, put this inside your logging thread:# ----log.update()Methodsset_write_header_function(write_header_function: Callable)set_write_data_function(write_data_function: Callable)record(state: bool = True)Can be called from any thread.start_recording()Can be called from any thread.stop_recording()Can be called from any thread.update(filepath: str = "", mode: str = "a")This method will have to get called repeatedly, presumably in the
thread where logging is required, e.g., the data-generation thread.
This method takes cares of the state machine behindFileLoggerand
will perform the appropriate action, such as creating a file on disk,
creating the header or writing new data to the log.Args:filepath (str):Location of the log file in case it has to be created or opened
for write access.Default:"{yyMMdd_HHmmss}.txt"denoting the current date and time.mode (str, optional):Mode in which the log file is to be opened, seeopen()for
more details. Most common options:w: Open for writing, truncating the file first.a: Open for writing, appending to the end of the file
if it exists.Defaults:awrite(data: AnyStr)->boolWrite binary or ASCII data to the currently opened log file. By
design any exceptions occurring in this method will not terminate the
execution, but it will report the error to the command line and continue
on instead.Returns True if successful, False otherwise.np_savetxt(*args,**kwargs)->boolWrite 1D or 2D array_like data to the currently opened log file. This
method passes all arguments directly tonumpy.savetxt(), seehttps://numpy.org/doc/stable/reference/generated/numpy.savetxt.html.
This method outperformsFileLogger.write(), especially when large
chunks of 2D data are passed (my test shows 8x faster).By design any exceptions occurring in this method will not terminate the
execution, but it will report the error to the command line and continue
on instead.Returns True if successful, False otherwise.flush()Force-flush the contents in the OS buffer to file as soon as
possible. Do not call repeatedly, because it causes overhead.close()is_recording()->boolelapsed()->floatReturns time in seconds (float) since start of recording.pretty_elapsed()->strReturns time as “h:mm:ss” (str) since start of recording.Changelog1.3.0 (2023-02-27)RaiseImportErrorinstead of generalException1.2.0 (2022-09-13)Added support for PyQt5, PyQt6, PySide2 and PySide61.1.0 (2021-05-13)Added support fornumpy.savetxt()1.0.0 (2020-08-11)First release on PyPI