p3lib 1.1.74__py3-none-any.whl → 1.1.76__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 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,22 @@ 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 = debugEnabled
108
- self._logFile = None # This must be defined in subclass if logging to a file is required.
109
- self._buttonList = []
110
- self._logMessageCount = 0
111
- self._progressStepValue = 0
112
- self._programVersion = TabbedNiceGui.GetProgramVersion()
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._expectedProgressBarMsgCount = 0
118
+ self._programVersion = TabbedNiceGui.GetProgramVersion()
113
119
 
114
120
  self._logPath = None
115
121
  if logPath:
@@ -145,29 +151,35 @@ class TabbedNiceGui(object):
145
151
  """@brief Send a info message to be displayed in the GUI.
146
152
  This can be called from outside the GUI thread.
147
153
  @param msg The message to be displayed."""
148
- msgDict = {TabbedNiceGui.INFO_MESSAGE: msg}
154
+ msgDict = {TabbedNiceGui.INFO_MESSAGE: str(msg)}
149
155
  self.updateGUI(msgDict)
150
156
 
151
157
  def warn(self, msg):
152
158
  """@brief Send a warning message to be displayed in the GUI.
153
159
  This can be called from outside the GUI thread.
154
160
  @param msg The message to be displayed."""
155
- msgDict = {TabbedNiceGui.WARN_MESSAGE: msg}
161
+ msgDict = {TabbedNiceGui.WARN_MESSAGE: str(msg)}
156
162
  self.updateGUI(msgDict)
157
163
 
158
164
  def error(self, msg):
159
165
  """@brief Send a error message to be displayed in the GUI.
160
166
  This can be called from outside the GUI thread.
161
167
  @param msg The message to be displayed."""
162
- msgDict = {TabbedNiceGui.ERROR_MESSAGE: repr(msg)}
168
+ msgDict = {TabbedNiceGui.ERROR_MESSAGE: str(msg)}
163
169
  self.updateGUI(msgDict)
164
170
 
171
+ def infoDialog(self, msg):
172
+ """@brief Display an info level dialog.
173
+ @param msg The message dialog."""
174
+ msgDict = {TabbedNiceGui.NOTIFY_DIALOG: str(msg)}
175
+ self.updateGUI(msgDict)
176
+
165
177
  def debug(self, msg):
166
178
  """@brief Send a debug message to be displayed in the GUI.
167
179
  This can be called from outside the GUI thread.
168
180
  @param msg The message to be displayed."""
169
181
  if self._debugEnabled:
170
- msgDict = {TabbedNiceGui.DEBUG_MESSAGE: msg}
182
+ msgDict = {TabbedNiceGui.DEBUG_MESSAGE: str(msg)}
171
183
  self.updateGUI(msgDict)
172
184
 
173
185
  async def getInput(self, prompt):
@@ -193,11 +205,11 @@ class TabbedNiceGui(object):
193
205
  If not then the exception message is displayed.
194
206
  @param exception The exception instance."""
195
207
  if self._debugEnabled:
196
- msg = traceback.format_exc()
197
- lines = msg.split('\n')
198
- for l in lines:
199
- self.error(l)
200
- self.error( exception.args[0] )
208
+ lines = traceback.format_exc().split("\n")
209
+ for line in lines:
210
+ self.error(line)
211
+ if len(exception.args) > 0:
212
+ self.error(exception.args[0])
201
213
 
202
214
  def _sendEnableAllButtons(self, state):
203
215
  """@brief Send a message to the GUI to enable/disable all the GUI buttons.
@@ -303,7 +315,8 @@ class TabbedNiceGui(object):
303
315
  self._log.push(msg)
304
316
  self._saveLogMsg(msg)
305
317
  self._logMessageCount += 1
306
- self._progress.set_value( int(self._logMessageCount*self._progressStepValue) )
318
+ # We've received a log message so update progress bar if required.
319
+ self._updateProgressBar(msg)
307
320
 
