atomicshop 2.18.27__py3-none-any.whl → 2.18.29__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.18.27'
4
+ __version__ = '2.18.29'
@@ -125,8 +125,8 @@ class MultiProcessorRecursive:
125
125
  result = async_result.get()
126
126
  # Assuming process_function returns a list, extend new_input_list
127
127
  new_input_list.extend(result)
128
- except Exception as e:
129
- print(f"An error occurred: {e}")
128
+ except Exception:
129
+ raise
130
130
 
131
131
  # Update the input_list for the next iteration
132
132
  self.input_list = new_input_list
@@ -1,5 +1,6 @@
1
1
  from typing import Union
2
2
  import functools
3
+ import os
3
4
 
4
5
  from .. import print_api
5
6
  from .. import inspect_wrapper
@@ -23,7 +24,7 @@ def write_file_decorator(function_name):
23
24
  print_api.print_api(message=f"Writing file: {kwargs['file_path']}", **kwargs)
24
25
 
25
26
  enable_long_file_path = kwargs.get('enable_long_file_path', False)
26
- if enable_long_file_path:
27
+ if enable_long_file_path and os.name == 'nt':
27
28
  # A simpler string method would be to add '\\?\' to the beginning of the file path.
28
29
  # kwargs['file_path'] = rf"\\?\{kwargs['file_path']}"
29
30
 
