atomicshop 2.14.8__py3-none-any.whl → 2.14.9__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.14.8'
4
+ __version__ = '2.14.9'
@@ -0,0 +1,79 @@
1
+ import logging
2
+ import os
3
+
4
+
5
+ class HeaderFilter(logging.Filter):
6
+ """
7
+ A logging.Filter that writes a header to a log file if the file is empty (
8
+ i.e., no log records have been written, i.e.2, on file rotation).
9
+ """
10
+ def __init__(self, header, baseFilename):
11
+ super().__init__()
12
+ self.header = header
13
+ self.baseFilename = baseFilename
14
+ self._write_header_if_needed()
15
+
16
+ def _write_header_if_needed(self):
17
+ if not os.path.exists(self.baseFilename) or os.path.getsize(self.baseFilename) == 0:
18
+ self._write_header()
19
+
20
+ def _write_header(self):
21
+ if self.header:
22
+ with open(self.baseFilename, 'a') as f:
23
+ f.write(self.header + '\n')
24
+
25
+ def filter(self, record):
26
+ self._write_header_if_needed()
27
+ return True
28
+
29
+
30
+ """
31
+ A logging.Filter in Python's logging module is an object that provides a way to perform fine-grained
32
+ filtering of log records.
33
+ It allows you to control which log records are passed through and which are filtered out,
34
+ based on specific criteria you define.
35
+
36
+ Basic Concepts of logging.Filter
37
+ Purpose: Filters are used to allow or deny log records from being processed further.
38
+ This can be based on various criteria, such as the level of the log record, the source logger, or custom attributes.
39
+ Implementation: Filters are typically subclasses of logging.Filter,
40
+ but they can also be any callable that accepts a log record and returns a boolean value.
41
+
42
+ How logging.Filter Works
43
+ When a log record is emitted, it is passed through any filters attached to the logger or the handler.
44
+ If the filter returns True, the log record is processed. If the filter returns False, the log record is ignored.
45
+
46
+ Example of logging.Filter
47
+ Here’s a simple example to demonstrate the use of logging.Filter:
48
+
49
+ Create a Filter: Subclass logging.Filter and override the filter method.
50
+ import logging
51
+
52
+ class MyFilter(logging.Filter):
53
+ def filter(self, record):
54
+ # Example: Allow only log records with a level of WARNING or higher
55
+ return record.levelno >= logging.WARNING
56
+
57
+ Attach the Filter to a Handler or Logger:
58
+ # Create a logger
59
+ logger = logging.getLogger('my_logger')
60
+ logger.setLevel(logging.DEBUG)
61
+
62
+ # Create a console handler
63
+ console_handler = logging.StreamHandler()
64
+
65
+ # Create an instance of the custom filter
66
+ my_filter = MyFilter()
67
+
68
+ # Add the filter to the handler
69
+ console_handler.addFilter(my_filter)
70
+
71
+ # Add the handler to the logger
72
+ logger.addHandler(console_handler)
73
+
74
+ # Log some messages
75
+ logger.debug('This is a debug message') # Will be filtered out
76
+ logger.info('This is an info message') # Will be filtered out
77
+ logger.warning('This is a warning message') # Will be displayed
78
+ logger.error('This is an error message') # Will be displayed
79
+ """
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  from logging.handlers import TimedRotatingFileHandler, QueueListener, QueueHandler
3
- from logging import FileHandler
4
3
  import time
5
4
  import re
6
5
  import os
@@ -10,66 +9,15 @@ from typing import Literal, Union
10
9
  import threading
11
10
  from datetime import datetime
12
11
 
13
- from . import loggers, formatters
12
+ from . import loggers, formatters, filters
14
13
  from ... import datetimes, filesystem
15
14
 
16
15
 
