p3lib 1.1.74__py3-none-any.whl → 1.1.75__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- p3lib/ngt.py +129 -54
- {p3lib-1.1.74.dist-info → p3lib-1.1.75.dist-info}/METADATA +1 -1
- {p3lib-1.1.74.dist-info → p3lib-1.1.75.dist-info}/RECORD +6 -6
- {p3lib-1.1.74.dist-info → p3lib-1.1.75.dist-info}/LICENSE +0 -0
- {p3lib-1.1.74.dist-info → p3lib-1.1.75.dist-info}/WHEEL +0 -0
- {p3lib-1.1.74.dist-info → p3lib-1.1.75.dist-info}/top_level.txt +0 -0
p3lib/ngt.py
CHANGED
@@ -8,22 +8,12 @@
|
|
8
8
|
import traceback
|
9
9
|
import os
|
10
10
|
import platform
|
11
|
-
import argparse
|
12
11
|
|
13
12
|
from time import sleep
|
14
|
-
from p3lib.uio import UIO
|
15
|
-
from p3lib.helper import logTraceBack
|
16
|
-
|
17
13
|
from queue import Queue
|
18
14
|
from time import time, strftime, localtime
|
19
15
|
|
20
|
-
|
21
|
-
from nicegui import ui, app
|
22
|
-
|
23
|
-
from pathlib import Path
|
24
|
-
from typing import Optional
|
25
|
-
|
26
|
-
from nicegui import events
|
16
|
+
from nicegui import ui
|
27
17
|
|
28
18
|
class TabbedNiceGui(object):
|
29
19
|
"""@brief Responsible for starting the providing a tabbed GUI.
|
@@ -38,6 +28,7 @@ class TabbedNiceGui(object):
|
|
38
28
|
# than normal.
|
39
29
|
DESCRIP_STYLE = '<span style="font-size:1.2em;">'
|
40
30
|
ENABLE_BUTTONS = "ENABLE_BUTTONS"
|
31
|
+
NOTIFY_DIALOG = "NOTIFY_DIALOG"
|
41
32
|
UPDATE_SECONDS = "UPDATE_SECONDS"
|
42
33
|
INFO_MESSAGE = "INFO: "
|
43
34
|
WARN_MESSAGE = "WARN: "
|
@@ -46,6 +37,7 @@ class TabbedNiceGui(object):
|
|
46
37
|
MAX_PROGRESS_VALUE = 100
|
47
38
|
DEFAULT_SERVER_PORT = 9812
|
48
39
|
GUI_TIMER_SECONDS = 0.1
|
40
|
+
PROGRESS_TIMER_SECONDS = 1.0
|
49
41
|
UPDATE_SECONDS = "UPDATE_SECONDS"
|
50
42
|
DEFAULT_GUI_RESPONSE_TIMEOUT= 30.0
|
51
43
|
POETRY_CONFIG_FILE = "pyproject.toml"
|
@@ -72,6 +64,15 @@ class TabbedNiceGui(object):
|
|
72
64
|
logFileName = f"{logFilePrefix}_{dateTimeStamp}.log"
|
73
65
|
return logFileName
|
74
66
|
|
67
|
+
@staticmethod
|
68
|
+
def CheckPort(port):
|
69
|
+
"""@brief Check the server port.
|
70
|
+
@param port The server port."""
|
71
|
+
if port < 1024:
|
72
|
+
raise Exception("The minimum TCP port that you can bind the GUI server to is 1024.")
|
73
|
+
if port > 65535:
|
74
|
+
raise Exception("The maximum TCP port that you can bind the GUI server to is 65535.")
|
75
|
+
|
75
76
|
@staticmethod
|
76
77
|
def GetProgramVersion():
|
77
78
|
"""@brief Get the program version from the poetry pyproject.toml file.
|
@@ -99,17 +100,21 @@ class TabbedNiceGui(object):
|
|
99
100
|
if programVersion is None:
|
100
101
|
raise Exception(f"Failed to extract program version from '{line}' line of {poetryConfigFile} file.")
|
101
102
|
return programVersion
|
102
|
-
|
103
|
+
|
103
104
|
def __init__(self, debugEnabled, logPath=None):
|
104
105
|
"""@brief Constructor
|
105
106
|
@param debugEnabled True if debugging is enabled.
|
106
107
|
@param logPath The path to store log files. If left as None then no log files are created."""
|
107
|
-
self._debugEnabled
|
108
|
-
self._logFile
|
109
|
-
self._buttonList
|
110
|
-
self._logMessageCount
|
111
|
-
self.
|
112
|
-
self.
|
108
|
+
self._debugEnabled = debugEnabled
|
109
|
+
self._logFile = None # This must be defined in subclass if logging to a file is required.
|
110
|
+
self._buttonList = []
|
111
|
+
self._logMessageCount = 0
|
112
|
+
self._updateProgressOnTimer = False
|
113
|
+
self._progressStepValue = 0
|
114
|
+
self._progressBarStartMessage = ""
|
115
|
+
self._progressBarExpectedMessageList = []
|
116
|
+
self._expectedProgressBarMessageIndex = 0
|
117
|
+
self._programVersion = TabbedNiceGui.GetProgramVersion()
|
113
118
|
|
114
119
|
self._logPath = None
|
115
120
|
if logPath:
|
@@ -145,29 +150,35 @@ class TabbedNiceGui(object):
|
|
145
150
|
"""@brief Send a info message to be displayed in the GUI.
|
146
151
|
This can be called from outside the GUI thread.
|
147
152
|
@param msg The message to be displayed."""
|
148
|
-
msgDict = {TabbedNiceGui.INFO_MESSAGE: msg}
|
153
|
+
msgDict = {TabbedNiceGui.INFO_MESSAGE: str(msg)}
|
149
154
|
self.updateGUI(msgDict)
|
150
155
|
|
151
156
|
def warn(self, msg):
|
152
157
|
"""@brief Send a warning message to be displayed in the GUI.
|
153
158
|
This can be called from outside the GUI thread.
|
154
159
|
@param msg The message to be displayed."""
|
155
|
-
msgDict = {TabbedNiceGui.WARN_MESSAGE: msg}
|
160
|
+
msgDict = {TabbedNiceGui.WARN_MESSAGE: str(msg)}
|
156
161
|
self.updateGUI(msgDict)
|
157
162
|
|
158
163
|
def error(self, msg):
|
159
164
|
"""@brief Send a error message to be displayed in the GUI.
|
160
165
|
This can be called from outside the GUI thread.
|
161
166
|
@param msg The message to be displayed."""
|
162
|
-
msgDict = {TabbedNiceGui.ERROR_MESSAGE:
|
167
|
+
msgDict = {TabbedNiceGui.ERROR_MESSAGE: str(msg)}
|
163
168
|
self.updateGUI(msgDict)
|
164
169
|
|
170
|
+
def infoDialog(self, msg):
|
171
|
+
"""@brief Display an info level dialog.
|
172
|
+
@param msg The message dialog."""
|
173
|
+
msgDict = {TabbedNiceGui.NOTIFY_DIALOG: str(msg)}
|
174
|
+
self.updateGUI(msgDict)
|
175
|
+
|
165
176
|
def debug(self, msg):
|
166
177
|
"""@brief Send a debug message to be displayed in the GUI.
|
167
178
|
This can be called from outside the GUI thread.
|
168
179
|
@param msg The message to be displayed."""
|
169
180
|
if self._debugEnabled:
|
170
|
-
msgDict = {TabbedNiceGui.DEBUG_MESSAGE: msg}
|
181
|
+
msgDict = {TabbedNiceGui.DEBUG_MESSAGE: str(msg)}
|
171
182
|
self.updateGUI(msgDict)
|
172
183
|
|
173
184
|
async def getInput(self, prompt):
|
@@ -193,11 +204,11 @@ class TabbedNiceGui(object):
|
|
193
204
|
If not then the exception message is displayed.
|
194
205
|
@param exception The exception instance."""
|
195
206
|
if self._debugEnabled:
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
207
|
+
lines = traceback.format_exc().split("\n")
|
208
|
+
for line in lines:
|
209
|
+
self.error(line)
|
210
|
+
if len(exception.args) > 0:
|
211
|
+
self.error(exception.args[0])
|
201
212
|
|
202
213
|
def _sendEnableAllButtons(self, state):
|
203
214
|
"""@brief Send a message to the GUI to enable/disable all the GUI buttons.
|
@@ -303,7 +314,8 @@ class TabbedNiceGui(object):
|
|
303
314
|
self._log.push(msg)
|
304
315
|
self._saveLogMsg(msg)
|
305
316
|
self._logMessageCount += 1
|
306
|
-
|
317
|
+
# We've received a log message so update progress bar if required.
|
318
|
+
self._updateProgressBar(msg)
|
307
319
|
|
308
320
|
def _infoGT(self, msg):
|
309
321
|
"""@brief Update an info level message. This must be called from the GUI thread.
|
@@ -344,7 +356,9 @@ class TabbedNiceGui(object):
|
|
344
356
|
if enabled:
|
345
357
|
for button in self._buttonList:
|
346
358
|
button.enable()
|
347
|
-
|
359
|
+
# No buttons are enabled, any executed task must be complete therefor hide the progress bar.
|
360
|
+
self._stopProgress()
|
361
|
+
|
348
362
|
else:
|
349
363
|
for button in self._buttonList:
|
350
364
|
button.disable()
|
@@ -352,8 +366,8 @@ class TabbedNiceGui(object):
|
|
352
366
|
if self._progressStepValue > 0:
|
353
367
|
self._progress.set_visibility(True)
|
354
368
|
|
355
|
-
def
|
356
|
-
"""@called periodically to allow updates of the GUI."""
|
369
|
+
def guiTimerCallback(self):
|
370
|
+
"""@called periodically (quickly) to allow updates of the GUI."""
|
357
371
|
while not self._toGUIQueue.empty():
|
358
372
|
rxMessage = self._toGUIQueue.get()
|
359
373
|
if isinstance(rxMessage, dict):
|
@@ -391,39 +405,97 @@ class TabbedNiceGui(object):
|
|
391
405
|
ui.label("Message Log")
|
392
406
|
self._progress = ui.slider(min=0,max=TabbedNiceGui.MAX_PROGRESS_VALUE,step=1)
|
393
407
|
self._progress.set_visibility(False)
|
408
|
+
self._progress.min = 0
|
409
|
+
# Don't allow user to adjust progress bar thumb
|
410
|
+
self._progress.disable()
|
394
411
|
self._log = ui.log(max_lines=2000)
|
395
412
|
self._log.set_visibility(True)
|
396
413
|
|
397
414
|
with ui.row():
|
398
|
-
ui.button('Quit', on_click=self.close)
|
399
|
-
ui.button('Log Message Count', on_click=self._showLogMsgCount)
|
400
415
|
ui.button('Clear Log', on_click=self._clearLog)
|
416
|
+
ui.button('Log Message Count', on_click=self._showLogMsgCount)
|
417
|
+
ui.button('Quit', on_click=self.close)
|
401
418
|
|
402
419
|
with ui.row():
|
403
420
|
ui.label(f"Software Version: {self._programVersion}")
|
404
421
|
|
405
|
-
ui.timer(interval=TabbedNiceGui.GUI_TIMER_SECONDS, callback=self.
|
422
|
+
ui.timer(interval=TabbedNiceGui.GUI_TIMER_SECONDS, callback=self.guiTimerCallback)
|
423
|
+
ui.timer(interval=TabbedNiceGui.PROGRESS_TIMER_SECONDS, callback=self.progressTimerCallback)
|
406
424
|
ui.run(host=address, port=port, title=pageTitle, dark=True, uvicorn_logging_level=guiLogLevel, reload=reload)
|
407
425
|
|
408
|
-
def
|
409
|
-
"""@brief
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
426
|
+
def progressTimerCallback(self):
|
427
|
+
"""@brief Time to update the progress bar. We run the timer all the time because there appears to be a
|
428
|
+
bug in the ui.timer instance. Calling cancel() does not appear to cancel the timer."""
|
429
|
+
if self._updateProgressOnTimer and self._progress.visible:
|
430
|
+
# Increment the progress bar
|
431
|
+
self._progress.set_value( self._progress.value + self._progressStepValue )
|
432
|
+
|
433
|
+
def _startProgress(self, durationSeconds=0, startMessage=None, expectedMsgList=[]):
|
434
|
+
"""@brief Start a timer that will update the progress bar.
|
435
|
+
The progress bar can simply update on a timer every second with durationSeconds set to the expected length
|
436
|
+
of the task if startMessage is unset and startMessage = None and expectedMessageCount = 0.
|
437
|
+
|
438
|
+
Alternatively if durationSeconds is set and startMessage (expectedMessageCount = 0) is set to some text that
|
439
|
+
we expect to receive in the log before the progress timer (as detailed above) is triggered.
|
440
|
+
|
441
|
+
Alternatively if expectedMsgList contains a list of strings we expect to receive then the progress bar is
|
442
|
+
updated as each message is received. The messages may be the entire line of a log message or parts of a log message line.
|
443
|
+
@param startMessage The text of the log message we expect to receive to trigger the progress bar timer start.
|
444
|
+
@param expectedMsgList A list of the expected log file messages."""
|
445
|
+
self._progressValue = 0
|
446
|
+
self._progressBarStartMessage = ""
|
447
|
+
self._progressBarExpectedMessageList = []
|
448
|
+
self._expectedProgressBarMessageIndex = 0
|
449
|
+
self._updateProgressOnTimer = False
|
450
|
+
self._progress.set_value( self._progressValue )
|
451
|
+
# If the caller wants to update the progress bar on expected messages.
|
452
|
+
if len(expectedMsgList):
|
453
|
+
#Use the text of log messages to increment the progress bar.
|
454
|
+
self._expectedProgressBarMessageIndex = 0
|
455
|
+
self._progressBarExpectedMessageList = expectedMsgList
|
456
|
+
self._progressStepValue = TabbedNiceGui.MAX_PROGRESS_VALUE/float(len(expectedMsgList))
|
457
|
+
|
458
|
+
elif durationSeconds > 0:
|
459
|
+
# Calc the step size required to give the required duration
|
460
|
+
self._progressStepValue = TabbedNiceGui.MAX_PROGRESS_VALUE/float(durationSeconds)
|
461
|
+
if startMessage:
|
462
|
+
self._progressBarStartMessage = startMessage
|
463
|
+
else:
|
464
|
+
# Start updating the progress bar now.
|
465
|
+
self._updateProgressOnTimer = True
|
466
|
+
|
417
467
|
else:
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
def
|
423
|
-
"""@brief
|
424
|
-
|
425
|
-
|
426
|
-
|
468
|
+
raise Exception("BUG: _startProgressTimer() called. len(expectedMsgList)=0 and durationSeconds<=0.")
|
469
|
+
|
470
|
+
self._progress.set_visibility(True)
|
471
|
+
|
472
|
+
def _stopProgress(self):
|
473
|
+
"""@brief Stop the progress bar being updated and hide it."""
|
474
|
+
self._updateProgressOnTimer = False
|
475
|
+
self._progress.set_visibility(False)
|
476
|
+
|
477
|
+
def _updateProgressBar(self, msg):
|
478
|
+
"""@brief Update the progress bar if required when a log message is received. This is called as each message is added to the log.
|
479
|
+
@param msg The log message received."""
|
480
|
+
# If we have a list of log messages to update the progress bar.
|
481
|
+
if len(self._progressBarExpectedMessageList) > 0:
|
482
|
+
if self._expectedProgressBarMessageIndex < len(self._progressBarExpectedMessageList):
|
483
|
+
# Get the message we expect to receive next
|
484
|
+
expectedMsg = self._progressBarExpectedMessageList[self._expectedProgressBarMessageIndex]
|
485
|
+
if msg.find(expectedMsg) != -1:
|
486
|
+
self._progressValue = self._progressValue + self._progressStepValue
|
487
|
+
self._progress.set_value( self._progressValue )
|
488
|
+
self._expectedProgressBarMessageIndex += 1
|
489
|
+
|
490
|
+
# If we have a message that we expect to receive to start the progress bar timer.
|
491
|
+
elif self._progressBarStartMessage and len(self._progressBarStartMessage):
|
492
|
+
# If we found the start message in the message received.
|
493
|
+
if msg.find(self._progressBarStartMessage) != -1:
|
494
|
+
# Start updating the progress bar now on the timer.
|
495
|
+
self._updateProgressOnTimer = True
|
496
|
+
|
497
|
+
def _initTask(self):
|
498
|
+
"""@brief Should be called before a task is started."""
|
427
499
|
self._enableAllButtons(False)
|
428
500
|
self._clearMessages()
|
429
501
|
|
@@ -438,7 +510,7 @@ class TabbedNiceGui(object):
|
|
438
510
|
|
439
511
|
def close(self):
|
440
512
|
"""@brief Close down the app server."""
|
441
|
-
ui.notify("Press 'CTRL C' at command line to quit.")
|
513
|
+
ui.notify("Press 'CTRL C' at command line or close the terminal window to quit.")
|
442
514
|
# A subclass close() method can call
|
443
515
|
# app.shutdown()
|
444
516
|
# if reload=False on ui.run()
|
@@ -471,6 +543,10 @@ class TabbedNiceGui(object):
|
|
471
543
|
state = rxDict[TabbedNiceGui.ENABLE_BUTTONS]
|
472
544
|
self._enableAllButtons(state)
|
473
545
|
|
546
|
+
elif TabbedNiceGui.NOTIFY_DIALOG in rxDict:
|
547
|
+
message = rxDict[TabbedNiceGui.NOTIFY_DIALOG]
|
548
|
+
ui.notify(message, close_button='OK', type="positive", position="center")
|
549
|
+
|
474
550
|
else:
|
475
551
|
|
476
552
|
self._handleGUIUpdate(rxDict)
|
@@ -714,4 +790,3 @@ class YesNoDialog(object):
|
|
714
790
|
def close(self):
|
715
791
|
"""@brief Close the boolean dialog."""
|
716
792
|
self._dialog.close()
|
717
|
-
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: p3lib
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.75
|
4
4
|
Summary: A group of python modules for networking, plotting data, config storage, automating boot scripts, ssh access and user input output.
|
5
5
|
Home-page: https://github.com/pjaos/p3lib
|
6
6
|
Author: Paul Austen
|
@@ -10,13 +10,13 @@ p3lib/json_networking.py,sha256=6u4s1SmypjTYPnSxHP712OgQ3ZJaxOqIkgHQ1J7Qews,9738
|
|
10
10
|
p3lib/mqtt_rpc.py,sha256=6LmFA1kR4HSJs9eWbOJORRHNY01L_lHWjvtE2fmY8P8,10511
|
11
11
|
p3lib/netif.py,sha256=3QV5OGdHhELIf4MBj6mx5MNCtVeZ7JXoNEkeu4KzCaE,9796
|
12
12
|
p3lib/netplotly.py,sha256=PMDx-w1jtRVW6Od5u_kuKbBxNpTS_Y88mMF60puMxLM,9363
|
13
|
-
p3lib/ngt.py,sha256=
|
13
|
+
p3lib/ngt.py,sha256=FWiRcVrWR0tTfscz6gWDHcJXam-00OezyQNjTaFXPh4,36635
|
14
14
|
p3lib/pconfig.py,sha256=_ri9w3aauHXZp8u2YLYHBVroFR_iCqaTCwj_MRa3rHo,30153
|
15
15
|
p3lib/ssh.py,sha256=klqQ9YuqU8GwPVPHrAJeEs5PI5hgoYiXflq2kIGG3as,39509
|
16
16
|
p3lib/table_plot.py,sha256=dRPZ9rFpwE9Dpyqrvbm5t2spVaPSHrx_B7KvfWVND3g,32166
|
17
17
|
p3lib/uio.py,sha256=hMarPnYXnqVF23HUIeDfzREo7TMdBjrupXMY_ffuCbI,23133
|
18
|
-
p3lib-1.1.
|
19
|
-
p3lib-1.1.
|
20
|
-
p3lib-1.1.
|
21
|
-
p3lib-1.1.
|
22
|
-
p3lib-1.1.
|
18
|
+
p3lib-1.1.75.dist-info/LICENSE,sha256=igqTy5u0kVWM1n-NUZMvAlinY6lVjAXKoag0okkS8V8,1067
|
19
|
+
p3lib-1.1.75.dist-info/METADATA,sha256=aBudwqSxnGiP-3sDRkKLdiv2ZpNErMlfcbthAg3bmb8,918
|
20
|
+
p3lib-1.1.75.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
|
21
|
+
p3lib-1.1.75.dist-info/top_level.txt,sha256=SDCpXYh-19yCFp4Z8ZK4B-3J4NvTCJElZ42NPgcR6-U,6
|
22
|
+
p3lib-1.1.75.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|