logger-36 2025.22__tar.gz → 2025.24__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.
Files changed (64) hide show
  1. {logger_36-2025.22 → logger_36-2025.24}/PKG-INFO +1 -1
  2. logger_36-2025.24/package/logger_36/api/memory.py +40 -0
  3. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/api/storage.py +0 -1
  4. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/api/time.py +0 -1
  5. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/handler/console.py +1 -1
  6. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/handler/console_rich.py +1 -1
  7. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/handler/generic.py +1 -1
  8. logger_36-2025.22/package/logger_36/extension/html_.py → logger_36-2025.24/package/logger_36/catalog/handler/memory.py +53 -45
  9. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/logger/system.py +6 -5
  10. logger_36-2025.22/package/logger_36/api/system.py → logger_36-2025.24/package/logger_36/config/rule.py +2 -1
  11. logger_36-2025.24/package/logger_36/constant/date_time.py +46 -0
  12. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/path.py +8 -7
  13. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/record.py +0 -1
  14. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/rule.py +2 -2
  15. {logger_36-2025.22/package/logger_36/task → logger_36-2025.24/package/logger_36/extension}/inspection.py +15 -29
  16. logger_36-2025.24/package/logger_36/extension/record.py +66 -0
  17. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/task/measure/chronos.py +2 -4
  18. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/task/storage.py +61 -20
  19. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/type/handler.py +6 -10
  20. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/type/logger.py +82 -182
  21. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/version.py +1 -1
  22. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36.egg-info/PKG-INFO +1 -1
  23. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36.egg-info/SOURCES.txt +7 -6
  24. logger_36-2025.22/package/logger_36/api/gpu.py +0 -39
  25. logger_36-2025.22/package/logger_36/api/memory.py +0 -49
  26. {logger_36-2025.22 → logger_36-2025.24}/MANIFEST.in +0 -0
  27. {logger_36-2025.22 → logger_36-2025.24}/README-COPYRIGHT-utf8.txt +0 -0
  28. {logger_36-2025.22 → logger_36-2025.24}/README-LICENCE-utf8.txt +0 -0
  29. {logger_36-2025.22 → logger_36-2025.24}/README.rst +0 -0
  30. {logger_36-2025.22 → logger_36-2025.24}/documentation/wiki/description.asciidoc +0 -0
  31. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/__init__.py +0 -0
  32. /logger_36-2025.22/package/logger_36/api/type.py → /logger_36-2025.24/package/logger_36/api/logger.py +0 -0
  33. /logger_36-2025.22/package/logger_36/api/content.py → /logger_36-2025.24/package/logger_36/api/message.py +0 -0
  34. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/config/console_rich.py +0 -0
  35. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/config/optional.py +0 -0
  36. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/handler/file.py +0 -0
  37. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/logger/chronos.py +0 -0
  38. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/logger/gpu.py +0 -0
  39. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/catalog/logger/memory.py +0 -0
  40. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/config/issue.py +0 -0
  41. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/config/memory.py +0 -0
  42. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/config/message.py +0 -0
  43. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/config/system.py +0 -0
  44. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/error.py +0 -0
  45. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/generic.py +0 -0
  46. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/html.py +0 -0
  47. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/issue.py +0 -0
  48. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/logger.py +0 -0
  49. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/memory.py +0 -0
  50. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/message.py +0 -0
  51. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/constant/system.py +0 -0
  52. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/extension/line.py +0 -0
  53. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/instance/logger.py +0 -0
  54. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/instance/loggers.py +0 -0
  55. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/task/format/memory.py +0 -0
  56. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/task/format/message.py +0 -0
  57. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/task/measure/memory.py +0 -0
  58. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/type/issue.py +0 -0
  59. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36/type/loggers.py +0 -0
  60. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36.egg-info/dependency_links.txt +0 -0
  61. {logger_36-2025.22 → logger_36-2025.24}/package/logger_36.egg-info/top_level.txt +0 -0
  62. {logger_36-2025.22 → logger_36-2025.24}/pyproject.toml +0 -0
  63. {logger_36-2025.22 → logger_36-2025.24}/setup.cfg +0 -0
  64. {logger_36-2025.22 → logger_36-2025.24}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: logger-36
