Skip to content

Commit 1dd7ba0

Browse files
committed
- updates usages of util.py:stringtoseconds to handle exceptions that are now thrown on malformed time input strings
- fixes typos in an yet unused function in artisanlib/filters.py found by new test cases - adds messages on import/export Artisan JSON and CSV - fixes an issue in the updated pid.py - fixes an issue in util.py:scaleFloat2String - adds Toper PLC machine setup - adds some more unit tests
1 parent 18124d9 commit 1dd7ba0

29 files changed

Lines changed: 5222 additions & 2001 deletions

doc/help_dialogs/Script/xlsx_to_artisan_help.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def buildpyCode(filename_in:str) -> str:
178178
note_table_attributes = "'width':'100%','border':'1','padding':'1','border-collapse':'collapse'"
179179

180180
outstr = ''
181-
181+
182182
outstr += '# This is an autogenerated file -- Do not edit'
183183
outstr += '\n' + '# Edit the source file in artisan/doc/help_dialogs/Input_files'
184184
outstr += '\n' + '# then execute artisan/doc/help_dialogs/Script/xlsx_to_artisan_help.py'
@@ -206,7 +206,7 @@ def buildpyCode(filename_in:str) -> str:
206206
print(ws.title, ' ', ws.max_row, 'rows ', ws.max_column, 'columns')
207207

208208
# hack to work around when openpyxl ws.max_row returns more rows than actual
209-
num_rows = ws.max_row
209+
num_rows:int = ws.max_row
210210
for row in ws.iter_rows(min_row=1, max_row=num_rows):
211211
if all(c.value is None for c in row):
212212
if row[0].row == num_rows + 2: # two empty rows signifies the end of the help sheet
@@ -264,7 +264,7 @@ def buildpyCode(filename_in:str) -> str:
264264
outstr += nlind + "helpstr = ''.join(strlist)"
265265

266266
# clean any html entities that get escaped by PrettyTable in its html output
267-
outstr += nlind + "return re.sub(r'&', r'&',helpstr)" + "\n"
267+
outstr += nlind + "return re.sub(r'&', r'&',helpstr)" + '\n'
268268

269269
return outstr
270270

src/artisanlib/async_comm.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# This program or module is free software: you can redistribute it and/or
77
# modify it under the terms of the GNU General Public License as published
88
# by the Free Software Foundation, either version 2 of the License, or
9-
# version 3 of the License, or (at your option) any later versison. It is
9+
# version 3 of the License, or (at your option) any later version. It is
1010
# provided for educational purposes and is distributed in the hope that
1111
# it will be useful, but WITHOUT ANY WARRANTY; without even the implied
1212
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
@@ -59,7 +59,8 @@ def start_background_loop(loop:asyncio.AbstractEventLoop) -> None:
5959
self.__thread.start()
6060