@@ -133,3 +133,52 @@ def is_dict_json_serializable(
133
133
  raise e
134
134
  else:
135
135
  return False, str(e)
136
+
137
+
138
+ def append_to_json(
139
+ dict_or_list: Union[dict, list],
140
+ json_file_path: str,
141
+ indent=None,
142
+ use_default_indent=False,
143
+ enable_long_file_path=False,
144
+ print_kwargs: dict = None
145
+ ) -> None:
146
+ """
147
+ Append dictionary or list of dictionaries to json file.
148
+
149
+ :param dict_or_list: dictionary or list of dictionaries to append.
150
+ :param json_file_path: full file path to the json file.
151
+ :param indent: integer number of spaces for indentation.
152
+ If 'ident=0' new lines still will be created. The most compact is 'indent=None' (from documentation)
153
+ So, using default as 'None' and not something else.
154
+ :param use_default_indent: boolean. Default indent for 'json' format in many places is '2'. So, if you don't want
155
+ to set 'indent=2', just set this to 'True'.
156
+ :param enable_long_file_path: Boolean, by default Windows has a limit of 260 characters for file path. If True,
157
+ the long file path will be enabled, and the limit will be 32,767 characters.
158
+ :param print_kwargs: dict, the print_api arguments.
159
+ :return:
160
+ """
161
+
162
+ # Read existing data from the file
163
+ try:
164
+ with open(json_file_path, 'r') as f:
165
+ current_json_file = json.load(f)
166
+ except FileNotFoundError:
167
+ current_json_file: list = []
168
+
169
+ # Append the new message to the existing data
170
+ final_json_list_of_dicts: list[dict] = []
171
+ if isinstance(current_json_file, list):
172
+ current_json_file.append(dict_or_list)
173
+ final_json_list_of_dicts = current_json_file
174
+ elif isinstance(current_json_file, dict):
175
+ final_json_list_of_dicts.append(current_json_file)
176
+ final_json_list_of_dicts.append(dict_or_list)
177
+ else:
178
+ error_message = "The current file is neither a list nor a dictionary."
179
+ raise TypeError(error_message)
180
+
181
+ # Write the data back to the file
182
+ write_json_file(
183
+ final_json_list_of_dicts, json_file_path, indent=indent, use_default_indent=use_default_indent,
184
+ enable_long_file_path=enable_long_file_path, **print_kwargs)
atomicshop/filesystem.py CHANGED
@@ -329,6 +329,30 @@ def remove_directory(directory_path: str, force_readonly: bool = False, print_kw
329
329
  return False
330
330
 
331
331
 
332
+ def clear_directory(directory: str) -> tuple[list[str], list[str]]:
333
+ """
334
+ The function will clear the directory of all files and subdirectories.
335
+ :param directory:
336
+ :return: tuple of lists of removed file paths and removed directory paths.
337
+ """
338
+
339
+ file_paths: list = []
340
+ directory_paths: list = []
341
+ # Iterate through all files and subdirectories in the directory
342
+ for item in os.listdir(directory):
343
+ item_path = os.path.join(directory, item)
344
+ # If it's a file, remove it
345
+ if os.path.isfile(item_path) or os.path.islink(item_path): # Handle symbolic links too
346
+ os.remove(item_path)
347
+ file_paths.append(item_path)
348
+ # If it's a directory, remove it and its contents
349
+ elif os.path.isdir(item_path):
350
+ shutil.rmtree(item_path)
351
+ directory_paths.append(item_path)
352
+
353
+ return file_paths, directory_paths
354
+
355
+
332
356
  def remove_empty_directories(directory_path: str) -> list[str]:
333
357
  """
334
358
  Recursively removes empty directories in the given path, including the given path if it is empty.
@@ -675,12 +699,12 @@ def move_folder_contents_to_folder(
675
699
 
676
700
  if os.path.isdir(s):
677
701
  if os.path.exists(d) and not overwrite:
678
- print(f"Directory {d} already exists. Skipping due to overwrite=False.")
702
+ raise FileExistsError(f"Directory already exists: {d}. Skipping due to overwrite=False.")
679
703
  else:
680
704
  shutil.move(s, d)
681
705
  else:
682
706
  if os.path.exists(d) and not overwrite:
683
- print(f"File {d} already exists. Skipping due to overwrite=False.")
707
+ raise FileExistsError(f"File {d} already exists. Skipping due to overwrite=False.")
684
708
  else:
685
709
  shutil.move(s, d)
686
710
 
@@ -1675,3 +1699,88 @@ def find_file(file_name: str, directory_path: str):
1675
1699
  if filename == file_name:
1676
1700
  return os.path.join(dir_path, filename)
1677
1701
  return None
1702
+
1703
+
1704
+ def create_ubuntu_desktop_shortcut(
1705
+ file_path: str = None,
1706
+ shortcut_name: str = None,
1707
+ command: str = None,
1708
+ working_directory: str = None,
1709
+ icon_path: str = None,
1710
+ terminal: bool = False,
1711
+ comment: str = "Shortcut to execute the Python script",
1712
+ categories: str = "Utility",
1713
+ set_executable: bool = False,
1714
+ set_xfce_exe_checksum: bool = False
1715
+ ):
1716
+ """
1717
+ Create a desktop shortcut on Ubuntu.
1718
+
1719
+ Either file_path or command must be specified.
1720
+ If command is specified, working_directory must be specified.
1721
+
1722
+ :param file_path: string, The file_path to execute when the shortcut is clicked.
1723
+ Example2: '/path/to/script.sh'
1724
+ :param shortcut_name: string, The name of the shortcut.
1725
+ Example: 'My Python Script'
1726
+ Result: 'My Python Script.desktop'
1727
+ :param command: string, The command to execute when the shortcut is clicked.
1728
+ Example: 'python3 /path/to/script.py'
1729
+ :param working_directory: string, The working directory for the command.
1730
+ If None, the command will be executed in the same script's directory.
1731
+ :param icon_path: string, The path to the icon file.
1732
+ :param terminal: boolean, If True, the command will be executed in a terminal.
1733
+ :param comment: string, A comment to describe the shortcut.
1734
+ :param categories: string, The categories of the shortcut.
1735
+ :param set_executable: boolean, If True, the shortcut will be made executable.
1736
+ :param set_xfce_exe_checksum: boolean, If True, the shortcut will be made safe executable for XFCE.
1737
+
1738
+ :return: None
1739
+ """
1740
+
1741
+ if not file_path and not command:
1742
+ raise ValueError("Either 'file_path' or 'command' must be specified.")
1743
+ if command and file_path:
1744
+ raise ValueError("Only one of 'file_path' or 'command' can be specified.")
1745
+ if command and not working_directory:
1746
+ raise ValueError("Working directory must be specified if 'command' is specified.")
1747
+
1748
+ from .permissions import ubuntu_permissions
1749
+
1750
+ # Get the user's directory.
1751
+ desktop_dir = os.path.expanduser("~/Desktop")
1752
+
1753
+ # Full path to the .desktop file
1754
+ shortcut_path = os.path.join(desktop_dir, f"{shortcut_name}.desktop")
1755
+
1756
+ if not working_directory:
1757
+ working_directory = os.path.dirname(file_path)
1758
+
1759
+ if not shortcut_name:
1760
+ shortcut_name: str = Path(file_path).stem
1761
+
1762
+ # Generate the content for the .desktop file
1763
+ desktop_entry = [
1764
+ "[Desktop Entry]",
1765
+ "Version=1.0",
1766
+ "Type=Application",
1767
+ f"Name={shortcut_name}",
1768
+ f"Exec={file_path}",
1769
+ f"Path={working_directory}",
1770
+ f"Icon={icon_path}" if icon_path else "",
1771
+ f"Terminal={'true' if terminal else 'false'}",
1772
+ f"Comment={comment}",
1773
+ f"Categories={categories};",
1774
+ ]
1775
+
1776
+ # Write the .desktop file
1777
+ with open(shortcut_path, "w") as shortcut_file:
1778
+ shortcut_file.write("\n".join(line for line in desktop_entry if line)) # Skip empty lines
1779
+
1780
+ # Make the .desktop file executable
1781
+ if set_executable:
1782
+ ubuntu_permissions.set_executable(shortcut_path)
1783
+
1784
+ # Make the .desktop file safe executable for XFCE
1785
+ if set_xfce_exe_checksum:
1786
+ ubuntu_permissions.set_xfce_exe_checksum(shortcut_path)
@@ -113,30 +113,14 @@ def save_message_worker(
113
113
  if record_message_dict is None:
114
114
  break
115
115
 
116
- # Read existing data from the file
117
116
  try:
118
- with open(record_file_path, 'r') as f:
119
- current_json_file = json.load(f)
120
- except FileNotFoundError:
121
- current_json_file: list = []
122
-
123
- # Append the new message to the existing data
124
- final_json_list_of_dicts: list[dict] = []
125
- if isinstance(current_json_file, list):
126
- current_json_file.append(record_message_dict)
127
- final_json_list_of_dicts = current_json_file
128
- elif isinstance(current_json_file, dict):
129
- final_json_list_of_dicts.append(current_json_file)
130
- final_json_list_of_dicts.append(record_message_dict)
131
- else:
132
- error_message = "The current file is neither a list nor a dictionary."
133
- print_api(error_message, logger_method="critical", logger=logger)
134
- raise TypeError(error_message)
135
-
136
- # Write the data back to the file
137
- jsons.write_json_file(
138
- final_json_list_of_dicts, record_file_path, indent=2,
139
- enable_long_file_path=True, **{'logger': logger})
117
+ jsons.append_to_json(
118
+ record_message_dict, record_file_path, indent=2,
119
+ enable_long_file_path=True, print_kwargs={'logger': logger}
120
+ )
121
+ except TypeError as e:
122
+ print_api(str(e), logger_method="critical", logger=logger)
123
+ raise e
140
124
 
141
125
  logger.info(f"Recorded to file: {record_file_path}")
142
126
 
@@ -33,6 +33,48 @@ def set_executable(file_path: str):
33
33
  os.chmod(file_path, os.stat(file_path).st_mode | stat.S_IXUSR)
34
34
 
35
35
 
36
+ def set_trusted_executable(file_path: str):
37
+ """
38
+ Function sets the executable permission on a file and marks it as trusted.
39
+ :param file_path: str, path to the file.
40
+ :return:
41
+ """
42
+
43
+ # Check if the file exists
44
+ if not os.path.exists(file_path):
45
+ raise FileNotFoundError(f"The file does not exist: {file_path} ")
46
+
47
+ # Execute the `gio set` command
48
+ subprocess.run(
49
+ ["gio", "set", file_path, "metadata::trusted", "true"],
50
+ check=True
51
+ )
52
+
53
+
54
+ def set_xfce_exe_checksum(desktop_file_path):
55
+ # Expand `~` to the full home directory path
56
+ desktop_file_path = os.path.expanduser(desktop_file_path)
57
+
58
+ # Ensure the file exists
59
+ if not os.path.exists(desktop_file_path):
60
+ raise FileNotFoundError(f"The file does not exist: {desktop_file_path} ")
61
+
62
+ # Calculate the SHA256 checksum of the file
63
+ result = subprocess.run(
64
+ ["sha256sum", desktop_file_path],
65
+ stdout=subprocess.PIPE,
66
+ check=True,
67
+ text=True
68
+ )
69
+ checksum = result.stdout.split()[0]
70
+
71
+ # Set the metadata::xfce-exe-checksum attribute using `gio`
72
+ subprocess.run(
73
+ ["gio", "set", "-t", "string", desktop_file_path, "metadata::xfce-exe-checksum", checksum],
74
+ check=True
75
+ )
76
+
77
+
36
78
  def change_file_owner(file_path: str, username: str):
37
79
  """
38
80
  Function changes the owner of the file to the specified user.
atomicshop/tempfiles.py CHANGED
@@ -1,4 +1,3 @@
1
- # v1.0.3 - 01.04.2021 - 15:30
2
1
  import os
3
2
  import datetime
4
3
  import tempfile
@@ -59,4 +58,4 @@ class TempFile:
59
58
  self.file_path: str = self.directory + os.sep + self.file_name
60
59
 
61
60
  def remove(self):
62
- os.remove(self.file_path)
61
+ os.remove(self.file_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.18.27
3
+ Version: 2.18.29
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=cgFc16qqVGnOgJgV1Zh4BmuMSDReWteBDmPf5OF4EiI,124
1
+ atomicshop/__init__.py,sha256=vD4D8D_jAMvDG5p9XvZfPSYd4zd_0MaNWcj-D9lkvE8,124
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
4
4
  atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
@@ -14,7 +14,7 @@ atomicshop/dns.py,sha256=5Gimq_WY2arqg7BeGmR7P--fGfnH0Dsh8lrOt_H0jRY,6817
14
14
  atomicshop/domains.py,sha256=Rxu6JhhMqFZRcoFs69IoEd1PtYca0lMCG6F1AomP7z4,3197
15
15
  atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
16
16
  atomicshop/file_types.py,sha256=-0jzQMRlmU1AP9DARjk-HJm1tVE22E6ngP2mRblyEjY,763
17
- atomicshop/filesystem.py,sha256=StVeiGCjlpvMOmB-4SW-s7eR_qxYofW9jsfh1ewpaG4,63263
17
+ atomicshop/filesystem.py,sha256=jSFHv34KhR4r2dt65pUYNy3bCqBtnOiqqxOo_vdrmdA,67573
18
18
  atomicshop/functions.py,sha256=pK8hoCE9z61PtWCxQJsda7YAphrLH1wxU5x-1QJP-sY,499
19
19
  atomicshop/get_process_list.py,sha256=8cxb7gKe9sl4R6H2yMi8J6oe-RkonTvCdKjRFqi-Fs4,6075
20
20
  atomicshop/get_process_name_cmd_dll.py,sha256=CtaSp3mgxxJKCCVW8BLx6BJNx4giCklU_T7USiCEwfc,5162
@@ -39,7 +39,7 @@ atomicshop/ssh_remote.py,sha256=Mxixqs2-xGy1bhbcP0LKqjxKTNPz1Gmzz8PzO8aLB4c,1734
39
39
  atomicshop/sys_functions.py,sha256=MTBxRve5bh58SPvhX3gMiGqHlSBuI_rdNN1NnnBBWqI,906
40
40
  atomicshop/system_resource_monitor.py,sha256=yHdBU4mAVqoVS0Nn_SM_H42i4PgsgXDaXaMxfnL5CgA,14588
41
41
  atomicshop/system_resources.py,sha256=iKUvVSaXR47inmr3cTYsgNfclT38dRia2oupnlhIpK4,9290
42
- atomicshop/tempfiles.py,sha256=uq1ve2WlWehZ3NOTXJnpBBMt6HyCdBufqedF0HyzA6k,2517
42
+ atomicshop/tempfiles.py,sha256=cI8IlINHAcqomBtLOQIedYDE--1J5GcUsFuOQ6fDn_Y,2484
43
43
  atomicshop/timer.py,sha256=7Zw1KRV0acHCRATMnanyX2MLBb63Hc-6us3rCZ9dNlY,2345
44
44
  atomicshop/urls.py,sha256=aJ0NGS9qqaKeqjkkWBs80jaBBg6MYBiPuLIyPGxscVc,1557
45
45
  atomicshop/uuids.py,sha256=JSQdm3ZTJiwPQ1gYe6kU0TKS_7suwVrHc8JZDGYlydM,2214
@@ -100,7 +100,7 @@ atomicshop/basics/isinstancing.py,sha256=fQ35xfqbguQz2BUn-3a4KVGskhTcIn8JjRtxV2r
100
100
  atomicshop/basics/list_of_classes.py,sha256=PJoE1VJdhhQ4gSFr88zW7IApXd4Ez7xLz-7vAM-7gug,978
101
101
  atomicshop/basics/list_of_dicts.py,sha256=tj0LNPf1ljNI_qpoO-PiOT4Ulmk1M-UpTGyn9twVcw8,8039
102
102
  atomicshop/basics/lists.py,sha256=I0C62vrDrNwCTNl0EjUZNa1Jsd8l0rTkp28GEx9QoEI,4258
103
- atomicshop/basics/multiprocesses.py,sha256=nSskxJSlEdalPM_Uf8cc9kAYYlVwYM1GonBLAhCL2mM,18831
103
+ atomicshop/basics/multiprocesses.py,sha256=oU6LjcLLGBtPIGJzZBpDWoLU3HRmMoanITEOE2luAYw,18799
104
104
  atomicshop/basics/numbers.py,sha256=ESX0z_7o_ok3sOmCKAUBoZinATklgMy2v-4RndqXlVM,1837
105
105
  atomicshop/basics/package_module.py,sha256=fBd0uVgFce25ZCVtLq83iyowRlbwdWYFj_t4Ml7LU14,391
106
106
  atomicshop/basics/randoms.py,sha256=DmYLtnIhDK29tAQrGP1Nt-A-v8WC7WIEB8Edi-nk3N4,282
@@ -119,8 +119,8 @@ atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=OM-bkK38uYMwWLZKN
119
119
  atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
120
  atomicshop/file_io/csvs.py,sha256=zv0kKjRT-ZWRi0WpMIUQ_FKyP9Dt0f5Bc98Qsj6ClPU,9495
121
121
  atomicshop/file_io/docxs.py,sha256=Nyt3hSpzwqUKZEP5p5efqNpjFs9XqkK40Kp7BbbPo7E,6245
122
- atomicshop/file_io/file_io.py,sha256=5Kl0P6vF4GQVdwew1lzHLb-db9qiMvDjTgccbi5P-zk,7167
123
- atomicshop/file_io/jsons.py,sha256=q9ZU8slBKnHLrtn3TnbK1qxrRpj5ZvCm6AlsFzoANjo,5303
122
+ atomicshop/file_io/file_io.py,sha256=8pKH08ILN91gfeNC0hrtLCx7l9ZgmcPAYIcLydDtZ-k,7198
123
+ atomicshop/file_io/jsons.py,sha256=GJyVlGTcdhjZ-andfz7_dYVk1O74f-23Mc9PDmdjtPI,7424
124
124
  atomicshop/file_io/tomls.py,sha256=ol8EvQPf9sryTmZUf1v55BYSUQ6ml7HVVBHpNKbsIlA,9768
125
125
  atomicshop/file_io/xlsxs.py,sha256=v_dyg9GD4LqgWi6wA1QuWRZ8zG4ZwB6Dz52ytdcmmmI,2184
126
126
  atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,2104
@@ -140,7 +140,7 @@ atomicshop/mitm/engines/create_module_template.py,sha256=TAzsA4eLD2wYr7auuL4Nf_7
140
140
  atomicshop/mitm/engines/create_module_template_example.py,sha256=X5xhvbV6-g9jU_bQVhf_crZmaH50LRWz3bS-faQ18ds,489
141
141
  atomicshop/mitm/engines/__parent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
142
  atomicshop/mitm/engines/__parent/parser___parent.py,sha256=HHaCXhScl3OlPjz6eUxsDpJaZyk6BNuDMc9xCkeo2Ws,661
143
- atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=exfElkgOU57hupV6opRCeYPHw91GIkIZL6UY3f2OClM,5635
143
+ atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=vG2h46CojK4jIinXmME2VwJFSWKygh4ayMwZyejwwI0,4846
144
144
  atomicshop/mitm/engines/__parent/responder___parent.py,sha256=yEgR33CkAd1b9jyH5E8I4E16upqjlcK3WLo3BFHdjyk,9157
145
145
  atomicshop/mitm/engines/__reference_general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
146
  atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256=57MEPZMAjTO6xBDZ-yt6lgGJyqRrP0Do5Gk_cgCiPns,2998
@@ -159,7 +159,7 @@ atomicshop/monitor/checks/process_running.py,sha256=x66wd6-l466r8sbRQaIli0yswyGt
159
159
  atomicshop/monitor/checks/url.py,sha256=1PvKt_d7wFg7rDMFpUejAQhj0mqWsmlmrNfjNAV2G4g,4123
160
160
  atomicshop/permissions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
161
161
  atomicshop/permissions/permissions.py,sha256=CYTDVOI0jh9ks0ZLnnOuPzppgCszFEc9-92DTkVTYi4,522
162
- atomicshop/permissions/ubuntu_permissions.py,sha256=xmLfrBh-uhJqmZzx754Yt2ECBsZI5uwWECg6hCsTtek,4649
162
+ atomicshop/permissions/ubuntu_permissions.py,sha256=n8z1vcIXDts4zLVue33dtJiTopjgEAYPg4dqFn0qwwc,5943
163
163
  atomicshop/permissions/win_permissions.py,sha256=eDQm1jfK9x_hkbLqIJjFTwfqinAWQ0iSr0kW3XrF1BE,1272
164
164
  atomicshop/process_poller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
165
165
  atomicshop/process_poller/process_pool.py,sha256=4Qs427qd7OcBxu5PMFU5PTmyuxRy0vgj2GLsRt0IoEw,9565
@@ -321,8 +321,8 @@ atomicshop/wrappers/socketw/statistics_csv.py,sha256=fgMzDXI0cybwUEqAxprRmY3lqbh
321
321
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
322
322
  atomicshop/wrappers/winregw/winreg_installed_software.py,sha256=Qzmyktvob1qp6Tjk2DjLfAqr_yXV0sgWzdMW_9kwNjY,2345
323
323
  atomicshop/wrappers/winregw/winreg_network.py,sha256=AENV88H1qDidrcpyM9OwEZxX5svfi-Jb4N6FkS1xtqA,8851
324
- atomicshop-2.18.27.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
325
- atomicshop-2.18.27.dist-info/METADATA,sha256=P-gMfXaiasKYKaXDUsQbwZ-YtcwJ-nFJNVBIW9UbTB4,10631
326
- atomicshop-2.18.27.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
327
- atomicshop-2.18.27.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
328
- atomicshop-2.18.27.dist-info/RECORD,,
324
+ atomicshop-2.18.29.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
325
+ atomicshop-2.18.29.dist-info/METADATA,sha256=qUnmPIO-_pwUQ74EV5jl84JWBrlUigxl-lavHMHKEHQ,10631
326
+ atomicshop-2.18.29.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
327
+ atomicshop-2.18.29.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
328
+ atomicshop-2.18.29.dist-info/RECORD,,