3
- Version: 2025.22
3
+ Version: 2025.24
4
4
  Summary: Simple logger with a catalog of handlers
5
5
  Home-page: https://src.koda.cnrs.fr/eric.debreuve/logger-36/
6
6
  Author: Eric Debreuve
@@ -0,0 +1,40 @@
1
+ """
2
+ Copyright CNRS (https://www.cnrs.fr/index.php/en)
3
+ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
+ SEE COPYRIGHT NOTICE BELOW
5
+ """
6
+
7
+ from logger_36.task.measure.memory import CanCheckUsage as CanCheckMemoryUsage # noqa
8
+ from logger_36.task.measure.memory import CurrentUsage as CurrentMemoryUsage # noqa
9
+
10
+ """
11
+ COPYRIGHT NOTICE
12
+
13
+ This software is governed by the CeCILL license under French law and
14
+ abiding by the rules of distribution of free software. You can use,
15
+ modify and/ or redistribute the software under the terms of the CeCILL
16
+ license as circulated by CEA, CNRS and INRIA at the following URL
17
+ "http://www.cecill.info".
18
+
19
+ As a counterpart to the access to the source code and rights to copy,
20
+ modify and redistribute granted by the license, users are provided only
21
+ with a limited warranty and the software's author, the holder of the
22
+ economic rights, and the successive licensors have only limited
23
+ liability.
24
+
25
+ In this respect, the user's attention is drawn to the risks associated
26
+ with loading, using, modifying and/or developing or reproducing the
27
+ software by the user in light of its specific status of free software,
28
+ that may mean that it is complicated to manipulate, and that also
29
+ therefore means that it is reserved for developers and experienced
30
+ professionals having in-depth computer knowledge. Users are therefore
31
+ encouraged to load and test the software's suitability as regards their
32
+ requirements in conditions enabling the security of their systems and/or
33
+ data to be ensured and, more generally, to use and operate it in the
34
+ same conditions as regards security.
35
+
36
+ The fact that you are presently reading this means that you have had
37
+ knowledge of the CeCILL license and that you accept its terms.
38
+
39
+ SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
40
+ """
@@ -4,7 +4,6 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from logger_36.extension.html_ import html_content_t # noqa
8
7
  from logger_36.task.storage import SaveLOGasHTML # noqa
9
8
 
10
9
  """
@@ -4,7 +4,6 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from logger_36.catalog.logger.chronos import LogElapsedTime # noqa
8
7
  from logger_36.task.measure.chronos import ElapsedTime, TimeStamp # noqa
9
8
 
10
9
  """
@@ -8,7 +8,7 @@ import logging as l
8
8
  import sys as s
9
9
  import typing as h
10
10
 
11
- from logger_36.type.handler import handler_t as base_t
11
+ from logger_36.type.handler import non_file_handler_t as base_t
12
12
 
13
13
 
14
14
  class console_handler_t(base_t):
@@ -26,7 +26,7 @@ from logger_36.catalog.config.console_rich import (
26
26
  )
27
27
  from logger_36.config.message import ACTUAL_PATTERNS, EXPECTED_PATTERNS, WHERE_SEPARATOR
28
28
  from logger_36.constant.message import CONTEXT_LENGTH
29
- from logger_36.type.handler import handler_t as base_t
29
+ from logger_36.type.handler import non_file_handler_t as base_t
30
30
 
31
31
  _COMMON_TRACEBACK_ARGUMENTS = ("theme", "width")
32
32
  _EXCLUSIVE_TRACEBACK_ARGUMENTS = (
@@ -23,7 +23,7 @@ else:
23
23
  RULE_COLOR
24
24
  ) = HighlightedVersion = None
25
25
 
26
- from logger_36.type.handler import handler_t as base_t
26
+ from logger_36.type.handler import non_file_handler_t as base_t
27
27
 
28
28
 
29
29
  class generic_handler_t(base_t):
@@ -4,60 +4,68 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- import dataclasses as d
8
- import re as r
9
- from html.parser import HTMLParser as base_t
7
+ import json
8
+ import logging as l
9
+ import typing as h
10
10
 
11
- _BODY_END_PATTERN = r"</[bB][oO][dD][yY]>(.|\n)*$"
11
+ from logger_36.type.handler import non_file_handler_t as base_t
12
12
 