308
321
  def _infoGT(self, msg):
309
322
  """@brief Update an info level message. This must be called from the GUI thread.
@@ -344,7 +357,9 @@ class TabbedNiceGui(object):
344
357
  if enabled:
345
358
  for button in self._buttonList:
346
359
  button.enable()
347
- self._progress.set_visibility(False)
360
+ # No buttons are enabled, any executed task must be complete therefor hide the progress bar.
361
+ self._stopProgress()
362
+
348
363
  else:
349
364
  for button in self._buttonList:
350
365
  button.disable()
@@ -352,8 +367,8 @@ class TabbedNiceGui(object):
352
367
  if self._progressStepValue > 0:
353
368
  self._progress.set_visibility(True)
354
369
 
355
- def periodicTimer(self):
356
- """@called periodically to allow updates of the GUI."""
370
+ def guiTimerCallback(self):
371
+ """@called periodically (quickly) to allow updates of the GUI."""
357
372
  while not self._toGUIQueue.empty():
358
373
  rxMessage = self._toGUIQueue.get()
359
374
  if isinstance(rxMessage, dict):
@@ -391,39 +406,115 @@ class TabbedNiceGui(object):
391
406
  ui.label("Message Log")
392
407
  self._progress = ui.slider(min=0,max=TabbedNiceGui.MAX_PROGRESS_VALUE,step=1)
393
408
  self._progress.set_visibility(False)
409
+ self._progress.min = 0
410
+ # Don't allow user to adjust progress bar thumb
411
+ self._progress.disable()
394
412
  self._log = ui.log(max_lines=2000)
395
413
  self._log.set_visibility(True)
396
414
 
397
415
  with ui.row():
398
- ui.button('Quit', on_click=self.close)
399
- ui.button('Log Message Count', on_click=self._showLogMsgCount)
400
416
  ui.button('Clear Log', on_click=self._clearLog)
417
+ ui.button('Log Message Count', on_click=self._showLogMsgCount)
418
+ ui.button('Quit', on_click=self.close)
401
419
 
402
420
  with ui.row():
403
421
  ui.label(f"Software Version: {self._programVersion}")
404
422
 
405
- ui.timer(interval=TabbedNiceGui.GUI_TIMER_SECONDS, callback=self.periodicTimer)
423
+ ui.timer(interval=TabbedNiceGui.GUI_TIMER_SECONDS, callback=self.guiTimerCallback)
424
+ ui.timer(interval=TabbedNiceGui.PROGRESS_TIMER_SECONDS, callback=self.progressTimerCallback)
406
425
  ui.run(host=address, port=port, title=pageTitle, dark=True, uvicorn_logging_level=guiLogLevel, reload=reload)
407
426
 
408
- def _setProgressMessageCount(self, normalCount, debugCount):
409
- """@brief Set the number of log messages expected for normal completion of the current action.
410
- @param normalCount The number of messages expected when debug is off.
411
- @param debugCount The number of messages expected when debug is on."""
412
- self._progressStepValue = 0
413
- if self._debugEnabled:
414
- self._progress.min=0
415
- if debugCount > 0:
416
- self._progressStepValue = TabbedNiceGui.MAX_PROGRESS_VALUE/float(debugCount)
427
+ def progressTimerCallback(self):
428
+ """@brief Time to update the progress bar. We run the timer all the time because there appears to be a
429
+ bug in the ui.timer instance. Calling cancel() does not appear to cancel the timer."""
430
+ if self._updateProgressOnTimer and self._progress.visible:
431
+ # Increment the progress bar
432
+ self._progress.set_value( self._progress.value + self._progressStepValue )
433
+
434
+ def _startProgress(self, durationSeconds=0, startMessage=None, expectedMsgList=[], expectedMsgCount=0):
435
+ """@brief Start a timer that will update the progress bar.
436
+ The progress bar can simply update on a timer every second with durationSeconds set to the expected length
437
+ of the task.
438
+
439
+ If startMessage is set to a text string the progress time will not start until the log message area contains
440
+ the start message.
441
+
442
+ Alternatively if expectedMsgList contains a list of strings we expect to receive then the progress bar is
443
+ updated as each message is received. The messages may be the entire line of a log message or parts of a
444
+ log message line.
445
+
446
+ Alternatively if expectedMsgCount is set to a value > 0 then the progress bar is updated as each message is
447
+ added to the log and reaches 100% when the number of messages added to the log file reaches the expectedMsgCount.
448
+
449
+ @param startMessage The text of the log message we expect to receive to trigger the progress bar timer start.
450
+ @param expectedMsgList A list of the expected log file messages.
451
+ @param expectedMsgCount A int value that defines the number of log messages we expect to receive for normal progress
452
+ completion."""
453
+ self._progressValue = 0
454
+ self._progressBarStartMessage = ""
455
+ self._progressBarExpectedMessageList = []
456
+ self._expectedProgressBarMessageIndex = 0
457
+ self._expectedProgressBarMsgCount = 0
458
+ self._updateProgressOnTimer = False
459
+ self._progress.set_value( self._progressValue )
460
+ # If the caller wants to the progress bar to update as the log file message count increases.
461
+ if expectedMsgCount > 0:
462
+ self._expectedProgressBarMsgCount = expectedMsgCount
463
+ self._progressStepValue = TabbedNiceGui.MAX_PROGRESS_VALUE/float(self._expectedProgressBarMsgCount)
464
+
465
+ # If the caller wants to update the progress bar on expected messages.
466
+ elif len(expectedMsgList):
467
+ #Use the text of log messages to increment the progress bar.
468
+ self._expectedProgressBarMessageIndex = 0
469
+ self._progressBarExpectedMessageList = expectedMsgList
470
+ self._progressStepValue = TabbedNiceGui.MAX_PROGRESS_VALUE/float(len(expectedMsgList))
471
+
472
+ elif durationSeconds > 0:
473
+ # Calc the step size required to give the required duration
474
+ self._progressStepValue = TabbedNiceGui.MAX_PROGRESS_VALUE/float(durationSeconds)
475
+ if startMessage:
476
+ self._progressBarStartMessage = startMessage
477
+ else:
478
+ # Start updating the progress bar now.
479
+ self._updateProgressOnTimer = True
480
+
417
481
  else:
418
- self._progress.min=0
419
- if normalCount > 0:
420
- self._progressStepValue = TabbedNiceGui.MAX_PROGRESS_VALUE/float(normalCount)
421
-
422
- def _initTask(self, normalCount, debugCount):
423
- """@brief Should be called before a task is started.
424
- @param normalCount The number of messages expected when debug is off.
425
- @param debugCount The number of messages expected when debug is on."""
426
- self._setProgressMessageCount(normalCount, debugCount)
482
+ raise Exception("BUG: _startProgressTimer() called. len(expectedMsgList)=0 and durationSeconds<=0.")
483
+
484
+ self._progress.set_visibility(True)
485
+
486
+ def _stopProgress(self):
487
+ """@brief Stop the progress bar being updated and hide it."""
488
+ self._updateProgressOnTimer = False
489
+ self._progress.set_visibility(False)
490
+
491
+ def _updateProgressBar(self, msg):
492
+ """@brief Update the progress bar if required when a log message is received. This is called as each message is added to the log.
493
+ @param msg The log message received."""
494
+ # If we update the progress bar as each message is received until we have a log with self._expectedProgressBarMsgCount many messages.
495
+ if self._expectedProgressBarMsgCount > 0:
496
+ self._progressValue = self._progressValue + self._progressStepValue
497
+ self._progress.set_value( self._progressValue )
498
+
499
+ # If we have a list of log messages to update the progress bar.
500
+ elif len(self._progressBarExpectedMessageList) > 0:
501
+ if self._expectedProgressBarMessageIndex < len(self._progressBarExpectedMessageList):
502
+ # Get the message we expect to receive next
503
+ expectedMsg = self._progressBarExpectedMessageList[self._expectedProgressBarMessageIndex]
504
+ if msg.find(expectedMsg) != -1:
505
+ self._progressValue = self._progressValue + self._progressStepValue
506
+ self._progress.set_value( self._progressValue )
507
+ self._expectedProgressBarMessageIndex += 1
508
+
509
+ # If we have a message that we expect to receive to start the progress bar timer.
510
+ elif self._progressBarStartMessage and len(self._progressBarStartMessage):
511
+ # If we found the start message in the message received.
512
+ if msg.find(self._progressBarStartMessage) != -1:
513
+ # Start updating the progress bar now on the timer.
514
+ self._updateProgressOnTimer = True
515
+
516
+ def _initTask(self):
517
+ """@brief Should be called before a task is started."""
427
518
  self._enableAllButtons(False)
428
519
  self._clearMessages()
429
520
 
@@ -438,7 +529,7 @@ class TabbedNiceGui(object):
438
529
 
439
530
  def close(self):
440
531
  """@brief Close down the app server."""
441
- ui.notify("Press 'CTRL C' at command line to quit.")
532
+ ui.notify("Press 'CTRL C' at command line or close the terminal window to quit.")
442
533
  # A subclass close() method can call
443
534
  # app.shutdown()
444
535
  # if reload=False on ui.run()
@@ -471,6 +562,10 @@ class TabbedNiceGui(object):
471
562
  state = rxDict[TabbedNiceGui.ENABLE_BUTTONS]
472
563
  self._enableAllButtons(state)
473
564
 
565
+ elif TabbedNiceGui.NOTIFY_DIALOG in rxDict:
566
+ message = rxDict[TabbedNiceGui.NOTIFY_DIALOG]
567
+ ui.notify(message, close_button='OK', type="positive", position="center")
568
+
474
569
  else:
475
570
 
476
571
  self._handleGUIUpdate(rxDict)
@@ -714,4 +809,3 @@ class YesNoDialog(object):
714
809
  def close(self):
715
810
  """@brief Close the boolean dialog."""
716
811
  self._dialog.close()
717
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: p3lib
3
- Version: 1.1.74
3
+ Version: 1.1.76
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=fKMrGKl1ASvwf0MOSPk3ZbiBxEqbDFpyuCleonfiwC4,31794
13
+ p3lib/ngt.py,sha256=rXA-6zQkfeOupZ-3Q-k3-1DvbKYIi2TCtLKgUb0waWY,37726
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.74.dist-info/LICENSE,sha256=igqTy5u0kVWM1n-NUZMvAlinY6lVjAXKoag0okkS8V8,1067
19
- p3lib-1.1.74.dist-info/METADATA,sha256=hWZ8Y0bkKQfhWO4dsyowfhI3j8B-fetIFZAC7DGGmBA,918
20
- p3lib-1.1.74.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
21
- p3lib-1.1.74.dist-info/top_level.txt,sha256=SDCpXYh-19yCFp4Z8ZK4B-3J4NvTCJElZ42NPgcR6-U,6
22
- p3lib-1.1.74.dist-info/RECORD,,
18
+ p3lib-1.1.76.dist-info/LICENSE,sha256=igqTy5u0kVWM1n-NUZMvAlinY6lVjAXKoag0okkS8V8,1067
19
+ p3lib-1.1.76.dist-info/METADATA,sha256=2jUaMjRM-yydYAzGuBZ8oTGOBDhBi6--Zxw4-qe2n-g,918
20
+ p3lib-1.1.76.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
21
+ p3lib-1.1.76.dist-info/top_level.txt,sha256=SDCpXYh-19yCFp4Z8ZK4B-3J4NvTCJElZ42NPgcR6-U,6
22
+ p3lib-1.1.76.dist-info/RECORD,,
File without changes