atomicshop 3.3.8__py3-none-any.whl → 3.10.0__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.

Potentially problematic release.


This version of atomicshop might be problematic. Click here for more details.

Files changed (120) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  3. atomicshop/a_mains/install_ca_certificate.py +172 -0
  4. atomicshop/a_mains/process_from_port.py +119 -0
  5. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  6. atomicshop/basics/strings.py +1 -1
  7. atomicshop/certificates.py +2 -2
  8. atomicshop/dns.py +26 -28
  9. atomicshop/etws/traces/trace_tcp.py +1 -2
  10. atomicshop/mitm/centered_settings.py +133 -0
  11. atomicshop/mitm/config_static.py +22 -44
  12. atomicshop/mitm/connection_thread_worker.py +383 -165
  13. atomicshop/mitm/engines/__parent/recorder___parent.py +1 -1
  14. atomicshop/mitm/engines/__parent/requester___parent.py +1 -1
  15. atomicshop/mitm/engines/__parent/responder___parent.py +15 -2
  16. atomicshop/mitm/engines/create_module_template.py +1 -2
  17. atomicshop/mitm/import_config.py +91 -89
  18. atomicshop/mitm/initialize_engines.py +1 -2
  19. atomicshop/mitm/message.py +5 -4
  20. atomicshop/mitm/mitm_main.py +238 -122
  21. atomicshop/mitm/recs_files.py +61 -5
  22. atomicshop/mitm/ssh_tester.py +82 -0
  23. atomicshop/mitm/statistic_analyzer.py +33 -12
  24. atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +104 -31
  25. atomicshop/networks.py +160 -92
  26. atomicshop/package_mains_processor.py +84 -0
  27. atomicshop/permissions/ubuntu_permissions.py +47 -0
  28. atomicshop/print_api.py +3 -5
  29. atomicshop/process.py +11 -4
  30. atomicshop/python_functions.py +23 -108
  31. atomicshop/speech_recognize.py +8 -0
  32. atomicshop/ssh_remote.py +140 -164
  33. atomicshop/web.py +63 -22
  34. atomicshop/web_apis/google_llm.py +22 -14
  35. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  36. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -1
  37. atomicshop/wrappers/dockerw/dockerw.py +2 -2
  38. atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
  39. atomicshop/wrappers/elasticsearchw/elastic_infra.py +0 -190
  40. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +5 -5
  41. atomicshop/wrappers/githubw.py +180 -68
  42. atomicshop/wrappers/loggingw/consts.py +1 -1
  43. atomicshop/wrappers/loggingw/handlers.py +1 -1
  44. atomicshop/wrappers/loggingw/loggingw.py +20 -4
  45. atomicshop/wrappers/loggingw/reading.py +18 -0
  46. atomicshop/wrappers/mongodbw/mongo_infra.py +0 -38
  47. atomicshop/wrappers/netshw.py +124 -3
  48. atomicshop/wrappers/playwrightw/scenarios.py +1 -1
  49. atomicshop/wrappers/powershell_networking.py +80 -0
  50. atomicshop/wrappers/psutilw/psutil_networks.py +9 -0
  51. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  52. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
  53. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
  54. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +12 -27
  55. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +15 -9
  56. atomicshop/wrappers/socketw/certificator.py +19 -9
  57. atomicshop/wrappers/socketw/creator.py +101 -14
  58. atomicshop/wrappers/socketw/dns_server.py +17 -5
  59. atomicshop/wrappers/socketw/exception_wrapper.py +21 -16
  60. atomicshop/wrappers/socketw/process_getter.py +86 -0
  61. atomicshop/wrappers/socketw/receiver.py +29 -9
  62. atomicshop/wrappers/socketw/sender.py +10 -9
  63. atomicshop/wrappers/socketw/sni.py +31 -10
  64. atomicshop/wrappers/socketw/{base.py → socket_base.py} +33 -1
  65. atomicshop/wrappers/socketw/socket_client.py +11 -10
  66. atomicshop/wrappers/socketw/socket_wrapper.py +125 -32
  67. atomicshop/wrappers/socketw/ssl_base.py +6 -2
  68. atomicshop/wrappers/ubuntu_terminal.py +21 -18
  69. atomicshop/wrappers/win_auditw.py +189 -0
  70. {atomicshop-3.3.8.dist-info → atomicshop-3.10.0.dist-info}/METADATA +25 -30
  71. {atomicshop-3.3.8.dist-info → atomicshop-3.10.0.dist-info}/RECORD +83 -109
  72. atomicshop/_basics_temp.py +0 -101
  73. atomicshop/a_installs/ubuntu/docker_rootless.py +0 -11
  74. atomicshop/a_installs/ubuntu/docker_sudo.py +0 -11
  75. atomicshop/a_installs/ubuntu/elastic_search_and_kibana.py +0 -10
  76. atomicshop/a_installs/ubuntu/mongodb.py +0 -12
  77. atomicshop/a_installs/win/fibratus.py +0 -9
  78. atomicshop/a_installs/win/mongodb.py +0 -9
  79. atomicshop/a_installs/win/wsl_ubuntu_lts.py +0 -10
  80. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  81. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  82. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  83. atomicshop/addons/package_setup/Setup.cmd +0 -7
  84. atomicshop/archiver/__init__.py +0 -0
  85. atomicshop/archiver/_search_in_zip.py +0 -189
  86. atomicshop/archiver/search_in_archive.py +0 -284
  87. atomicshop/archiver/sevenz_app_w.py +0 -86
  88. atomicshop/archiver/sevenzs.py +0 -73
  89. atomicshop/archiver/shutils.py +0 -34
  90. atomicshop/archiver/zips.py +0 -353
  91. atomicshop/file_types.py +0 -24
  92. atomicshop/pbtkmultifile_argparse.py +0 -88
  93. atomicshop/script_as_string_processor.py +0 -42
  94. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  95. atomicshop/ssh_scripts/process_from_port.py +0 -27
  96. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  97. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  98. atomicshop/wrappers/dockerw/install_docker.py +0 -449
  99. atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -233
  100. atomicshop/wrappers/ffmpegw.py +0 -125
  101. atomicshop/wrappers/fibratusw/__init__.py +0 -0
  102. atomicshop/wrappers/fibratusw/install.py +0 -80
  103. atomicshop/wrappers/mongodbw/install_mongodb_ubuntu.py +0 -100
  104. atomicshop/wrappers/mongodbw/install_mongodb_win.py +0 -244
  105. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  106. atomicshop/wrappers/socketw/get_process.py +0 -123
  107. atomicshop/wrappers/wslw.py +0 -192
  108. atomicshop-3.3.8.dist-info/entry_points.txt +0 -2
  109. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  110. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  111. /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  112. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  113. /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
  114. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
  115. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
  116. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
  117. /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
  118. {atomicshop-3.3.8.dist-info → atomicshop-3.10.0.dist-info}/WHEEL +0 -0
  119. {atomicshop-3.3.8.dist-info → atomicshop-3.10.0.dist-info}/licenses/LICENSE.txt +0 -0
  120. {atomicshop-3.3.8.dist-info → atomicshop-3.10.0.dist-info}/top_level.txt +0 -0
@@ -1,189 +0,0 @@
1
- # This was written before 'search_in_archive', currently search_in_archive is in test mode.
2
- # So probably this will go away eventually.
3
- import os
4
- import zipfile
5
- from io import BytesIO
6
-
7
-
8
- def _get_unique_filename(directory, filename):
9
- """
10
- Generates a unique filename by appending a number if the file already exists.
11
- """
12
- name, ext = os.path.splitext(filename)
13
- counter = 1
14
- unique_filename = filename
15
- while os.path.exists(os.path.join(directory, unique_filename)):
16
- unique_filename = f"{name}_{counter}{ext}"
17
- counter += 1
18
- return unique_filename
19
-
20
-
21
- def _is_zip_file(file, zip_obj):
22
- try:
23
- with zip_obj.open(file) as file_data:
24
- with zipfile.ZipFile(BytesIO(file_data.read())) as zip_file:
25
- if zip_file.testzip() is None: # No errors found
26
- return True
27
- except zipfile.BadZipFile:
28
- return False
29
- return False
30
-
31
-
32
- def _match_file_name(target, current, case_sensitive):
33
- if case_sensitive:
34
- return current.endswith(target)
35
- else:
36
- return current.lower().endswith(target.lower())
37
-
38
-
39
- def _handle_nested_zip(
40
- zip_obj, item, archived_file_bytes, file_names, results, found_set, recursive, return_first_only,
41
- case_sensitive, callback_functions, extract_file_to_path):
42
-
43
- if recursive and _is_zip_file(item.filename, zip_obj):
44
- nested_zip_bytes = BytesIO(archived_file_bytes)
45
- with zipfile.ZipFile(nested_zip_bytes) as nested_zip:
46
- _search_in_zip(
47
- nested_zip, file_names, results, found_set, case_sensitive, return_first_only, recursive,
48
- callback_functions, extract_file_to_path)
49
-
50
-
51
- def _handle_file_extraction(item, extract_file_to_path, archived_file_bytes):
52
- if extract_file_to_path:
53
- unique_filename = _get_unique_filename(extract_file_to_path, os.path.basename(item.filename))
54
- with open(os.path.join(extract_file_to_path, unique_filename), 'wb') as f:
55
- f.write(archived_file_bytes)
56
-
57
-
58
- def _handle_callback_matching(item, archived_file_bytes, callback_functions, results, found_set, return_first_only):
59
- for callback in callback_functions:
60
- callback_result = callback(archived_file_bytes)
61
- if callback_result:
62
- # Initialize key for callback function name if not present
63
- if callback.__name__ not in results:
64
- results[callback.__name__] = []
65
- file_info = {
66
- 'bytes': archived_file_bytes,
67
- 'name': item.filename,
68
- 'size': item.file_size,
69
- 'modified_time': item.date_time
70
- }
71
- results[callback.__name__].append(file_info)
72
- if return_first_only:
73
- found_set.add(item.filename)
74
- return True
75
- return False
76
-
77
-
78
- def _handle_name_matching(item, archived_file_bytes, file_names, case_sensitive, results, found_set, return_first_only):
79
- if any(_match_file_name(file_name, item.filename, case_sensitive) for file_name in file_names):
80
- if item.filename not in results:
81
- results[item.filename] = []
82
- file_info = {
83
- 'bytes': archived_file_bytes,
84
- 'name': item.filename,
85
- 'size': item.file_size,
86
- 'modified_time': item.date_time
87
- }
88
- results[item.filename].append(file_info)
89
- if return_first_only:
90
- found_set.add(item.filename)
91
-
92
-
93
- def _search_in_zip(
94
- zip_obj, file_names, results, found_set, case_sensitive, return_first_only, recursive, callback_functions,
95
- extract_file_to_path):
96
-
97
- for item in zip_obj.infolist():
98
- if item.filename.endswith('/'): # Skip directories
99
- continue
100
-
101
- with zip_obj.open(item) as file_data:
102
- archived_file_bytes = file_data.read()
103
-
104
- callback_matched = False
105
- if callback_functions:
106
- callback_matched = _handle_callback_matching(
107
- item, archived_file_bytes, callback_functions, results, found_set, return_first_only)
108
-
109
- if callback_matched:
110
- _handle_file_extraction(item, extract_file_to_path, archived_file_bytes)
111
- else:
112
- _handle_nested_zip(
113
- zip_obj, item, archived_file_bytes, file_names, results, found_set, recursive, return_first_only,
114
- case_sensitive, callback_functions, extract_file_to_path)
115
- if file_names and not callback_matched:
116
- _handle_name_matching(
117
- item, archived_file_bytes, file_names, case_sensitive, results, found_set, return_first_only)
118
-
119
- if file_names is not None and len(found_set) == len(file_names):
120
- break # All files found, stop searching
121
-
122
-
123
- def _initialize_results(callback_functions):
124
- if callback_functions:
125
- return {callback.__name__: [] for callback in callback_functions}
126
- else:
127
- return {}
128
-
129
-
130
- def _search_zip_content(
131
- file_path, file_bytes, file_names_to_search, results, found_set, case_sensitive, return_first_only, recursive,
132
- callback_functions, extract_file_to_path):
133
- if file_bytes is not None:
134
- with zipfile.ZipFile(BytesIO(file_bytes), 'r') as zip_ref:
135
- _search_in_zip(zip_ref, file_names_to_search, results, found_set, case_sensitive, return_first_only,
136
- recursive, callback_functions, extract_file_to_path)
137
- elif file_path is not None:
138
- with zipfile.ZipFile(file_path, 'r') as zip_ref:
139
- _search_in_zip(zip_ref, file_names_to_search, results, found_set, case_sensitive, return_first_only,
140
- recursive, callback_functions, extract_file_to_path)
141
- else:
142
- raise ValueError("Either file_path or file_bytes must be provided.")
143
-
144
-
145
- def search_file_in_zip(
146
- file_path: str = None,
147
- file_bytes: bytes = None,
148
- file_names_to_search: list[str] = None,
149
- case_sensitive: bool = True,
150
- return_first_only: bool = False,
151
- return_empty_list_per_file_name: bool = False,
152
- recursive: bool = False,
153
- callback_functions: list = None,
154
- extract_file_to_path: str = None
155
- ) -> dict[str, list[bytes]]:
156
- """
157
- Function searches for the file names inside the zip file and returns a dictionary where the keys are the
158
- names of the callback functions and the values are lists of found file bytes.
159
- :param file_path: string, full path to the zip file.
160
- :param file_bytes: bytes, the bytes of the zip file.
161
- :param file_names_to_search: list of strings, the names of the files to search.
162
- :param case_sensitive: boolean, default is 'True'. Determines if file name search should be case sensitive.
163
- :param return_first_only: boolean, default is 'False'. Return only the first found file for each file name.
164
- :param return_empty_list_per_file_name: boolean, default is 'False'.
165
- True: Return empty list for each file name that wasn't found.
166
- False: Don't return empty list for each file name that wasn't found.
167
- :param recursive: boolean, default is 'False'. If True, search for file names recursively in nested zip files.
168
- :param callback_functions: list of callables, default is None. Each function takes a file name and should return a
169
- boolean that will tell the main function if this file is 'found' or not.
170
- :param extract_file_to_path: string, full path to the directory where the found files should be extracted.
171
- :return: dictionary of lists of bytes.
172
- """
173
-
174
- if file_names_to_search is None and callback_functions is None:
175
- raise ValueError("Either file_names_to_search or callback_functions must be provided.")
176
-
177
- # Initialize results dictionary.
178
- results = _initialize_results(callback_functions)
179
- found_set = set()
180
-
181
- _search_zip_content(
182
- file_path, file_bytes, file_names_to_search, results, found_set, case_sensitive, return_first_only, recursive,
183
- callback_functions, extract_file_to_path)
184
-
185
- if not return_empty_list_per_file_name:
186
- # Filter out keys with empty lists.
187
- results = {key: value for key, value in results.items() if value}
188
-
189
- return results
@@ -1,284 +0,0 @@
1
- import os
2
- import zipfile
3
- from io import BytesIO
4
- from typing import Union
5
-
6
- from . import zips, sevenzs
7
- from .. import file_types
8
-
9
- import py7zr
10
-
11
-
12
- SUPPORTED_ARCHIVE_MIMES: list = [
13
- 'application/x-7z-compressed',
14
- 'application/zip',
15
- 'application/x-dosexec', # SFX zip files.
16
- 'application/octet-stream', # There are some non-standard zip files that are not recognized by magic.
17
- 'application/vnd.microsoft.portable-executable' # PE files. Some self extracting archives are PE files, But the zip module can handle them.
18
- ]
19
-
20
-
21
- # Custom exception if the file is not known archive type.
22
- class UnknownArchiveType(Exception):
23
- pass
24
-
25
-
26
- def _get_unique_filename(directory, filename):
27
- """
28
- Generates a unique filename by appending a number if the file already exists.
29
- """
30
- name, ext = os.path.splitext(filename)
31
- counter = 1
32
- unique_filename = filename
33
- while os.path.exists(os.path.join(directory, unique_filename)):
34
- unique_filename = f"{name}_{counter}{ext}"
35
- counter += 1
36
- return unique_filename
37
-
38
-
39
- def _match_file_name(target, current, case_sensitive):
40
- if case_sensitive:
41
- return current.endswith(target)
42
- else:
43
- return current.lower().endswith(target.lower())
44
-
45
-
46
- def _handle_file_extraction(item, extract_file_to_path, archived_file_bytes):
47
- if extract_file_to_path:
48
- unique_filename = _get_unique_filename(extract_file_to_path, os.path.basename(item.filename))
49
- with open(os.path.join(extract_file_to_path, unique_filename), 'wb') as f:
50
- f.write(archived_file_bytes)
51
-
52
-
53
- def _handle_callback_matching(
54
- item, archive_type, archived_file_bytes, callback_functions, results, found_set, return_first_only):
55
- for callback in callback_functions:
56
- callback_result = callback(archived_file_bytes)
57
- if callback_result:
58
- # Initialize key for callback function name if not present
59
- if _get_callback_name(callback) not in results:
60
- results[_get_callback_name(callback)]: dict = {}
61
- results[_get_callback_name(callback)]['files']: list = []
62
-
63
- if archive_type == 'zip':
64
- file_info = {
65
- 'bytes': archived_file_bytes,
66
- 'name': item.filename,
67
- 'size': item.file_size,
68
- 'modified_time': item.date_time
69
- }
70
- elif archive_type == '7z':
71
- file_info = {
72
- 'bytes': archived_file_bytes,
73
- 'name': item.filename,
74
- 'size': item.uncompressed,
75
- 'modified_time': item.creationtime
76
- }
77
- results[_get_callback_name(callback)]['files'].append(file_info)
78
- results[_get_callback_name(callback)]['callable_result'] = callback_result
79
- if return_first_only:
80
- found_set.add(item.filename)
81
- return True
82
- return False
83
-
84
-
85
- def _handle_name_matching(item, archived_file_bytes, file_names, case_sensitive, results, found_set, return_first_only):
86
- if any(_match_file_name(file_name, item.filename, case_sensitive) for file_name in file_names):
87
- if item.filename not in results:
88
- results[item.filename] = []
89
- file_info = {
90
- 'bytes': archived_file_bytes,
91
- 'name': item.filename,
92
- 'size': item.file_size,
93
- 'modified_time': item.date_time
94
- }
95
- results[item.filename].append(file_info)
96
- if return_first_only:
97
- found_set.add(item.filename)
98
-
99
-
100
- def _search_in_archive(
101
- arch_obj, archive_type, file_names, results, found_set, case_sensitive, return_first_only, recursive,
102
- callback_functions, extract_file_to_path):
103
- file_info_list = None
104
- if archive_type == 'zip':
105
- file_info_list = arch_obj.infolist()
106
- elif archive_type == '7z':
107
- file_info_list = arch_obj.list()
108
-
109
- # Iterate over each file in the archive.
110
- for item_index, item in enumerate(file_info_list):
111
- # At this stage we will get the bytes of the archived file, which is an 'item' in the archive.
112
- archived_file_bytes = None
113
- # If the main archive is zip we will use the 'open' method, if it's 7z we will use the 'read' method.
114
- if archive_type == 'zip':
115
- # Skip directories.
116
- if item.filename.endswith('/'):
117
- continue
118
-
119
- with arch_obj.open(item) as file_data:
120
- archived_file_bytes = file_data.read()
121
- elif archive_type == '7z':
122
- # Skip directories.
123
- if item.is_directory:
124
- continue
125
-
126
- # If 'SevenZipFile.red()' is used once, the second time you need to read it you will need to reset the
127
- # SevenZipFile object in order to read again:
128
- # https://py7zr.readthedocs.io/en/latest/api.html#py7zr.SevenZipFile.read
129
- file_dict = arch_obj.read([item.filename])
130
- archived_file_bytes = file_dict[item.filename].read()
131
- arch_obj.reset()
132
-
133
- # After we get the file bytes we will check if the file matches the callback functions.
134
- callback_matched = False
135
- if callback_functions:
136
- callback_matched = _handle_callback_matching(
137
- item, archive_type, archived_file_bytes, callback_functions, results, found_set, return_first_only)
138
-
139
- if callback_matched:
140
- _handle_file_extraction(item, extract_file_to_path, archived_file_bytes)
141
- else:
142
- if recursive and (zips.is_zip_zipfile(archived_file_bytes) or sevenzs.is_7z_magic_number(archived_file_bytes)):
143
- _search_archive_content(
144
- archived_file_bytes, file_names, results, found_set, case_sensitive, return_first_only,
145
- recursive, callback_functions, extract_file_to_path)
146
- if file_names and not callback_matched:
147
- _handle_name_matching(
148
- item, archived_file_bytes, file_names, case_sensitive, results, found_set, return_first_only)
149
-
150
- if file_names is not None and len(found_set) == len(file_names):
151
- break # All files found, stop searching
152
-
153
-
154
- def _get_callback_name(callback: callable) -> str:
155
- """
156
- Get the name of the callback function.
157
- :param callback: callable.
158
- :return: string, the name of the callback function. If the function is part of the class, the name will be
159
- 'class_name.function_name', if not the only the function name will be returned.
160
- """
161
- try:
162
- class_name = callback.__self__.__class__.__name__
163
- except AttributeError:
164
- class_name = None
165
-
166
- function_name = callback.__name__
167
-
168
- if class_name:
169
- return f"{class_name}.{function_name}"
170
- else:
171
- return function_name
172
-
173
-
174
- # def _initialize_results(callback_functions: list[callable]) -> dict:
175
- # """
176
- # Initialize the results dictionary.
177
- # :param callback_functions:
178
- # :return:
179
- # """
180
- # if callback_functions:
181
- # result_dict: dict = {}
182
- # for callback in callback_functions:
183
- # result_dict[_get_callback_name(callback)]: dict = {}
184
- # result_dict[_get_callback_name(callback)]['files']: list = []
185
- # result_dict[_get_callback_name(callback)]['callable_result']: any = None
186
- #
187
- # return result_dict
188
- # else:
189
- # return {}
190
-
191
-
192
- def _get_archive_type(file_object) -> Union[str, None]:
193
- file_mime: str = file_types.get_mime_type(file_object)
194
-
195
- if file_mime not in SUPPORTED_ARCHIVE_MIMES:
196
- return None
197
-
198
- if zips.is_zip_zipfile(file_object):
199
- return 'zip'
200
- elif sevenzs.is_7z_magic_number(file_object):
201
- return '7z'
202
- else:
203
- raise UnknownArchiveType(f"{file_object[:10]} is not a known archive type.")
204
- # print_api(f"{file_object[:10]} is not a known archive type.", color='yellow')
205
- # return None
206
-
207
-
208
- def _search_archive_content(
209
- file_object, file_names_to_search, results, found_set, case_sensitive, return_first_only, recursive,
210
- callback_functions, extract_file_to_path):
211
- archive_type = _get_archive_type(file_object)
212
-
213
- if isinstance(file_object, str):
214
- if archive_type == 'zip':
215
- with zipfile.ZipFile(file_object, 'r') as archive_ref:
216
- _search_in_archive(
217
- archive_ref, archive_type, file_names_to_search, results, found_set, case_sensitive,
218
- return_first_only, recursive, callback_functions, extract_file_to_path)
219
- elif archive_type == '7z':
220
- with py7zr.SevenZipFile(file_object, 'r') as archive_ref:
221
- _search_in_archive(
222
- archive_ref, archive_type, file_names_to_search, results, found_set, case_sensitive,
223
- return_first_only, recursive, callback_functions, extract_file_to_path)
224
- elif isinstance(file_object, bytes):
225
- if archive_type == 'zip':
226
- with BytesIO(file_object) as file_like_object:
227
- with zipfile.ZipFile(file_like_object, 'r') as archive_ref:
228
- _search_in_archive(
229
- archive_ref, archive_type, file_names_to_search, results, found_set, case_sensitive,
230
- return_first_only, recursive, callback_functions, extract_file_to_path)
231
- elif archive_type == '7z':
232
- with BytesIO(file_object) as file_like_object:
233
- with py7zr.SevenZipFile(file_like_object, 'r') as archive_ref:
234
- _search_in_archive(
235
- archive_ref, archive_type, file_names_to_search, results, found_set, case_sensitive,
236
- return_first_only, recursive, callback_functions, extract_file_to_path)
237
-
238
-
239
- def search_file_in_archive(
240
- file_object: Union[str, bytes] = None,
241
- file_names_to_search: list[str] = None,
242
- case_sensitive: bool = True,
243
- return_first_only: bool = False,
244
- return_empty_list_per_file_name: bool = False,
245
- recursive: bool = False,
246
- callback_functions: list = None,
247
- extract_file_to_path: str = None
248
- ) -> dict[list[bytes], str]:
249
- """
250
- Function searches for the file names inside the zip file and returns a dictionary where the keys are the
251
- names of the callback functions and the values are lists of found file bytes.
252
- :param file_object: it can be two types:
253
- string, full path to the zip file.
254
- bytes, the bytes of the zip file.
255
- :param file_names_to_search: list of strings, the names of the files to search.
256
- :param case_sensitive: boolean, default is 'True'. Determines if file name search should be case sensitive.
257
- :param return_first_only: boolean, default is 'False'. Return only the first found file for each file name.
258
- :param return_empty_list_per_file_name: boolean, default is 'False'.
259
- True: Return empty list for each file name that wasn't found.
260
- False: Don't return empty list for each file name that wasn't found.
261
- :param recursive: boolean, default is 'False'. If True, search for file names recursively in nested zip files.
262
- :param callback_functions: list of callables, default is None. Each function takes a file name and should return a
263
- boolean that will tell the main function if this file is 'found' or not.
264
- :param extract_file_to_path: string, full path to the directory where the found files should be extracted.
265
- :return: dictionary of lists of bytes.
266
- """
267
-
268
- if file_names_to_search is None and callback_functions is None:
269
- raise ValueError("Either file_names_to_search or callback_functions must be provided.")
270
-
271
- # Initialize results dictionary.
272
- # results = _initialize_results(callback_functions)
273
- results: dict[list[bytes], str] = {}
274
- found_set = set()
275
-
276
- _search_archive_content(
277
- file_object, file_names_to_search, results, found_set, case_sensitive, return_first_only, recursive,
278
- callback_functions, extract_file_to_path)
279
-
280
- if not return_empty_list_per_file_name:
281
- # Filter out keys with empty lists.
282
- results = {key: value for key, value in results.items() if value}
283
-
284
- return results
@@ -1,86 +0,0 @@
1
- import os
2
- import subprocess
3
- from pathlib import Path
4
-
5
- from ..print_api import print_api
6
- from .. import process
7
-
8
-
9
- def is_path_contains_7z_executable(sevenz_path: str) -> bool:
10
- """
11
- Checks if the path contains 7z executable.
12
- :param sevenz_path: string, The path to the 7z executable.
13
- :return: bool, True if the path contains 7z executable, False otherwise.
14
- """
15
- executable_path_parts: tuple = Path(sevenz_path).parts
16
-
17
- if '7z' not in executable_path_parts[-1]:
18
- return False
19
- else:
20
- return True
21
-
22
-
23
- def is_executable_a_7z(sevenz_path: str) -> bool:
24
- """
25
- Checks if the 7z executable is installed.
26
- :param sevenz_path: string, The path to the 7z executable.
27
- :return: bool, True if the 7z executable is installed, False otherwise.
28
- """
29
-
30
- # Check if the process itself is installed.
31
- if process.is_command_exists(sevenz_path):
32
- # Check that this is the 7z executable.
33
- try:
34
- # Run '7z' command and capture output
35
- result = subprocess.run([sevenz_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
36
-
37
- # Check if the output contains identifying information
38
- if b"7-Zip" in result.stdout or b"7-Zip" in result.stderr:
39
- return True
40
- except Exception:
41
- return False
42
-
43
- return False
44
-
45
-
46
- def extract_file(
47
- file_path: str,
48
- extract_to: str,
49
- sevenz_path: str = None,
50
- force_overwrite: bool = False,
51
- print_kwargs: dict = None
52
- ):
53
- """
54
- Extracts a file to a directory using 7z executable.
55
- :param file_path: string, The path to the file to extract.
56
- :param extract_to: string, The directory to extract the file to.
57
- :param sevenz_path: string, The path to the 7z executable.
58
- If None, the default path is used, assuming you added 7z to the PATH environment variable.
59
- :param force_overwrite: bool, If True, the files will be overwritten if they already exist in the output folder.
60
- :param print_kwargs: dict, The keyword arguments to pass to the print function.
61
- :return:
62
- """
63
-
64
- # Check if the path contains 7z executable.
65
- if not is_path_contains_7z_executable(sevenz_path):
66
- raise ValueError("The path to 7z does not contain 7z executable")
67
-
68
- if not sevenz_path:
69
- sevenz_path = '7z'
70
-
71
- # Check if the 7z executable is installed.
72
- if not is_executable_a_7z(sevenz_path):
73
- raise RuntimeError("'7z executable' is not a 7z")
74
-
75
- if not os.path.exists(extract_to):
76
- os.makedirs(extract_to)
77
-
78
- command = [f'{sevenz_path}', 'x', file_path, f'-o{extract_to}']
79
- if force_overwrite:
80
- command.append('-y')
81
-
82
- try:
83
- subprocess.run(command, check=True)
84
- print_api(f"Extracted {file_path} to {extract_to}", **(print_kwargs or {}))
85
- except subprocess.CalledProcessError as e:
86
- print_api(f"An error occurred: {e}", **(print_kwargs or {}))
@@ -1,73 +0,0 @@
1
- from io import BytesIO
2
- from typing import Union
3
-
4
- import py7zr
5
-
6
-
7
- def is_7z_magic_number(
8
- file_object: Union[str, bytes]
9
- ) -> bool:
10
- """
11
- Function checks if the file is a 7z file, by checking the magic number.
12
-
13
- :param file_object: can be two types:
14
- string, full path to the file.
15
- bytes or BytesIO, the bytes of the file.
16
- :return: boolean.
17
- """
18
-
19
- if isinstance(file_object, str):
20
- with open(file_object, 'rb') as file:
21
- data = file.read(6)
22
- elif isinstance(file_object, bytes):
23
- data = file_object
24
- else:
25
- raise TypeError(f'The file_object must be a string or bytes, not {type(file_object)}')
26
-
27
- # Check if the data is at least 6 bytes long
28
- if len(data) < 6:
29
- return False
30
-
31
- # 7z file signature (magic number)
32
- # The signature is '7z' followed by 'BCAF271C'
33
- seven_z_signature = b'7z\xBC\xAF\x27\x1C'
34
-
35
- # Compare the first 6 bytes of the data with the 7z signature
36
- result = data.startswith(seven_z_signature)
37
-
38
- return result
39
-
40
-
41
- def _is_7z(file_object: Union[str, bytes]) -> bool:
42
- """
43
- THIS IS ONLY FOR THE REFERENCE.
44
-
45
- Used to use this function since it raised 'py7zr.Bad7zFile' if the file was not a 7z file.
46
- The problem that 'SevenZipFile.testzip()' checks archived files CRCs and returns the first bad file:
47
- https://py7zr.readthedocs.io/en/latest/api.html#py7zr.SevenZipFile.testzip
48
- The problem is when the file IS 7z file, but there can be other problems with the file, it can raise a RuntimeError.
49
- So, better use the 'is_7z_magic_number' function.
50
-
51
- Function checks if the file is a 7z file.
52
- :param file_object: can be two types:
53
- string, full path to the file.
54
- bytes or BytesIO, the bytes of the file.
55
- :return: boolean.
56
- """
57
-
58
- try:
59
- if isinstance(file_object, bytes):
60
- with BytesIO(file_object) as file_object:
61
- with py7zr.SevenZipFile(file_object) as archive:
62
- archive.testzip()
63
- return True
64
- elif isinstance(file_object, str):
65
- with py7zr.SevenZipFile(file_object) as archive:
66
- archive.testzip()
67
- return True
68
- except py7zr.Bad7zFile:
69
- return False
70
- # For some reason there are files that return this exception instead of Bad7zFile.
71
- except OSError as e:
72
- if e.args[0] == 22:
73
- return False
@@ -1,34 +0,0 @@
1
- import os
2
- import shutil
3
-
4
- from ..print_api import print_api
5
-
6
-
7
- def extract_archive_with_shutil(file_path: str, target_directory: str, **kwargs) -> str:
8
- """
9
- Function extracts the archive to target directory.
10
- Returns full path to extracted directory.
11
- This function doesn't preserve the original date and time of files from the archive, instead the time of extraction
12
- will be applied.
13
-
14
- :param file_path: Full file path to archived file to extract.
15
- :param target_directory: The directory on the filesystem to extract the file to.
16
- :return: str.
17
- """
18
-
19
- print_api(f'Extracting {file_path}', **kwargs)
20
-
21
- extracted_directory: str = str()
22
-
23
- try:
24
- shutil.unpack_archive(file_path, target_directory)
25
- file_name = file_path.rsplit(os.sep, maxsplit=1)[1]
26
- file_name_no_extension = file_name.rsplit('.', maxsplit=1)[0]
27
- extracted_directory: str = target_directory + os.sep + file_name_no_extension
28
- except Exception as exception_object:
29
- print_api(f'Error extracting: {file_path}', error_type=True, **kwargs)
30
- print_api(exception_object, error_type=True, **kwargs)
31
- pass
32
-
33
- print_api(f'Extracted to: {extracted_directory}', **kwargs)
34
- return extracted_directory