13
+ formats_h = h.Literal["dict", "json", "message", "raw"]
13
14
 
14
- @d.dataclass(slots=True, repr=False, eq=False)
15
- class html_content_t(base_t):
16
- source: str = ""
17
- inside_body: bool = d.field(init=False, default=False)
18
- body_position_start: tuple[int, int] = d.field(init=False, default=(-1, -1))
19
- body_position_end: tuple[int, int] = d.field(init=False, default=(-1, -1))
20
- pieces: list[str] = d.field(init=False, default_factory=list)
21
15
 
22
- @property
23
- def body(self) -> str:
16
+ class memory_handler_t(base_t):
17
+ def __init__(
18
+ self, name: str | None, message_width: int, level: int, format_: formats_h
19
+ ) -> None:
24
20
  """"""
25
- output = self.source.splitlines()
26
- output = "\n".join(
27
- output[self.body_position_start[0] : (self.body_position_end[0] + 1)]
28
- )
29
- output = output[self.body_position_start[1] :]
30
- output = r.sub(_BODY_END_PATTERN, "", output, count=1)
31
-
32
- return output.strip()
33
-
34
- @property
35
- def body_as_text(self) -> str:
21
+ assert format_ in h.get_args(formats_h)
22
+
23
+ base_t.__init__(self, name, message_width, None, level)
24
+
25
+ self.format_ = format_
26
+ self.records = []
27
+
28
+ @classmethod
29
+ def New(
30
+ cls,
31
+ /,
32
+ *,
33
+ name: str | None = None,
34
+ message_width: int = -1,
35
+ level: int = l.NOTSET,
36
+ format_: formats_h = "message",
37
+ **_,
38
+ ) -> h.Self:
36
39
  """"""
37
- return "".join(self.pieces).strip()
40
+ return cls(name, message_width, level, format_)
38
41
 
39
- def __post_init__(self) -> None:
42
+ def emit(self, record: l.LogRecord, /) -> None:
40
43
  """"""
41
- base_t.__init__(self)
42
- self.source = self.source.strip()
43
- self.feed(self.source)
44
-
45
- def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]], /) -> None:
44
+ level = record.levelno
45
+
46
+ if self.format_ == "raw":
47
+ is_not_a_rule = True
48
+ elif self.format_ == "dict":
49
+ record = dict(record.__dict__)
50
+ is_not_a_rule = True
51
+ elif self.format_ == "json":
52
+ record = json.dumps(record.__dict__)
53
+ is_not_a_rule = True
54
+ else:
55
+ record, is_not_a_rule = self.MessageFromRecord(record)
56
+
57
+ self.records.append((level, record, is_not_a_rule))
58
+
59
+ def EmitMessage(self, message: str, /) -> None:
46
60
  """"""
47
- if tag == "body":
48
- self.body_position_start = self.getpos()
49
- self.inside_body = True
50
-
51
- def handle_endtag(self, tag: str, /) -> None:
52
- """"""
53
- if tag == "body":
54
- self.body_position_end = self.getpos()
55
- self.inside_body = False
56
-
57
- def handle_data(self, data: str, /) -> None:
58
- """"""
59
- if self.inside_body:
60
- self.pieces.append(data)
61
+ if self.format_ == "message":
62
+ message_key = "msg"
63
+ else:
64
+ message_key = "message"
65
+ record = l.makeLogRecord(
66
+ {"name": "<UNKNOWN LOGGER>", "levelno": l.INFO, message_key: message}
67
+ )
68
+ self.emit(record)
61
69
 
62
70
 
63
71
  """
@@ -5,16 +5,17 @@ SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
7
  from logger_36.constant.system import MAX_DETAIL_NAME_LENGTH, SYSTEM_DETAILS_AS_DICT
8
+ from logger_36.extension.inspection import Modules
8
9
  from logger_36.instance.logger import L
9
- from logger_36.task.inspection import Modules
10
10
  from logger_36.type.logger import logger_t
11
11
 
12
12
 
13
13
  def LogSystemDetails(
14
14
  *,
15
+ should_restrict_modules_to_loaded: bool = True,
15
16
  modules_with_version: bool = True,
16
17
  modules_formatted: bool = True,
17
- should_restrict_modules_to_loaded: bool = True,
18
+ indent: int = 4,
18
19
  logger: logger_t = L,
19
20
  ) -> None:
20
21
  """"""
@@ -23,10 +24,10 @@ def LogSystemDetails(
23
24
  for _key, _vle in SYSTEM_DETAILS_AS_DICT.items()
24
25
  )
25
26
  modules = Modules(
26
- modules_with_version,
27
- modules_formatted,
28
27
  only_loaded=should_restrict_modules_to_loaded,
29
- indent=4,
28
+ with_version=modules_with_version,
29
+ formatted=modules_formatted,
30
+ indent=indent,
30
31
  )
31
32
 
32
33
  logger.info(
@@ -4,7 +4,8 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from logger_36.catalog.logger.system import LogSystemDetails # noqa
7
+ RULE_CHARACTER = "-"
8
+ DEFAULT_RULE_LENGTH = 50
8
9
 
9
10
  """
10
11
  COPYRIGHT NOTICE
@@ -0,0 +1,46 @@
1
+ """
2
+ Copyright CNRS (https://www.cnrs.fr/index.php/en)
3
+ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
+ SEE COPYRIGHT NOTICE BELOW
5
+ """
6
+
7
+ from datetime import datetime as date_time_t
8
+
9
+ # This module is imported early. Therefore, the current date and time should be close
10
+ # enough to the real start date and time of the main script.
11
+ START_DATE_TIME = date_time_t.now()
12
+
13
+ DATE_TIME_ORIGIN = date_time_t.fromtimestamp(1970, None)
14
+ DATE_ORIGIN = DATE_TIME_ORIGIN.date()
15
+
16
+ """
17
+ COPYRIGHT NOTICE
18
+
19
+ This software is governed by the CeCILL license under French law and
20
+ abiding by the rules of distribution of free software. You can use,
21
+ modify and/ or redistribute the software under the terms of the CeCILL
22
+ license as circulated by CEA, CNRS and INRIA at the following URL
23
+ "http://www.cecill.info".
24
+
25
+ As a counterpart to the access to the source code and rights to copy,
26
+ modify and redistribute granted by the license, users are provided only
27
+ with a limited warranty and the software's author, the holder of the
28
+ economic rights, and the successive licensors have only limited
29
+ liability.
30
+
31
+ In this respect, the user's attention is drawn to the risks associated
32
+ with loading, using, modifying and/or developing or reproducing the
33
+ software by the user in light of its specific status of free software,
34
+ that may mean that it is complicated to manipulate, and that also
35
+ therefore means that it is reserved for developers and experienced
36
+ professionals having in-depth computer knowledge. Users are therefore
37
+ encouraged to load and test the software's suitability as regards their
38
+ requirements in conditions enabling the security of their systems and/or
39
+ data to be ensured and, more generally, to use and operate it in the
40
+ same conditions as regards security.
41
+
42
+ The fact that you are presently reading this means that you have had
43
+ knowledge of the CeCILL license and that you accept its terms.
44
+
45
+ SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
46
+ """
@@ -12,15 +12,16 @@ USER_FOLDER = path_t.home()
12
12
 
13
13
  frame = e.stack(context=0)[-1] # -1=root caller.
14
14
  if path_t(frame.filename).exists():
15
- PROJECT_FILE = path_t(frame.filename)
16
- if PROJECT_FILE.is_relative_to(USER_FOLDER):
17
- PROJECT_FILE_RELATIVE = PROJECT_FILE.relative_to(USER_FOLDER)
15
+ LAUNCH_ROOT_FILE = path_t(frame.filename)
16
+ LAUNCH_FOLDER = LAUNCH_ROOT_FILE.parent
17
+
18
+ if LAUNCH_ROOT_FILE.is_relative_to(USER_FOLDER):
19
+ LAUNCH_ROOT_FILE_relative = LAUNCH_ROOT_FILE.relative_to(USER_FOLDER)
18
20
  else:
19
- PROJECT_FILE_RELATIVE = PROJECT_FILE
20
- PROJECT_FOLDER = PROJECT_FILE.parent
21
+ LAUNCH_ROOT_FILE_relative = LAUNCH_ROOT_FILE
21
22
  else:
22
- PROJECT_FILE = PROJECT_FILE_RELATIVE = "<unknown>"
23
- PROJECT_FOLDER = path_t(tmps.mkdtemp())
23
+ LAUNCH_ROOT_FILE = LAUNCH_ROOT_FILE_relative = "<unknown launch root file>"
24
+ LAUNCH_FOLDER = path_t(tmps.mkdtemp())
24
25
 
25
26
  """
26
27
  COPYRIGHT NOTICE
@@ -4,7 +4,6 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- INTERNAL_INFO_ATTR = "internal_info"
8
7
  SHOW_WHERE_ATTR = "should_show_where"
9
8
  SHOW_W_RULE_ATTR = "should_show_w_rule"
10
9
  WHEN_OR_ELAPSED_ATTR = "when_or_elapsed"
@@ -4,9 +4,9 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- RULE_CHARACTER = "-"
7
+ from logger_36.config.rule import DEFAULT_RULE_LENGTH, RULE_CHARACTER
8
+
8
9
  MIN_HALF_RULE_LENGTH = 4
9
- DEFAULT_RULE_LENGTH = 50
10
10
  DEFAULT_RULE = DEFAULT_RULE_LENGTH * RULE_CHARACTER
11
11
 
12
12
  """
@@ -4,14 +4,16 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- import importlib.metadata as mprt
8
7
  import pkgutil as pkgs
9
8
  import sys as s
10
- from types import FunctionType, MethodType
11
9
 
12
10
 
13
11
  def Modules(
14
- with_version: bool, formatted: bool, /, *, only_loaded: bool = True, indent: int = 0
12
+ *,
13
+ only_loaded: bool = True,
14
+ with_version: bool = True,
15
+ formatted: bool = False,
16
+ indent: int = 0,
15
17
  ) -> tuple[str, ...] | str:
16
18
  """"""
17
19
  output = []
@@ -61,23 +63,6 @@ def Modules(
61
63
  return tuple(output)
62
64
 
63
65
 
64
- def WhereFunction(function: FunctionType, /) -> str:
65
- """"""
66
- return f"{function.__module__}:{function.__name__}"
67
-
68
-
69
- def WhereMethod(instance: object, method: MethodType, /) -> str:
70
- """
71
- method: Could be a str instead, which would require changing method.__name__ into
72
- getattr(cls, method). But if the method name changes while forgetting to change the
73
- string in the call to WhereMethod accordingly, then an exception would be raised
74
- here.
75
- """
76
- cls = instance.__class__
77
-
78
- return f"{cls.__module__}:{cls.__name__}:{method.__name__}"
79
-
80
-
81
66
  def _ModulesUsingPkgUtil() -> tuple[str, ...]:
82
67
  """
83
68
  Returns more results than using importlib.
@@ -91,15 +76,16 @@ def _ModulesUsingPkgUtil() -> tuple[str, ...]:
91
76
  )
92
77
 
93
78
 
94
- def _ModulesUsingImportlib() -> tuple[str, ...]:
95
- """"""
96
- return tuple(
97
- sorted(
98
- _elm
99
- for _elm in mprt.packages_distributions()
100
- if (_elm[0] != "_") and ("__" not in _elm) and ("/" not in _elm)
101
- )
102
- )
79
+ # import importlib.metadata as mprt
80
+ # def _ModulesUsingImportlib() -> tuple[str, ...]:
81
+ # """"""
82
+ # return tuple(
83
+ # sorted(
84
+ # _elm
85
+ # for _elm in mprt.packages_distributions()
86
+ # if (_elm[0] != "_") and ("__" not in _elm) and ("/" not in _elm)
87
+ # )
88
+ # )
103
89
 
104
90
 
105
91
  """
@@ -0,0 +1,66 @@
1
+ """
2
+ Copyright CNRS (https://www.cnrs.fr/index.php/en)
3
+ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
+ SEE COPYRIGHT NOTICE BELOW
5
+ """
6
+
7
+ import logging as l
8
+ import sys as s
9
+ from os import sep as FOLDER_SEPARATOR
10
+ from pathlib import Path as path_t
11
+
12
+ from logger_36.constant.path import USER_FOLDER
13
+ from logger_36.constant.record import WHERE_ATTR
14
+
15
+
16
+ def RecordLocation(record: l.LogRecord, should_also_store: bool, /) -> str:
17
+ """"""
18
+ module = path_t(record.pathname)
19
+ for path in s.path:
20
+ if module.is_relative_to(path):
21
+ module = module.relative_to(path).with_suffix("")
22
+ module = str(module).replace(FOLDER_SEPARATOR, ".")
23
+ break
24
+ else:
25
+ if module.is_relative_to(USER_FOLDER):
26
+ module = module.relative_to(USER_FOLDER)
27
+
28
+ output = f"{module}:{record.funcName}:{record.lineno}"
29
+
30
+ if should_also_store:
31
+ setattr(record, WHERE_ATTR, output)
32
+
33
+ return output
34
+
35
+
36
+ """
37
+ COPYRIGHT NOTICE
38
+
39
+ This software is governed by the CeCILL license under French law and
40
+ abiding by the rules of distribution of free software. You can use,
41
+ modify and/ or redistribute the software under the terms of the CeCILL
42
+ license as circulated by CEA, CNRS and INRIA at the following URL
43
+ "http://www.cecill.info".
44
+
45
+ As a counterpart to the access to the source code and rights to copy,
46
+ modify and redistribute granted by the license, users are provided only
47
+ with a limited warranty and the software's author, the holder of the
48
+ economic rights, and the successive licensors have only limited
49
+ liability.
50
+
51
+ In this respect, the user's attention is drawn to the risks associated
52
+ with loading, using, modifying and/or developing or reproducing the
53
+ software by the user in light of its specific status of free software,
54
+ that may mean that it is complicated to manipulate, and that also
55
+ therefore means that it is reserved for developers and experienced
56
+ professionals having in-depth computer knowledge. Users are therefore
57
+ encouraged to load and test the software's suitability as regards their
58
+ requirements in conditions enabling the security of their systems and/or
59
+ data to be ensured and, more generally, to use and operate it in the
60
+ same conditions as regards security.
61
+
62
+ The fact that you are presently reading this means that you have had
63
+ knowledge of the CeCILL license and that you accept its terms.
64
+
65
+ SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
66
+ """
@@ -7,9 +7,7 @@ SEE COPYRIGHT NOTICE BELOW
7
7
  import time
8
8
  from datetime import datetime as date_time_t
9
9
 
10
- # This module is imported early. Therefore, the current date and time should be close
11
- # enough to the real start time of the main script.
12
- _START_DATE_AND_TIME = date_time_t.now()
10
+ from logger_36.constant.date_time import START_DATE_TIME
13
11
 
14
12
 
15
13
  def TimeStamp(*, precision: str = "microseconds") -> str:
@@ -25,7 +23,7 @@ def TimeStamp(*, precision: str = "microseconds") -> str:
25
23
  def ElapsedTime(*, should_return_now: bool = False) -> str | tuple[str, date_time_t]:
26
24
  """"""
27
25
  now = date_time_t.now()
28
- elapsed_seconds = (now - _START_DATE_AND_TIME).total_seconds()
26
+ elapsed_seconds = (now - START_DATE_TIME).total_seconds()
29
27
  output = time.strftime("%H:%M:%S", time.gmtime(elapsed_seconds))
30
28
  while output.startswith("00:"):
31
29
  output = output.split(sep=":", maxsplit=1)[-1]
@@ -5,30 +5,35 @@ SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
7
  import logging as l
8
+ import os as o
9
+ import tempfile as tmps
8
10
  from io import IOBase as io_base_t
9
11
  from pathlib import Path as path_t
10
12
 
11
13
  from logger_36.constant.html import BODY_PLACEHOLDER, MINIMAL_HTML, TITLE_PLACEHOLDER
12
14
  from logger_36.instance.logger import L
15
+ from logger_36.type.logger import logger_t
13
16
 
14
17
 
15
- def SaveLOGasHTML(path: str | path_t | io_base_t | None = None) -> None:
18
+ def SaveLOGasHTML(
19
+ path: str | path_t | io_base_t | None = None, /, *, logger: logger_t = L
20
+ ) -> None:
16
21
  """
17
22
  From first console handler found.
18
23
  """
19
24
  cannot_save = "Cannot save logging record as HTML"
20
25
 
21
26
  if path is None:
22
- for handler in L.handlers:
27
+ for handler in logger.handlers:
23
28
  if isinstance(handler, l.FileHandler):
24
29
  path = path_t(handler.baseFilename).with_suffix(".htm")
25
30
  break
26
31
  else:
27
- L.warning(f"{cannot_save}: No file handler to build a filename from.")
32
+ logger.warning(f"{cannot_save}: No file handler to build a filename from.")
28
33
  return
29
34
 
30
35
  if path.exists():
31
- L.warning(
36
+ logger.warning(
32
37
  f'{cannot_save}: Automatically generated path "{path}" already exists.'
33
38
  )
34
39
  return
@@ -38,13 +43,45 @@ def SaveLOGasHTML(path: str | path_t | io_base_t | None = None) -> None:
38
43
  actual_file = isinstance(path, path_t)
39
44
 
40
45
  if actual_file and path.exists():
41
- L.warning(f'{cannot_save}: File "{path}" already exists.')
46
+ existing = path
47
+
48
+ accessor, path = tmps.mkstemp(suffix=".htm")
49
+ o.close(accessor)
50
+ path = path_t(path)
51
+
52
+ logger.warning(
53
+ f'File "{existing}" already exists: Saving LOG as HTML in {path} instead.'
54
+ )
55
+
56
+ for handler in logger.handlers:
57
+ records = getattr(handler, "records", None)
58
+ if isinstance(records, list) and (
59
+ (records.__len__() == 0)
60
+ or all(
61
+ isinstance(_, tuple)
62
+ and isinstance(_[0], int)
63
+ and isinstance(_[1], dict | str | l.LogRecord)
64
+ and isinstance(_[2], bool)
65
+ for _ in records
66
+ )
67
+ ):
68
+ break
69
+ else:
70
+ logger.warning(f"{cannot_save}: No handlers with recording capability found.")
42
71
  return
43
72
 
44
- body = "\n".join(map(_HighlightedEvent, L.recorded))
45
- html = MINIMAL_HTML.replace(TITLE_PLACEHOLDER, L.name).replace(
73
+ if records.__len__() == 0:
74
+ return
75
+
76
+ if isinstance(records[0][1], str):
77
+ records = map(_HighlightedEvent, records)
78
+ else:
79
+ records = map(lambda _: str(_[1]), records)
80
+ body = "\n".join(records)
81
+ html = MINIMAL_HTML.replace(TITLE_PLACEHOLDER, logger.name).replace(
46
82
  BODY_PLACEHOLDER, body
47
83
  )
84
+
48
85
  if actual_file:
49
86
  with open(path, "w") as accessor:
50
87
  accessor.write(html)
@@ -52,21 +89,25 @@ def SaveLOGasHTML(path: str | path_t | io_base_t | None = None) -> None:
52
89
  path.write(html)
53
90
 
54
91
 
55
- def _HighlightedEvent(event: tuple[int, str], /) -> str:
92
+ def _HighlightedEvent(event: tuple[int, str, bool], /) -> str:
56
93
  """"""
57
- level, message = event
58
- if level == l.DEBUG:
59
- color = "BlueViolet"
60
- elif level == l.INFO:
61
- color = "black"
62
- elif level == l.WARNING:
63
- color = "gold"
64
- elif level == l.ERROR:
65
- color = "orange"
66
- elif level == l.CRITICAL:
67
- color = "red"
94
+ level, message, is_not_a_rule = event
95
+
96
+ if is_not_a_rule:
97
+ if level == l.DEBUG:
98
+ color = "BlueViolet"
99
+ elif level == l.INFO:
100
+ color = "black"
101
+ elif level == l.WARNING:
102
+ color = "gold"
103
+ elif level == l.ERROR:
104
+ color = "orange"
105
+ elif level == l.CRITICAL:
106
+ color = "red"
107
+ else:
108
+ color = "black"
68
109
  else:
69
- color = "black"
110
+ color = "DarkTurquoise"
70
111
 
71
112
  return f'<span style="color:{color}">{message}</span>'
72
113