log21 3.2.0__tar.gz → 3.3.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: log21
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: A simple logging package
5
5
  Keywords: python,log,colorize,color,logging,Python3,CodeWriter21
6
6
  Author: CodeWriter21(Mehrad Pooryoussof)
@@ -94,24 +94,55 @@ pip install git+https://github.com/MPCodeWriter21/log21
94
94
  Changelog
95
95
  ---------
96
96
 
97
- ### v3.2.0
97
+ ### v3.3.0
98
98
 
99
- Add `file_mode` and `file_encoding` parameters to `get_logger` for finer control over
100
- the way a simple logger handles files.
99
+ Add `log21.helper_types` module.
100
+
101
+ This module contains a collection of useful types meant for using with argument parser
102
+ to parse CLI arguments to more usable formats.
103
+
104
+ + `FileSize`: Can take `str` and `int` values. Will convert human inputs such as "121 KB",
105
+ "21MiB", or "4.56 GB" to bytes. Can also be used to represent bytes value in more
106
+ human-readable formats.
101
107
 
102
108
  For even more control you can still define Logger, Handlers, and Formatters manually.
103
109
 
104
110
  #### Example
105
111
 
106
112
  ```python
113
+ from pathlib import Path
114
+
107
115
  import log21
116
+ from log21.helper_types import FileSize
117
+
118
+
119
+ def main(path: Path, min_size: FileSize, max_size: FileSize, /):
120
+ log21.info(
121
+ "Files that are smaller than %s or bigger than %s will be ignored.",
122
+ args=(min_size, max_size),
123
+ )
124
+
125
+ for file in path.iterdir():
126
+ if not file.is_file():
127
+ continue
128
+ if min_size <= (size := file.stat().st_size) <= max_size:
129
+ log21.print(
130
+ "`%s` is %s.",
131
+ args=(file, FileSize(size).humanize(binary=False, fmt="%.4f")),
132
+ )
133
+
134
+
135
+ if __name__ == "__main__":
136
+ log21.argumentify(main)
137
+ ```
108
138
 
109
- logger = log21.get_logger(
110
- "My File Logger", show_level=False, show_time=True, file="myapp.log", file_mode="a",
111
- file_encoding="utf-8"
112
- )
139
+ Example usage and output:
113
140
 
114
- logger.info("Hello World!")
141
+ ```shell
142
+ $ uv run test.py . "1.23MiB" "0.5 GB"
143
+ [21:21:21] [INFO] Files that are smaller than 1.23 MiB or bigger than 476.84 MiB will be
144
+ ignored.
145
+ `myfile21.zip` is 35.1856 MB.
115
146
  ```
116
147
 
