ScriptCollection 3.5.108__py3-none-any.whl → 3.5.110__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 +26 -0
- ScriptCollection/ScriptCollectionCore.py +46 -15
- ScriptCollection/TasksForCommonProjectStructure.py +14 -7
- {scriptcollection-3.5.108.dist-info → scriptcollection-3.5.110.dist-info}/METADATA +5 -4
- {scriptcollection-3.5.108.dist-info → scriptcollection-3.5.110.dist-info}/RECORD +8 -8
- {scriptcollection-3.5.108.dist-info → scriptcollection-3.5.110.dist-info}/WHEEL +1 -1
- {scriptcollection-3.5.108.dist-info → scriptcollection-3.5.110.dist-info}/entry_points.txt +1 -0
- {scriptcollection-3.5.108.dist-info → scriptcollection-3.5.110.dist-info}/top_level.txt +0 -0
ScriptCollection/Executables.py
CHANGED
@@ -628,3 +628,29 @@ def CurrentUserHasElevatedPrivileges() -> int:
|
|
628
628
|
return 1
|
629
629
|
else:
|
630
630
|
return 0
|
631
|
+
|
632
|
+
|
633
|
+
def Espoc() -> int:
|
634
|
+
GeneralUtilities.write_message_to_stdout("check...")
|
635
|
+
parser = argparse.ArgumentParser(description="Espoc (appreviation for 'exit started programs on close') is a tool to ensure the started processes of your program will also get terminated when the execution of your program is finished.")
|
636
|
+
parser.add_argument('-p', '--processid', required=True)
|
637
|
+
parser.add_argument('-f', '--file', required=True, help='Specifies the file where the process-ids of the started processes are stored (line by line). This file will be deleted when all started processes are terminated.')
|
638
|
+
args = parser.parse_args()
|
639
|
+
process_id = args.processid
|
640
|
+
process_list_file: str = args.file
|
641
|
+
if not os.path.isabs(process_list_file):
|
642
|
+
process_list_file = GeneralUtilities.resolve_relative_path(process_list_file, os.getcwd())
|
643
|
+
GeneralUtilities.assert_condition(GeneralUtilities.process_is_running_by_id(process_id), f"Process with id {process_id} is not running.")
|
644
|
+
while GeneralUtilities.process_is_running_by_id(process_id):
|
645
|
+
time.sleep(1)
|
646
|
+
GeneralUtilities.write_message_to_stdout(f"Process with id {process_id} is not running anymore. Start terminating remaining processes.")
|
647
|
+
if os.path.exists(process_list_file):
|
648
|
+
for line in GeneralUtilities.read_lines_from_file(process_list_file):
|
649
|
+
if GeneralUtilities.string_has_content(line):
|
650
|
+
current_process_id = int(line.strip())
|
651
|
+
GeneralUtilities.kill_process(current_process_id, True)
|
652
|
+
GeneralUtilities.ensure_file_does_not_exist(process_list_file)
|
653
|
+
GeneralUtilities.write_message_to_stdout("All started processes terminated.")
|
654
|
+
else:
|
655
|
+
GeneralUtilities.write_message_to_stdout(f"File '{process_list_file}' does not exist. No processes to terminate.")
|
656
|
+
return 0
|
@@ -33,7 +33,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
|
|
33
33
|
from .ProgramRunnerPopen import ProgramRunnerPopen
|
34
34
|
from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
|
35
35
|
|
36
|
-
version = "3.5.
|
36
|
+
version = "3.5.110"
|
37
37
|
__version__ = version
|
38
38
|
|
39
39
|
|
@@ -603,6 +603,12 @@ class ScriptCollectionCore:
|
|
603
603
|
self.assert_is_git_repository(repository_folder)
|
604
604
|
return self.run_program_argsasarray("git", ["rev-parse", "--verify", "HEAD"], repository_folder, throw_exception_if_exitcode_is_not_zero=False)[0] == 0
|
605
605
|
|
606
|
+
@GeneralUtilities.check_arguments
|
607
|
+
def run_git_command_in_repository_and_submodules(self, repository_folder: str, arguments: list[str]) -> None:
|
608
|
+
self.assert_is_git_repository(repository_folder)
|
609
|
+
self.run_program_argsasarray("git", arguments, repository_folder)
|
610
|
+
self.run_program_argsasarray("git", ["submodule", "foreach", "--recursive", "git"]+arguments, repository_folder)
|
611
|
+
|
606
612
|
@GeneralUtilities.check_arguments
|
607
613
|
def export_filemetadata(self, folder: str, target_file: str, encoding: str = "utf-8", filter_function=None) -> None:
|
608
614
|
folder = GeneralUtilities.resolve_relative_path_from_current_working_directory(folder)
|
@@ -881,7 +887,7 @@ class ScriptCollectionCore:
|
|
881
887
|
|
882
888
|
@GeneralUtilities.check_arguments
|
883
889
|
def __create_thumbnails(self, filename: str, fps: str, folder: str, tempname_for_thumbnails: str) -> list[str]:
|
884
|
-
argument = ['-i', filename, '-r',
|
890
|
+
argument = ['-i', filename, '-r', fps, '-vf', 'scale=-1:120', '-vcodec', 'png', f'{tempname_for_thumbnails}-%002d.png']
|
885
891
|
self.run_program_argsasarray("ffmpeg", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
886
892
|
files = GeneralUtilities.get_direct_files_of_folder(folder)
|
887
893
|
result: list[str] = []
|
@@ -898,8 +904,17 @@ class ScriptCollectionCore:
|
|
898
904
|
def __create_thumbnail(self, outputfilename: str, folder: str, length_in_seconds: float, tempname_for_thumbnails: str, amount_of_images: int) -> None:
|
899
905
|
duration = timedelta(seconds=length_in_seconds)
|
900
906
|
info = GeneralUtilities.timedelta_to_simple_string(duration)
|
901
|
-
|
902
|
-
|
907
|
+
next_square_number = GeneralUtilities.get_next_square_number(amount_of_images)
|
908
|
+
root = math.sqrt(next_square_number)
|
909
|
+
rows: int = root # 5
|
910
|
+
columns: int = root # math.ceil(amount_of_images/rows)
|
911
|
+
argument = ['-title', f'"{outputfilename} ({info})"', '-tile', f'{rows}x{columns}', f'{tempname_for_thumbnails}*.png', f'{outputfilename}.png']
|
912
|
+
self.run_program_argsasarray("montage", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
913
|
+
|
914
|
+
@GeneralUtilities.check_arguments
|
915
|
+
def __create_thumbnail2(self, outputfilename: str, folder: str, length_in_seconds: float, rows: int, columns: int, tempname_for_thumbnails: str, amount_of_images: int) -> None:
|
916
|
+
duration = timedelta(seconds=length_in_seconds)
|
917
|
+
info = GeneralUtilities.timedelta_to_simple_string(duration)
|
903
918
|
argument = ['-title', f'"{outputfilename} ({info})"', '-tile', f'{rows}x{columns}', f'{tempname_for_thumbnails}*.png', f'{outputfilename}.png']
|
904
919
|
self.run_program_argsasarray("montage", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
905
920
|
|
@@ -912,7 +927,7 @@ class ScriptCollectionCore:
|
|
912
927
|
return math.ceil(x * d) / d
|
913
928
|
|
914
929
|
@GeneralUtilities.check_arguments
|
915
|
-
def generate_thumbnail(self, file: str, frames_per_second:
|
930
|
+
def generate_thumbnail(self, file: str, frames_per_second: float, tempname_for_thumbnails: str = None, hook=None) -> None:
|
916
931
|
if tempname_for_thumbnails is None:
|
917
932
|
tempname_for_thumbnails = "t_"+str(uuid.uuid4())
|
918
933
|
|
@@ -923,16 +938,9 @@ class ScriptCollectionCore:
|
|
923
938
|
preview_files: list[str] = []
|
924
939
|
try:
|
925
940
|
length_in_seconds = self.__calculate_lengh_in_seconds(filename, folder)
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
frames_per_second_as_string = str(frames_per_second)
|
930
|
-
amounf_of_previewframes = int(math.floor(length_in_seconds*frames_per_second))
|
931
|
-
else:
|
932
|
-
# concrete amount of frame, examples: frames_per_second="16" => 16 frames for entire video
|
933
|
-
amounf_of_previewframes = int(float(frames_per_second))
|
934
|
-
# self.roundup((amounf_of_previewframes-2)/length_in_seconds, 2)
|
935
|
-
frames_per_second_as_string = f"{amounf_of_previewframes-2}/{length_in_seconds}"
|
941
|
+
# frames per second, example: frames_per_second="20fps" => 20 frames per second
|
942
|
+
frames_per_second = self.__roundup(float(frames_per_second[:-3]), 2)
|
943
|
+
frames_per_second_as_string = str(frames_per_second)
|
936
944
|
preview_files = self.__create_thumbnails(filename, frames_per_second_as_string, folder, tempname_for_thumbnails)
|
937
945
|
if hook is not None:
|
938
946
|
hook(file, preview_files)
|
@@ -942,6 +950,29 @@ class ScriptCollectionCore:
|
|
942
950
|
for thumbnail_to_delete in preview_files:
|
943
951
|
os.remove(thumbnail_to_delete)
|
944
952
|
|
953
|
+
@GeneralUtilities.check_arguments
|
954
|
+
def generate_thumbnail_by_amount_of_pictures(self, file: str, amount_of_columns: int, amount_of_rows: int, tempname_for_thumbnails: str = None, hook=None) -> None:
|
955
|
+
if tempname_for_thumbnails is None:
|
956
|
+
tempname_for_thumbnails = "t_"+str(uuid.uuid4())
|
957
|
+
|
958
|
+
file = GeneralUtilities.resolve_relative_path_from_current_working_directory(file)
|
959
|
+
filename = os.path.basename(file)
|
960
|
+
folder = os.path.dirname(file)
|
961
|
+
filename_without_extension = Path(file).stem
|
962
|
+
preview_files: list[str] = []
|
963
|
+
try:
|
964
|
+
length_in_seconds = self.__calculate_lengh_in_seconds(filename, folder)
|
965
|
+
amounf_of_previewframes = int(amount_of_columns*amount_of_rows)
|
966
|
+
frames_per_second_as_string = f"{amounf_of_previewframes-2}/{length_in_seconds}"
|
967
|
+
preview_files = self.__create_thumbnails(filename, frames_per_second_as_string, folder, tempname_for_thumbnails)
|
968
|
+
if hook is not None:
|
969
|
+
hook(file, preview_files)
|
970
|
+
actual_amounf_of_previewframes = len(preview_files)
|
971
|
+
self.__create_thumbnail2(filename_without_extension, folder, length_in_seconds, amount_of_rows, amount_of_columns, tempname_for_thumbnails, actual_amounf_of_previewframes)
|
972
|
+
finally:
|
973
|
+
for thumbnail_to_delete in preview_files:
|
974
|
+
os.remove(thumbnail_to_delete)
|
975
|
+
|
945
976
|
@GeneralUtilities.check_arguments
|
946
977
|
def extract_pdf_pages(self, file: str, from_page: int, to_page: int, outputfile: str) -> None:
|
947
978
|
pdf_reader: PdfReader = PdfReader(file)
|
@@ -862,7 +862,7 @@ class TasksForCommonProjectStructure:
|
|
862
862
|
if os.path.isfile(os.path.join(codeunit_folder, runsettings_file)):
|
863
863
|
arg = f"{arg} --settings {runsettings_file}"
|
864
864
|
arg = f"{arg} /p:CollectCoverage=true /p:CoverletOutput=../Other/Artifacts/TestCoverage/Testcoverage /p:CoverletOutputFormat=cobertura"
|
865
|
-
self.__sc.run_program("dotnet", arg, codeunit_folder, verbosity=verbosity)
|
865
|
+
self.__sc.run_program("dotnet", arg, codeunit_folder, verbosity=verbosity,print_live_output=True)
|
866
866
|
target_file = os.path.join(coverage_file_folder, "TestCoverage.xml")
|
867
867
|
GeneralUtilities.ensure_file_does_not_exist(target_file)
|
868
868
|
os.rename(os.path.join(coverage_file_folder, "Testcoverage.cobertura.xml"), target_file)
|
@@ -2477,11 +2477,18 @@ class TasksForCommonProjectStructure:
|
|
2477
2477
|
GeneralUtilities.copy_content_of_folder(ca_source_folder, ca_target_folder)
|
2478
2478
|
|
2479
2479
|
@GeneralUtilities.check_arguments
|
2480
|
-
def _internal_get_sorted_codeunits_by_dict(self, codeunits
|
2481
|
-
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2480
|
+
def _internal_get_sorted_codeunits_by_dict(self, codeunits: dict[str, set[str]]) -> list[str]:
|
2481
|
+
sorted_codeunits = {
|
2482
|
+
node: sorted(codeunits[node])
|
2483
|
+
for node in sorted(codeunits)
|
2484
|
+
}
|
2485
|
+
|
2486
|
+
ts = TopologicalSorter()
|
2487
|
+
for node, deps in sorted_codeunits.items():
|
2488
|
+
ts.add(node, *deps)
|
2489
|
+
|
2490
|
+
result_typed = list(ts.static_order())
|
2491
|
+
result = [str(item) for item in result_typed]
|
2485
2492
|
return result
|
2486
2493
|
|
2487
2494
|
@GeneralUtilities.check_arguments
|
@@ -2546,7 +2553,7 @@ class TasksForCommonProjectStructure:
|
|
2546
2553
|
|
2547
2554
|
@GeneralUtilities.check_arguments
|
2548
2555
|
def build_specific_codeunits(self, repository_folder: str, codeunits: list[str], verbosity: int = 1, target_environmenttype: str = "QualityCheck", additional_arguments_file: str = None, is_pre_merge: bool = False, export_target_directory: str = None, assume_dependent_codeunits_are_already_built: bool = True, commandline_arguments: list[str] = [], do_git_clean_when_no_changes: bool = False, note: str = None, check_for_new_files: bool = True) -> None:
|
2549
|
-
codeunits_list = {", ".join(
|
2556
|
+
codeunits_list = "{"+", ".join(["a","b"])+"}"
|
2550
2557
|
if verbosity > 2:
|
2551
2558
|
GeneralUtilities.write_message_to_stdout(f"Start building codeunits ({codeunits_list}) in repository '{repository_folder}'...")
|
2552
2559
|
self.__sc.assert_is_git_repository(repository_folder)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ScriptCollection
|
3
|
-
Version: 3.5.
|
3
|
+
Version: 3.5.110
|
4
4
|
Summary: The ScriptCollection is the place for reusable scripts.
|
5
5
|
Home-page: https://github.com/anionDev/ScriptCollection
|
6
6
|
Author: Marius Göcke
|
@@ -24,13 +24,14 @@ Requires-Python: >=3.10
|
|
24
24
|
Description-Content-Type: text/markdown
|
25
25
|
Requires-Dist: build>=1.2.2.post1
|
26
26
|
Requires-Dist: coverage>=7.8.0
|
27
|
-
Requires-Dist: cyclonedx-bom>=
|
27
|
+
Requires-Dist: cyclonedx-bom>=6.0.0
|
28
28
|
Requires-Dist: defusedxml>=0.7.1
|
29
29
|
Requires-Dist: keyboard>=0.13.5
|
30
30
|
Requires-Dist: lcov-cobertura>=2.1.1
|
31
|
-
Requires-Dist: lxml>=5.
|
31
|
+
Requires-Dist: lxml>=5.4.0
|
32
32
|
Requires-Dist: ntplib>=0.4.0
|
33
33
|
Requires-Dist: Pillow>=11.2.1
|
34
|
+
Requires-Dist: psutil>=7.0.0
|
34
35
|
Requires-Dist: pycdlib>=1.14.0
|
35
36
|
Requires-Dist: Pygments>=2.19.1
|
36
37
|
Requires-Dist: pylint>=3.3.6
|
@@ -38,7 +39,7 @@ Requires-Dist: pyOpenSSL>=25.0.0
|
|
38
39
|
Requires-Dist: PyPDF>=5.4.0
|
39
40
|
Requires-Dist: pytest>=8.3.5
|
40
41
|
Requires-Dist: PyYAML>=6.0.2
|
41
|
-
Requires-Dist: qrcode>=8.
|
42
|
+
Requires-Dist: qrcode>=8.2
|
42
43
|
Requires-Dist: send2trash>=1.8.3
|
43
44
|
Requires-Dist: twine>=6.1.0
|
44
45
|
Requires-Dist: xmlschema>=4.0.1
|
@@ -1,16 +1,16 @@
|
|
1
1
|
ScriptCollection/CertificateUpdater.py,sha256=pJopWFcwaLAEVljtC4O3SVrlpIpoJNUhT1V4mgiqLvE,8970
|
2
|
-
ScriptCollection/Executables.py,sha256=
|
2
|
+
ScriptCollection/Executables.py,sha256=BsDgpqU_XKXg-7paQdmamzU14-2kcqjz9v13r96EiEk,32319
|
3
3
|
ScriptCollection/GeneralUtilities.py,sha256=VO4a7xctkjN5dcBXc32gz0x9U07DEagasjvYVKqLmdM,44173
|
4
4
|
ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
|
5
5
|
ScriptCollection/ProgramRunnerBase.py,sha256=2kMIAqdc65UjBAddOZkzy_aFx9h5roZ5a4bQNM6RV6Y,2480
|
6
6
|
ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1X43regfU,6477
|
7
7
|
ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
|
8
8
|
ScriptCollection/SCLog.py,sha256=Gw27Oclcb0ten7_89PD5CdNMoO-at2hGUOYbF-x1HPQ,2296
|
9
|
-
ScriptCollection/ScriptCollectionCore.py,sha256=
|
10
|
-
ScriptCollection/TasksForCommonProjectStructure.py,sha256=
|
9
|
+
ScriptCollection/ScriptCollectionCore.py,sha256=2RmUIh9GWngFo9ucfNrTfcTYQ5KD7RI4iJOUSPelqsA,130404
|
10
|
+
ScriptCollection/TasksForCommonProjectStructure.py,sha256=5GnI89wwy8_uJH_pZtd0zgZ1C0ReIrZeePjUIwo2sus,232910
|
11
11
|
ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
-
scriptcollection-3.5.
|
13
|
-
scriptcollection-3.5.
|
14
|
-
scriptcollection-3.5.
|
15
|
-
scriptcollection-3.5.
|
16
|
-
scriptcollection-3.5.
|
12
|
+
scriptcollection-3.5.110.dist-info/METADATA,sha256=W6tx5MA4Vq71V45HNdsJG1MHJDd9ifbe7OVmgaEm780,7694
|
13
|
+
scriptcollection-3.5.110.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
|
14
|
+
scriptcollection-3.5.110.dist-info/entry_points.txt,sha256=3qMbfZEMhc_VTJj-bcLwB8AWcn9iXSB3l0AWpuu52Bs,3689
|
15
|
+
scriptcollection-3.5.110.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
|
16
|
+
scriptcollection-3.5.110.dist-info/RECORD,,
|
@@ -15,6 +15,7 @@ sccreatehashofallfiles = ScriptCollection.Executables:CreateHashOfAllFiles
|
|
15
15
|
sccreateisofilewithobfuscatedfiles = ScriptCollection.Executables:CreateISOFileWithObfuscatedFiles
|
16
16
|
sccreatesimplemergewithoutrelease = ScriptCollection.Executables:CreateSimpleMergeWithoutRelease
|
17
17
|
sccurrentuserhaselevatedprivileges = ScriptCollection.Executables:CurrentUserHasElevatedPrivileges
|
18
|
+
scespoc = ScriptCollection.Executables:Espoc
|
18
19
|
scextractpdfpages = ScriptCollection.Executables:ExtractPDFPages
|
19
20
|
scfilecontainscontent = ScriptCollection.Executables:FileContainsContent
|
20
21
|
scfileexists = ScriptCollection.Executables:FileExists
|
File without changes
|