6161
def __del__(self) -> None:
62-
self.__loop.call_soon_threadsafe(self.__loop.stop) # pyrefly: ignore[bad-argument-type]
62+
if not self.__loop.is_closed():
63+
self.__loop.call_soon_threadsafe(self.__loop.stop) # pyrefly: ignore[bad-argument-type] # __loop.stop() might raise exception if __loop is closed
6364
# self.__thread.join()
6465
# WARNING: we don't join and expect the clients running on this thread to stop them
6566
# (using self._running) to finally get rid of this thread to prevent hangs
@@ -149,7 +150,7 @@ def __init__(self, host:str = '127.0.0.1', port:int = 8080, serial:Optional['Ser
149150
disconnected_handler:Optional[Callable[[], None]] = None) -> None:
150151
# internals
151152
self._asyncLoopThread: Optional[AsyncLoopThread] = None # the asyncio AsyncLoopThread object
152-
self._write_queue: 'Optional[asyncio.Queue[bytes]]' = None # noqa: UP037 # quotes for Python3.8 # the write_queue
153+
self._write_queue: Optional[asyncio.Queue[bytes]] = None # noqa: UP037 # quotes for Python3.8 # the write_queue
153154
self._running:bool = False # while true we keep running the thread
154155

155156
# connection

src/artisanlib/axis.py

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -644,26 +644,34 @@ def autoAxis(self, _:bool = False) -> None:
644644
self.xlimitEdit_min.repaint()
645645
self.xlimitEdit.repaint()
646646

647-
endedittime_str = str(self.xlimitEdit.text())
648-
if endedittime_str is not None and endedittime_str != '':
649-
endeditime = stringtoseconds(endedittime_str)
650-
if self.aw.qmc.endofx != endeditime:
651-
self.aw.qmc.endofx = endeditime
652-
self.aw.qmc.locktimex_end = endeditime
647+
try:
648+
endedittime_str = str(self.xlimitEdit.text())
649+
if endedittime_str is not None and endedittime_str != '':
650+
endeditime = stringtoseconds(endedittime_str)
651+
if self.aw.qmc.endofx != endeditime:
652+
self.aw.qmc.endofx = endeditime
653+
self.aw.qmc.locktimex_end = endeditime
654+
changed = True
655+
except Exception: # pylint: disable=broad-except
656+
pass # stringtoseconds raises exception on malformed input
657+
658+
try:
659+
startedittime_str = str(self.xlimitEdit_min.text())
660+
if startedittime_str is not None and startedittime_str != '':
661+
starteditime = stringtoseconds(startedittime_str)
662+
if starteditime >= 0 and self.aw.qmc.timeindex[0] != -1:
663+
self.aw.qmc.startofx = self.aw.qmc.timex[self.aw.qmc.timeindex[0]] + starteditime
664+
elif starteditime >= 0 and self.aw.qmc.timeindex[0] == -1:
665+
self.aw.qmc.startofx = starteditime
666+
elif starteditime < 0 and self.aw.qmc.timeindex[0] != -1:
667+
self.aw.qmc.startofx = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]-abs(starteditime)
668+
else:
669+
self.aw.qmc.startofx = starteditime
670+
self.aw.qmc.locktimex_start = starteditime
653671
changed = True
654-
startedittime_str = str(self.xlimitEdit_min.text())
655-
if startedittime_str is not None and startedittime_str != '':
656-
starteditime = stringtoseconds(startedittime_str)
657-
if starteditime >= 0 and self.aw.qmc.timeindex[0] != -1:
658-
self.aw.qmc.startofx = self.aw.qmc.timex[self.aw.qmc.timeindex[0]] + starteditime
659-
elif starteditime >= 0 and self.aw.qmc.timeindex[0] == -1:
660-
self.aw.qmc.startofx = starteditime
661-
elif starteditime < 0 and self.aw.qmc.timeindex[0] != -1:
662-
self.aw.qmc.startofx = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]-abs(starteditime)
663-
else:
664-
self.aw.qmc.startofx = starteditime
665-
self.aw.qmc.locktimex_start = starteditime
666-
changed = True
672+
except Exception: # pylint: disable=broad-except
673+
pass # stringtoseconds raises exception on malformed input
674+
667675
if changed:
668676
self.aw.qmc.redraw(recomputeAllDeltas=False)
669677

@@ -833,25 +841,33 @@ def updatewindow(self) -> None:
833841

834842
endedittime_str = str(self.xlimitEdit.text())
835843
if endedittime_str is not None and endedittime_str != '':
836-
endeditime = stringtoseconds(endedittime_str)
837-
self.aw.qmc.endofx = endeditime
838-
self.aw.qmc.locktimex_end = endeditime
844+
try:
845+
endeditime = stringtoseconds(endedittime_str)
846+
self.aw.qmc.endofx = endeditime
847+
self.aw.qmc.locktimex_end = endeditime
848+
except Exception: # pylint: disable=broad-except
849+
self.aw.qmc.endofx = self.aw.qmc.endofx_default
850+
self.aw.qmc.locktimex_end = self.aw.qmc.endofx_default
839851
else:
840852
self.aw.qmc.endofx = self.aw.qmc.endofx_default
841853
self.aw.qmc.locktimex_end = self.aw.qmc.endofx_default
842854

