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 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 = 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._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: repr(msg)}
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
- msg = traceback.format_exc()
197
- lines = msg.split('\n')
198
- for l in lines:
199
- self.error(l)
200
- self.error( exception.args[0] )
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
- self._progress.set_value( int(self._logMessageCount*self._progressStepValue) )
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
- self._progress.set_visibility(False)
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 periodicTimer(self):
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.periodicTimer)
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 _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)
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
- 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)
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.74
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=fKMrGKl1ASvwf0MOSPk3ZbiBxEqbDFpyuCleonfiwC4,31794
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.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.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