quarchpy 2.1.20.dev2__py2.py3-none-any.whl → 2.1.20.dev3__py2.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.
Files changed (150) hide show
  1. quarchpy/.idea/.name +1 -1
  2. quarchpy/.idea/inspectionProfiles/Project_Default.xml +26 -0
  3. quarchpy/.idea/modules.xml +0 -1
  4. quarchpy/.idea/quarchpy.iml +1 -4
  5. quarchpy/.idea/workspace.xml +21 -226
  6. quarchpy/__pycache__/__init__.cpython-311.pyc +0 -0
  7. quarchpy/__pycache__/_version.cpython-311.pyc +0 -0
  8. quarchpy/__pycache__/connection.cpython-311.pyc +0 -0
  9. quarchpy/__pycache__/run.cpython-311.pyc +0 -0
  10. quarchpy/_version.py +1 -1
  11. quarchpy/config_files/__pycache__/__init__.cpython-311.pyc +0 -0
  12. quarchpy/config_files/__pycache__/quarch_config_parser.cpython-311.pyc +0 -0
  13. quarchpy/connection_specific/QPS/qis/help.txt +12 -4
  14. quarchpy/connection_specific/QPS/qis/qis.jar +0 -0
  15. quarchpy/connection_specific/QPS/qis/qis_lib/CInterface-1.7.8.jar +0 -0
  16. quarchpy/connection_specific/QPS/qis/qis_lib/Collections-2.4.jar +0 -0
  17. quarchpy/connection_specific/QPS/qis/qis_lib/Desktop-1.1.jar +0 -0
  18. quarchpy/connection_specific/QPS/qis/qis_lib/Executor-3.13.jar +0 -0
  19. quarchpy/connection_specific/QPS/qis/qis_lib/JNA-1.2.jar +0 -0
  20. quarchpy/connection_specific/QPS/qis/qis_lib/OS-1.8.jar +0 -0
  21. quarchpy/connection_specific/QPS/qis/qis_lib/QuarchCommon-0.2.9.jar +0 -0
  22. quarchpy/connection_specific/QPS/qis/qis_lib/SystemTray-4.4.jar +0 -0
  23. quarchpy/connection_specific/QPS/qis/qis_lib/Updates-1.1.jar +0 -0
  24. quarchpy/connection_specific/QPS/qis/qis_lib/Utilities-1.46.jar +0 -0
  25. quarchpy/connection_specific/QPS/qis/qis_lib/commons-csv-1.8.jar +0 -0
  26. quarchpy/connection_specific/QPS/qis/qis_lib/javassist-3.29.2-GA.jar +0 -0
  27. quarchpy/connection_specific/QPS/qis/qis_lib/jna-jpms-5.12.1.jar +0 -0
  28. quarchpy/connection_specific/QPS/qis/qis_lib/jna-platform-jpms-5.12.1.jar +0 -0
  29. quarchpy/connection_specific/QPS/qis/qis_lib/kotlin-stdlib-1.9.21.jar +0 -0
  30. quarchpy/connection_specific/QPS/qis/qis_lib/slf4j-api-2.0.9.jar +0 -0
  31. quarchpy/connection_specific/QPS/qis/qis_lib/slf4j-simple-2.0.9.jar +0 -0
  32. quarchpy/connection_specific/QPS/qis/resources/filters/Example.txt +36 -0
  33. quarchpy/connection_specific/QPS/qis/resources/filters/filters.csv +1004 -0
  34. quarchpy/connection_specific/QPS/qis/resources/filters/iec_filters.xml +26 -0
  35. quarchpy/connection_specific/QPS/qis/resources/filters/iec_filters.xml.bak +26 -0
  36. quarchpy/connection_specific/QPS/qps.jar +0 -0
  37. quarchpy/connection_specific/QPS/qps_lib/QuarchCommon-0.2.9.jar +0 -0
  38. quarchpy/connection_specific/QPS/qps_lib/commons-lang3-3.12.0.jar +0 -0
  39. quarchpy/connection_specific/QPS/qps_lib/opencsv-5.9.jar +0 -0
  40. quarchpy/connection_specific/QPS/qps_lib/qis-1.40.jar +0 -0
  41. quarchpy/connection_specific/QPS/scriptCommands.txt +2 -2
  42. quarchpy/connection_specific/__pycache__/StreamChannels.cpython-311.pyc +0 -0
  43. quarchpy/connection_specific/__pycache__/__init__.cpython-311.pyc +0 -0
  44. quarchpy/connection_specific/__pycache__/connection_QIS.cpython-311.pyc +0 -0
  45. quarchpy/connection_specific/__pycache__/connection_QPS.cpython-311.pyc +0 -0
  46. quarchpy/connection_specific/__pycache__/connection_ReST.cpython-311.pyc +0 -0
  47. quarchpy/connection_specific/__pycache__/connection_Serial.cpython-311.pyc +0 -0
  48. quarchpy/connection_specific/__pycache__/connection_TCP.cpython-311.pyc +0 -0
  49. quarchpy/connection_specific/__pycache__/connection_Telnet.cpython-311.pyc +0 -0
  50. quarchpy/connection_specific/__pycache__/connection_USB.cpython-311.pyc +0 -0
  51. quarchpy/connection_specific/__pycache__/connection_mDNS.cpython-311.pyc +0 -0
  52. quarchpy/connection_specific/connection_QIS.py +5 -3
  53. quarchpy/connection_specific/connection_QIS.py.bak +1738 -0
  54. quarchpy/connection_specific/serial/__pycache__/__init__.cpython-311.pyc +0 -0
  55. quarchpy/connection_specific/serial/__pycache__/serialutil.cpython-311.pyc +0 -0
  56. quarchpy/connection_specific/serial/__pycache__/serialwin32.cpython-311.pyc +0 -0
  57. quarchpy/connection_specific/serial/__pycache__/win32.cpython-311.pyc +0 -0
  58. quarchpy/connection_specific/serial/tools/__pycache__/__init__.cpython-311.pyc +0 -0
  59. quarchpy/connection_specific/serial/tools/__pycache__/list_ports.cpython-311.pyc +0 -0
  60. quarchpy/connection_specific/serial/tools/__pycache__/list_ports_common.cpython-311.pyc +0 -0
  61. quarchpy/connection_specific/serial/tools/__pycache__/list_ports_windows.cpython-311.pyc +0 -0
  62. quarchpy/connection_specific/usb_libs/__pycache__/libusb1.cpython-311.pyc +0 -0
  63. quarchpy/connection_specific/usb_libs/__pycache__/usb1.cpython-311.pyc +0 -0
  64. quarchpy/debug/TextScanIP.py +11 -0
  65. quarchpy/debug/__pycache__/SystemTest.cpython-311.pyc +0 -0
  66. quarchpy/debug/__pycache__/__init__.cpython-311.pyc +0 -0
  67. quarchpy/debug/__pycache__/module_debug.cpython-311.pyc +0 -0
  68. quarchpy/debug/__pycache__/simple_terminal.cpython-311.pyc +0 -0
  69. quarchpy/debug/__pycache__/upgrade_quarchpy.cpython-311.pyc +0 -0
  70. quarchpy/debug/__pycache__/versionCompare.cpython-311.pyc +0 -0
  71. quarchpy/device/__pycache__/__init__.cpython-311.pyc +0 -0
  72. quarchpy/device/__pycache__/device.cpython-311.pyc +0 -0
  73. quarchpy/device/__pycache__/quarchArray.cpython-311.pyc +0 -0
  74. quarchpy/device/__pycache__/quarchPPM.cpython-311.pyc +0 -0
  75. quarchpy/device/__pycache__/quarchQPS.cpython-311.pyc +0 -0
  76. quarchpy/device/__pycache__/scanDevices.cpython-311.pyc +0 -0
  77. quarchpy/device/device.py.bak +504 -0
  78. quarchpy/device/quarchPPM.py.bak +67 -0
  79. quarchpy/device/quarchQPS.py.bak +396 -0
  80. quarchpy/device/scanDevices.py.bak +130 -108
  81. quarchpy/disk_test/__pycache__/AbsDiskFinder.cpython-311.pyc +0 -0
  82. quarchpy/disk_test/__pycache__/DiskTargetSelection.cpython-311.pyc +0 -0
  83. quarchpy/disk_test/__pycache__/__init__.cpython-311.pyc +0 -0
  84. quarchpy/disk_test/__pycache__/iometerDiskFinder.cpython-311.pyc +0 -0
  85. quarchpy/docs/CHANGES.rst.bak +4 -2
  86. quarchpy/docs/_build/doctrees/CHANGES.doctree +0 -0
  87. quarchpy/docs/_build/doctrees/environment.pickle +0 -0
  88. quarchpy/docs/_build/doctrees/source/changelog.doctree +0 -0
  89. quarchpy/docs/_build/doctrees/source/quarchpy.fio.doctree +0 -0
  90. quarchpy/docs/_build/html/CHANGES.html +121 -113
  91. quarchpy/docs/_build/html/_sources/CHANGES.rst.txt +6 -1
  92. quarchpy/docs/_build/html/_static/alabaster.css +14 -9
  93. quarchpy/docs/_build/html/_static/basic.css +1 -1
  94. quarchpy/docs/_build/html/_static/pygments.css +1 -1
  95. quarchpy/docs/_build/html/genindex.html +9 -27
  96. quarchpy/docs/_build/html/index.html +62 -60
  97. quarchpy/docs/_build/html/objects.inv +0 -0
  98. quarchpy/docs/_build/html/py-modindex.html +7 -11
  99. quarchpy/docs/_build/html/readme.html +7 -6
  100. quarchpy/docs/_build/html/search.html +7 -6
  101. quarchpy/docs/_build/html/searchindex.js +1 -1
  102. quarchpy/docs/_build/html/source/changelog.html +176 -167
  103. quarchpy/docs/_build/html/source/licenses.html +7 -6
  104. quarchpy/docs/_build/html/source/modules.html +8 -7
  105. quarchpy/docs/_build/html/source/quarchpy.calibration.html +7 -6
  106. quarchpy/docs/_build/html/source/quarchpy.config_files.html +7 -6
  107. quarchpy/docs/_build/html/source/quarchpy.connection_specific.html +7 -6
  108. quarchpy/docs/_build/html/source/quarchpy.debug.html +7 -6
  109. quarchpy/docs/_build/html/source/quarchpy.device.html +7 -6
  110. quarchpy/docs/_build/html/source/quarchpy.disk_test.html +7 -6
  111. quarchpy/docs/_build/html/source/quarchpy.fio.html +9 -34
  112. quarchpy/docs/_build/html/source/quarchpy.html +8 -16
  113. quarchpy/docs/_build/html/source/quarchpy.iometer.html +7 -6
  114. quarchpy/docs/_build/html/source/quarchpy.qis.html +7 -6
  115. quarchpy/docs/_build/html/source/quarchpy.qps.html +7 -6
  116. quarchpy/docs/_build/html/source/quarchpy.user_interface.html +7 -6
  117. quarchpy/docs/_build/html/source/quarchpy.utilities.html +7 -6
  118. quarchpy/docs/_build/html/source/readme.html +7 -6
  119. quarchpy/fio/__pycache__/FIO_interface.cpython-311.pyc +0 -0
  120. quarchpy/fio/__pycache__/__init__.cpython-311.pyc +0 -0
  121. quarchpy/fio/__pycache__/fioDiskFinder.cpython-311.pyc +0 -0
  122. quarchpy/iometer/__pycache__/__init__.cpython-311.pyc +0 -0
  123. quarchpy/iometer/__pycache__/gen_iometer_template.cpython-311.pyc +0 -0
  124. quarchpy/iometer/__pycache__/iometerFuncs.cpython-311.pyc +0 -0
  125. quarchpy/qis/__pycache__/StreamHeaderInfo.cpython-311.pyc +0 -0
  126. quarchpy/qis/__pycache__/__init__.cpython-311.pyc +0 -0
  127. quarchpy/qis/__pycache__/qisFuncs.cpython-311.pyc +0 -0
  128. quarchpy/qps/__pycache__/__init__.cpython-311.pyc +0 -0
  129. quarchpy/qps/__pycache__/qpsFuncs.cpython-311.pyc +0 -0
  130. quarchpy/qps/qpsFuncs.py.bak +28 -68
  131. quarchpy/user_interface/__pycache__/__init__.cpython-311.pyc +0 -0
  132. quarchpy/user_interface/__pycache__/user_interface.cpython-311.pyc +0 -0
  133. quarchpy/user_interface/user_interface.py.bak +749 -0
  134. quarchpy/utilities/TestCenter.py.bak +150 -0
  135. quarchpy/utilities/__pycache__/BitManipulation.cpython-311.pyc +0 -0
  136. quarchpy/utilities/__pycache__/TestCenter.cpython-311.pyc +0 -0
  137. quarchpy/utilities/__pycache__/TimeValue.cpython-311.pyc +0 -0
  138. quarchpy/utilities/__pycache__/Version.cpython-311.pyc +0 -0
  139. quarchpy/utilities/__pycache__/__init__.cpython-311.pyc +0 -0
  140. {quarchpy-2.1.20.dev2.dist-info → quarchpy-2.1.20.dev3.dist-info}/METADATA +1 -1
  141. {quarchpy-2.1.20.dev2.dist-info → quarchpy-2.1.20.dev3.dist-info}/RECORD +143 -114
  142. quarchpy/_version.py.bak +0 -1
  143. quarchpy/connection_specific/connection_mDNS.py.bak +0 -48
  144. quarchpy/debug/SystemTest.py.bak +0 -188
  145. quarchpy/debug/simple_terminal.py.bak +0 -50
  146. quarchpy/fio/FIO_interface.py.bak +0 -322
  147. quarchpy/qis/qisFuncs.py.bak +0 -265
  148. quarchpy/run.py.bak +0 -283
  149. {quarchpy-2.1.20.dev2.dist-info → quarchpy-2.1.20.dev3.dist-info}/WHEEL +0 -0
  150. {quarchpy-2.1.20.dev2.dist-info → quarchpy-2.1.20.dev3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,749 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ This module provides standard user interface elements to quarchpy functions, ensuring common style
4
+ and support for both terminal and TestCenter (quarch internal) execution
5
+ """
6
+
7
+ # TODO: This class uses 'if' to switch between terminal and testcenter actions. This is not good practice: The singleton factory should return an appropriate subclass which implements the testcenter OR terminal options
8
+ # The entire module needs review and discussion
9
+
10
+ # Needed for python2 compatibility
11
+ # coding: utf-8
12
+ from __future__ import print_function
13
+ import tempfile
14
+
15
+ import traceback, sys, os, math, logging
16
+ from quarchpy.utilities import TestCenter
17
+ import time
18
+
19
+ class User_interface:
20
+ """
21
+ This class is a singleton pattern and provides common access to the user interace for user
22
+ interaction. The UI can be the terminal or TestCenter
23
+ """
24
+
25
+ instance = None
26
+
27
+ class __user_interface:
28
+ def __init__(self, ui):
29
+ if ui in ["console", "testcenter"]:
30
+ self.selectedInterface = ui
31
+ if "console" in ui:
32
+ import logging
33
+ else:
34
+ raise ValueError("requested ui type not valid")
35
+
36
+ def __init__(self, ui):
37
+ """
38
+ """
39
+
40
+ # if we haven't create a user_interface object before
41
+ if not User_interface.instance:
42
+ # create a user interface object with our selected interface type
43
+ User_interface.instance = User_interface.__user_interface(ui)
44
+ # otherwise change the existing user interface object to the new type
45
+ else:
46
+ User_interface.instance.selectedInterface = ui
47
+ '''Setup Logging'''
48
+ def setup_logging(logLevel):
49
+ # check log file is present or writeable
50
+ numeric_level = getattr(logging, logLevel.upper(), None)
51
+ if not isinstance(numeric_level, int):
52
+ raise ValueError('Invalid log level: %s' % logLevel)
53
+ logging.basicConfig(format='%(asctime)s.%(msecs)03d %(levelname)s {%(module)s} [%(funcName)s] %(message)s', datefmt='%Y-%m-%d,%H:%M:%S', level=numeric_level)
54
+
55
+ '''
56
+ def listSelection(title,message,selectionList)
57
+
58
+ prompts the user to return a selection from the list
59
+ if nice = False:
60
+ selectionList format is a comma delimited string (key1=value1,key2=value2...)
61
+ the function will return the selected key
62
+ if nice = True:
63
+ selectionList format is a list of lists containing each column value [["NAME1","DESCRIPTION1"],[["NAME2","DESCRIPTION2"]]]
64
+ the function will return the selected list with the index in position 0 ["1","NAME1","DESCRIPTION1"]
65
+
66
+
67
+ THIS IS MORE LIKE A DICTIONARY SELECTION FUNC THAT RETURNS THE KEY
68
+
69
+ '''
70
+ def listSelection(title="",message="",selectionList=[], additionalOptions = [], nice = False, tableHeaders=[], indexReq=True, align="l"):
71
+
72
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
73
+
74
+ converted = False
75
+ itemListString = ""
76
+ if type(selectionList) is list:
77
+ converted = True
78
+ tempSelectionListStringDict = ""
79
+ for row in selectionList:
80
+ tempSelectionListStringDict += str(row[0]) + "=" + str(row[1]) + ","
81
+ itemListString = tempSelectionListStringDict[0:-1]
82
+ else:
83
+ itemListString = selectionList
84
+
85
+ retVal = TestCenter.testPoint("Quarch_Host.ShowGenericDialog", "Title=" + __formatForTestcenter(title),
86
+ "Message=" + __formatForTestcenter(message),
87
+ "ItemListString=" + __formatForTestcenter(itemListString),
88
+ "OptionListString=" + __formatForTestcenter(str(additionalOptions)), stack_level=2);
89
+ if converted:
90
+ i = 0
91
+ for row in selectionList:
92
+ i += 1
93
+ if retVal == row[0] or retVal == row[1]:
94
+ retVal = [str(i)] + row
95
+
96
+ return retVal
97
+
98
+ else: # default mode console output
99
+
100
+ # print message
101
+ if message not in "":
102
+ print(message)
103
+ if nice is True:
104
+ retVal = niceListSelection(selectionList, tableHeaders=tableHeaders, indexReq=indexReq, additionalOptions=additionalOptions, align=align)
105
+ return retVal
106
+
107
+
108
+ # split selection list into key=value pairs and print each value
109
+ # first split on ','s into list of key=value pairs
110
+ selectionList = selectionList.split(',')
111
+ # then split each list item on '=' into a [key,value] list
112
+ selectionList = [str(x).split("=") for x in selectionList]
113
+
114
+ count = 1
115
+ for item in selectionList:
116
+ # if list item has index and value print them
117
+ if len(item) > 1:
118
+ print(str(count) + " - " + item[1])
119
+ else:
120
+ print(item[0])
121
+ count += 1
122
+
123
+ print("")
124
+ # Request user selection
125
+ while (True):
126
+ if sys.version_info.major >= 3:
127
+ userStr = input("Please select an option:\n>")
128
+ else:
129
+ userStr = raw_input("Please select an option:\n>")
130
+
131
+ # Validate the response
132
+ try:
133
+ userNumber = int(userStr)
134
+ if (userNumber <= len(selectionList) and userNumber >= 1):
135
+ break
136
+ except:
137
+ print("INVALID SELECTION!")
138
+
139
+ # return the key associated with this entry
140
+ return selectionList[userNumber - 1][0]
141
+
142
+ '''
143
+ niceListSelection
144
+ Takes in a 2D List and displays a table. Returns one list (row)
145
+ Will take 2DList, 2DTuple, Dictionary and return a list element
146
+ '''
147
+ def niceListSelection(selectionList,title="",message="", tableHeaders=None, indexReq=True, additionalOptions = None, align="l"):
148
+ # takes in a 2d list and display it with an index column for selection
149
+ # get user input of selection
150
+ # return 2d[selection]
151
+ try:
152
+ selectionList = selectionList.copy()
153
+ additionalOptions = additionalOptions.copy()
154
+ tableHeaders = tableHeaders.copy()
155
+ except:
156
+ pass
157
+
158
+ if additionalOptions is not None and additionalOptions.__len__() > 0:
159
+ if isinstance(additionalOptions, str):
160
+ additionalOptions = additionalOptions.split(',')
161
+ selectionList += additionalOptions
162
+
163
+
164
+ if isinstance(selectionList, str):
165
+ selectionList = selectionList.split(',')
166
+ elif isinstance(selectionList, dict):
167
+ selectionList = dictToList(selectionList)
168
+
169
+ displayTable(selectionList, indexReq=indexReq, tableHeaders=tableHeaders, align=align)
170
+ print("")
171
+ # Request user selection
172
+ while (True):
173
+ if sys.version_info.major >= 3:
174
+ userStr = input("Please select an option:\n>")
175
+ else:
176
+ userStr = raw_input("Please select an option:\n>")
177
+
178
+ # Validate the response
179
+ try:
180
+ userNumber = int(userStr)
181
+ if (userNumber <= len(selectionList) and userNumber >= 1):
182
+ break
183
+ except:
184
+ print("INVALID SELECTION!")
185
+
186
+ # return the key associated with this entry
187
+ return selectionList[userNumber - 1]
188
+
189
+
190
+ '''
191
+ printText(text)
192
+
193
+ prints out the specified text via the currently selected user interface
194
+
195
+ arguments:
196
+ text - a string of text, or a list of strings
197
+ fillLine - If true print will cover the width of the screen (useful when using "\r" to write on the same line)
198
+ terminalWidth - Width of terminal writing to
199
+ fill - The character that will be used to fill the remaining space
200
+
201
+
202
+ '''
203
+ def printText(text, fillLine=False, terminalWidth=100, fill=" ", **kwargs):
204
+
205
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
206
+ # if line is not empty
207
+ if text.strip() != "":
208
+ TestCenter.testPoint ("Quarch_Host.LogComment","Message=" + __formatForTestcenter(text),stack_level=2)
209
+
210
+ else:
211
+ if fillLine:
212
+ text +=fill*(terminalWidth-len(text)) #TODO Split string at \n or \r\n make a list, add the line fill for each item,then add back the \n and \r\n and combine together again.
213
+ if kwargs != {}:
214
+ print(text, **kwargs)
215
+ else:
216
+ print(text)
217
+ return
218
+
219
+ def logWarning(text, fillLine=False):
220
+ '''
221
+ logWarning(text)
222
+ Processes a warning message and diaplays it using python standar logging or a warning message in test centre.
223
+ arguments:
224
+ text - a string of text, or a list of strings
225
+ '''
226
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
227
+ # if line is not empty
228
+ if text.strip() != "":
229
+ TestCenter.testPoint("Quarch_Host.LogWarning", "Message=" + __formatForTestcenter(text))
230
+
231
+ else:
232
+ logging.warning(text)
233
+ return
234
+
235
+
236
+ '''
237
+ showDialog(title,message)
238
+ prints a message to the user and waits for acknowledgement
239
+ '''
240
+ def showDialog(message="",title=""):
241
+
242
+
243
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
244
+ TestCenter.testPoint ("Quarch_Host.ShowDialog","Title=" + __formatForTestcenter(title),"Message=" + __formatForTestcenter(message), stack_level=2)
245
+
246
+ else:
247
+ print(message)
248
+ if sys.version_info.major >= 3:
249
+ userStr = input("Press enter to continue\n>")
250
+ else:
251
+ userStr = raw_input("Press enter to continue\n>")
252
+
253
+
254
+ def showImage(title="", message="", imagePath=""):
255
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
256
+ TestCenter.testPoint("Quarch_Host.ShowImageDialog", "Title=" + __formatForTestcenter(title),
257
+ "Message=" + __formatForTestcenter(message),
258
+ "ImagePath=" + __formatForTestcenter(imagePath), stack_level=2)
259
+
260
+ else:
261
+ print("show image at " + str(imagePath))
262
+
263
+
264
+ '''
265
+ printProgressBar (iteration,total,prefix='',suffix='',decimals=1,length=100,fill='█')
266
+
267
+ prints a text based progress bar
268
+
269
+ iteration - Required : current iteration (Int)
270
+ total - Required : total iterations (Int)
271
+ prefix - Optional : prefix string (Str)
272
+ suffix - Optional : suffix string (Str)
273
+ decimals - Optional : positive number of decimals in percent complete (Int)
274
+ length - Optional : character length of bar (Int)
275
+ fill - Optional : bar fill character (Str)
276
+
277
+ '''
278
+ def progressBar(iteration, total, prefix='', suffix='', decimals=1, fill='█', fullWidth=100):
279
+ if iteration >= 0 and total > 0:
280
+
281
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
282
+ TestCenter.testPoint ("Quarch_Host.ShowTaskProgress","Title=Task Progress", "Iteration="+str(int(iteration)), "Total="+str(int(total)), stack_level=2);
283
+
284
+ else:
285
+ percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
286
+ length = fullWidth - (len(prefix)+len(suffix)+len(percent) +4) #the length of the bar must scale acording to anything else on the line
287
+
288
+ filledLength = int(length * iteration // total)
289
+ bar = fill * filledLength + '-' * (length - filledLength)
290
+ print('%s|%s|%s%%%s' % (prefix, bar, percent, suffix), end='\r')
291
+
292
+ # Print New Line on Complete
293
+ if iteration >= total:
294
+ print()
295
+
296
+
297
+ '''
298
+ startTestBlock(text)
299
+ prints out the specified text via the currently selected user interface
300
+ arguments:
301
+ text - a string of text, or a list of strings
302
+ '''
303
+ def startTestBlock(text):
304
+
305
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
306
+ return TestCenter.beginTestBlock(__formatForTestcenter(text), stack_level=2)
307
+
308
+ else:
309
+ print("")
310
+ print("*** " + text + " ***")
311
+ return True
312
+
313
+ '''
314
+ endTestBlock()
315
+ finishes the current test block in testcenter, no action in console
316
+ '''
317
+ def endTestBlock(message="End test block"):
318
+
319
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
320
+ return TestCenter.endTestBlock(stack_level=2)
321
+ else:
322
+ print("*** "+message+" *** \r\n")
323
+ return
324
+
325
+ '''
326
+ logCalibrationResult(title,result)
327
+ This was a little naughty as its callibration specific. If you are looking for something without the report obj look at logSimpleResult() func.
328
+ '''
329
+ def logCalibrationResult(title, report):
330
+
331
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
332
+ if report["result"]:
333
+ TestCenter.testPoint("Quarch_Host.LogTestPoint", "Test=" + __formatForTestcenter(title), "Result=True",
334
+ "Message=" + __formatForTestcenter(
335
+ title) + " Passed, worst case: " + __formatForTestcenter(report["worst case"]), stack_level=2)
336
+ # add the report as comments
337
+ for line in report["report"].splitlines():
338
+ TestCenter.testPoint("Quarch_Host.LogComment", "Message=" + __formatForTestcenter(line), stack_level=2)
339
+ TestCenter.endTestBlock(stack_level=2)
340
+ else:
341
+
342
+ TestCenter.testPoint("Quarch_Host.LogTestPoint", "Test=" + __formatForTestcenter(title), "Result=False",
343
+ "Message=" + __formatForTestcenter(
344
+ title) + " Failed, worst case: " + __formatForTestcenter(report["worst case"]), stack_level=2)
345
+ # add the report as comments
346
+ for line in report["report"].splitlines():
347
+ TestCenter.testPoint("Quarch_Host.LogComment", "Message=" + __formatForTestcenter(line), stack_level=2)
348
+ TestCenter.endTestBlock(stack_level=2)
349
+
350
+ else:
351
+ if report["result"]:
352
+ print("\t" + title + " Passed")
353
+ print("\tworst case: " + report["worst case"])
354
+ else:
355
+ print("\t" + title + " Failed")
356
+ print("")
357
+ data = report["report"]
358
+ print(data)
359
+
360
+ '''
361
+ storeResult(string)
362
+ '''
363
+ def storeResult(message):
364
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
365
+ TestCenter.testPoint("Quarch_Internal.storeMessage", "Message=" + message, stack_level=2)
366
+ else:
367
+ print(message)
368
+
369
+ '''
370
+ logsSimpleCalibrationResult(title,result)
371
+ PASS/FAIL ONLY
372
+ '''
373
+ def logSimpleResult(title, result):
374
+ # printText("Result = "+str(result))
375
+ if type(result) == str:
376
+ if result.lower() in ['true', '1', 't', 'y', 'yes', 'pass']:
377
+ result = True
378
+ elif result.lower() in ['false', '0', 'f', 'n', 'no', 'fail']:
379
+ result = False
380
+ else:
381
+ raise ValueError("Result = " + result + " is not valid.")
382
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
383
+ if result == True:
384
+ TestCenter.testPoint("Quarch_Host.LogTestPoint", "Test=" + __formatForTestcenter(title), "Result=True",
385
+ "Message=" + __formatForTestcenter(title), stack_level=2)
386
+ elif result == False:
387
+
388
+ TestCenter.testPoint("Quarch_Host.LogTestPoint", "Test=" + __formatForTestcenter(title), "Result=False",
389
+ "Message=" + __formatForTestcenter(title), stack_level=2)
390
+ else:
391
+ title = "Result is bad format! Title:" + str(title) + " result: " + str(result)
392
+ TestCenter.testPoint("Quarch_Host.LogTestPoint", "Test=" + __formatForTestcenter(title), "Result=False",
393
+ "Message=" + __formatForTestcenter(title), stack_level=2)
394
+ else:
395
+
396
+ if result == True:
397
+ print("\t" + title + " Passed")
398
+ elif result == False:
399
+ print("\t" + title + " Failed")
400
+ else:
401
+ title = "Result is bad format! Title:" + str(title) + " result: " + str(result)
402
+ print("\t" + title)
403
+
404
+ '''
405
+ logResults(test,notes)
406
+ '''
407
+ def logResults(test, notes):
408
+
409
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
410
+ TestCenter.testPoint ("Quarch_Internal.ResultDialog","Test="+ __formatForTestcenter(test),"Notes=" + __formatForTestcenter(notes), stack_level=2)
411
+
412
+ else:
413
+ print("\t" + test + ": " + notes)
414
+
415
+ return
416
+
417
+
418
+ def showYesNoDialog(title, message):
419
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
420
+ response = TestCenter.testPoint("Quarch_Host.ShowYesNoDialog", "Title=" + title,
421
+ "Message=" + message, stack_level=2)
422
+ else:
423
+ response = listSelection(title, message, "Yes,No", nice=True)
424
+ return response
425
+
426
+
427
+ '''
428
+ requestDialog(title, message)
429
+ '''
430
+ def requestDialog(title="", message="", desiredType=None, minRange=None, maxRange=None, defaultUserInput=""):
431
+ validValue = False
432
+ if desiredType != None and desiredType.lower() == "string": # If "string" or None do the same thing. Default is string type.
433
+ desiredType = None
434
+ while validValue == False:
435
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
436
+
437
+ userStr = TestCenter.testPoint("Quarch_Host.ShowRequestDialog","Title= " + __formatForTestcenter(title), "Message=" + __formatForTestcenter(message), stack_level=2);
438
+
439
+ else: # default mode console output
440
+ # Request user selection
441
+ if message == "" and title != "":
442
+ message = title
443
+ if sys.version_info.major >= 3:
444
+ userStr = input(message + "\n>")
445
+ else:
446
+ userStr = raw_input(message + "\n>")
447
+ if userStr == "":
448
+ userStr = defaultUserInput
449
+ validValue = validateUserInput(userStr, desiredType, minRange, maxRange)
450
+
451
+ return userStr
452
+ '''
453
+ Takes string checks if can cast to desired type and returns it as that type, can check if within range for ints and floats.
454
+ '''
455
+ def validateUserInput(userStr, desiredType, minRange, maxRange):
456
+ validValue = False
457
+ if desiredType == None:
458
+ validValue = True
459
+ if desiredType == "float":
460
+ try:
461
+ userStr = float(userStr)
462
+ if ((minRange != None and maxRange != None) and (userStr < minRange or userStr > maxRange)):
463
+ validValue = False
464
+ else:
465
+ validValue = True
466
+ except:
467
+ pass
468
+
469
+ elif desiredType == "int":
470
+ try:
471
+ userStr = int(userStr)
472
+ if ((minRange != None and maxRange != None) and (userStr < minRange or userStr > maxRange)):
473
+ validValue = False
474
+ else:
475
+ validValue = True
476
+ except:
477
+ pass
478
+ elif desiredType == "path":
479
+ if (os.path.isdir(userStr) == False):
480
+ validValue = False
481
+ else:
482
+ validValue = True
483
+ if validValue == False:
484
+ printText(str(userStr) + " is not a valid " + str(desiredType))
485
+ if minRange != None and maxRange != None:
486
+ printText("Please enter a " + str(desiredType) + " between " + str(minRange) + " and " + str(maxRange))
487
+ else:
488
+ printText("Please enter a valid " + str(desiredType))
489
+ return validValue
490
+
491
+ '''
492
+ Takes a string input of comma seperated ints or range of ints and converts it to an array of strings with padding if requested eg:
493
+ 2-5, 9,11,31-35 -> 002,003,004,005,009,011,031,032,033,034,035
494
+ intLength tells the function to zeo pad the int before returning it.
495
+ '''
496
+ def userRangeIntSelection(inputString, intLength=3):
497
+ inputList = inputString.split(",")
498
+ returnList = []
499
+ for item in inputList:
500
+ if "-" in item:
501
+ myRange = item.split("-")
502
+ myRange = range(int(myRange[0]), int(myRange[1]) + 1)
503
+ returnList.extend(myRange)
504
+ else:
505
+ if validateUserInput(item, "int", 0, 999):
506
+ returnList.append(item)
507
+
508
+ for i, item in enumerate(returnList):
509
+ returnList[i] = str(item)
510
+ if intLength != None:
511
+ returnList[i] = returnList[i].zfill(intLength)
512
+ return returnList
513
+
514
+
515
+ '''
516
+ Takes in a 2D List and displays a table.
517
+ Will take 2DList/Tuple. Will Process a Dictionary, 1DList/Tuple, CSV String
518
+ '''
519
+ def displayTable(tableData=[[""]], message="", tableHeaders=None, indexReq=False, printToConsole=True, align="l"):
520
+ retVal = ""
521
+ try:
522
+ tableData = tableData.copy()
523
+ if tableHeaders is not None: tableHeaders = tableHeaders.copy()
524
+ except:
525
+ pass
526
+ if tableHeaders == []:
527
+ tableHeaders = None
528
+ if isinstance(tableData, str):
529
+ tableData = tableData.split(',')
530
+ elif isinstance(tableData, dict):
531
+ tableData = dictToList(tableData)
532
+ # Process list to make it into 2d list to display.
533
+ try:
534
+ if not isinstance(tableData[0], tuple) and not isinstance(tableData[0], list) and not isinstance(tableData[0], dict):
535
+ tempList = list()
536
+ for item in tableData:
537
+ tempList.append(list([item]))
538
+ tableData = tempList
539
+ except:
540
+ pass
541
+ # print message
542
+ if message != "":
543
+ print(message)
544
+
545
+ if indexReq:
546
+ if tableHeaders is not None:
547
+ tableHeaders.insert(0, "#")
548
+ counter = 1
549
+ for rows in tableData:
550
+ rows.insert(0, counter)
551
+ counter += 1
552
+
553
+ # calculate required column width for each column
554
+ columnWidths = []
555
+ itemLegnth = 0
556
+ for row in range(len(tableData)):
557
+ for column in range(len(tableData[row])):
558
+ item = str(tableData[row][column])
559
+ if item == None:
560
+ item = "NoneType"
561
+ tableData[row][column] = item
562
+ if item.__contains__("\r") or item.__contains__("\n"):
563
+ item = item.replace("\r", "\\r").replace("\n", "\\n")
564
+ tableData[row][column] = item
565
+ itemLegnth = len(str(item))
566
+ try:
567
+ if columnWidths[column] < itemLegnth:
568
+ columnWidths[column] = itemLegnth
569
+ except: # if null pointer
570
+ columnWidths.append(itemLegnth)
571
+ if tableHeaders is not None:
572
+ index = 0
573
+ for item in tableHeaders:
574
+ itemLegnth = len(str(item))
575
+ try:
576
+ if columnWidths[index] < itemLegnth:
577
+ columnWidths[index] = itemLegnth
578
+ except: # if null pointer
579
+ columnWidths.append(itemLegnth)
580
+ index += 1
581
+
582
+ # Calculate the edge to be displayed at the top and bottom
583
+ topEdge = "+"
584
+ middleEdge = "+"
585
+ bottomEdge = "+"
586
+
587
+ firstLoop = True
588
+ for columnWidth in columnWidths:
589
+ if firstLoop is False:
590
+ topEdge += "+"
591
+ middleEdge += "+"
592
+ bottomEdge += "+"
593
+ topEdge += "-" * (columnWidth + 2)
594
+ middleEdge += "-" * (columnWidth + 2)
595
+ bottomEdge += "-" * (columnWidth + 2)
596
+ firstLoop = False
597
+
598
+ topEdge = topEdge + "+"
599
+ middleEdge = middleEdge + "+"
600
+ bottomEdge = bottomEdge + "+"
601
+
602
+ # Always add the top reguardless of table headers or not.
603
+ retVal += topEdge + "\n"
604
+ # Add table headers section
605
+ if tableHeaders is not None:
606
+ rowString = "|"
607
+ index = 0
608
+ for item in tableHeaders:
609
+ spaces = (columnWidths[index] - len(str(item)) + 2)
610
+ if align.lower() in "l":
611
+ rowString += str(item) + " " * spaces + "|"
612
+ elif align.lower() in "c":
613
+ prefix = " " * math.floor(spaces / 2)
614
+ suffix = " " * math.ceil(spaces / 2)
615
+ rowString += prefix + str(item) + suffix + "|"
616
+ elif align.lower() in "r":
617
+ rowString += " " * spaces + str(item) + "|"
618
+ index += 1
619
+ retVal += rowString + "\n"
620
+ retVal += middleEdge + "\n"
621
+ # Add table data section
622
+ for rowData in tableData:
623
+ index = 0
624
+ rowString = "|"
625
+ for item in rowData:
626
+ spaces = (columnWidths[index] - len(str(item)) + 2)
627
+ if align.lower() in "l":
628
+ rowString += str(item) + " " * spaces + "|"
629
+ elif align.lower() in "c":
630
+ prefix = " " * math.floor(spaces / 2)
631
+ suffix = " " * math.ceil(spaces / 2)
632
+ rowString += prefix + str(item) + suffix + "|"
633
+ elif align.lower() in "r":
634
+ rowString += " " * spaces + str(item) + "|"
635
+
636
+ index += 1
637
+ retVal += rowString + "\n"
638
+ retVal += bottomEdge
639
+ if printToConsole: printText(retVal)
640
+ return retVal
641
+
642
+ '''Converts dictionary to list'''
643
+ def dictToList(tableData):
644
+ tempList = []
645
+ tempEl = []
646
+ for k, v in tableData.items():
647
+ tempEl = []
648
+ tempEl.append(v)
649
+ tempEl.append(k)
650
+ tempList.append(tempEl)
651
+ tableData = tempList
652
+ return tableData
653
+
654
+
655
+ def is_user_admin():
656
+ if os.name == 'nt':
657
+ import ctypes
658
+ # WARNING: requires Windows XP SP2 or higher!
659
+ try:
660
+ # If == 1, user is running from elevated cmd prompt
661
+ # printText(ctypes.windll.shell32.IsUserAnAdmin() == 1)
662
+ return ctypes.windll.shell32.IsUserAnAdmin() == 1
663
+ except:
664
+ traceback.print_exc()
665
+ return False
666
+ elif os.name == 'posix':
667
+ # Check for root on Posix
668
+ return os.getuid() == 0
669
+ else:
670
+ raise RuntimeError("Unsupported operating system for this module: %s" % (os.name,))
671
+
672
+
673
+ '''
674
+ '''
675
+ def __formatForTestcenter(text):
676
+ # escape special characters
677
+ # turn \' to \\'s
678
+ text = text.replace('\\', '\\\\')
679
+ # get rid of any alarms that may be included in console mode
680
+ text = text.replace('\a', '')
681
+ # replace line endings
682
+ text = '|'.join(text.splitlines())
683
+ return text
684
+
685
+ def get_check_valid_calPath(calPath, message="Enter the desired save path for the calibration report."):
686
+ inputOK = False
687
+ while inputOK is False:
688
+ if (calPath is None):
689
+ calPath = os.path.expanduser("~")
690
+ calPath = requestDialog("Enter Report Path",
691
+ message + " Leave blank to default to [" + calPath + "] :",
692
+ desiredType="path", defaultUserInput=os.path.expanduser("~"))
693
+
694
+ if (os.path.isdir(calPath) == False):
695
+ printText("Supplied calibration path is invalid: " + calPath)
696
+ inputOK = False
697
+ calPath = None
698
+ else:
699
+ inputOK = True
700
+ return calPath
701
+
702
+ def check_path_write_permissions(path, message="Please enter a valid path with write permissions: "):
703
+ import tempfile, errno
704
+ valid_path=False
705
+ # Create a temporary directory
706
+ calPath = tempfile.mkdtemp()
707
+ while valid_path==False:
708
+ try:
709
+ if path==None:
710
+ # provide a path if no path was provided
711
+ path = requestDialog("No path was provided. ",
712
+ message + " Leave blank to default to [" + calPath + "] :", desiredType="path",
713
+ defaultUserInput=calPath)
714
+ f = open(path+"\\tempFile.txt", "w")
715
+ f.write("some text")
716
+ f.flush()
717
+ f.close()
718
+ os.remove(path + "\\tempFile.txt")
719
+ valid_path = True
720
+ except OSError as e:
721
+ if e.errno == errno.EACCES or e.errno == errno.EEXIST: # 13 or 17
722
+ # provide a path if write permissions are encountered
723
+ path = requestDialog("No write permissions at path: \"" + path + "\". ",
724
+ message + " Leave blank to default to [" + calPath + "] :", desiredType="path",
725
+ defaultUserInput=calPath)
726
+ else:
727
+ e.filename = path
728
+ raise e
729
+ return path
730
+
731
+
732
+ # Deprecated version of the function, here for compatability only
733
+ # calls into the visual_sleep() function
734
+ def quarchSleep(sleepLength, updatePeriod=1, title=""):
735
+ visual_sleep(sleepLength, updatePeriod, title)
736
+
737
+ def visual_sleep(sleepLength, updatePeriod=1, title=""):
738
+ """
739
+ Wrapper for sleep function that gives a visual indicator of the sleep time
740
+ """
741
+ if title != "":
742
+ printText(title)
743
+ startTime = time.time()
744
+ currentTime = time.time()
745
+ while (currentTime - startTime < sleepLength):
746
+ progressBar(iteration=currentTime - startTime, total=sleepLength)
747
+ time.sleep(updatePeriod)
748
+ currentTime = time.time()
749
+ progressBar(iteration=1, total=1) # show 100%