843855
startedittime_str = str(self.xlimitEdit_min.text())
844856
if startedittime_str is not None and startedittime_str != '':
845-
starteditime = stringtoseconds(startedittime_str)
846-
if starteditime >= 0 and self.aw.qmc.timeindex[0] != -1:
847-
self.aw.qmc.startofx = self.aw.qmc.timex[self.aw.qmc.timeindex[0]] + starteditime
848-
elif starteditime >= 0 and self.aw.qmc.timeindex[0] == -1:
849-
self.aw.qmc.startofx = starteditime
850-
elif starteditime < 0 and self.aw.qmc.timeindex[0] != -1:
851-
self.aw.qmc.startofx = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]-abs(starteditime)
852-
else:
853-
self.aw.qmc.startofx = starteditime
854-
self.aw.qmc.locktimex_start = starteditime
857+
try:
858+
starteditime = stringtoseconds(startedittime_str)
859+
if starteditime >= 0 and self.aw.qmc.timeindex[0] != -1:
860+
self.aw.qmc.startofx = self.aw.qmc.timex[self.aw.qmc.timeindex[0]] + starteditime
861+
elif starteditime >= 0 and self.aw.qmc.timeindex[0] == -1:
862+
self.aw.qmc.startofx = starteditime
863+
elif starteditime < 0 and self.aw.qmc.timeindex[0] != -1:
864+
self.aw.qmc.startofx = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]-abs(starteditime)
865+
else:
866+
self.aw.qmc.startofx = starteditime
867+
self.aw.qmc.locktimex_start = starteditime
868+
except Exception: # pylint: disable=broad-except
869+
self.aw.qmc.startofx = self.aw.qmc.startofx_default
870+
self.aw.qmc.locktimex_start = self.aw.qmc.startofx_default
855871
else:
856872
self.aw.qmc.startofx = self.aw.qmc.startofx_default
857873
self.aw.qmc.locktimex_start = self.aw.qmc.startofx_default
@@ -865,13 +881,19 @@ def updatewindow(self) -> None:
865881
except Exception: # pylint: disable=broad-except
866882
pass
867883

868-
resettime = stringtoseconds(str(self.resetEdit.text()))
869-
if resettime > 0:
870-
self.aw.qmc.resetmaxtime = resettime
884+
try:
885+
resettime = stringtoseconds(str(self.resetEdit.text()))
886+
if resettime > 0:
887+
self.aw.qmc.resetmaxtime = resettime
888+
except Exception: # pylint: disable=broad-except
889+
pass
871890

872-
chargetime = stringtoseconds(str(self.chargeminEdit.text()))
873-
if chargetime <= 0:
874-
self.aw.qmc.chargemintime = chargetime
891+
try:
892+
chargetime = stringtoseconds(str(self.chargeminEdit.text()))
893+
if chargetime <= 0:
894+
self.aw.qmc.chargemintime = chargetime
895+
except Exception: # pylint: disable=broad-except
896+
pass
875897

876898
self.aw.qmc.fixmaxtime = not self.fixmaxtimeFlag.isChecked()
877899
self.aw.qmc.locktimex = self.locktimexFlag.isChecked()

