ScriptCollection 3.4.56__py3-none-any.whl → 3.5.44__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.
- ScriptCollection/Executables.py +389 -353
- ScriptCollection/GeneralUtilities.py +38 -14
- ScriptCollection/ProcessesRunner.py +41 -0
- ScriptCollection/ProgramRunnerBase.py +47 -42
- ScriptCollection/ProgramRunnerEpew.py +122 -122
- ScriptCollection/ProgramRunnerPopen.py +51 -52
- ScriptCollection/RPStream.py +42 -0
- ScriptCollection/ScriptCollectionCore.py +1930 -1710
- ScriptCollection/TasksForCommonProjectStructure.py +2980 -2426
- ScriptCollection/UpdateCertificates.py +126 -128
- {ScriptCollection-3.4.56.dist-info → ScriptCollection-3.5.44.dist-info}/METADATA +22 -21
- ScriptCollection-3.5.44.dist-info/RECORD +16 -0
- {ScriptCollection-3.4.56.dist-info → ScriptCollection-3.5.44.dist-info}/WHEEL +1 -1
- {ScriptCollection-3.4.56.dist-info → ScriptCollection-3.5.44.dist-info}/entry_points.txt +3 -0
- ScriptCollection-3.4.56.dist-info/RECORD +0 -14
- {ScriptCollection-3.4.56.dist-info → ScriptCollection-3.5.44.dist-info}/top_level.txt +0 -0
|
@@ -51,15 +51,13 @@ class GeneralUtilities:
|
|
|
51
51
|
# Check type of arguments if the type is a generic type seems to be impossible.
|
|
52
52
|
if not GeneralUtilities.is_generic(function.__annotations__[parameters[index]]):
|
|
53
53
|
if not isinstance(argument, function.__annotations__[parameters[index]]):
|
|
54
|
-
raise TypeError(f"Argument with index {index} for function {function.__name__} ('{str(argument)}') is not of type "
|
|
55
|
-
f"{ function.__annotations__[parameters[index]]} but has type "+str(type(argument)))
|
|
54
|
+
raise TypeError(f"Argument with index {index} for function {function.__name__} ('{str(argument)}') is not of type {function.__annotations__[parameters[index]]} but has type "+str(type(argument)))
|
|
56
55
|
for index, named_argument in enumerate(named_args):
|
|
57
56
|
if named_args[named_argument] is not None:
|
|
58
57
|
if parameters[index] in function.__annotations__:
|
|
59
58
|
if not GeneralUtilities.is_generic(function.__annotations__.get(named_argument)):
|
|
60
59
|
if not isinstance(named_args[named_argument], function.__annotations__.get(named_argument)):
|
|
61
|
-
raise TypeError(f"Argument with name {named_argument} for function {function.__name__} ('{str(named_args[named_argument])}') "
|
|
62
|
-
f"is not of type { function.__annotations__.get(named_argument)}")
|
|
60
|
+
raise TypeError(f"Argument with name {named_argument} for function {function.__name__} ('{str(named_args[named_argument])}') is not of type {function.__annotations__.get(named_argument)}")
|
|
63
61
|
return function(*args, **named_args)
|
|
64
62
|
__check_function.__doc__ = function.__doc__
|
|
65
63
|
return __check_function
|
|
@@ -69,9 +67,7 @@ class GeneralUtilities:
|
|
|
69
67
|
@functools.wraps(func)
|
|
70
68
|
def new_func(*args, **kwargs):
|
|
71
69
|
warnings.simplefilter('always', DeprecationWarning)
|
|
72
|
-
warnings.warn(f"Call to deprecated function {func.__name__}",
|
|
73
|
-
category=DeprecationWarning,
|
|
74
|
-
stacklevel=2)
|
|
70
|
+
warnings.warn(f"Call to deprecated function {func.__name__}", category=DeprecationWarning, stacklevel=2)
|
|
75
71
|
warnings.simplefilter('default', DeprecationWarning)
|
|
76
72
|
return func(*args, **kwargs)
|
|
77
73
|
return new_func
|
|
@@ -395,8 +391,8 @@ class GeneralUtilities:
|
|
|
395
391
|
|
|
396
392
|
@staticmethod
|
|
397
393
|
@check_arguments
|
|
398
|
-
def
|
|
399
|
-
shutil.rmtree(directory, onerror=GeneralUtilities.__remove_readonly)
|
|
394
|
+
def __rmtree(directory: str) -> None:
|
|
395
|
+
shutil.rmtree(directory, onerror=GeneralUtilities.__remove_readonly) # pylint: disable=deprecated-argument
|
|
400
396
|
|
|
401
397
|
@staticmethod
|
|
402
398
|
@check_arguments
|
|
@@ -408,8 +404,8 @@ class GeneralUtilities:
|
|
|
408
404
|
os.chmod(filename, stat.S_IWUSR)
|
|
409
405
|
os.remove(filename)
|
|
410
406
|
for name in dirs:
|
|
411
|
-
GeneralUtilities.
|
|
412
|
-
GeneralUtilities.
|
|
407
|
+
GeneralUtilities.__rmtree(os.path.join(root, name))
|
|
408
|
+
GeneralUtilities.__rmtree(path)
|
|
413
409
|
|
|
414
410
|
@staticmethod
|
|
415
411
|
@check_arguments
|
|
@@ -475,6 +471,16 @@ class GeneralUtilities:
|
|
|
475
471
|
result.append(fileB)
|
|
476
472
|
return result
|
|
477
473
|
|
|
474
|
+
@staticmethod
|
|
475
|
+
@check_arguments
|
|
476
|
+
def to_pascal_case(s: str) -> str:
|
|
477
|
+
return ''.join(current.lower() if prev.isalnum() else current.upper() for prev, current in zip(' ' + s, s) if current.isalnum())
|
|
478
|
+
|
|
479
|
+
@staticmethod
|
|
480
|
+
@check_arguments
|
|
481
|
+
def find_between(s: str, start: str, end: str) -> str:
|
|
482
|
+
return s.split(start)[1].split(end)[0]
|
|
483
|
+
|
|
478
484
|
@staticmethod
|
|
479
485
|
@check_arguments
|
|
480
486
|
def write_lines_to_file(file: str, lines: list, encoding="utf-8") -> None:
|
|
@@ -559,6 +565,12 @@ class GeneralUtilities:
|
|
|
559
565
|
except AttributeError:
|
|
560
566
|
return ctypes.windll.shell32.IsUserAnAdmin() == 1
|
|
561
567
|
|
|
568
|
+
@staticmethod
|
|
569
|
+
@check_arguments
|
|
570
|
+
def ensure_elevated_privileges() -> None:
|
|
571
|
+
if (not GeneralUtilities.current_user_has_elevated_privileges()):
|
|
572
|
+
raise ValueError("Not enough privileges.")
|
|
573
|
+
|
|
562
574
|
@staticmethod
|
|
563
575
|
@check_arguments
|
|
564
576
|
def rename_names_of_all_files_and_folders(folder: str, replace_from: str, replace_to: str, replace_only_full_match=False):
|
|
@@ -572,12 +584,14 @@ class GeneralUtilities:
|
|
|
572
584
|
@check_arguments
|
|
573
585
|
def get_direct_files_of_folder(folder: str) -> list[str]:
|
|
574
586
|
result = [os.path.join(folder, f) for f in listdir(folder) if isfile(join(folder, f))]
|
|
587
|
+
result = sorted(result, key=str.casefold)
|
|
575
588
|
return result
|
|
576
589
|
|
|
577
590
|
@staticmethod
|
|
578
591
|
@check_arguments
|
|
579
592
|
def get_direct_folders_of_folder(folder: str) -> list[str]:
|
|
580
593
|
result = [os.path.join(folder, f) for f in listdir(folder) if isdir(join(folder, f))]
|
|
594
|
+
result = sorted(result, key=str.casefold)
|
|
581
595
|
return result
|
|
582
596
|
|
|
583
597
|
@staticmethod
|
|
@@ -587,6 +601,7 @@ class GeneralUtilities:
|
|
|
587
601
|
result.extend(GeneralUtilities.get_direct_files_of_folder(folder))
|
|
588
602
|
for subfolder in GeneralUtilities.get_direct_folders_of_folder(folder):
|
|
589
603
|
result.extend(GeneralUtilities.get_all_files_of_folder(subfolder))
|
|
604
|
+
result = sorted(result, key=str.casefold)
|
|
590
605
|
return result
|
|
591
606
|
|
|
592
607
|
@staticmethod
|
|
@@ -597,12 +612,13 @@ class GeneralUtilities:
|
|
|
597
612
|
result.extend(subfolders)
|
|
598
613
|
for subfolder in subfolders:
|
|
599
614
|
result.extend(GeneralUtilities.get_all_folders_of_folder(subfolder))
|
|
615
|
+
result = sorted(result, key=str.casefold)
|
|
600
616
|
return result
|
|
601
617
|
|
|
602
618
|
@staticmethod
|
|
603
619
|
@check_arguments
|
|
604
620
|
def get_all_objects_of_folder(folder: str) -> list[str]:
|
|
605
|
-
return GeneralUtilities.get_all_files_of_folder(folder) + GeneralUtilities.get_all_folders_of_folder(folder)
|
|
621
|
+
return sorted(GeneralUtilities.get_all_files_of_folder(folder) + GeneralUtilities.get_all_folders_of_folder(folder), key=str.casefold)
|
|
606
622
|
|
|
607
623
|
@staticmethod
|
|
608
624
|
@check_arguments
|
|
@@ -732,8 +748,7 @@ class GeneralUtilities:
|
|
|
732
748
|
|
|
733
749
|
@staticmethod
|
|
734
750
|
@check_arguments
|
|
735
|
-
def read_csv_file(file: str, ignore_first_line: bool = False, treat_number_sign_at_begin_of_line_as_comment: bool = True, trim_values: bool = True,
|
|
736
|
-
encoding="utf-8", ignore_empty_lines: bool = True, separator_character: str = ";", values_are_surrounded_by_quotes: bool = False) -> list[list[str]]:
|
|
751
|
+
def read_csv_file(file: str, ignore_first_line: bool = False, treat_number_sign_at_begin_of_line_as_comment: bool = True, trim_values: bool = True, encoding="utf-8", ignore_empty_lines: bool = True, separator_character: str = ";", values_are_surrounded_by_quotes: bool = False) -> list[list[str]]:
|
|
737
752
|
lines = GeneralUtilities.read_lines_from_file(file, encoding)
|
|
738
753
|
|
|
739
754
|
if ignore_first_line:
|
|
@@ -865,3 +880,12 @@ class GeneralUtilities:
|
|
|
865
880
|
@check_arguments
|
|
866
881
|
def replace_variable_in_string(input_string: str, variable_name: str, variable_value: str) -> None:
|
|
867
882
|
return input_string.replace(f"__[{variable_name}]__", variable_value)
|
|
883
|
+
|
|
884
|
+
@staticmethod
|
|
885
|
+
@check_arguments
|
|
886
|
+
def input(prompt: str, print_result: bool) -> str: # This function is a workaround for usescases like python scripts which calls input(...) using epew because then the prompt is not printed by the built-in-input-function.
|
|
887
|
+
GeneralUtilities.write_message_to_stdout(prompt)
|
|
888
|
+
result: str = input()
|
|
889
|
+
if print_result:
|
|
890
|
+
GeneralUtilities.write_message_to_stdout(f"Result: {result}")
|
|
891
|
+
return result
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import psutil
|
|
2
|
+
from .ScriptCollectionCore import ScriptCollectionCore
|
|
3
|
+
|
|
4
|
+
# runs multiple processes in parallel and terminate all if at least one is terminated
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ProcessStartInformation:
|
|
8
|
+
workingdirectory: str = None
|
|
9
|
+
program: str = None
|
|
10
|
+
arguments: str = None
|
|
11
|
+
|
|
12
|
+
def __init__(self, workingdirectory: str, program: str, arguments: str):
|
|
13
|
+
self.workingdirectory = workingdirectory
|
|
14
|
+
self.program = program
|
|
15
|
+
self.arguments = arguments
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ProcessesRunner:
|
|
19
|
+
sc: ScriptCollectionCore
|
|
20
|
+
processes: list[ProcessStartInformation]
|
|
21
|
+
|
|
22
|
+
def __init__(self, processes: list[ProcessStartInformation]):
|
|
23
|
+
self.sc = ScriptCollectionCore()
|
|
24
|
+
self.processes = processes
|
|
25
|
+
|
|
26
|
+
def run(self):
|
|
27
|
+
pids: list[int] = list[int]()
|
|
28
|
+
for processstartinfo in self.processes:
|
|
29
|
+
pids.append(self.sc.run_program_async(processstartinfo.program, processstartinfo.argumentss, processstartinfo.workingdirectory))
|
|
30
|
+
enabled = True
|
|
31
|
+
while enabled:
|
|
32
|
+
for pid in pids:
|
|
33
|
+
if not psutil.pid_exists(pid):
|
|
34
|
+
enabled = False
|
|
35
|
+
# one program terminate so exit and terminate all now
|
|
36
|
+
processes = psutil.process_iter()
|
|
37
|
+
for pid in pids:
|
|
38
|
+
if psutil.pid_exists(pid):
|
|
39
|
+
for proc in processes:
|
|
40
|
+
if proc.pid == pid:
|
|
41
|
+
proc.kill()
|
|
@@ -1,42 +1,47 @@
|
|
|
1
|
-
from abc import abstractmethod
|
|
2
|
-
from subprocess import Popen
|
|
3
|
-
from .GeneralUtilities import GeneralUtilities
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class ProgramRunnerBase:
|
|
7
|
-
|
|
8
|
-
# Return-values program_runner: Pid
|
|
9
|
-
@abstractmethod
|
|
10
|
-
@GeneralUtilities.check_arguments
|
|
11
|
-
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> Popen:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from subprocess import Popen
|
|
3
|
+
from .GeneralUtilities import GeneralUtilities
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ProgramRunnerBase:
|
|
7
|
+
|
|
8
|
+
# Return-values program_runner: Pid
|
|
9
|
+
@abstractmethod
|
|
10
|
+
@GeneralUtilities.check_arguments
|
|
11
|
+
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> Popen:
|
|
12
|
+
# Verbosity:
|
|
13
|
+
# 0=Quiet (No output will be printed.)
|
|
14
|
+
# 1=Normal (If the exitcode of the executed program is not 0 then the StdErr will be printed.)
|
|
15
|
+
# 2=Full (Prints StdOut and StdErr of the executed program.)
|
|
16
|
+
# 3=Verbose (Same as "Full" but with some more information.)
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
|
|
19
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
20
|
+
@abstractmethod
|
|
21
|
+
@GeneralUtilities.check_arguments
|
|
22
|
+
def wait(self, process: Popen, custom_argument: object) -> tuple[int, str, str, int]:
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
26
|
+
@abstractmethod
|
|
27
|
+
@GeneralUtilities.check_arguments
|
|
28
|
+
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
29
|
+
raise NotImplementedError
|
|
30
|
+
|
|
31
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
32
|
+
@abstractmethod
|
|
33
|
+
@GeneralUtilities.check_arguments
|
|
34
|
+
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
35
|
+
raise NotImplementedError
|
|
36
|
+
|
|
37
|
+
# Return-values program_runner: Pid
|
|
38
|
+
@abstractmethod
|
|
39
|
+
@GeneralUtilities.check_arguments
|
|
40
|
+
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
|
|
43
|
+
# Return-values program_runner: Pid
|
|
44
|
+
@abstractmethod
|
|
45
|
+
@GeneralUtilities.check_arguments
|
|
46
|
+
def run_program_async(self, program: str, arguments: str, working_directory: str, custom_argument: object, interactive:bool=False) -> int:
|
|
47
|
+
raise NotImplementedError
|
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import base64
|
|
3
|
-
import tempfile
|
|
4
|
-
from subprocess import Popen
|
|
5
|
-
from uuid import uuid4
|
|
6
|
-
|
|
7
|
-
from .GeneralUtilities import GeneralUtilities
|
|
8
|
-
from .ProgramRunnerBase import ProgramRunnerBase
|
|
9
|
-
from .ProgramRunnerPopen import ProgramRunnerPopen
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class CustomEpewArgument:
|
|
13
|
-
|
|
14
|
-
print_errors_as_information: bool
|
|
15
|
-
log_file: str
|
|
16
|
-
timeoutInSeconds: int
|
|
17
|
-
addLogOverhead: bool
|
|
18
|
-
title: str
|
|
19
|
-
log_namespace: str
|
|
20
|
-
verbosity: int
|
|
21
|
-
arguments_for_log: list[str]
|
|
22
|
-
tempdir = os.path.join(tempfile.gettempdir(), str(uuid4()))
|
|
23
|
-
stdoutfile = tempdir + ".epew.stdout.txt"
|
|
24
|
-
stderrfile = tempdir + ".epew.stderr.txt"
|
|
25
|
-
exitcodefile = tempdir + ".epew.exitcode.txt"
|
|
26
|
-
pidfile = tempdir + ".epew.pid.txt"
|
|
27
|
-
|
|
28
|
-
def __init__(self, print_errors_as_information: bool, log_file: str, timeoutInSeconds: int, addLogOverhead: bool, title: str, log_namespace: str, verbosity: int, arguments_for_log: list[str]):
|
|
29
|
-
self.print_errors_as_information = print_errors_as_information
|
|
30
|
-
self.log_file = log_file
|
|
31
|
-
self.timeoutInSeconds = timeoutInSeconds
|
|
32
|
-
self.addLogOverhead = addLogOverhead
|
|
33
|
-
self.title = title
|
|
34
|
-
self.log_namespace = log_namespace
|
|
35
|
-
self.verbosity = verbosity
|
|
36
|
-
self.arguments_for_log = arguments_for_log
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class ProgramRunnerEpew(ProgramRunnerBase):
|
|
40
|
-
|
|
41
|
-
@GeneralUtilities.check_arguments
|
|
42
|
-
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> Popen:
|
|
43
|
-
if GeneralUtilities.epew_is_available():
|
|
44
|
-
custom_argument: CustomEpewArgument = custom_argument
|
|
45
|
-
args = []
|
|
46
|
-
|
|
47
|
-
base64argument = base64.b64encode(' '.join(arguments_as_array).encode('utf-8')).decode('utf-8')
|
|
48
|
-
args.append(f'-p "{program}"')
|
|
49
|
-
args.append(f'-a {base64argument}')
|
|
50
|
-
args.append('-b')
|
|
51
|
-
args.append(f'-w "{working_directory}"')
|
|
52
|
-
if custom_argument.stdoutfile is not None:
|
|
53
|
-
args.append(f'-o {custom_argument.stdoutfile}')
|
|
54
|
-
if custom_argument.stderrfile is not None:
|
|
55
|
-
args.append(f'-e {custom_argument.stderrfile}')
|
|
56
|
-
if custom_argument.exitcodefile is not None:
|
|
57
|
-
args.append(f'-x {custom_argument.exitcodefile}')
|
|
58
|
-
if custom_argument.pidfile is not None:
|
|
59
|
-
args.append(f'-r {custom_argument.pidfile}')
|
|
60
|
-
args.append(f'-d {str(custom_argument.timeoutInSeconds*1000)}')
|
|
61
|
-
args.append(f'-t "{custom_argument.title}"')
|
|
62
|
-
args.append(f'-l "{custom_argument.log_namespace}"')
|
|
63
|
-
if not GeneralUtilities.string_is_none_or_whitespace(custom_argument.log_file):
|
|
64
|
-
args.append(f'-f "{custom_argument.log_file}"')
|
|
65
|
-
if custom_argument.print_errors_as_information:
|
|
66
|
-
args.append("-i")
|
|
67
|
-
if custom_argument.addLogOverhead:
|
|
68
|
-
args.append("-g")
|
|
69
|
-
args.append("-v "+str(custom_argument.verbosity))
|
|
70
|
-
return ProgramRunnerPopen().run_program_argsasarray_async_helper("epew", args, working_directory)
|
|
71
|
-
else:
|
|
72
|
-
raise ValueError("Epew is not available.")
|
|
73
|
-
|
|
74
|
-
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
75
|
-
@GeneralUtilities.check_arguments
|
|
76
|
-
def wait(self, process: Popen, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
77
|
-
process.wait()
|
|
78
|
-
custom_argument: CustomEpewArgument = custom_argument
|
|
79
|
-
stdout = self.__load_text(custom_argument.output_file_for_stdout)
|
|
80
|
-
stderr = self.__load_text(custom_argument.output_file_for_stderr)
|
|
81
|
-
exit_code = self.__get_number_from_filecontent(self.__load_text(custom_argument.output_file_for_exit_code))
|
|
82
|
-
pid = self.__get_number_from_filecontent(self.__load_text(custom_argument.output_file_for_pid))
|
|
83
|
-
GeneralUtilities.ensure_directory_does_not_exist(custom_argument.tempdir)
|
|
84
|
-
result = (exit_code, stdout, stderr, pid)
|
|
85
|
-
return result
|
|
86
|
-
|
|
87
|
-
@GeneralUtilities.check_arguments
|
|
88
|
-
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
89
|
-
process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument)
|
|
90
|
-
return self.wait(process, custom_argument)
|
|
91
|
-
|
|
92
|
-
@GeneralUtilities.check_arguments
|
|
93
|
-
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
94
|
-
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
|
|
95
|
-
|
|
96
|
-
@GeneralUtilities.check_arguments
|
|
97
|
-
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> int:
|
|
98
|
-
return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument).pid
|
|
99
|
-
|
|
100
|
-
@GeneralUtilities.check_arguments
|
|
101
|
-
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None) -> int:
|
|
102
|
-
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
|
|
103
|
-
|
|
104
|
-
@GeneralUtilities.check_arguments
|
|
105
|
-
def __get_number_from_filecontent(self, filecontent: str) -> int:
|
|
106
|
-
for line in filecontent.splitlines():
|
|
107
|
-
try:
|
|
108
|
-
striped_line = GeneralUtilities.strip_new_line_character(line)
|
|
109
|
-
result = int(striped_line)
|
|
110
|
-
return result
|
|
111
|
-
except:
|
|
112
|
-
pass
|
|
113
|
-
raise ValueError(f"'{filecontent}' does not containe an int-line")
|
|
114
|
-
|
|
115
|
-
@GeneralUtilities.check_arguments
|
|
116
|
-
def __load_text(self, file: str) -> str:
|
|
117
|
-
if os.path.isfile(file):
|
|
118
|
-
content = GeneralUtilities.read_text_from_file(file).replace('\r', '')
|
|
119
|
-
os.remove(file)
|
|
120
|
-
return content
|
|
121
|
-
else:
|
|
122
|
-
raise ValueError(f"File '{file}' does not exist")
|
|
1
|
+
import os
|
|
2
|
+
import base64
|
|
3
|
+
import tempfile
|
|
4
|
+
from subprocess import Popen
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from .GeneralUtilities import GeneralUtilities
|
|
8
|
+
from .ProgramRunnerBase import ProgramRunnerBase
|
|
9
|
+
from .ProgramRunnerPopen import ProgramRunnerPopen
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CustomEpewArgument:
|
|
13
|
+
|
|
14
|
+
print_errors_as_information: bool
|
|
15
|
+
log_file: str
|
|
16
|
+
timeoutInSeconds: int
|
|
17
|
+
addLogOverhead: bool
|
|
18
|
+
title: str
|
|
19
|
+
log_namespace: str
|
|
20
|
+
verbosity: int
|
|
21
|
+
arguments_for_log: list[str]
|
|
22
|
+
tempdir = os.path.join(tempfile.gettempdir(), str(uuid4()))
|
|
23
|
+
stdoutfile = tempdir + ".epew.stdout.txt"
|
|
24
|
+
stderrfile = tempdir + ".epew.stderr.txt"
|
|
25
|
+
exitcodefile = tempdir + ".epew.exitcode.txt"
|
|
26
|
+
pidfile = tempdir + ".epew.pid.txt"
|
|
27
|
+
|
|
28
|
+
def __init__(self, print_errors_as_information: bool, log_file: str, timeoutInSeconds: int, addLogOverhead: bool, title: str, log_namespace: str, verbosity: int, arguments_for_log: list[str]):
|
|
29
|
+
self.print_errors_as_information = print_errors_as_information
|
|
30
|
+
self.log_file = log_file
|
|
31
|
+
self.timeoutInSeconds = timeoutInSeconds
|
|
32
|
+
self.addLogOverhead = addLogOverhead
|
|
33
|
+
self.title = title
|
|
34
|
+
self.log_namespace = log_namespace
|
|
35
|
+
self.verbosity = verbosity
|
|
36
|
+
self.arguments_for_log = arguments_for_log
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ProgramRunnerEpew(ProgramRunnerBase):
|
|
40
|
+
|
|
41
|
+
@GeneralUtilities.check_arguments
|
|
42
|
+
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> Popen:
|
|
43
|
+
if GeneralUtilities.epew_is_available():
|
|
44
|
+
custom_argument: CustomEpewArgument = custom_argument
|
|
45
|
+
args = []
|
|
46
|
+
|
|
47
|
+
base64argument = base64.b64encode(' '.join(arguments_as_array).encode('utf-8')).decode('utf-8')
|
|
48
|
+
args.append(f'-p "{program}"')
|
|
49
|
+
args.append(f'-a {base64argument}')
|
|
50
|
+
args.append('-b')
|
|
51
|
+
args.append(f'-w "{working_directory}"')
|
|
52
|
+
if custom_argument.stdoutfile is not None:
|
|
53
|
+
args.append(f'-o {custom_argument.stdoutfile}')
|
|
54
|
+
if custom_argument.stderrfile is not None:
|
|
55
|
+
args.append(f'-e {custom_argument.stderrfile}')
|
|
56
|
+
if custom_argument.exitcodefile is not None:
|
|
57
|
+
args.append(f'-x {custom_argument.exitcodefile}')
|
|
58
|
+
if custom_argument.pidfile is not None:
|
|
59
|
+
args.append(f'-r {custom_argument.pidfile}')
|
|
60
|
+
args.append(f'-d {str(custom_argument.timeoutInSeconds*1000)}')
|
|
61
|
+
args.append(f'-t "{custom_argument.title}"')
|
|
62
|
+
args.append(f'-l "{custom_argument.log_namespace}"')
|
|
63
|
+
if not GeneralUtilities.string_is_none_or_whitespace(custom_argument.log_file):
|
|
64
|
+
args.append(f'-f "{custom_argument.log_file}"')
|
|
65
|
+
if custom_argument.print_errors_as_information:
|
|
66
|
+
args.append("-i")
|
|
67
|
+
if custom_argument.addLogOverhead:
|
|
68
|
+
args.append("-g")
|
|
69
|
+
args.append("-v "+str(custom_argument.verbosity))
|
|
70
|
+
return ProgramRunnerPopen().run_program_argsasarray_async_helper("epew", args, working_directory,custom_argument,interactive)
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError("Epew is not available.")
|
|
73
|
+
|
|
74
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
75
|
+
@GeneralUtilities.check_arguments
|
|
76
|
+
def wait(self, process: Popen, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
77
|
+
process.wait()
|
|
78
|
+
custom_argument: CustomEpewArgument = custom_argument
|
|
79
|
+
stdout = self.__load_text(custom_argument.output_file_for_stdout)
|
|
80
|
+
stderr = self.__load_text(custom_argument.output_file_for_stderr)
|
|
81
|
+
exit_code = self.__get_number_from_filecontent(self.__load_text(custom_argument.output_file_for_exit_code))
|
|
82
|
+
pid = self.__get_number_from_filecontent(self.__load_text(custom_argument.output_file_for_pid))
|
|
83
|
+
GeneralUtilities.ensure_directory_does_not_exist(custom_argument.tempdir)
|
|
84
|
+
result = (exit_code, stdout, stderr, pid)
|
|
85
|
+
return result
|
|
86
|
+
|
|
87
|
+
@GeneralUtilities.check_arguments
|
|
88
|
+
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
89
|
+
process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument,interactive)
|
|
90
|
+
return self.wait(process, custom_argument)
|
|
91
|
+
|
|
92
|
+
@GeneralUtilities.check_arguments
|
|
93
|
+
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
94
|
+
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument,interactive)
|
|
95
|
+
|
|
96
|
+
@GeneralUtilities.check_arguments
|
|
97
|
+
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
98
|
+
return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument,interactive).pid
|
|
99
|
+
|
|
100
|
+
@GeneralUtilities.check_arguments
|
|
101
|
+
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
102
|
+
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument,interactive)
|
|
103
|
+
|
|
104
|
+
@GeneralUtilities.check_arguments
|
|
105
|
+
def __get_number_from_filecontent(self, filecontent: str) -> int:
|
|
106
|
+
for line in filecontent.splitlines():
|
|
107
|
+
try:
|
|
108
|
+
striped_line = GeneralUtilities.strip_new_line_character(line)
|
|
109
|
+
result = int(striped_line)
|
|
110
|
+
return result
|
|
111
|
+
except:
|
|
112
|
+
pass
|
|
113
|
+
raise ValueError(f"'{filecontent}' does not containe an int-line")
|
|
114
|
+
|
|
115
|
+
@GeneralUtilities.check_arguments
|
|
116
|
+
def __load_text(self, file: str) -> str:
|
|
117
|
+
if os.path.isfile(file):
|
|
118
|
+
content = GeneralUtilities.read_text_from_file(file).replace('\r', '')
|
|
119
|
+
os.remove(file)
|
|
120
|
+
return content
|
|
121
|
+
else:
|
|
122
|
+
raise ValueError(f"File '{file}' does not exist")
|
|
@@ -1,52 +1,51 @@
|
|
|
1
|
-
import
|
|
2
|
-
from subprocess import PIPE, Popen
|
|
3
|
-
from .GeneralUtilities import GeneralUtilities
|
|
4
|
-
from .ProgramRunnerBase import ProgramRunnerBase
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ProgramRunnerPopen(ProgramRunnerBase):
|
|
8
|
-
|
|
9
|
-
@GeneralUtilities.check_arguments
|
|
10
|
-
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> Popen:
|
|
11
|
-
arguments_for_process = [program]
|
|
12
|
-
arguments_for_process.extend(arguments_as_array)
|
|
13
|
-
# "shell=True" is not allowed because it is not recommended and also something like
|
|
14
|
-
# "ScriptCollectionCore().run_program('curl', 'https://example.com/dataset?id=1&format=json')"
|
|
15
|
-
# would not be possible anymore because the ampersand will be treated as shell-command.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
result
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
|
|
1
|
+
import sys
|
|
2
|
+
from subprocess import PIPE, Popen
|
|
3
|
+
from .GeneralUtilities import GeneralUtilities
|
|
4
|
+
from .ProgramRunnerBase import ProgramRunnerBase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ProgramRunnerPopen(ProgramRunnerBase):
|
|
8
|
+
|
|
9
|
+
@GeneralUtilities.check_arguments
|
|
10
|
+
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> Popen:
|
|
11
|
+
arguments_for_process = [program]
|
|
12
|
+
arguments_for_process.extend(arguments_as_array)
|
|
13
|
+
# "shell=True" is not allowed because it is not recommended and also something like
|
|
14
|
+
# "ScriptCollectionCore().run_program('curl', 'https://example.com/dataset?id=1&format=json')"
|
|
15
|
+
# would not be possible anymore because the ampersand will be treated as shell-command.
|
|
16
|
+
try:
|
|
17
|
+
if interactive:
|
|
18
|
+
result = Popen(arguments_for_process, cwd=working_directory, stdout=PIPE, stderr=PIPE, shell=False, text=True, stdin=sys.stdin) # pylint: disable=consider-using-with
|
|
19
|
+
else:
|
|
20
|
+
result = Popen(arguments_for_process, cwd=working_directory, stdout=PIPE, stderr=PIPE, shell=False, text=True) # pylint: disable=consider-using-with
|
|
21
|
+
except FileNotFoundError as fileNotFoundError:
|
|
22
|
+
raise FileNotFoundError(f"Starting '{program}' in '{working_directory}' resulted in a FileNotFoundError: '{fileNotFoundError.filename}'")
|
|
23
|
+
return result
|
|
24
|
+
|
|
25
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
26
|
+
@GeneralUtilities.check_arguments
|
|
27
|
+
def wait(self, process: Popen, custom_argument: object) -> tuple[int, str, str, int]:
|
|
28
|
+
pid = process.pid
|
|
29
|
+
stdout, stderr = process.communicate()
|
|
30
|
+
exit_code = process.wait()
|
|
31
|
+
stdout = GeneralUtilities.bytes_to_string(stdout).replace('\r', '')
|
|
32
|
+
stderr = GeneralUtilities.bytes_to_string(stderr).replace('\r', '')
|
|
33
|
+
result = (exit_code, stdout, stderr, pid)
|
|
34
|
+
return result
|
|
35
|
+
|
|
36
|
+
@GeneralUtilities.check_arguments
|
|
37
|
+
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
|
|
38
|
+
process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument, interactive)
|
|
39
|
+
return self.wait(process, custom_argument)
|
|
40
|
+
|
|
41
|
+
@GeneralUtilities.check_arguments
|
|
42
|
+
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
|
|
43
|
+
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
|
|
44
|
+
|
|
45
|
+
@GeneralUtilities.check_arguments
|
|
46
|
+
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> int:
|
|
47
|
+
return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument, interactive).pid
|
|
48
|
+
|
|
49
|
+
@GeneralUtilities.check_arguments
|
|
50
|
+
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> int:
|
|
51
|
+
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument, interactive)
|