logger-36 2023.4__py3-none-any.whl → 2023.6__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.
logger_36/main.py CHANGED
@@ -46,29 +46,27 @@ try:
46
46
  from psutil import Process as process_t
47
47
 
48
48
  _PROCESS = process_t()
49
- _GIGA_SCALING = 1.0 / (1024**3)
50
-
51
- def UsedMemoryInGb() -> float:
52
- """"""
53
- return round(_GIGA_SCALING * _PROCESS.memory_info().rss, 1)
54
-
49
+ _MEGA_SCALING = 1.0 / (1024.0**2)
50
+ _GIGA_SCALING = _MEGA_SCALING / 1024.0
55
51
  except ModuleNotFoundError:
56
52
  _PROCESS = None
57
-
58
- def UsedMemoryInGb() -> float:
59
- """"""
60
- return 0.0
53
+ _MEGA_SCALING = _GIGA_SCALING = 0.0
61
54
 
62
55
 
63
56
  # This module is certainly imported early. Therefore, the current time should be close enough to the real start time.
64
57
  _START_TIME = time.time()
65
58
 
59
+ _TERMINAL_WIDTH = 1000
60
+ _TAB_SIZE = 5
66
61
 
62
+ _WHERE_SEPARATOR = "@"
63
+ # Tab size is set by console_t so that the dash is aligned for all log levels (might not work for file handlers though)
67
64
  _MESSAGE_FORMAT = (
68
- "%(asctime)s[%(levelname)s]\t- "
69
- "%(message)s @ "
70
- "%(module)s:%(funcName)s:%(lineno)d"
65
+ f"%(asctime)s[%(levelname)s]\t- "
66
+ f"%(message)s {_WHERE_SEPARATOR} "
67
+ f"%(module)s:%(funcName)s:%(lineno)d"
71
68
  )
69
+ _NEXT_LINE_PROLOGUE = "\n" + (27 + _TAB_SIZE) * " "
72
70
  _DATE_FORMAT = "%Y-%m-%d@%H:%M:%S"
73
71
 