src/artisanlib/calculator.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -234,31 +234,34 @@ def calculateRC(self) -> None:
234234
if not self.startEdit.text() or not self.endEdit.text():
235235
#empty field
236236
return
237-
starttime = stringtoseconds(str(self.startEdit.text()))
238-
endtime = stringtoseconds(str(self.endEdit.text()))
239-
if starttime == -1 or endtime == -1:
240-
self.result1.setText(QApplication.translate('Label', 'Time syntax error. Time not valid'))
237+
try:
238+
starttime = stringtoseconds(str(self.startEdit.text()))
239+
endtime = stringtoseconds(str(self.endEdit.text()))
240+
if endtime > self.aw.qmc.timex[-1] or endtime < starttime:
241+
self.aw.sendmessage(QApplication.translate('Label', 'Error: End time smaller than Start time'))
242+
self.result1.setText('')
243+
self.result2.setText('')
244+
return
245+
if self.aw.qmc.timeindex[0] != -1:
246+
start = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]
247+
else:
248+
start = 0
249+
startindex = self.aw.qmc.time2index(starttime + start)
250+
endindex = self.aw.qmc.time2index(endtime + start)
251+
#delta
252+
deltatime = self.aw.qmc.timex[endindex] - self.aw.qmc.timex[startindex]
253+
deltatemperature = self.aw.qmc.temp2[endindex] - self.aw.qmc.temp2[startindex]
254+
deltaseconds = 0 if deltatime == 0 else deltatemperature / deltatime
255+
deltaminutes = deltaseconds*60.
256+
string1 = QApplication.translate('Label', 'Best approximation was made from {0} to {1}').format(stringfromseconds(self.aw.qmc.timex[startindex]- start),stringfromseconds(self.aw.qmc.timex[endindex]- start))
257+
string2 = QApplication.translate('Label', '<b>{0}</b> {1}/sec, <b>{2}</b> {3}/min').format(f'{deltaseconds:.2f}',self.aw.qmc.mode,f'{deltaminutes:.2f}',self.aw.qmc.mode)
258+
self.result1.setText(string1)
259+
self.result2.setText(string2)
260+
except Exception: # pylint: disable=broad-except
261+
self.aw.sendmessage(QApplication.translate('Label', 'Time syntax error. Time not valid'))
262+
self.result1.setText('')
241263
self.result2.setText('')
242264
return
243-
if endtime > self.aw.qmc.timex[-1] or endtime < starttime:
244-
self.result1.setText(QApplication.translate('Label', 'Error: End time smaller than Start time'))
245-
self.result2.setText('')
246-
return
247-
if self.aw.qmc.timeindex[0] != -1:
248-
start = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]
249-
else:
250-
start = 0
251-
startindex = self.aw.qmc.time2index(starttime + start)
252-
endindex = self.aw.qmc.time2index(endtime + start)
253-
#delta
254-
deltatime = self.aw.qmc.timex[endindex] - self.aw.qmc.timex[startindex]
255-
deltatemperature = self.aw.qmc.temp2[endindex] - self.aw.qmc.temp2[startindex]
256-
deltaseconds = 0 if deltatime == 0 else deltatemperature / deltatime
257-
deltaminutes = deltaseconds*60.
258-
string1 = QApplication.translate('Label', 'Best approximation was made from {0} to {1}').format(stringfromseconds(self.aw.qmc.timex[startindex]- start),stringfromseconds(self.aw.qmc.timex[endindex]- start))
259-
string2 = QApplication.translate('Label', '<b>{0}</b> {1}/sec, <b>{2}</b> {3}/min').format(f'{deltaseconds:.2f}',self.aw.qmc.mode,f'{deltaminutes:.2f}',self.aw.qmc.mode)
260-
self.result1.setText(string1)
261-
self.result2.setText(string2)
262265
else:
263266
self.result1.setText(QApplication.translate('Label', 'No profile found'))
264267
self.result2.setText('')