117
148
  [Full CHANGELOG](https://github.com/MPCodeWriter21/log21/blob/master/CHANGELOG.md)
@@ -69,24 +69,55 @@ pip install git+https://github.com/MPCodeWriter21/log21
69
69
  Changelog
70
70
  ---------
71
71
 
72
- ### v3.2.0
72
+ ### v3.3.0
73
73
 
74
- Add `file_mode` and `file_encoding` parameters to `get_logger` for finer control over
75
- the way a simple logger handles files.
74
+ Add `log21.helper_types` module.
75
+
76
+ This module contains a collection of useful types meant for using with argument parser
77
+ to parse CLI arguments to more usable formats.
78
+
79
+ + `FileSize`: Can take `str` and `int` values. Will convert human inputs such as "121 KB",
80
+ "21MiB", or "4.56 GB" to bytes. Can also be used to represent bytes value in more
81
+ human-readable formats.
76
82
 
77
83
  For even more control you can still define Logger, Handlers, and Formatters manually.
78
84
 
79
85
  #### Example
80
86
 
81
87
  ```python
88
+ from pathlib import Path
89
+
82
90
  import log21
91
+ from log21.helper_types import FileSize
92
+
93
+
94
+ def main(path: Path, min_size: FileSize, max_size: FileSize, /):
95
+ log21.info(
96
+ "Files that are smaller than %s or bigger than %s will be ignored.",
97
+ args=(min_size, max_size),
98
+ )
99
+
100
+ for file in path.iterdir():
101
+ if not file.is_file():
102
+ continue
103
+ if min_size <= (size := file.stat().st_size) <= max_size:
104
+ log21.print(
105
+ "`%s` is %s.",
106
+ args=(file, FileSize(size).humanize(binary=False, fmt="%.4f")),
107
+ )
108
+
109
+
110
+ if __name__ == "__main__":
111
+ log21.argumentify(main)
112
+ ```
83
113
 
84
- logger = log21.get_logger(
85
- "My File Logger", show_level=False, show_time=True, file="myapp.log", file_mode="a",
86
- file_encoding="utf-8"
87
- )
114
+ Example usage and output:
88
115
 
89
- logger.info("Hello World!")
116
+ ```shell
117
+ $ uv run test.py . "1.23MiB" "0.5 GB"
118
+ [21:21:21] [INFO] Files that are smaller than 1.23 MiB or bigger than 476.84 MiB will be
119
+ ignored.
120
+ `myfile21.zip` is 35.1856 MB.
90
121
  ```
91
122
 
92
123
  [Full CHANGELOG](https://github.com/MPCodeWriter21/log21/blob/master/CHANGELOG.md)
@@ -23,7 +23,7 @@ dependencies = [
23
23
  "webcolors",
24
24
  "docstring-parser"
25
25
  ]
26
- version = "3.2.0"
26
+ version = "3.3.0"
27
27
 
28
28
  [build-system]
29
29
  requires = ["uv_build>=0.8.15,<0.9.0"]
@@ -10,6 +10,8 @@ from types import ModuleType as _ModuleType
10
10
  from typing import (Type as _Type, Union as _Union, Literal as _Literal,
11
11
  Mapping as _Mapping, Iterable as _Iterable, Optional as _Optional)
12
12
 
13
+ import log21.helper_types
14
+
13
15
  from . import crash_reporter
14
16
  from .colors import (Colors, get_color, get_colors, ansi_escape, closest_color,
15
17
  get_color_name)
@@ -31,7 +33,7 @@ from .stream_handler import StreamHandler, ColorizingStreamHandler
31
33
  # yapf: enable
32
34
 
33
35
  __author__ = 'CodeWriter21 (Mehrad Pooryoussof)'
34
- __version__ = '3.2.0'
36
+ __version__ = '3.3.0'
35
37
  __github__ = 'https://GitHub.com/MPCodeWriter21/log21'
36
38
  __all__ = [
37
39
  'ColorizingStreamHandler', 'DecolorizingFileHandler', 'ColorizingFormatter',
@@ -44,7 +46,7 @@ __all__ = [
44
46
  'log', 'basic_config', 'basicConfig', 'ProgressBar', 'LoggingWindow',
45
47
  'LoggingWindowHandler', 'get_logging_window', 'crash_reporter', 'console_reporter',
46
48
  'file_reporter', 'argumentify', 'ArgumentError', 'IncompatibleArgumentsError',
47
- 'RequiredArgumentError', 'TooFewArgumentsError'
49
+ 'RequiredArgumentError', 'TooFewArgumentsError', 'FileHandler'
48
50
  ]
49
51
 
50
52
  _manager = Manager()
@@ -0,0 +1,126 @@
1
+ # log21.helper_types.py
2
+ # CodeWriter21
3
+ """A collection of useful types meant for using with argument parser to parse CLI
4
+ arguments to more usable formats.
5
+
6
+ + FileSize: Can take `str` and `int` values. Will convert human inputs such as "121 KB",
7
+ "21MiB", or "4.56 GB" to bytes. Can also be used to represent bytes value in more
8
+ human-readable formats.
9
+ """
10
+
11
+ # yapf: disable
12
+
13
+ import re as _re
14
+ from math import log as _log
15
+ from typing import Union as _Union, SupportsInt as _SupportsInt
16
+
17
+ # yapf: enable
18
+
19
+ __all__ = ["FileSize"]
20
+
21
+ POWERS = "KMGTPEZYRQ"
22
+ FILE_SIZE_PATTERN = _re.compile(rf"^([+-]?[0-9]+(?:\.[0-9]+)?)\s*(|[{POWERS}])(i?)B$")
23
+
24
+
25
+ class FileSize:
26
+
27
+ def __init__(self, value: _Union[int, str]) -> None:
28
+ """An interface for converting different inputs to file-size (bytes).
29
+
30
+ :param value: int value in bytes or a string such as "100 KB", "20MiB", or "1.23
31
+ GB"
32
+ :raises TypeError: If the value is not of type int or str
33
+ :raises ValueError: If the str value does not match the file-size pattern:
34
+ ^([+-]?[0-9]+(?:\\.[0-9]+)?)\\s*(|[KMGTPEZYRQ])(i?)B$
35
+ """
36
+ if isinstance(value, int):
37
+ self.bytes = value
38
+ elif isinstance(value, str):
39
+ match = FILE_SIZE_PATTERN.match(value)
40
+ if not match:
41
+ raise ValueError(f"Input does not match the file-size pattern: {value}")
42
+ val, prefix, binary = match.groups()
43
+ power = POWERS.index(prefix) + 1
44
+ assert power is not None
45
+ self.bytes = int(float(val) * (1024 if binary else 1000)**power)
46
+ else:
47
+ raise TypeError(f"Input to FileSize() can be int or str, not {type(value)}")
48
+
49
+ def humanize(
50
+ self,
51
+ binary: bool = False,
52
+ gnu: bool = False,
53
+ fmt: str = "%.2f",
54
+ ) -> str:
55
+ """Returns the size in a human readable way."""
56
+ base = 1024 if (gnu or binary) else 1000
57
+ abs_bytes = abs(self.bytes)
58
+
59
+ if abs_bytes == 1 and not gnu:
60
+ return f"{self.bytes} Byte"
61
+
62
+ if abs_bytes < base:
63
+ return f"{self.bytes}B" if gnu else f"{self.bytes} Bytes"
64
+
65
+ power = int(min(_log(abs_bytes, base), len(POWERS)))
66
+ result: str = fmt % (self.bytes / (base**power))
67
+ if gnu:
68
+ return result + POWERS[power - 1]
69
+ result += " " + POWERS[power - 1]
70
+ if binary:
71
+ result += "i"
72
+ result += "B"
73
+ return result
74
+
75
+ @property
76
+ def KB(self) -> float:
77
+ return self.bytes / 1000
78
+
79
+ @property
80
+ def MB(self) -> float:
81
+ return self.bytes / 1000_000
82
+
83
+ @property
84
+ def GB(self) -> float:
85
+ return self.bytes / 1000_000_000
86
+
87
+ @property
88
+ def KiB(self) -> float:
89
+ return self.bytes / 1024
90
+
91
+ @property
92
+ def MiB(self) -> float:
93
+ return self.bytes / 1048576
94
+
95
+ @property
96
+ def GiB(self) -> float:
97
+ return self.bytes / 1073741824
98
+
99
+ def __int__(self) -> int:
100
+ return self.bytes
101
+
102
+ def __eq__(self, value: object) -> bool:
103
+ if not isinstance(value, _SupportsInt):
104
+ return False
105
+ return self.bytes == int(value)
106
+
107
+ def __lt__(self, value: _SupportsInt) -> bool:
108
+ return self.bytes < int(value)
109
+
110
+ def __le__(self, value: _SupportsInt) -> bool:
111
+ return self.bytes <= int(value)
112
+
113
+ def __gt__(self, value: _SupportsInt) -> bool:
114
+ return int(value) < self.bytes
115
+
116
+ def __ge__(self, value: _SupportsInt) -> bool:
117
+ return int(value) <= self.bytes
118
+
119
+ def __add__(self, value: _SupportsInt) -> "FileSize":
120
+ return FileSize(self.bytes + int(value))
121
+
122
+ def __str__(self) -> str:
123
+ return self.humanize(binary=True)
124
+
125
+ def __repr__(self) -> str:
126
+ return f"<{self.__class__.__name__}: '{self!s}'>"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes