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.
@@ -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 rmtree(directory: str) -> None:
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.rmtree(os.path.join(root, name))
412
- GeneralUtilities.rmtree(path)
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
- raise NotImplementedError
13
-
14
- # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
15
- @abstractmethod
16
- @GeneralUtilities.check_arguments
17
- def wait(self, process: Popen, custom_argument: object) -> tuple[int, str, str, int]:
18
- raise NotImplementedError
19
-
20
- # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
21
- @abstractmethod
22
- @GeneralUtilities.check_arguments
23
- 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]:
24
- raise NotImplementedError
25
-
26
- # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
27
- @abstractmethod
28
- @GeneralUtilities.check_arguments
29
- def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None) -> tuple[int, str, str, int]:
30
- raise NotImplementedError
31
-
32
- # Return-values program_runner: Pid
33
- @abstractmethod
34
- @GeneralUtilities.check_arguments
35
- def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> int:
36
- raise NotImplementedError
37
-
38
- # Return-values program_runner: Pid
39
- @abstractmethod
40
- @GeneralUtilities.check_arguments
41
- def run_program_async(self, program: str, arguments: str, working_directory: str, custom_argument: object) -> int:
42
- raise NotImplementedError
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 os
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
- cwd = os.getcwd()
17
- try:
18
- os.chdir(working_directory)
19
- result = Popen(arguments_for_process, stdout=PIPE, stderr=PIPE, shell=False) # pylint: disable=consider-using-with
20
- except FileNotFoundError as fileNotFoundError:
21
- raise FileNotFoundError(f"Starting '{program}' in '{working_directory}' resulted in a FileNotFoundError: '{fileNotFoundError.filename}'")
22
- finally:
23
- os.chdir(cwd)
24
- return result
25
-
26
- # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
27
- @GeneralUtilities.check_arguments
28
- def wait(self, process: Popen, custom_argument: object) -> tuple[int, str, str, int]:
29
- pid = process.pid
30
- stdout, stderr = process.communicate()
31
- exit_code = process.wait()
32
- stdout = GeneralUtilities.bytes_to_string(stdout).replace('\r', '')
33
- stderr = GeneralUtilities.bytes_to_string(stderr).replace('\r', '')
34
- result = (exit_code, stdout, stderr, pid)
35
- return result
36
-
37
- @GeneralUtilities.check_arguments
38
- 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]:
39
- process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument)
40
- return self.wait(process, custom_argument)
41
-
42
- @GeneralUtilities.check_arguments
43
- def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None) -> tuple[int, str, str, int]:
44
- return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
45
-
46
- @GeneralUtilities.check_arguments
47
- def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> int:
48
- return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument).pid
49
-
50
- @GeneralUtilities.check_arguments
51
- def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None) -> int:
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)