src/artisanlib/canvas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7018,7 +7018,7 @@ def eval_math_expression(self,mathexpression:str, t:float, equeditnumber:Optiona
70187018
#find right most occurrence before index of given event type
70197019
if nint in self.specialeventstype and nint < 4:
70207020
spevtylen = len(self.specialeventstype)-1
7021-
iii = None
7021+
iii:Optional[int] = None
70227022
for iii in range(spevtylen,-1,-1):
70237023
if self.specialeventstype[iii] == nint and index >= self.specialevents[iii]:
70247024
break #index found

src/artisanlib/curves.py

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,38 +2131,41 @@ def eventlist(self) -> List[Tuple[str,int]]:
21312131
return events
21322132

21332133
def doPolyfit(self) -> bool:
2134-
ll = min(len(self.aw.qmc.timex),len(self.curves[self.c1ComboBox.currentIndex()]),len(self.curves[self.c2ComboBox.currentIndex()]))
2135-
starttime = stringtoseconds(str(self.startEdit.text()))
2136-
endtime = stringtoseconds(str(self.endEdit.text()))
2137-
if starttime == -1 or endtime == -1:
2138-
self.resultWidget.setText('')
2139-
self.resultWidget.repaint()
2140-
return False
2141-
if endtime > self.aw.qmc.timex[-1] or endtime < starttime:
2142-
self.resultWidget.setText('')
2143-
self.resultWidget.repaint()
2144-
return False
2145-
if self.aw.qmc.timeindex[0] != -1:
2146-
start = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]
2147-
else:
2148-
start = 0
2149-
startindex = self.aw.qmc.time2index(starttime + start)
2150-
endindex = min(ll,self.aw.qmc.time2index(endtime + start))
2151-
c1 = self.curves[self.c1ComboBox.currentIndex()]
2152-
c2 = self.curves[self.c2ComboBox.currentIndex()]
2153-
z = self.aw.qmc.polyfit(c1,c2,
2154-
self.polyfitdeg.value(),startindex,endindex,self.deltacurves[self.c2ComboBox.currentIndex()],onDeltaAxis=self.polyfitRoR)
2155-
res = True
2156-
if z is not None:
2157-
for e in z:
2158-
if numpy.isnan(e):
2159-
res = False
2160-
break
2161-
if res and z is not None:
2162-
s = self.aw.fit2str(z)
2163-
self.resultWidget.setText(s)
2164-
self.resultWidget.repaint()
2165-
return True
2134+
try:
2135+
ll = min(len(self.aw.qmc.timex),len(self.curves[self.c1ComboBox.currentIndex()]),len(self.curves[self.c2ComboBox.currentIndex()]))
2136+
starttime = stringtoseconds(str(self.startEdit.text()))
2137+
endtime = stringtoseconds(str(self.endEdit.text()))
2138+
if starttime == -1 or endtime == -1:
2139+
self.resultWidget.setText('')
2140+
self.resultWidget.repaint()
2141+
return False
2142+
if endtime > self.aw.qmc.timex[-1] or endtime < starttime:
2143+
self.resultWidget.setText('')
2144+
self.resultWidget.repaint()
2145+
return False
2146+
if self.aw.qmc.timeindex[0] != -1:
2147+
start = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]
2148+
else:
2149+
start = 0
2150+
startindex = self.aw.qmc.time2index(starttime + start)
2151+
endindex = min(ll,self.aw.qmc.time2index(endtime + start))
2152+
c1 = self.curves[self.c1ComboBox.currentIndex()]
2153+
c2 = self.curves[self.c2ComboBox.currentIndex()]
2154+
z = self.aw.qmc.polyfit(c1,c2,
2155+
self.polyfitdeg.value(),startindex,endindex,self.deltacurves[self.c2ComboBox.currentIndex()],onDeltaAxis=self.polyfitRoR)
2156+
res = True
2157+
if z is not None:
2158+
for e in z:
2159+
if numpy.isnan(e):
2160+
res = False
2161+
break
2162+
if res and z is not None:
2163+
s = self.aw.fit2str(z)
2164+
self.resultWidget.setText(s)
2165+
self.resultWidget.repaint()
2166+
return True
2167+
except Exception: # pylint: disable=broad-except
2168+
pass
21662169
self.resultWidget.setText('')
21672170
self.resultWidget.repaint()
21682171
return False

0 commit comments

Comments
 (0)