17
- DEFAULT_DATE_STRING_FORMAT: str = "%Y_%m_%d"
16
+ """
18
17
  # Not used, only for the reference:
19
- # _DEFAULT_DATE_REGEX_PATTERN: str = r"^\d{4}_\d{2}_\d{2}$"
20
-
21
-
22
- class ForceAtTimeRotationTimedRotatingFileHandler(TimedRotatingFileHandler):
23
- def __init__(self, *args, **kwargs):
24
- super().__init__(*args, **kwargs)
25
- self._last_rotated_date = None
26
- self._start_rotation_check()
27
-
28
- def _start_rotation_check(self):
29
- self._rotation_thread = threading.Thread(target=self._check_for_rotation)
30
- self._rotation_thread.daemon = True
31
- self._rotation_thread.start()
32
-
33
- def _check_for_rotation(self):
34
- while True:
35
- now = datetime.now()
36
- current_date = now.date()
37
- # Check if it's midnight and the logs haven't been rotated today
38
- if now.hour == 0 and now.minute == 0 and current_date != self._last_rotated_date:
39
- self._last_rotated_date = current_date
40
- self.doRollover()
41
- time.sleep(0.1)
42
-
43
- def doRollover(self):
44
- self._last_rotated_date = datetime.now().date()
45
- super().doRollover()
46
-
47
-
48
- class TimedRotatingFileHandlerWithHeader(ForceAtTimeRotationTimedRotatingFileHandler):
49
- """
50
- Custom TimedRotatingFileHandler that writes a header to the log file each time there is a file rotation.
51
- Useful for writing CSV files.
52
-
53
- :param header: string, Header to write to the log file.
54
- Example: "time,host,error"
55
- """
56
- def __init__(self, *args, **kwargs):
57
- self.header = kwargs.pop('header', None)
58
- super().__init__(*args, **kwargs)
59
-
60
- def doRollover(self):
61
- super().doRollover()
62
- self._write_header()
63
-
64
- def _write_header(self):
65
- if self.header:
66
- with open(self.baseFilename, 'a') as f:
67
- f.write(self.header + '\n')
68
-
69
- def emit(self, record):
70
- if not os.path.exists(self.baseFilename) or os.path.getsize(self.baseFilename) == 0:
71
- self._write_header()
72
- super().emit(record)
18
+ DEFAULT_DATE_STRING_FORMAT: str = "%Y_%m_%d"
19
+ DEFAULT_DATE_REGEX_PATTERN: str = r"^\d{4}_\d{2}_\d{2}$"
20
+ """
73
21
 
74
22
 
75
23
  def _process_formatter_attribute(
@@ -134,6 +82,48 @@ def add_stream_handler(
134
82
  loggers.set_propagation(logger)
135
83
 
136
84
 
85
+ # Function to start the interval-based rotation check
86
+ def _start_interval_rotation(handler):
87
+ def check_rotation():
88
+ while True:
89
+ next_rollover = _calculate_next_rollover()
90
+ while datetime.now() < next_rollover:
91
+ time.sleep(0.1)
92
+
93
+ # Check if the next_rollover has changed (indicating a rollover by an event)
94
+ if _calculate_next_rollover() != next_rollover:
95
+ next_rollover = _calculate_next_rollover()
96
+ break
97
+
98
+ # Perform manual rollover if needed
99
+ if datetime.now() >= next_rollover:
100
+ _rotate_log()
101
+
102
+ def _calculate_next_rollover():
103
+ return datetime.fromtimestamp(handler.rolloverAt)
104
+
105
+ # Function to rotate logs
106
+ def _rotate_log():
107
+ handler.doRollover()
108
+
109
+ rotation_thread = threading.Thread(target=check_rotation)
110
+ rotation_thread.daemon = True
111
+ rotation_thread.start()
112
+
113
+
114
+ def _wrap_do_rollover(handler, header):
115
+ original_do_rollover = handler.doRollover
116
+
117
+ def new_do_rollover():
118
+ original_do_rollover()
119
+ # After rollover, write the header
120
+ if header:
121
+ with open(handler.baseFilename, 'a') as f:
122
+ f.write(header + '\n')
123
+
124
+ handler.doRollover = new_do_rollover
125
+
126
+
137
127
  def add_timedfilehandler_with_queuehandler(
138
128
  logger: logging.Logger,
139
129
  file_path: str,
@@ -147,6 +137,10 @@ def add_timedfilehandler_with_queuehandler(
147
137
  str,
148
138
  None] = None,
149
139
  formatter_use_nanoseconds: bool = False,
140
+ rotate_at_rollover_time: bool = True,
141
+ rotation_date_format: str = None,
142
+ rotation_callback_namer_function: callable = None,
143
+ rotation_use_default_callback_namer_function: bool = True,
150
144
  when: str = 'midnight',
151
145
  interval: int = 1,
152
146
  delay: bool = True,
@@ -159,10 +153,6 @@ def add_timedfilehandler_with_queuehandler(
159
153
  This is needed, since TimedRotatingFileHandler is not thread-safe, though official docs say it is.
160
154
  """
161
155
 
162
- # If file name wasn't provided we will use the logger name instead.
163
- # if not file_name_no_extension:
164
- # file_name_no_extension = logger.name
165
-
166
156
  # Setting the TimedRotatingFileHandler, without adding it to the logger.
167
157
  # It will be added to the QueueListener, which will use the TimedRotatingFileHandler to write logs.
168
158
  # This is needed since there's a bug in TimedRotatingFileHandler, which won't let it be used with
@@ -173,15 +163,8 @@ def add_timedfilehandler_with_queuehandler(
173
163
 
174
164
  filesystem.create_directory(os.path.dirname(file_path))
175
165
 
176
- if file_type == "csv":
177
- # If file extension is CSV, we'll set the header to the file.
178
- # This is needed since the CSV file will be rotated, and we'll need to set the header each time.
179
- # We'll use the custom TimedRotatingFileHandlerWithHeader class.
180
- file_handler = get_timed_rotating_file_handler_with_header(
181
- file_path, when=when, interval=interval, delay=delay, encoding=encoding, header=header)
182
- else:
183
- file_handler = get_timed_rotating_file_handler(
184
- file_path, when=when, interval=interval, delay=delay, encoding=encoding)
166
+ file_handler = get_timed_rotating_file_handler(
167
+ file_path, when=when, interval=interval, delay=delay, encoding=encoding)
185
168
 
186
169
  loggers.set_logging_level(file_handler, logging_level)
187
170
 
@@ -196,7 +179,23 @@ def add_timedfilehandler_with_queuehandler(
196
179
  set_formatter(file_handler, logging_formatter)
197
180
 
198
181
  # This function will change the suffix behavior of the rotated file name.
199
- change_rotated_filename(file_handler)
182
+ change_rotated_filename(
183
+ file_handler=file_handler, date_format_string=rotation_date_format,
184
+ callback_namer_function=rotation_callback_namer_function,
185
+ use_default_callback_namer_function=rotation_use_default_callback_namer_function
186
+ )
187
+
188
+ # If header is set, we'll add the filter to the handler that will create the header on file rotation.
189
+ if header:
190
+ # Filter is added to write header on logger startup.
191
+ add_filter_to_handler(file_handler, filters.HeaderFilter(header, file_handler.baseFilename))
192
+ # Wrap the doRollover method to write the header after each rotation, since adding the filter
193
+ # will only write the header on log file creation.
194
+ _wrap_do_rollover(file_handler, header)
195
+
196
+ # Start the interval-based rotation forcing.
197
+ if rotate_at_rollover_time:
198
+ _start_interval_rotation(file_handler)
200
199
 
201
200
  queue_handler = start_queue_listener_for_file_handler_and_get_queue_handler(file_handler)
202
201
  loggers.set_logging_level(queue_handler, logging_level)
@@ -243,7 +242,7 @@ def get_stream_handler() -> logging.StreamHandler:
243
242
 
244
243
  def get_timed_rotating_file_handler(
245
244
  log_file_path: str, when: str = "midnight", interval: int = 1, delay: bool = False, encoding=None
246
- ) -> ForceAtTimeRotationTimedRotatingFileHandler:
245
+ ) -> TimedRotatingFileHandler:
247
246
  """
248
247
  Function to get a TimedRotatingFileHandler.
249
248
  This handler will output messages to a file, rotating the log file at certain timed intervals.
@@ -261,32 +260,10 @@ def get_timed_rotating_file_handler(
261
260
  :return: TimedRotatingFileHandler.
262
261
  """
263
262
 
264
- return ForceAtTimeRotationTimedRotatingFileHandler(
263
+ return TimedRotatingFileHandler(
265
264
  filename=log_file_path, when=when, interval=interval, delay=delay, encoding=encoding)
266
265
 
267
266
 
268
- def get_timed_rotating_file_handler_with_header(
269
- log_file_path: str, when: str = "midnight", interval: int = 1, delay: bool = False, encoding=None,
270
- header: str = None) -> TimedRotatingFileHandlerWithHeader:
271
- """
272
- Function to get a TimedRotatingFileHandler with header.
273
- This handler will output messages to a file, rotating the log file at certain timed intervals.
274
- It will write a header to the log file each time there is a file rotation.
275
-
276
- :param log_file_path: Path to the log file.
277
- :param when: When to rotate the log file. Possible
278
- :param interval: Interval to rotate the log file.
279
- :param delay: bool, If set to True, the log file will be created only if there's something to write.
280
- :param encoding: Encoding to use for the log file. Same as for the TimeRotatingFileHandler, which uses Default None.
281
- :param header: Header to write to the log file.
282
- Example: "time,host,error"
283
- :return: TimedRotatingFileHandlerWithHeader.
284
- """
285
-
286
- return TimedRotatingFileHandlerWithHeader(
287
- filename=log_file_path, when=when, interval=interval, delay=delay, encoding=encoding, header=header)
288
-
289
-
290
267
  def start_queue_listener_for_file_handler(
291
268
  file_handler: logging.FileHandler, queue_object) -> logging.handlers.QueueListener:
292
269
  """
@@ -351,72 +328,74 @@ def get_handler_name(handler: logging.Handler) -> str:
351
328
 
352
329
  def change_rotated_filename(
353
330
  file_handler: logging.Handler,
354
- date_format_string: str = None
331
+ date_format_string: str = None,
332
+ callback_namer_function: callable = None,
333
+ use_default_callback_namer_function: bool = True
355
334
  ):
356
335
  """
357
336
  Function to change the way TimedRotatingFileHandler managing the rotating filename.
358
337
 
359
338
  :param file_handler: FileHandler to change the rotating filename for.
360
- :param date_format_string: Date format string to use for the rotated log filename.
361
- If None, the default 'DEFAULT_DATE_STRING_FORMAT' will be used.
339
+ :param date_format_string: Date format string to set to the handler's suffix.
340
+ :param callback_namer_function: Callback function to change the filename on rotation.
341
+ :param use_default_callback_namer_function: If set to True, the default callback namer function will be used
342
+ and the filename will be changed on rotation instead of using the default like this:
343
+ 'file.log.2021-12-24' -> 'file_2021-12-24.log'.
344
+
345
+ ---------------------
346
+
347
+ At this point, 'file_handler.suffix' is already '%Y-%m-%d' if 'when' is set to 'midnight'.
348
+ You can change it if you wish (example: '%Y_%m_%d'), the method is described below.
362
349
  """
363
- # Changing the way TimedRotatingFileHandler managing the rotating filename
364
- # Default file suffix is only "Year_Month_Day" with addition of the dot (".") character to the
365
- # "file name + extension" that you provide it. Example: log file name:
366
- # test.log
367
- # After file is rotated at midnight, by default the old filename will be:
368
- # test.log.2021_12_24
369
- # And the log file of 25th, now will be "test.log".
370
- # So, Changing the file suffix to include the extension to the suffix, so it will be:
371
- # test.log.2021_12_24.log
372
- # file_handler.suffix = logfile_suffix
373
- # file_handler.suffix = "_%Y_%m_%d.txt"
374
- # This step will remove the created ".log." above before the suffix and the filename will look like:
375
- # test.2021_12_24.log
376
- # file_handler.namer = lambda name: name.replace(log_file_extension + ".", "") + log_file_extension
377
- # file_handler.namer = lambda name: name.replace(".txt.", "") + log_file_extension
378
- # This will recompile the string to tell the handler the length of the suffix parts
379
- # file_handler.extMatch = re.compile(r"^\d{4}_\d{2}_\d{2}" + re.escape(log_file_extension) + r"$")
380
- # file_handler.extMatch = re.compile(r"^\d{4}_\d{2}_\d{2}.txt$")
381
350
 
382
351
  def callback_namer(name):
383
352
  """
384
353
  Callback function to change the filename of the rotated log file on file rotation.
385
354
  """
386
355
  # Currently the 'name' is full file path + '.' + logfile_suffix.
387
- # Example: 'C:\\path\\to\\file.log._2021_12_24'
356
+ # Example: 'C:\\path\\to\\file.log.2021-12-24'
388
357
  # Get the parent directory of the file: C:\path\to
389
358
  parent_dir: str = str(Path(name).parent)
390
359
  # Get the base filename without the extension: file.log
391
360
  filename: str = Path(name).stem
392
- # Get the date part of the filename: _2021_12_24
361
+ # Get the date part of the filename: 2021-12-24
393
362
  date_part: str = str(Path(name).suffix).replace(".", "")
394
363
  # Get the file extension: log
395
364
  file_extension: str = Path(filename).suffix
396
365
  # Get the file name without the extension: file
397
366
  file_stem: str = Path(filename).stem
398
367
 
399
- return f"{parent_dir}{os.sep}{file_stem}{date_part}{file_extension}"
368
+ return f"{parent_dir}{os.sep}{file_stem}_{date_part}{file_extension}"
369
+
370
+ def change_file_handler_suffix():
371
+ # Get regex pattern from string format.
372
+ # Example: '%Y_%m_%d' -> r'\d{4}_\d{2}_\d{2}'
373
+ date_regex_pattern = datetimes.datetime_format_to_regex(date_format_string)
400
374
 
401
- if date_format_string is None:
402
- date_format_string = DEFAULT_DATE_STRING_FORMAT
375
+ # Regex pattern to match the rotated log filenames
376
+ logfile_regex_suffix = re.compile(date_regex_pattern)
403
377
 
404
- # Construct the new suffix without the file extension
405
- logfile_suffix = f"_{date_format_string}"
378
+ # Update the handler's suffix to include the date format
379
+ file_handler.suffix = date_format_string
406
380
 
407
- # Get regex pattern from string format.
408
- # Example: '%Y_%m_%d' -> r'\d{4}_\d{2}_\d{2}'
409
- date_regex_pattern = datetimes.datetime_format_to_regex(date_format_string)
381
+ # Update the handler's extMatch regex to match the new filename format
382
+ file_handler.extMatch = logfile_regex_suffix
410
383
 
411
- # Regex pattern to match the rotated log filenames
412
- logfile_regex_suffix = re.compile(date_regex_pattern)
384
+ if use_default_callback_namer_function and callback_namer_function:
385
+ raise ValueError("You can't use both default and custom callback namer function.")
386
+ elif not use_default_callback_namer_function and not callback_namer_function:
387
+ raise ValueError(
388
+ "You need to provide a 'callback_namer_function' or our 'use_default_callback_namer_function'.")
413
389
 
414
- # Update the handler's suffix to include the date format
415
- file_handler.suffix = logfile_suffix
390
+ if date_format_string:
391
+ change_file_handler_suffix()
416
392
 
417
- file_handler.namer = callback_namer
418
- # Update the handler's extMatch regex to match the new filename format
419
- file_handler.extMatch = logfile_regex_suffix
393
+ # Set the callback function to change the filename on rotation.
394
+ if use_default_callback_namer_function:
395
+ file_handler.namer = callback_namer
396
+
397
+ if callback_namer_function:
398
+ file_handler.namer = callback_namer_function
420
399
 
421
400
 
422
401
  def has_handlers(logger: logging.Logger) -> bool:
@@ -438,7 +417,7 @@ def has_handlers(logger: logging.Logger) -> bool:
438
417
  return True
439
418
 
440
419
 
441
- def extract_datetime_format_from_file_handler(file_handler: FileHandler) -> Union[str, None]:
420
+ def extract_datetime_format_from_file_handler(file_handler: logging.FileHandler) -> Union[str, None]:
442
421
  """
443
422
  Extract the datetime string formats from all TimedRotatingFileHandlers in the logger.
444
423
 
@@ -456,3 +435,13 @@ def extract_datetime_format_from_file_handler(file_handler: FileHandler) -> Unio
456
435
  return datetime_format
457
436
 
458
437
  return None
438
+
439
+
440
+ def add_filter_to_handler(handler: logging.Handler, filter_object: logging.Filter):
441
+ """
442
+ Function to add a filter to the handler.
443
+ :param handler: Handler to add the filter to.
444
+ :param filter_object: Filter object to add to the handler.
445
+ """
446
+
447
+ handler.addFilter(filter_object)
@@ -2,7 +2,7 @@ import logging
2
2
  import os
3
3
  from typing import Literal, Union
4
4
 
5
- from . import loggers, handlers, formatters
5
+ from . import loggers, handlers
6
6
 
7
7
 
8
8
  def create_logger(
@@ -26,6 +26,10 @@ def create_logger(
26
26
  None] = None,
27
27
  formatter_streamhandler_use_nanoseconds: bool = True,
28
28
  formatter_filehandler_use_nanoseconds: bool = True,
29
+ filehandler_rotate_at_rollover_time: bool = True,
30
+ filehandler_rotation_date_format: str = None,
31
+ filehandler_rotation_callback_namer_function: callable = None,
32
+ filehandler_rotation_use_default_namer_function: bool = True,
29
33
  when: str = "midnight",
30
34
  interval: int = 1,
31
35
  delay: bool = False,
@@ -67,6 +71,20 @@ def create_logger(
67
71
  in the formatter in case you provide 'asctime' element.
68
72
  :param formatter_filehandler_use_nanoseconds: bool, If set to True, the nanoseconds will be used
69
73
  in the formatter in case you provide 'asctime' element.
74
+ :param filehandler_rotate_at_rollover_time: bool,
75
+ If set to True, the log file will be rotated at the rollover time, even if there's nothing to write.
76
+ If set to False, the log file will be rotated after 'when' time, but only when event occurs.
77
+ :param filehandler_rotation_date_format: string, Date format to use for the log file rotation.
78
+ Example for 'when="midnight"': the default date format is '%Y-%m-%d', resulting in filename on rotation like:
79
+ "test.log.2021-11-25"
80
+ If you want to change the date format to '%Y_%m_%d', the filename will be:
81
+ "test.log.2021_11_25"
82
+ :param filehandler_rotation_callback_namer_function: callable, Callback function to use for the log file naming
83
+ on rotation. If set to None, logging module default function will be used. With "when='midnight'",
84
+ and filename: "test.log" this will name the file on rotation similar to: "test.log.2021-11-25".
85
+ :param filehandler_rotation_use_default_namer_function: bool, If set to True, the default namer function will be
86
+ used for the log file naming on rotation. With "when='midnight'" and filename: "test.log",
87
+ this will name the file on rotation similar to: "test_2021-11-25.log".
70
88
  :param when: string, When to rotate the log file. Default is 'midnight'.
71
89
  [when="midnight"] is set to rotate the filename at midnight. This means that the current file name will be
72
90
  added Yesterday's date to the end of the file and today's file will continue to write at the same
@@ -159,6 +177,10 @@ def create_logger(
159
177
  handlers.add_timedfilehandler_with_queuehandler(
160
178
  logger=logger, file_path=file_path, logging_level=logging_level, formatter=formatter_filehandler,
161
179
  formatter_use_nanoseconds=formatter_filehandler_use_nanoseconds, file_type=file_type,
180
+ rotate_at_rollover_time=filehandler_rotate_at_rollover_time,
181
+ rotation_date_format=filehandler_rotation_date_format,
182
+ rotation_callback_namer_function=filehandler_rotation_callback_namer_function,
183
+ rotation_use_default_callback_namer_function=filehandler_rotation_use_default_namer_function,
162
184
  when=when, interval=interval, delay=delay, encoding=encoding, header=header)
163
185
 
164
186
  return logger
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.14.8
3
+ Version: 2.14.9
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=gZdXspcvPZo8Qcm-5yJOZLVwsJp8kFqubdBUfmwcABs,123
1
+ atomicshop/__init__.py,sha256=DBF3vx08oq-VNJ9rHPgRbBVXDm9QZq_mn99gKX4ERy0,123
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
@@ -234,10 +234,11 @@ atomicshop/wrappers/factw/rest/statistics.py,sha256=vznwzKP1gEF7uXz3HsuV66BU9wrp
234
234
  atomicshop/wrappers/factw/rest/status.py,sha256=4O3xS1poafwyUiLDkhyx4oMMe4PBwABuRPpOMnMKgIU,641
235
235
  atomicshop/wrappers/fibratusw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
236
236
  atomicshop/wrappers/fibratusw/install.py,sha256=PLVymDe0HuOvU0r2lje8BkQAgtiOWEeRO7n-1zKuL7A,3287
237
+ atomicshop/wrappers/loggingw/filters.py,sha256=CMs5PAMb68zxJgBcQobaOFDG5kLJBOVYnoBHjDgksO8,2859
237
238
  atomicshop/wrappers/loggingw/formatters.py,sha256=808R7K3e3ZJD2BXfqI6UMOyXGrCgt9SYh2Uv7sL_1KQ,7432
238
- atomicshop/wrappers/loggingw/handlers.py,sha256=ofm7pEhD0aPGOGc9QAJT8S00FVD30X5g06KZntoOLc0,18071
239
+ atomicshop/wrappers/loggingw/handlers.py,sha256=bv3oCm_P0JdXaJKYjhyfFNMNong6Nc9LE4JGFxLN2As,16940
239
240
  atomicshop/wrappers/loggingw/loggers.py,sha256=DHOOTAtqkwn1xgvLHSkOiBm6yFGNuQy1kvbhG-TDog8,2374
240
- atomicshop/wrappers/loggingw/loggingw.py,sha256=irzlIYXTcCpSVjmb6NU6GJGCIy3V48ZVKNvKOlH70CU,9417
241
+ atomicshop/wrappers/loggingw/loggingw.py,sha256=lo4OZPXCbYZi3GqpaaJSs9SOGFfqD2EgHzzTK7f5IR4,11275
241
242
  atomicshop/wrappers/loggingw/reading.py,sha256=yh7uNPxEdn6KsxSKrYny2C57XdI25F5gaByz77CO_pw,17038
242
243
  atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
243
244
  atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=QZg-R2iTQt7kFb8wNtnTmwraSGwvUs34JIasdbNa7ZU,5154
@@ -283,8 +284,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
283
284
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
284
285
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
285
286
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
286
- atomicshop-2.14.8.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
287
- atomicshop-2.14.8.dist-info/METADATA,sha256=tcSG898X9bqGNFLcBWRjXFgnEP1s4aRQWPXVIqH8Sz4,10478
288
- atomicshop-2.14.8.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
289
- atomicshop-2.14.8.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
290
- atomicshop-2.14.8.dist-info/RECORD,,
287
+ atomicshop-2.14.9.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
288
+ atomicshop-2.14.9.dist-info/METADATA,sha256=TL4CY4-kaxRLWK4vD8N1GxSUsFCHwBesZSZB3nAz7OU,10478
289
+ atomicshop-2.14.9.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
290
+ atomicshop-2.14.9.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
291
+ atomicshop-2.14.9.dist-info/RECORD,,