19
19
# flag to track and print debug output
20
20
_tagui_debug = False
21
21
22
- # id to track instruction count between tagui- python and tagui
22
+ # id to track instruction count from tagui python to tagui
23
23
_tagui_id = 0
24
24
25
25
# delete tagui temp output text file to avoid reading old data
@@ -210,10 +210,19 @@ def setup():
210
210
if os .path .isfile (temp_directory + '/' + tagui_zip_file ):
211
211
os .remove (temp_directory + '/' + tagui_zip_file )
212
212
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
+
213
221
# perform Linux specific setup actions
214
222
if platform .system () == 'Linux' :
215
223
# zipfile extractall does not preserve execute permissions
216
224
# invoking chmod to set all files with execute permissions
225
+ # and update delta tagui/src/tagui with execute permission
217
226
if os .system ('chmod -R 755 ' + temp_directory + '/' + 'tagui > /dev/null 2>&1' ) != 0 :
218
227
print ('[TAGUI][ERROR] - unable to set permissions for tagui folder' )
219
228
return False
@@ -232,6 +241,7 @@ def setup():
232
241
if platform .system () == 'Darwin' :
233
242
# zipfile extractall does not preserve execute permissions
234
243
# invoking chmod to set all files with execute permissions
244
+ # and update delta tagui/src/tagui with execute permission
235
245
if os .system ('chmod -R 755 ' + temp_directory + '/' + 'tagui > /dev/null 2>&1' ) != 0 :
236
246
print ('[TAGUI][ERROR] - unable to set permissions for tagui folder' )
237
247
return False
@@ -276,7 +286,7 @@ def setup():
276
286
# check that tagui packaged php is working, it has dependency on MSVCR110.dll
277
287
if os .system (temp_directory + '/' + 'tagui' + '/' + 'src' + '/' + 'php/php.exe -v > nul 2>&1' ) != 0 :
278
288
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'
280
290
if download (vcredist_x86_url , temp_directory + '/vcredist_x86.exe' ):
281
291
os .system (temp_directory + '/vcredist_x86.exe' )
282
292
@@ -304,8 +314,18 @@ def init(visual_automation = False, chrome_browser = True):
304
314
print ('[TAGUI][ERROR] - use close() before using init() again' )
305
315
return False
306
316
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
+
307
327
# 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'
309
329
310
330
# if tagui executable is not found, initiate setup() to install tagui
311
331
if not os .path .isfile (tagui_executable ):
@@ -320,14 +340,15 @@ def init(visual_automation = False, chrome_browser = True):
320
340
shell_silencer = '> nul 2>&1'
321
341
else :
322
342
shell_silencer = '> /dev/null 2>&1'
343
+
323
344
if os .system ('java -version ' + shell_silencer ) != 0 :
324
345
print ('[TAGUI][INFO] - for visual automation mode, Java JDK v8 (64-bit) or later is required' )
325
346
print ('[TAGUI][INFO] - to use visual automation feature, download Java JDK v8 (64-bit) from below' )
326
347
print ('[TAGUI][INFO] - https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html' )
327
348
return False
328
349
else :
329
350
# 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'
331
352
if os .path .isfile (sikulix_folder + '/' + 'jython-standalone-2.7.1.jar' ):
332
353
os .system ('java -jar ' + sikulix_folder + '/' + 'sikulix.jar -h ' + shell_silencer )
333
354
_visual_flow ()
@@ -371,11 +392,21 @@ def init(visual_automation = False, chrome_browser = True):
371
392
372
393
# check that tagui live mode is ready then start listening for inputs
373
394
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
376
396
_tagui_write ('echo "[TAGUI][STARTED]"\n ' )
377
397
_tagui_write ('echo "[TAGUI][' + str (_tagui_id ) + '] - listening for inputs"\n ' )
378
398
_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
+
379
410
return True
380
411
381
412
except Exception as e :
@@ -434,13 +465,6 @@ def send(tagui_instruction = None):
434
465
_tagui_started = False
435
466
return False
436
467
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
-
444
468
# escape special characters for them to reach tagui correctly
445
469
tagui_instruction = tagui_instruction .replace ('\\ ' ,'\\ \\ ' )
446
470
tagui_instruction = tagui_instruction .replace ('\n ' ,'\\ n' )
@@ -465,9 +489,18 @@ def send(tagui_instruction = None):
465
489
# send live mode instruction to be executed
466
490
_tagui_write (tagui_instruction + '\n ' )
467
491
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
+
468
502
# increment id and prepare for next instruction
469
503
_tagui_id = _tagui_id + 1
470
- _tagui_write ('echo "[TAGUI][' + str (_tagui_id ) + '] - listening for inputs"\n ' )
471
504
472
505
return True
473
506
@@ -482,7 +515,6 @@ def close():
482
515
483
516
if not _tagui_started :
484
517
print ('[TAGUI][ERROR] - use init() before using close()' )
485
- _tagui_started = False
486
518
return False
487
519
488
520
try :
@@ -492,28 +524,23 @@ def close():
492
524
_tagui_started = False
493
525
return False
494
526
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
-
502
527
# send 'done' instruction to terminate live mode and exit tagui
503
528
_tagui_write ('echo "[TAGUI][FINISHED]"\n ' )
504
529
_tagui_write ('done\n ' )
505
530
506
531
# loop until tagui process has closed before returning control
507
532
while _process .poll () is None : pass
508
533
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
510
541
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' )
514
542
if os .path .isfile ('tagui_python.log' ): os .remove ('tagui_python.log' )
515
543
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' )
517
544
518
545
_tagui_started = False
519
546
return True
@@ -531,7 +558,7 @@ def exist(element_identifier = None):
531
558
if element_identifier is None or element_identifier == '' :
532
559
return False
533
560
534
- # check for existence of specified image file for visual automation
561
+ # pre-emptive check for existence of specified image file for visual automation
535
562
if element_identifier .lower ().endswith ('.png' ) or element_identifier .lower ().endswith ('.bmp' ):
536
563
if not os .path .isfile (element_identifier ):
537
564
print ('[TAGUI][ERROR] - missing image file ' + element_identifier )
@@ -685,7 +712,7 @@ def type(element_identifier = None, text_to_type = None, test_coordinate = None)
685
712
else :
686
713
return True
687
714
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 ):
689
716
if not _started ():
690
717
print ('[TAGUI][ERROR] - use init() before using select()' )
691
718
return False
@@ -698,9 +725,21 @@ def select(element_identifier = None, option_value = None, test_coordinate = Non
698
725
print ('[TAGUI][ERROR] - option value missing for select()' )
699
726
return False
700
727
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 ):
702
730
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
704
743
705
744
if not exist (element_identifier ):
706
745
print ('[TAGUI][ERROR] - cannot find ' + element_identifier )
@@ -847,8 +886,15 @@ def write(text_to_write = None, filename_to_save = None):
847
886
return True
848
887
849
888
def 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 )
852
898
853
899
def keyboard (keys_and_modifiers = None ):
854
900
if not _started ():
@@ -962,31 +1008,29 @@ def download(download_url = None, filename_to_save = None):
962
1008
if os .path .isfile (filename_to_save ):
963
1009
os .remove (filename_to_save )
964
1010
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 )
969
1017
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
970
1023
if os .path .isfile (filename_to_save ):
971
1024
return True
1025
+
972
1026
else :
973
- print ('[TAGUI][ERROR] - downloading to ' + filename_to_save + ' failed)' )
1027
+ print ('[TAGUI][ERROR] - failed downloading to ' + filename_to_save )
974
1028
return False
975
1029
976
1030
def 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
990
1034
991
1035
def run (command_to_run = None ):
992
1036
if command_to_run is None or command_to_run == '' :
@@ -1009,7 +1053,7 @@ def dom(statement_to_run = None):
1009
1053
return ''
1010
1054
1011
1055
else :
1012
- send ('dom ' + _esq ( statement_to_run ) )
1056
+ send ('dom ' + statement_to_run )
1013
1057
send ('dump dom_result to tagui_python.txt' )
1014
1058
dom_result = _tagui_output ()
1015
1059
return dom_result
@@ -1023,7 +1067,7 @@ def vision(command_to_run = None):
1023
1067
print ('[TAGUI][ERROR] - command(s) missing for vision()' )
1024
1068
return False
1025
1069
1026
- elif not send ('vision ' + _esq ( command_to_run ) ):
1070
+ elif not send ('vision ' + command_to_run ):
1027
1071
return False
1028
1072
1029
1073
else :
@@ -1056,6 +1100,18 @@ def present(element_identifier = None):
1056
1100
if element_identifier is None or element_identifier == '' :
1057
1101
return False
1058
1102
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
+
1059
1115
send ('present_result = present(\' ' + _sdq (element_identifier ) + '\' ).toString()' )
1060
1116
send ('dump present_result to tagui_python.txt' )
1061
1117
if _tagui_output () == 'true' :
@@ -1071,6 +1127,18 @@ def visible(element_identifier = None):
1071
1127
if element_identifier is None or element_identifier == '' :
1072
1128
return False
1073
1129
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
+
1074
1142
send ('visible_result = visible(\' ' + _sdq (element_identifier ) + '\' ).toString()' )
1075
1143
send ('dump visible_result to tagui_python.txt' )
1076
1144
if _tagui_output () == 'true' :
0 commit comments