atomicshop 2.12.19__py3-none-any.whl → 2.12.20__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 +1 -1
- atomicshop/startup/__init__.py +0 -0
- atomicshop/startup/win/__init__.py +0 -0
- atomicshop/startup/win/startup_folder.py +53 -0
- atomicshop/startup/win/task_scheduler.py +119 -0
- atomicshop/wrappers/loggingw/loggingw.py +82 -4
- atomicshop/wrappers/pywin32w/winshell.py +19 -0
- {atomicshop-2.12.19.dist-info → atomicshop-2.12.20.dist-info}/METADATA +1 -1
- {atomicshop-2.12.19.dist-info → atomicshop-2.12.20.dist-info}/RECORD +12 -7
- {atomicshop-2.12.19.dist-info → atomicshop-2.12.20.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.12.19.dist-info → atomicshop-2.12.20.dist-info}/WHEEL +0 -0
- {atomicshop-2.12.19.dist-info → atomicshop-2.12.20.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from ...wrappers.pywin32w import winshell
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
STARTUP_FOLDER = os.path.join(os.environ['APPDATA'], 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def add_to_startup_folder_with_shortcut(exe_file_path: str, shortcut_name: str) -> str:
|
|
11
|
+
"""
|
|
12
|
+
This function will create a shortcut in the startup folder to your executable.
|
|
13
|
+
|
|
14
|
+
:param exe_file_path: The path to your executable file.
|
|
15
|
+
:param shortcut_name: The name of the shortcut file to create in the startup folder.
|
|
16
|
+
No need to add the ".lnk" extension.
|
|
17
|
+
:return: The path to the shortcut file created.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# Get the startup folder path and create if non-existent.
|
|
21
|
+
Path(STARTUP_FOLDER).mkdir(parents=True, exist_ok=True)
|
|
22
|
+
|
|
23
|
+
shortcut_file_path = str(Path(STARTUP_FOLDER, f'{shortcut_name}.lnk'))
|
|
24
|
+
|
|
25
|
+
# Create a shortcut to the executable file.
|
|
26
|
+
winshell.create_shortcut(exe_file_path, shortcut_file_path)
|
|
27
|
+
|
|
28
|
+
return shortcut_file_path
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def is_in_startup_folder(shortcut_name: str):
|
|
32
|
+
"""
|
|
33
|
+
This function will check if the shortcut is in the startup folder.
|
|
34
|
+
|
|
35
|
+
:param shortcut_name: The name of the shortcut file to check in the startup folder.
|
|
36
|
+
No need to add the ".LNK" extension.
|
|
37
|
+
:return: True if the shortcut is in the startup folder, False otherwise.
|
|
38
|
+
"""
|
|
39
|
+
return Path(STARTUP_FOLDER, f'{shortcut_name}.lnk').exists()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def remove_from_startup_folder(shortcut_name: str):
|
|
43
|
+
"""
|
|
44
|
+
This function will remove the shortcut from the startup folder.
|
|
45
|
+
|
|
46
|
+
:param shortcut_name: The name of the shortcut file to remove from the startup folder.
|
|
47
|
+
No need to add the ".LNK" extension.
|
|
48
|
+
"""
|
|
49
|
+
shortcut_file_path = Path(STARTUP_FOLDER, f'{shortcut_name}.lnk')
|
|
50
|
+
if shortcut_file_path.exists():
|
|
51
|
+
shortcut_file_path.unlink()
|
|
52
|
+
return True
|
|
53
|
+
return False
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import datetime
|
|
3
|
+
|
|
4
|
+
import win32com.client
|
|
5
|
+
import pythoncom
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
TRIGGER_ONE_TIME: int = 1
|
|
9
|
+
TRIGGER_DAILY: int = 2
|
|
10
|
+
TRIGGER_AT_SYSTEM_STARTUP: int = 8
|
|
11
|
+
TRIGGER_ON_LOGON: int = 9
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def create_on_logon_task_with_system_privileges(exe_file_path: str, task_name: str, user_id: str = None):
|
|
15
|
+
"""
|
|
16
|
+
This function will add a task to the Windows Task Scheduler with system privileges.
|
|
17
|
+
|
|
18
|
+
:param exe_file_path: The path to your executable file.
|
|
19
|
+
:param task_name: The name of the task to create in the Task Scheduler.
|
|
20
|
+
:param user_id: The user ID to run the task as.
|
|
21
|
+
None: the task will run for every user that logs on.
|
|
22
|
+
"SYSTEM": is a common user ID to run tasks with system privileges.
|
|
23
|
+
:return: True if the task was added successfully, False otherwise.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
scheduler = win32com.client.Dispatch('Schedule.Service')
|
|
27
|
+
scheduler.Connect()
|
|
28
|
+
|
|
29
|
+
root_folder = scheduler.GetFolder('\\')
|
|
30
|
+
task_def = scheduler.NewTask(0)
|
|
31
|
+
|
|
32
|
+
# Set up registration information for the task
|
|
33
|
+
reg_info = task_def.RegistrationInfo
|
|
34
|
+
reg_info.Description = f'Task to run {os.path.basename(exe_file_path)} at logon'
|
|
35
|
+
reg_info.Author = 'Your Name'
|
|
36
|
+
|
|
37
|
+
# Set up the principal for the task
|
|
38
|
+
principal = task_def.Principal
|
|
39
|
+
if user_id is not None:
|
|
40
|
+
principal.UserId = user_id
|
|
41
|
+
# principal.LogonType = 3 # TaskLogonTypeInteractiveToken, Only run when the user is logged on.
|
|
42
|
+
principal.LogonType = 1 # 1 is for password not required
|
|
43
|
+
principal.RunLevel = 1 # TaskRunLevelHighest
|
|
44
|
+
|
|
45
|
+
# Create the logon trigger
|
|
46
|
+
trigger = task_def.Triggers.Create(TRIGGER_ON_LOGON)
|
|
47
|
+
if user_id:
|
|
48
|
+
trigger.UserId = user_id
|
|
49
|
+
trigger.Id = "LogonTriggerId"
|
|
50
|
+
trigger.Enabled = True
|
|
51
|
+
trigger.StartBoundary = datetime.datetime.now().isoformat() # Set start boundary to current time in ISO format
|
|
52
|
+
|
|
53
|
+
# Create the action to run the executable
|
|
54
|
+
action = task_def.Actions.Create(0) # 0 stands for TASK_ACTION_EXEC
|
|
55
|
+
action.Path = exe_file_path
|
|
56
|
+
action.WorkingDirectory = os.path.dirname(exe_file_path)
|
|
57
|
+
action.Arguments = ''
|
|
58
|
+
|
|
59
|
+
# Set task settings
|
|
60
|
+
settings = task_def.Settings
|
|
61
|
+
settings.Enabled = True
|
|
62
|
+
settings.StartWhenAvailable = True
|
|
63
|
+
settings.Hidden = False
|
|
64
|
+
settings.StopIfGoingOnBatteries = False
|
|
65
|
+
settings.DisallowStartIfOnBatteries = False
|
|
66
|
+
# Sets the limit to zero, which means the task will run indefinitely. The default is 3 days.
|
|
67
|
+
settings.ExecutionTimeLimit = 'PT0S'
|
|
68
|
+
|
|
69
|
+
# Register the task
|
|
70
|
+
root_folder.RegisterTaskDefinition(
|
|
71
|
+
task_name, task_def, 6, # 6 is for CREATE_OR_UPDATE
|
|
72
|
+
None, # No user (runs in system context)
|
|
73
|
+
None, # No password
|
|
74
|
+
3
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def is_task_in_scheduler(task_name: str, scheduler_instance=None) -> bool:
|
|
79
|
+
"""
|
|
80
|
+
This function will check if the task is in the Windows Task Scheduler.
|
|
81
|
+
|
|
82
|
+
:param task_name: The name of the task to check in the Task Scheduler.
|
|
83
|
+
:param scheduler_instance: The instance of the Task Scheduler to use.
|
|
84
|
+
If None, a new instance will be created.
|
|
85
|
+
:return: True if the task is in the Task Scheduler, False otherwise.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
if scheduler_instance is None:
|
|
89
|
+
scheduler_instance = win32com.client.Dispatch('Schedule.Service')
|
|
90
|
+
scheduler_instance.Connect()
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
root_folder = scheduler_instance.GetFolder('\\')
|
|
94
|
+
root_folder.GetTask(task_name)
|
|
95
|
+
return True
|
|
96
|
+
except pythoncom.com_error as e:
|
|
97
|
+
if e.hresult == -2147352567 and e.excepinfo[5] == -2147024894: # HRESULT code for "Task does not exist"
|
|
98
|
+
return False
|
|
99
|
+
else:
|
|
100
|
+
raise
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def remove_task_from_scheduler(task_name: str) -> bool:
|
|
104
|
+
"""
|
|
105
|
+
This function will remove the task from the Windows Task Scheduler.
|
|
106
|
+
|
|
107
|
+
:param task_name: The name of the task to remove from the Task Scheduler.
|
|
108
|
+
:return: True if the task was removed successfully, False otherwise.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
scheduler_instance = win32com.client.Dispatch('Schedule.Service')
|
|
112
|
+
scheduler_instance.Connect()
|
|
113
|
+
|
|
114
|
+
if not is_task_in_scheduler(task_name, scheduler_instance=scheduler_instance):
|
|
115
|
+
return False
|
|
116
|
+
else:
|
|
117
|
+
root_folder = scheduler_instance.GetFolder('\\')
|
|
118
|
+
root_folder.GetTask(task_name)
|
|
119
|
+
return True
|
|
@@ -67,12 +67,90 @@ def get_logger_with_timedfilehandler(
|
|
|
67
67
|
|
|
68
68
|
def get_logger_with_stream_handler_and_timedfilehandler(
|
|
69
69
|
logger_name: str,
|
|
70
|
-
directory_path,
|
|
71
|
-
|
|
70
|
+
directory_path,
|
|
71
|
+
file_name: str = None,
|
|
72
|
+
file_extension: str = '.txt',
|
|
73
|
+
logging_level="DEBUG",
|
|
74
|
+
formatter_filehandler='default',
|
|
72
75
|
formatter_streamhandler: str = "%(levelname)s | %(threadName)s | %(name)s | %(message)s",
|
|
73
|
-
formatter_message_only: bool = False,
|
|
74
|
-
|
|
76
|
+
formatter_message_only: bool = False,
|
|
77
|
+
disable_duplicate_ms: bool = False,
|
|
78
|
+
when: str = "midnight",
|
|
79
|
+
interval: int = 1,
|
|
80
|
+
delay: bool = True,
|
|
81
|
+
encoding=None
|
|
75
82
|
) -> logging.Logger:
|
|
83
|
+
"""
|
|
84
|
+
Function to get a logger and add StreamHandler and TimedRotatingFileHandler to it.
|
|
85
|
+
|
|
86
|
+
:param logger_name: Name of the logger.
|
|
87
|
+
:param directory_path: string, Path to the directory where the log file will be created.
|
|
88
|
+
:param file_name: string, Name of the log file without file extension, since we add it through separate argument.
|
|
89
|
+
If not provided, logger name will be used.
|
|
90
|
+
:param file_extension: string, Extension of the log file. Default is '.txt'.
|
|
91
|
+
'.txt': Text file.
|
|
92
|
+
'.csv': CSV file.
|
|
93
|
+
'.json': JSON file.
|
|
94
|
+
:param logging_level: str or int, Logging level for the handler, that will use the logger while initiated.
|
|
95
|
+
:param formatter_filehandler: string, Formatter to use for handler. It is template of how a message will look like.
|
|
96
|
+
None: No formatter will be used.
|
|
97
|
+
'default': Default formatter will be used for each file extension:
|
|
98
|
+
.txt: "%(asctime)s | %(levelname)s | %(threadName)s | %(name)s | %(message)s"
|
|
99
|
+
.csv: "%(asctime)s,%(levelname)s,%(threadName)s,%(name)s,%(message)s"
|
|
100
|
+
.json: '{"time": "%(asctime)s", "level": "%(levelname)s", "thread": "%(threadName)s",
|
|
101
|
+
"logger": "%(name)s", "message": "%(message)s"}'
|
|
102
|
+
:param formatter_streamhandler: string, Formatter to use for StreamHandler. It is template of how a message will
|
|
103
|
+
look like.
|
|
104
|
+
:param formatter_message_only: bool, If set to True, formatter will be used only for the 'message' part.
|
|
105
|
+
:param disable_duplicate_ms: bool, If set to True, duplicate milliseconds will be removed from formatter
|
|
106
|
+
'asctime' element.
|
|
107
|
+
:param when: string, When to rotate the log file. Default is 'midnight'.
|
|
108
|
+
[when="midnight"] is set to rotate the filename at midnight. This means that the current file name will be
|
|
109
|
+
added Yesterday's date to the end of the file and today's file will continue to write at the same
|
|
110
|
+
filename. Also, if the script finished working on 25.11.2021, the name of the log file will be "test.log"
|
|
111
|
+
If you run the script again on 28.11.2021, the logging module will take the last modification date of
|
|
112
|
+
the file "test.log" and assign a date to it: test.log.2021_11_25
|
|
113
|
+
The log filename of 28.11.2021 will be called "test.log" again.
|
|
114
|
+
:param interval: int, Interval to rotate the log file. Default is 1.
|
|
115
|
+
If 'when="midnight"' and 'interval=1', then the log file will be rotated every midnight.
|
|
116
|
+
If 'when="midnight"' and 'interval=2', then the log file will be rotated every 2nd midnights.
|
|
117
|
+
:param delay: bool, If set to True, the log file will be created only if there's something to write.
|
|
118
|
+
:param encoding: string, Encoding to use for the log file. Default is None.
|
|
119
|
+
|
|
120
|
+
:return: Logger.
|
|
121
|
+
|
|
122
|
+
================================================================================================================
|
|
123
|
+
|
|
124
|
+
Working example to write CSV logs to the file and output messages to the console:
|
|
125
|
+
from atomicshop.wrappers.loggingw import loggingw
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def main():
|
|
129
|
+
def output_csv_header():
|
|
130
|
+
# Since there is no implementation of header in logging file handler modules, we'll do it manually each time.
|
|
131
|
+
header: list = ['time',
|
|
132
|
+
'host',
|
|
133
|
+
'path',
|
|
134
|
+
'error'
|
|
135
|
+
]
|
|
136
|
+
error_logger.info(','.join(header))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
output_directory: str = "D:\\logs"
|
|
140
|
+
|
|
141
|
+
error_logger = loggingw.get_logger_with_stream_handler_and_timedfilehandler(
|
|
142
|
+
logger_name="errors", directory_path=output_directory,
|
|
143
|
+
file_extension=".csv", formatter_message_only=True
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
output_csv_header()
|
|
147
|
+
|
|
148
|
+
error_logger.info(f"{datetime.now()},host1,/path/to/file,error message")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
main()
|
|
153
|
+
"""
|
|
76
154
|
logger = get_logger_with_level(logger_name, logging_level)
|
|
77
155
|
add_stream_handler(logger, logging_level, formatter_streamhandler, formatter_message_only)
|
|
78
156
|
add_timedfilehandler_with_queuehandler(
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from win32com.client import Dispatch
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def create_shortcut(file_path_to_link: str, shortcut_file_path: str):
|
|
7
|
+
"""
|
|
8
|
+
Create a shortcut in the startup folder to the specified file.
|
|
9
|
+
|
|
10
|
+
:param file_path_to_link: The path to the file you want to create a shortcut to.
|
|
11
|
+
:param shortcut_file_path: The name of the shortcut file. Should be with the ".lnk" extension.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
shell = Dispatch('WScript.Shell')
|
|
15
|
+
shortcut = shell.CreateShortCut(shortcut_file_path)
|
|
16
|
+
shortcut.Targetpath = file_path_to_link
|
|
17
|
+
shortcut.WorkingDirectory = str(Path(file_path_to_link).parent)
|
|
18
|
+
shortcut.Description = f"Shortcut for {Path(file_path_to_link).name}"
|
|
19
|
+
shortcut.save()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=U5HBBCgZbCFjvJTS1UanW_wKk5yZesdp5sAnQ2RGDSg,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
|
|
@@ -142,6 +142,10 @@ atomicshop/monitor/checks/process_running.py,sha256=x66wd6-l466r8sbRQaIli0yswyGt
|
|
|
142
142
|
atomicshop/monitor/checks/url.py,sha256=1PvKt_d7wFg7rDMFpUejAQhj0mqWsmlmrNfjNAV2G4g,4123
|
|
143
143
|
atomicshop/ssh_scripts/process_from_ipv4.py,sha256=uDBKZ2Ds20614JW1xMLr4IPB-z1LzIwy6QH5-SJ4j0s,1681
|
|
144
144
|
atomicshop/ssh_scripts/process_from_port.py,sha256=uDTkVh4zc3HOTTGv1Et3IxM3PonDJCPuFRL6rnZDQZ4,1389
|
|
145
|
+
atomicshop/startup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
146
|
+
atomicshop/startup/win/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
147
|
+
atomicshop/startup/win/startup_folder.py,sha256=2RZEyF-Mf8eWPlt_-OaoGKKnMs6YhELEzJZ376EI0E0,1891
|
|
148
|
+
atomicshop/startup/win/task_scheduler.py,sha256=qALe-8sfthYxsdCViH2r8OsH3x-WauDqteg5RzElPdk,4348
|
|
145
149
|
atomicshop/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
146
150
|
atomicshop/wrappers/_process_wrapper_curl.py,sha256=XkZZXYl7D0Q6UfdWqy-18AvpU0yVp9i2BVD2qRcXlkk,841
|
|
147
151
|
atomicshop/wrappers/_process_wrapper_tar.py,sha256=WUMZFKNrlG4nJP9tWZ51W7BR1j_pIjsjgyAStmWjRGs,655
|
|
@@ -214,7 +218,7 @@ atomicshop/wrappers/loggingw/checks.py,sha256=AGFsTsLxHQd1yAraa5popqLaGO9VM0KpcP
|
|
|
214
218
|
atomicshop/wrappers/loggingw/formatters.py,sha256=mUtcJJfmhLNrwUVYShXTmdu40dBaJu4TS8FiuTXI7ys,7189
|
|
215
219
|
atomicshop/wrappers/loggingw/handlers.py,sha256=qm5Fbu8eDmlstMduUe5nKUlJU5IazFkSnQizz8Qt2os,5479
|
|
216
220
|
atomicshop/wrappers/loggingw/loggers.py,sha256=DHOOTAtqkwn1xgvLHSkOiBm6yFGNuQy1kvbhG-TDog8,2374
|
|
217
|
-
atomicshop/wrappers/loggingw/loggingw.py,sha256=
|
|
221
|
+
atomicshop/wrappers/loggingw/loggingw.py,sha256=TJBT8n9wCcAgrnjvT3sz3OvRqJ0A3Q5GtYt7ZncvVv4,16146
|
|
218
222
|
atomicshop/wrappers/loggingw/reading.py,sha256=CtYOwOLFHj_hqYyZx-dKUo5ZDrn3cO-f7vU4EX515xI,14980
|
|
219
223
|
atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
220
224
|
atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=QZg-R2iTQt7kFb8wNtnTmwraSGwvUs34JIasdbNa7ZU,5154
|
|
@@ -233,6 +237,7 @@ atomicshop/wrappers/psutilw/disks.py,sha256=3ZSVoommKH1TWo37j_83frB-NqXF4Nf5q5mB
|
|
|
233
237
|
atomicshop/wrappers/psutilw/memories.py,sha256=_S0aL8iaoIHebd1vOFrY_T9aROM5Jx2D5CvDh_4j0Vc,528
|
|
234
238
|
atomicshop/wrappers/psutilw/psutilw.py,sha256=G22ZQfGnqX15-feD8KUXfEZO4pFkIEnB8zgPzJ2jc7M,20868
|
|
235
239
|
atomicshop/wrappers/psycopgw/psycopgw.py,sha256=XJvVf0oAUjCHkrYfKeFuGCpfn0Oxj3u4SbKMKA1508E,7118
|
|
240
|
+
atomicshop/wrappers/pywin32w/winshell.py,sha256=i2bKiMldPU7_azsD5xGQDdMwjaM7suKJd3k0Szmcs6c,723
|
|
236
241
|
atomicshop/wrappers/pywin32w/wmi_win32process.py,sha256=qMzXtJ5hBZ5ydAyqpDbSx0nO2RJQL95HdmV5SzNKMhk,6826
|
|
237
242
|
atomicshop/wrappers/socketw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
238
243
|
atomicshop/wrappers/socketw/accepter.py,sha256=HQC1EyZmyUtVEfFbaBkHCE-VZp6RWyd9mEqAkgsE1fk,1749
|
|
@@ -250,8 +255,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
|
|
|
250
255
|
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
|
|
251
256
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
|
|
252
257
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
|
|
253
|
-
atomicshop-2.12.
|
|
254
|
-
atomicshop-2.12.
|
|
255
|
-
atomicshop-2.12.
|
|
256
|
-
atomicshop-2.12.
|
|
257
|
-
atomicshop-2.12.
|
|
258
|
+
atomicshop-2.12.20.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
259
|
+
atomicshop-2.12.20.dist-info/METADATA,sha256=tpZ7mC5c8cpsmgMGGFRrXl5NUsNi8yfGpcMhH8HEYFY,10479
|
|
260
|
+
atomicshop-2.12.20.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
261
|
+
atomicshop-2.12.20.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
262
|
+
atomicshop-2.12.20.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|