74
72
  _SYSTEM_DETAILS = (
@@ -93,15 +91,52 @@ _SYSTEM_DETAILS = {_dtl.capitalize(): getattr(pltf, _dtl)() for _dtl in _SYSTEM_
93
91
  _MAX_DETAIL_NAME_LENGTH = max(map(len, _SYSTEM_DETAILS.keys()))
94
92
 
95
93
 
96
- # TODO: might be simpler/better to use filters (https://devdocs.io/python~3.10/howto/logging-cookbook#context-info) or a
97
- # logging.LoggerAdapter
94
+ # Alternative implementations: using logging.Filter or logging.LoggerAdapter
95
+
96
+
98
97
  class _handler_extension:
99
- formatter: lggg.Formatter = None
100
- show_memory_usage: bool = False
98
+ __slots__ = ("formatter", "show_memory_usage")
99
+ formatter: lggg.Formatter
100
+ show_memory_usage: bool
101
101
 
102
102
  def __init__(self) -> None:
103
103
  """"""
104
104
  self.formatter = lggg.Formatter(fmt=_MESSAGE_FORMAT, datefmt=_DATE_FORMAT)
105
+ self.show_memory_usage = False
106
+
107
+ def FormattedMessage(
108
+ self, record: lggg.LogRecord, /
109
+ ) -> tuple[str, list[str] | None]:
110
+ """
111
+ Note: "message" is not yet an attribute of record (it will be set by format()); Use "msg" instead.
112
+ """
113
+ if not isinstance(record.msg, str):
114
+ record.msg = str(record.msg)
115
+ if "\n" in record.msg:
116
+ original_message = record.msg
117
+ lines = original_message.splitlines()
118
+ record.msg = lines[0]
119
+ else:
120
+ original_message = lines = None
121
+
122
+ formatted = self.formatter.format(record)
123
+
124
+ # Revert the record message to its original value for subsequent handlers
125
+ if original_message is not None:
126
+ record.msg = original_message
127
+
128
+ return formatted, lines
129
+
130
+ def MemoryUsage(self) -> str:
131
+ """"""
132
+ if self.show_memory_usage:
133
+ usage = _PROCESS.memory_info().rss
134
+ if usage > _GIGA_SCALING:
135
+ return f" :{round(_GIGA_SCALING * usage, 1)}GB"
136
+ else:
137
+ return f" :{round(_MEGA_SCALING * usage, 1)}MB"
138
+
139
+ return ""
105
140
 
106
141
 
107
142
  class console_handler_t(lggg.Handler, _handler_extension):
@@ -116,7 +151,7 @@ class console_handler_t(lggg.Handler, _handler_extension):
116
151
  _ACTUAL: ClassVar[str] = r" Actual=[^.]+\."
117
152
  _EXPECTED: ClassVar[str] = r" Expected([!<>]=|: )[^.]+\."
118
153
 
119
- console: console_t = None
154
+ console: console_t
120
155
 
121
156
  def __init__(self, /, *, level=lggg.NOTSET) -> None:
122
157
  """"""
@@ -125,33 +160,28 @@ class console_handler_t(lggg.Handler, _handler_extension):
125
160
 
126
161
  self.setFormatter(self.formatter)
127
162
  self.console = console_t(
128
- record=True, force_terminal=True, width=1000, tab_size=5
163
+ record=True, force_terminal=True, width=_TERMINAL_WIDTH, tab_size=_TAB_SIZE
129
164
  )
130
165
 
131
166
  def emit(self, record: lggg.LogRecord, /) -> None:
132
167
  """"""
133
168
  cls = self.__class__
134
169
 
135
- formatted = self.formatter.format(record)
136
- if self.show_memory_usage:
137
- memory_usage = f" :{UsedMemoryInGb()}Gb"
138
- else:
139
- memory_usage = ""
140
- if "\n" in formatted:
141
- lines = formatted.splitlines()
142
- highlighted = text_t(lines[0])
143
- highlighted.append(f" +{ElapsedTime()}{memory_usage}\n", style="green")
144
- highlighted.append(" " + "\n ".join(lines[1:]))
145
- else:
146
- highlighted = text_t(formatted)
147
- highlighted.append(f" +{ElapsedTime()}{memory_usage}", style="green")
170
+ formatted, lines = self.FormattedMessage(record)
171
+
172
+ highlighted = text_t(formatted)
173
+ highlighted.append(f" +{ElapsedTime()}{self.MemoryUsage()}", style="green")
174
+ if lines is not None:
175
+ highlighted.append(
176
+ _NEXT_LINE_PROLOGUE + _NEXT_LINE_PROLOGUE.join(lines[1:])
177
+ )
148
178
 
149
179
  highlighted.stylize("dodger_blue2", end=19)
150
180
  highlighted.highlight_words(
151
181
  (f"[{record.levelname}]",), style=cls._LEVEL_COLOR[record.levelno]
152
182
  )
153
183
  highlighted.highlight_regex(
154
- f"@ {record.module}:{record.funcName}:{record.lineno}",
184
+ f"{_WHERE_SEPARATOR} {record.module}:{record.funcName}:{record.lineno}",
155
185
  style=cls._GRAY_STYLE,
156
186
  )
157
187
  highlighted.highlight_regex(cls._ACTUAL, style="red")
@@ -161,26 +191,23 @@ class console_handler_t(lggg.Handler, _handler_extension):
161
191
 
162
192
 
163
193
  class file_handler_t(lggg.FileHandler, _handler_extension):
164
- def __init__(self, file: str, *args, **kwargs) -> None:
194
+ def __init__(self, file: str | path_t, *args, **kwargs) -> None:
165
195
  """"""
166
- lggg.FileHandler.__init__(self, file, *args, **kwargs)
196
+ lggg.FileHandler.__init__(self, str(file), *args, **kwargs)
167
197
  _handler_extension.__init__(self)
168
198
 
169
199
  self.setFormatter(self.formatter)
170
200
 
171
201
  def emit(self, record: lggg.LogRecord, /) -> None:
172
202
  """"""
173
- formatted = self.formatter.format(record)
174
- if self.show_memory_usage:
175
- memory_usage = f" :{UsedMemoryInGb()}Gb"
176
- else:
177
- memory_usage = ""
178
- if "\n" in formatted:
179
- lines = formatted.splitlines()
180
- next_lines = "\n ".join(lines[1:])
181
- message = f"{lines[0]} +{ElapsedTime()}{memory_usage}\n {next_lines}"
203
+ formatted, lines = self.FormattedMessage(record)
204
+ formatted = formatted.replace("\t", (9 - record.levelname.__len__()) * " ")
205
+
206
+ if lines is None:
207
+ message = f"{formatted} +{ElapsedTime()}{self.MemoryUsage()}"
182
208
  else:
183
- message = f"{formatted} +{ElapsedTime()}{memory_usage}"
209
+ next_lines = _NEXT_LINE_PROLOGUE.join(lines[1:])
210
+ message = f"{formatted} +{ElapsedTime()}{self.MemoryUsage()}{_NEXT_LINE_PROLOGUE}{next_lines}"
184
211
 
185
212
  print(message, file=self.stream)
186
213
  self.stream.flush()
@@ -213,7 +240,7 @@ def AddFileHandler(file: Union[str, path_t], /) -> None:
213
240
  def SaveLOGasHTML(file: Union[str, path_t], /) -> None:
214
241
  """"""
215
242
  if file.exists():
216
- raise ValueError(f"{file}: File already exists")
243
+ print(f'Cannot save logging record as HTML: File "{file}" already exists')
217
244
 
218
245
  console = None
219
246
  found = False
@@ -225,7 +252,7 @@ def SaveLOGasHTML(file: Union[str, path_t], /) -> None:
225
252
  with open(file, "w") as accessor:
226
253
  accessor.write(console.export_html())
227
254
 
228
- raise ValueError("Cannot save logging record as HTML: Handler has no RICH console")
255
+ print("Cannot save logging record as HTML: No handler has a RICH console")
229
256
 
230
257
 
231
258
  def WhereFunction(function: Any, /) -> str:
logger_36/test.py ADDED
@@ -0,0 +1,50 @@
1
+ # Copyright CNRS/Inria/UCA
2
+ # Contributor(s): Eric Debreuve (since 2023)
3
+ #
4
+ # eric.debreuve@cnrs.fr
5
+ #
6
+ # This software is governed by the CeCILL license under French law and
7
+ # abiding by the rules of distribution of free software. You can use,
8
+ # modify and/ or redistribute the software under the terms of the CeCILL
9
+ # license as circulated by CEA, CNRS and INRIA at the following URL
10
+ # "http://www.cecill.info".
11
+ #
12
+ # As a counterpart to the access to the source code and rights to copy,
13
+ # modify and redistribute granted by the license, users are provided only
14
+ # with a limited warranty and the software's author, the holder of the
15
+ # economic rights, and the successive licensors have only limited
16
+ # liability.
17
+ #
18
+ # In this respect, the user's attention is drawn to the risks associated
19
+ # with loading, using, modifying and/or developing or reproducing the
20
+ # software by the user in light of its specific status of free software,
21
+ # that may mean that it is complicated to manipulate, and that also
22
+ # therefore means that it is reserved for developers and experienced
23
+ # professionals having in-depth computer knowledge. Users are therefore
24
+ # encouraged to load and test the software's suitability as regards their
25
+ # requirements in conditions enabling the security of their systems and/or
26
+ # data to be ensured and, more generally, to use and operate it in the
27
+ # same conditions as regards security.
28
+ #
29
+ # The fact that you are presently reading this means that you have had
30
+ # knowledge of the CeCILL license and that you accept its terms.
31
+
32
+ from pathlib import Path as path_t
33
+ from tempfile import TemporaryDirectory
34
+
35
+ from logger_36 import LOGGER, AddFileHandler
36
+
37
+
38
+ with TemporaryDirectory() as tmp_folder:
39
+ tmp_folder = path_t(tmp_folder)
40
+ tmp_file = tmp_folder / "log.txt"
41
+
42
+ AddFileHandler(tmp_file)
43
+
44
+ for level in ("debug", "info", "warning", "error", "critical"):
45
+ LogMessage = getattr(LOGGER, level)
46
+ LogMessage(f"{level.capitalize()} message")
47
+ LogMessage(f"Multi-line\n{level.capitalize()}\nmessage")
48
+
49
+ content = open(tmp_file, "r").read()
50
+ print(f"\n{content}")
logger_36/version.py CHANGED
@@ -29,4 +29,4 @@
29
29
  # The fact that you are presently reading this means that you have had
30
30
  # knowledge of the CeCILL license and that you accept its terms.
31
31
 
32
- __version__ = "2023.4"
32
+ __version__ = "2023.6"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: logger-36
3
- Version: 2023.4
3
+ Version: 2023.6
4
4
  Summary: Simple logger using rich_
5
5
  Home-page: https://src.koda.cnrs.fr/eric.debreuve/logger-36/
6
6
  Author: Eric Debreuve
@@ -0,0 +1,8 @@
1
+ logger_36/__init__.py,sha256=hoDitcbdJeHgQYTpkAnfYepCxUxkP6lbxPbHkHas3AU,1739
2
+ logger_36/main.py,sha256=gMML8vC0QmYItGvzrFIQxYohHMTANVdji5Y3FgW2GJQ,10257
3
+ logger_36/test.py,sha256=8bh0i-HZaZVImf66M0F-0R-T_PI6gYlPxO44KbCjI5s,2118
4
+ logger_36/version.py,sha256=r36L0uTNUpNnKoBVQqEARtyQO1bzYXBVu9Z2Af_Lnjg,1575
5
+ logger_36-2023.6.dist-info/METADATA,sha256=aosgF4UGoXIRGGc5XodWc0CKGtciMbpqpIlG0TaviBs,4241
6
+ logger_36-2023.6.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
7
+ logger_36-2023.6.dist-info/top_level.txt,sha256=sM95BTMWmslEEgR_1pzwZsOeSp8C_QBiu8ImbFr0XLc,10
8
+ logger_36-2023.6.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- logger_36/__init__.py,sha256=hoDitcbdJeHgQYTpkAnfYepCxUxkP6lbxPbHkHas3AU,1739
2
- logger_36/main.py,sha256=3B9rupYmD9uetFeHzb_dk8l_7sx51-in1-yYbV3abpg,9227
3
- logger_36/version.py,sha256=mwuHINlUSknBMxwdd964m2zq-4spq-ceuSw63CAiS0A,1575
4
- logger_36-2023.4.dist-info/METADATA,sha256=tUdw-rpD5BJ3194-Uh337d3MccZwVFJ9F3Mf08BaTJU,4241
5
- logger_36-2023.4.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
6
- logger_36-2023.4.dist-info/top_level.txt,sha256=sM95BTMWmslEEgR_1pzwZsOeSp8C_QBiu8ImbFr0XLc,10
7
- logger_36-2023.4.dist-info/RECORD,,