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

atomicshop/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '2.5.13'
4
+ __version__ = '2.5.15'
@@ -0,0 +1,16 @@
1
+ import os
2
+ from atomicshop import filesystem
3
+ from atomicshop.file_io import docxs, file_io
4
+
5
+ # Usage
6
+ directory_path = r"D:/directory_with_docx_files"
7
+ script_directory: str = filesystem.get_file_directory(__file__)
8
+ string_file_path: str = script_directory + os.sep + r"hyperlink.txt"
9
+ hyperlink: str = file_io.read_file(string_file_path)
10
+
11
+ found_in_files = docxs.search_for_hyperlink_in_files(directory_path, hyperlink, relative_paths=True)
12
+
13
+ for found_file in found_in_files:
14
+ print(found_file)
15
+
16
+ input('press Enter')
@@ -33,32 +33,35 @@ def get_hyperlinks(docx_path):
33
33
 
34
34
 
35
35
  def search_for_hyperlink_in_files(directory_path: str, hyperlink: str, relative_paths: bool = False):
36
+ # noinspection GrazieInspection
36
37
  """
37
- Search for a hyperlink in all the docx files in the specified directory.
38
- :param directory_path: string, path to the directory with docx files.
39
- :param hyperlink: string, hyperlink to search for.
40
- :param relative_paths: boolean, if True, the function will return relative paths to the files and not the full
41
- file paths. Example: 'content\file.docx' instead of 'D:/content/file.docx' if you specified 'D:/' as
42
- 'directory_path'.
43
- :return:
38
+ Search for a hyperlink in all the docx files in the specified directory.
39
+ :param directory_path: string, path to the directory with docx files.
40
+ :param hyperlink: string, hyperlink to search for.
41
+ :param relative_paths: boolean, if True, the function will return relative paths to the files and not the full
42
+ file paths. Example: 'content\file.docx' instead of 'D:/content/file.docx' if you specified 'D:/' as
43
+ 'directory_path'.
44
+ :return:
44
45
 
45
- Main function example:
46
- from atomicshop import filesystem
47
- from atomicshop.file_io import docxs
48
- from atomicshop import file_io
46
+ Main function example:
47
+ import os
48
+ from atomicshop import filesystem
49
+ from atomicshop.file_io import docxs, file_io
49
50
 
50
- directory_path = r"D:/directory_with_docx_files"
51
- script_directory: str = filesystem.get_file_directory(__file__)
52
- string_file_path: str = script_directory + r"/hyperlink.txt"
53
- hyperlink: str = file_io.read_file(string_file_path)
54
51
 
55
- found_in_files = docxs.search_for_hyperlink_in_files(directory_path, hyperlink, relative_paths=True)
52
+ # Usage
53
+ directory_path = r"D:/directory_with_docx_files"
54
+ script_directory: str = filesystem.get_file_directory(__file__)
55
+ string_file_path: str = script_directory + os.sep + r"hyperlink.txt"
56
+ hyperlink: str = file_io.read_file(string_file_path)
56
57
 
57
- for found_file in found_in_files:
58
- print(found_file)
58
+ found_in_files = docxs.search_for_hyperlink_in_files(directory_path, hyperlink, relative_paths=True)
59
59
 
60
- input('press Enter')
61
- """
60
+ for found_file in found_in_files:
61
+ print(found_file)
62
+
63
+ input('press Enter')
64
+ """
62
65
 
63
66
  if not filesystem.check_directory_existence(directory_path):
64
67
  raise NotADirectoryError(f"Directory doesn't exist: {directory_path}")
@@ -22,7 +22,7 @@ def write_file_decorator(function_name):
22
22
  print_api(message=f"Writing file: {kwargs['file_path']}", **kwargs)
23
23
 
24
24
  try:
25
- with open(kwargs['file_path'], kwargs['file_mode']) as output_file:
25
+ with open(kwargs['file_path'], kwargs['file_mode'], encoding=kwargs['encoding']) as output_file:
26
26
  # Pass the 'output_file' object to kwargs that will pass the object to the executing function.
27
27
  kwargs['file_object'] = output_file
28
28
  # Since our 'kwargs' has already all the needed arguments, we don't need 'args'.
@@ -73,24 +73,33 @@ def read_file_decorator(function_name):
73
73
 
74
74
 
75
75
  @write_file_decorator
76
- def write_file(content: str,
77
- file_path: str,
78
- file_mode: str = 'w',
79
- file_object=None,
80
- **kwargs) -> None:
76
+ def write_file(
77
+ content: Union[str, list[str]],
78
+ file_path: str,
79
+ file_mode: str = 'w',
80
+ encoding: str = None,
81
+ file_object=None,
82
+ **kwargs) -> None:
81
83
  """
82
84
  Export string to text file.
83
85
 
84
- :param content: string, that includes formatted text content.
86
+ :param content: string or list of strings, that includes formatted text content.
85
87
  :param file_path: Full file path string to the file to output. Used in the decorator, then passed to this function.
86
88
  :param file_mode: string, file writing mode. Examples: 'x', 'w', 'wb'.
87
89
  Default is 'w'.
90
+ :param encoding: string, write the file with encoding. Example: 'utf-8'. 'None' is default, since it is default
91
+ in 'open()' function.
88
92
  :param file_object: file object of the 'open()' function in the decorator. Decorator executes the 'with open()'
89
93
  statement and passes to this function. That's why the default is 'None', since we get it from the decorator.
90
94
  :return:
91
95
  """
92
96
 
93
- file_object.write(content)
97
+ if isinstance(content, list):
98
+ file_object.writelines(content)
99
+ elif isinstance(content, str):
100
+ file_object.write(content)
101
+ else:
102
+ raise TypeError(f"Content type is not supported: {type(content)}")
94
103
 
95
104
 
96
105
  @read_file_decorator
@@ -122,3 +131,41 @@ def read_file(file_path: str,
122
131
  result = file_object.read()
123
132
 
124
133
  return result
134
+
135
+
136
+ def find_and_replace_in_file(
137
+ file_path: str,
138
+ find_what: str,
139
+ replace_to: str,
140
+ encoding: str = None,
141
+ raise_if_more_than_one_found: bool = False,
142
+ **kwargs
143
+ ) -> None:
144
+ """
145
+ Find and replace string in file.
146
+
147
+ :param file_path: String with full file path to read.
148
+ :param find_what: String to find in the file.
149
+ :param replace_to: String to replace the found string.
150
+ :param encoding: string, read the file with encoding. Example: 'utf-8'. 'None' is default, since it is default
151
+ in 'open()' function.
152
+ :param raise_if_more_than_one_found: Boolean, if True, the function will raise an error if more than one string
153
+ instance was found in the file.
154
+ :return: None
155
+ """
156
+
157
+ # Read the file to variable.
158
+ file_data = read_file(file_path=file_path, read_to_list=True, encoding=encoding)
159
+
160
+ # Find and replace the string.
161
+ found_string_counter = 0
162
+ for index, line in enumerate(file_data):
163
+ if find_what in line:
164
+ file_data[index] = line.replace(find_what, replace_to)
165
+ found_string_counter += 1
166
+
167
+ if raise_if_more_than_one_found and found_string_counter > 1:
168
+ raise LookupError(f"More than one string instance was found in the file: {file_path}\n"
169
+ f"Nothing was changed.")
170
+
171
+ write_file(content=file_data, file_path=file_path, encoding=encoding)
atomicshop/permissions.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import ctypes
3
+ import contextlib
3
4
 
4
5
 
5
6
  def is_admin() -> bool:
@@ -20,3 +21,37 @@ def is_admin() -> bool:
20
21
  result = False
21
22
 
22
23
  return result
24
+
25
+
26
+ @contextlib.contextmanager
27
+ def temporary_regular_permissions():
28
+ """
29
+ This function is used to temporarily change the effective user and group ID to the original user's.
30
+ This is used to run commands with the original user's permissions.
31
+ If you executed a script with 'sudo' and wanted certain action to execute as regular user and not root.
32
+
33
+ Example:
34
+ with temporary_regular_permissions():
35
+ # Do something with regular permissions.
36
+ pass
37
+
38
+ :return:
39
+ """
40
+ # Save the current effective user and group ID
41
+ original_euid, original_egid = os.geteuid(), os.getegid()
42
+
43
+ try:
44
+ # Get the original user's UID and GID
45
+ orig_uid = int(os.environ.get('SUDO_UID', os.getuid()))
46
+ orig_gid = int(os.environ.get('SUDO_GID', os.getgid()))
47
+
48
+ # Set the effective user and group ID to the original user's
49
+ os.setegid(orig_gid)
50
+ os.seteuid(orig_uid)
51
+
52
+ # Provide the context to do something with these permissions
53
+ yield
54
+ finally:
55
+ # Revert to the original effective user and group ID
56
+ os.seteuid(original_euid)
57
+ os.setegid(original_egid)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.5.13
3
+ Version: 2.5.15
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=EI41sLBzEv1XL9PjDvBLAUPXQiEGOfUb64ozpuMkcYE,123
1
+ atomicshop/__init__.py,sha256=VHWnXlEZ9dAZpc3c2DWsrkxZnCkZZZQ7x9bDbQCK-1A,123
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/appointment_management.py,sha256=N3wVGJgrqJfsj_lqiRfaL3FxMEe57by5Stzanh189mk,7263
4
4
  atomicshop/archiver.py,sha256=QuDKx6bJEM29u-7r2tsizXEEGJmPuv0Xm91JQOpg__8,7152
@@ -20,7 +20,7 @@ atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw
20
20
  atomicshop/ip_addresses.py,sha256=GBG9YXEqHItmGEgKwqatx28CbWislFI2ZI2xVHGIqO4,759
21
21
  atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
22
22
  atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
23
- atomicshop/permissions.py,sha256=CYTDVOI0jh9ks0ZLnnOuPzppgCszFEc9-92DTkVTYi4,522
23
+ atomicshop/permissions.py,sha256=tfODaD-81zv0PrpAW-9MMULHaGe2r9TRnkP7MPhN-mQ,1735
24
24
  atomicshop/print_api.py,sha256=3n1CoiXvDcDGg00n5gEmQYInHryIhWbcpNjVobO1Gao,11468
25
25
  atomicshop/process.py,sha256=i_25PrSqSBbTcstCi_8rWVXAEYco81l6b9x1l_egTOY,14193
26
26
  atomicshop/process_name_cmd.py,sha256=TNAK6kQZm5JKWzEW6QLqVHEG98ZLNDQiSS4YwDk8V8c,3830
@@ -45,6 +45,7 @@ atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh,sha256=lM7LkXQ2AxfF
45
45
  atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd,sha256=lEP_o6rWcBFUyup6_c-LTL3Q2LRMqryLuG3mJw080Zc,115
46
46
  atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py,sha256=3VDGDO41Vubzf64DaBapLlFYX52dEdyPBNfolSsbGcM,161
47
47
  atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py,sha256=PrvZ4hMuadzj2GYKRZSwyNayJUuaSnCF9nV6ORqoPdo,123
48
+ atomicshop/addons/mains/search_for_hyperlinks_in_docx.py,sha256=HkIdo_Sz9nPbbbJf1mwfwFkyI7vkvpH8qiIkuYopN4w,529
48
49
  atomicshop/addons/mains/FACT/factw_fact_extractor_docker_image_main_sudo.py,sha256=DDKX3Wp2SmzMCEtCIEOUbEKMob2ZQ7VEQGLEf9uYXrs,320
49
50
  atomicshop/addons/mains/FACT/update_extract.py,sha256=rvpgoBqDKlVsI9WxJfkpjbVPAWTsxC7M3MdmXJhrqo8,171
50
51
  atomicshop/addons/package_setup/CreateWheel.cmd,sha256=hq9aWBSH6iffYlZyaCNrFlA0vxMh3j1k8DQE8IARQuA,189
@@ -83,8 +84,8 @@ atomicshop/etw/dns_trace.py,sha256=ZbEf1gptnUnJwaRURUW9ENDwC9Q41Zl6NtxgMNELJcg,5
83
84
  atomicshop/etw/etw.py,sha256=xVJNbfCq4KgRfsDnul6CrIdAMl9xRBixZ-hUyqiB2g4,2403
84
85
  atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
86
  atomicshop/file_io/csvs.py,sha256=4R4Kij8FmxNwXFjDtlF_A0flAk0Hj5nZKlEnqC5VxgQ,3125
86
- atomicshop/file_io/docxs.py,sha256=V2jwNrDWb2xYL-qS-kYRcK-yy3JIaND8o7gVwWJSYno,4223
87
- atomicshop/file_io/file_io.py,sha256=kaRMSm8sNrnos1gqgAcPVkUXjXgZE-uW_STueqsFZyw,5657
87
+ atomicshop/file_io/docxs.py,sha256=2lue7_eAz0fI8X3vCn34lHarU5xGSm4-Yqr0PeUPt84,4359
88
+ atomicshop/file_io/file_io.py,sha256=5bLEXOhvem-k8UwbmvFugyvzt-zgIdz2RVSR4ZZNV3Y,7557
88
89
  atomicshop/file_io/jsons.py,sha256=4xCnC6MfajLouXUFl2aVXUPvftQVf2eS5DgydPZHF_c,4170
89
90
  atomicshop/file_io/tomls.py,sha256=oa0Wm8yMkPRXKN9jgBuTnKbioSOee4mABW5IMUFCYyU,3041
90
91
  atomicshop/file_io/xlsxs.py,sha256=v_dyg9GD4LqgWi6wA1QuWRZ8zG4ZwB6Dz52ytdcmmmI,2184
@@ -191,8 +192,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=VfNthyBvgI5tL9v3Qprh4
191
192
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
192
193
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
193
194
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
194
- atomicshop-2.5.13.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
195
- atomicshop-2.5.13.dist-info/METADATA,sha256=GCuGrNYefFroSpVHNZJF1ZvWP3ejrLKruqMa4hweegU,10268
196
- atomicshop-2.5.13.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
197
- atomicshop-2.5.13.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
198
- atomicshop-2.5.13.dist-info/RECORD,,
195
+ atomicshop-2.5.15.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
196
+ atomicshop-2.5.15.dist-info/METADATA,sha256=AyVvRv1KbiiTq3Nt404Vt_r12RbbmEYuCOs5oOZ_HaM,10268
197
+ atomicshop-2.5.15.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
198
+ atomicshop-2.5.15.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
199
+ atomicshop-2.5.15.dist-info/RECORD,,