1919# flag to track and print debug output
2020_tagui_debug = False
2121
22- # id to track instruction count between tagui- python and tagui
22+ # id to track instruction count from tagui python to tagui
2323_tagui_id = 0
2424
2525# delete tagui temp output text file to avoid reading old data
@@ -210,10 +210,19 @@ def setup():
210210 if os .path .isfile (temp_directory + '/' + tagui_zip_file ):
211211 os .remove (temp_directory + '/' + tagui_zip_file )
212212
213+ # download stable delta files from tagui cutting edge version
214+ print ('[TAGUI][INFO] - done. syncing TagUI files from stable cutting edge version' )
215+ delta_list = ['tagui' , 'tagui.cmd' , 'tagui_header.js' , 'tagui_parse.php' ]
216+ for delta_file in delta_list :
217+ tagui_delta_url = 'https://raw.githubusercontent.com/tebelorg/Tump/master/TagUI-Python/' + delta_file
218+ tagui_delta_file = temp_directory + '/' + 'tagui' + '/' + 'src' + '/' + delta_file
219+ if not download (tagui_delta_url , tagui_delta_file ): return False
220+
213221 # perform Linux specific setup actions
214222 if platform .system () == 'Linux' :
215223 # zipfile extractall does not preserve execute permissions
216224 # invoking chmod to set all files with execute permissions
225+ # and update delta tagui/src/tagui with execute permission
217226 if os .system ('chmod -R 755 ' + temp_directory + '/' + 'tagui > /dev/null 2>&1' ) != 0 :
218227 print ('[TAGUI][ERROR] - unable to set permissions for tagui folder' )
219228 return False
@@ -232,6 +241,7 @@ def setup():
232241 if platform .system () == 'Darwin' :
233242 # zipfile extractall does not preserve execute permissions
234243 # invoking chmod to set all files with execute permissions
244+ # and update delta tagui/src/tagui with execute permission
235245 if os .system ('chmod -R 755 ' + temp_directory + '/' + 'tagui > /dev/null 2>&1' ) != 0 :
236246 print ('[TAGUI][ERROR] - unable to set permissions for tagui folder' )
237247 return False
@@ -276,7 +286,7 @@ def setup():
276286 # check that tagui packaged php is working, it has dependency on MSVCR110.dll
277287 if os .system (temp_directory + '/' + 'tagui' + '/' + 'src' + '/' + 'php/php.exe -v > nul 2>&1' ) != 0 :
278288 print ('[TAGUI][INFO] - now installing missing Visual C++ Redistributable dependency' )
279- vcredist_x86_url = 'https://github. com/tebelorg/Tump/raw /master/vcredist_x86.exe'
289+ vcredist_x86_url = 'https://raw.githubusercontent. com/tebelorg/Tump/master/vcredist_x86.exe'
280290 if download (vcredist_x86_url , temp_directory + '/vcredist_x86.exe' ):
281291 os .system (temp_directory + '/vcredist_x86.exe' )
282292
@@ -304,8 +314,18 @@ def init(visual_automation = False, chrome_browser = True):
304314 print ('[TAGUI][ERROR] - use close() before using init() again' )
305315 return False
306316
317+ # reset id to track instruction count from tagui python to tagui
318+ _tagui_id = 0
319+
320+ # get system temporary folder location to locate tagui executable
321+ temp_directory = tempfile .gettempdir ()
322+
323+ # special handling for Linux as /tmp is non-executable by default
324+ if platform .system () == 'Linux' :
325+ temp_directory = os .path .expanduser ('~' ) + '/tmp'
326+
307327 # get system temporary folder location to form tagui executable path
308- tagui_executable = tempfile . gettempdir () + '/' + 'tagui' + '/' + 'src' + '/' + 'tagui'
328+ tagui_executable = temp_directory + '/' + 'tagui' + '/' + 'src' + '/' + 'tagui'
309329
310330 # if tagui executable is not found, initiate setup() to install tagui
311331 if not os .path .isfile (tagui_executable ):
@@ -320,14 +340,15 @@ def init(visual_automation = False, chrome_browser = True):
320340 shell_silencer = '> nul 2>&1'
321341 else :
322342 shell_silencer = '> /dev/null 2>&1'
343+
323344 if os .system ('java -version ' + shell_silencer ) != 0 :
324345 print ('[TAGUI][INFO] - for visual automation mode, Java JDK v8 (64-bit) or later is required' )
325346 print ('[TAGUI][INFO] - to use visual automation feature, download Java JDK v8 (64-bit) from below' )
326347 print ('[TAGUI][INFO] - https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html' )
327348 return False
328349 else :
329350 # start a dummy first run if never run before, to let sikulix integrate jython
330- sikulix_folder = tempfile . gettempdir () + '/' + 'tagui' + '/' + 'src' + '/' + 'sikulix'
351+ sikulix_folder = temp_directory + '/' + 'tagui' + '/' + 'src' + '/' + 'sikulix'
331352 if os .path .isfile (sikulix_folder + '/' + 'jython-standalone-2.7.1.jar' ):
332353 os .system ('java -jar ' + sikulix_folder + '/' + 'sikulix.jar -h ' + shell_silencer )
333354 _visual_flow ()
@@ -371,11 +392,21 @@ def init(visual_automation = False, chrome_browser = True):
371392
372393 # check that tagui live mode is ready then start listening for inputs
373394 if 'LIVE MODE - type done to quit' in tagui_out :
374- # print new line to clear live mode backspace character before listening
375- _tagui_write ('echo ""\n ' )
395+ # dummy + start line to clear live mode backspace char before listening
376396 _tagui_write ('echo "[TAGUI][STARTED]"\n ' )
377397 _tagui_write ('echo "[TAGUI][' + str (_tagui_id ) + '] - listening for inputs"\n ' )
378398 _tagui_started = True
399+
400+ # loop until tagui live mode is ready and listening for inputs
401+ # also check _tagui_started to handle unexpected termination
402+ while _tagui_started and not _ready (): pass
403+ if not _tagui_started :
404+ print ('[TAGUI][ERROR] - TagUI process ended unexpectedly' )
405+ return False
406+
407+ # increment id and prepare for next instruction
408+ _tagui_id = _tagui_id + 1
409+
379410 return True
380411
381412 except Exception as e :
@@ -434,13 +465,6 @@ def send(tagui_instruction = None):
434465 _tagui_started = False
435466 return False
436467
437- # loop until tagui live mode is ready and listening for inputs
438- # also check _tagui_started to handle unexpected termination
439- while _tagui_started and not _ready (): pass
440- if not _tagui_started :
441- print ('[TAGUI][ERROR] - TagUI process ended unexpectedly' )
442- return False
443-
444468 # escape special characters for them to reach tagui correctly
445469 tagui_instruction = tagui_instruction .replace ('\\ ' ,'\\ \\ ' )
446470 tagui_instruction = tagui_instruction .replace ('\n ' ,'\\ n' )
@@ -465,9 +489,18 @@ def send(tagui_instruction = None):
465489 # send live mode instruction to be executed
466490 _tagui_write (tagui_instruction + '\n ' )
467491
492+ # echo marker text to prepare for next instruction
493+ _tagui_write ('echo "[TAGUI][' + str (_tagui_id ) + '] - listening for inputs"\n ' )
494+
495+ # loop until tagui live mode is ready and listening for inputs
496+ # also check _tagui_started to handle unexpected termination
497+ while _tagui_started and not _ready (): pass
498+ if not _tagui_started :
499+ print ('[TAGUI][ERROR] - TagUI process ended unexpectedly' )
500+ return False
501+
468502 # increment id and prepare for next instruction
469503 _tagui_id = _tagui_id + 1
470- _tagui_write ('echo "[TAGUI][' + str (_tagui_id ) + '] - listening for inputs"\n ' )
471504
472505 return True
473506
@@ -482,7 +515,6 @@ def close():
482515
483516 if not _tagui_started :
484517 print ('[TAGUI][ERROR] - use init() before using close()' )
485- _tagui_started = False
486518 return False
487519
488520 try :
@@ -492,28 +524,23 @@ def close():
492524 _tagui_started = False
493525 return False
494526
495- # loop until tagui live mode is ready and listening for inputs
496- # also check _tagui_started to handle unexpected termination
497- while _tagui_started and not _ready (): pass
498- if not _tagui_started :
499- print ('[TAGUI][ERROR] - TagUI process ended unexpectedly' )
500- return False
501-
502527 # send 'done' instruction to terminate live mode and exit tagui
503528 _tagui_write ('echo "[TAGUI][FINISHED]"\n ' )
504529 _tagui_write ('done\n ' )
505530
506531 # loop until tagui process has closed before returning control
507532 while _process .poll () is None : pass
508533
509- # remove generated tagui flow and log files if not in debug mode
534+ # remove generated tagui flow, js code and custom functions files
535+ if os .path .isfile ('tagui_python' ): os .remove ('tagui_python' )
536+ if os .path .isfile ('tagui_python.js' ): os .remove ('tagui_python.js' )
537+ if os .path .isfile ('tagui_python.raw' ): os .remove ('tagui_python.raw' )
538+ if os .path .isfile ('tagui_local.js' ): os .remove ('tagui_local.js' )
539+
540+ # remove generated tagui log and data files if not in debug mode
510541 if not debug ():
511- if os .path .isfile ('tagui_python' ): os .remove ('tagui_python' )
512- if os .path .isfile ('tagui_python.js' ): os .remove ('tagui_python.js' )
513- if os .path .isfile ('tagui_python.raw' ): os .remove ('tagui_python.raw' )
514542 if os .path .isfile ('tagui_python.log' ): os .remove ('tagui_python.log' )
515543 if os .path .isfile ('tagui_python.txt' ): os .remove ('tagui_python.txt' )
516- if os .path .isfile ('tagui_local.js' ): os .remove ('tagui_local.js' )
517544
518545 _tagui_started = False
519546 return True
@@ -531,7 +558,7 @@ def exist(element_identifier = None):
531558 if element_identifier is None or element_identifier == '' :
532559 return False
533560
534- # check for existence of specified image file for visual automation
561+ # pre-emptive check for existence of specified image file for visual automation
535562 if element_identifier .lower ().endswith ('.png' ) or element_identifier .lower ().endswith ('.bmp' ):
536563 if not os .path .isfile (element_identifier ):
537564 print ('[TAGUI][ERROR] - missing image file ' + element_identifier )
@@ -685,7 +712,7 @@ def type(element_identifier = None, text_to_type = None, test_coordinate = None)
685712 else :
686713 return True
687714
688- def select (element_identifier = None , option_value = None , test_coordinate = None ):
715+ def select (element_identifier = None , option_value = None , test_coordinate1 = None , test_coordinate2 = None ):
689716 if not _started ():
690717 print ('[TAGUI][ERROR] - use init() before using select()' )
691718 return False
@@ -698,9 +725,21 @@ def select(element_identifier = None, option_value = None, test_coordinate = Non
698725 print ('[TAGUI][ERROR] - option value missing for select()' )
699726 return False
700727
701- if test_coordinate is not None and isinstance (option_value , int ):
728+ if test_coordinate1 is not None and test_coordinate2 is not None and \
729+ isinstance (option_value , int ) and isinstance (test_coordinate2 , int ):
702730 element_identifier = coord (element_identifier , option_value )
703- option_value = test_coordinate
731+ option_value = coord (test_coordinate1 , test_coordinate2 )
732+
733+ # pre-emptive checks if image files are specified for visual automation
734+ if element_identifier .lower ().endswith ('.png' ) or element_identifier .lower ().endswith ('.bmp' ):
735+ if not os .path .isfile (element_identifier ):
736+ print ('[TAGUI][ERROR] - missing image file ' + element_identifier )
737+ return False
738+
739+ if option_value .lower ().endswith ('.png' ) or option_value .lower ().endswith ('.bmp' ):
740+ if not os .path .isfile (option_value ):
741+ print ('[TAGUI][ERROR] - missing image file ' + option_value )
742+ return False
704743
705744 if not exist (element_identifier ):
706745 print ('[TAGUI][ERROR] - cannot find ' + element_identifier )
@@ -847,8 +886,15 @@ def write(text_to_write = None, filename_to_save = None):
847886 return True
848887
849888def ask (text_to_prompt = '' ):
850- if _python2_env (): return raw_input (text_to_prompt + ' ' )
851- else : return input (text_to_prompt + ' ' )
889+ if text_to_prompt == '' :
890+ space_padding = ''
891+ else :
892+ space_padding = ' '
893+
894+ if _python2_env ():
895+ return raw_input (text_to_prompt + space_padding )
896+ else :
897+ return input (text_to_prompt + space_padding )
852898
853899def keyboard (keys_and_modifiers = None ):
854900 if not _started ():
@@ -962,31 +1008,29 @@ def download(download_url = None, filename_to_save = None):
9621008 if os .path .isfile (filename_to_save ):
9631009 os .remove (filename_to_save )
9641010
965- if _python2_env ():
966- import urllib ; urllib .urlretrieve (download_url , filename_to_save )
967- else :
968- import urllib .request ; urllib .request .urlretrieve (download_url , filename_to_save )
1011+ # handle case where url is invalid or has no content
1012+ try :
1013+ if _python2_env ():
1014+ import urllib ; urllib .urlretrieve (download_url , filename_to_save )
1015+ else :
1016+ import urllib .request ; urllib .request .urlretrieve (download_url , filename_to_save )
9691017
1018+ except Exception as e :
1019+ print ('[TAGUI][ERROR] - failed downloading from ' + download_url )
1020+ return False
1021+
1022+ # take the existence of downloaded file as success
9701023 if os .path .isfile (filename_to_save ):
9711024 return True
1025+
9721026 else :
973- print ('[TAGUI][ERROR] - downloading to ' + filename_to_save + ' failed)' )
1027+ print ('[TAGUI][ERROR] - failed downloading to ' + filename_to_save )
9741028 return False
9751029
9761030def api (url_to_query = None ):
977- if not _started ():
978- print ('[TAGUI][ERROR] - use init() before using api()' )
979- return ''
980-
981- if url_to_query is None or url_to_query == '' :
982- print ('[TAGUI][ERROR] - API URL missing for api()' )
983- return ''
984-
985- else :
986- send ('api ' + _esq (url_to_query ))
987- send ('dump api_result to tagui_python.txt' )
988- api_result = _tagui_output ()
989- return api_result
1031+ print ('[TAGUI][INFO] - although TagUI supports calling APIs with headers and body,' )
1032+ print ('[TAGUI][INFO] - users better off with requests package - lots of online docs' )
1033+ return True
9901034
9911035def run (command_to_run = None ):
9921036 if command_to_run is None or command_to_run == '' :
@@ -1009,7 +1053,7 @@ def dom(statement_to_run = None):
10091053 return ''
10101054
10111055 else :
1012- send ('dom ' + _esq ( statement_to_run ) )
1056+ send ('dom ' + statement_to_run )
10131057 send ('dump dom_result to tagui_python.txt' )
10141058 dom_result = _tagui_output ()
10151059 return dom_result
@@ -1023,7 +1067,7 @@ def vision(command_to_run = None):
10231067 print ('[TAGUI][ERROR] - command(s) missing for vision()' )
10241068 return False
10251069
1026- elif not send ('vision ' + _esq ( command_to_run ) ):
1070+ elif not send ('vision ' + command_to_run ):
10271071 return False
10281072
10291073 else :
@@ -1056,6 +1100,18 @@ def present(element_identifier = None):
10561100 if element_identifier is None or element_identifier == '' :
10571101 return False
10581102
1103+ # check for existence of specified image file for visual automation
1104+ if element_identifier .lower ().endswith ('.png' ) or element_identifier .lower ().endswith ('.bmp' ):
1105+ if not os .path .isfile (element_identifier ):
1106+ print ('[TAGUI][ERROR] - missing image file ' + element_identifier )
1107+ return False
1108+
1109+ # assume that (x,y) coordinates for visual automation always exist
1110+ if element_identifier .startswith ('(' ) and element_identifier .endswith (')' ):
1111+ if len (element_identifier .split (',' )) == 2 :
1112+ if not any (c .isalpha () for c in element_identifier ):
1113+ return True
1114+
10591115 send ('present_result = present(\' ' + _sdq (element_identifier ) + '\' ).toString()' )
10601116 send ('dump present_result to tagui_python.txt' )
10611117 if _tagui_output () == 'true' :
@@ -1071,6 +1127,18 @@ def visible(element_identifier = None):
10711127 if element_identifier is None or element_identifier == '' :
10721128 return False
10731129
1130+ # check for existence of specified image file for visual automation
1131+ if element_identifier .lower ().endswith ('.png' ) or element_identifier .lower ().endswith ('.bmp' ):
1132+ if not os .path .isfile (element_identifier ):
1133+ print ('[TAGUI][ERROR] - missing image file ' + element_identifier )
1134+ return False
1135+
1136+ # assume that (x,y) coordinates for visual automation always exist
1137+ if element_identifier .startswith ('(' ) and element_identifier .endswith (')' ):
1138+ if len (element_identifier .split (',' )) == 2 :
1139+ if not any (c .isalpha () for c in element_identifier ):
1140+ return True
1141+
10741142 send ('visible_result = visible(\' ' + _sdq (element_identifier ) + '\' ).toString()' )
10751143 send ('dump visible_result to tagui_python.txt' )
10761144 if _tagui_output () == 'true' :
0 commit comments