zstdlib 0.0.6__tar.gz → 0.0.9__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 (30) hide show
  1. {zstdlib-0.0.6 → zstdlib-0.0.9}/PKG-INFO +1 -1
  2. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/log/test_cute.py +39 -8
  3. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/__init__.py +1 -1
  4. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/ansi.py +6 -0
  5. zstdlib-0.0.9/zstdlib/log/cute.py +104 -0
  6. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib.egg-info/PKG-INFO +1 -1
  7. zstdlib-0.0.6/zstdlib/log/cute.py +0 -92
  8. {zstdlib-0.0.6 → zstdlib-0.0.9}/LICENSE +0 -0
  9. {zstdlib-0.0.6 → zstdlib-0.0.9}/README.md +0 -0
  10. {zstdlib-0.0.6 → zstdlib-0.0.9}/pyproject.toml +0 -0
  11. {zstdlib-0.0.6 → zstdlib-0.0.9}/setup.cfg +0 -0
  12. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/__init__.py +0 -0
  13. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/log/__init__.py +0 -0
  14. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/log/base.py +0 -0
  15. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/log/test_trace.py +0 -0
  16. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/not_set.py +0 -0
  17. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/test_ansi.py +0 -0
  18. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/test_enum.py +0 -0
  19. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/test_frozen.py +0 -0
  20. {zstdlib-0.0.6 → zstdlib-0.0.9}/tests/test_singleton.py +0 -0
  21. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/enum.py +0 -0
  22. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/frozen.py +0 -0
  23. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/log/__init__.py +0 -0
  24. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/log/trace.py +0 -0
  25. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/not_set.py +0 -0
  26. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/py.typed +0 -0
  27. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib/singleton.py +0 -0
  28. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib.egg-info/SOURCES.txt +0 -0
  29. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib.egg-info/dependency_links.txt +0 -0
  30. {zstdlib-0.0.6 → zstdlib-0.0.9}/zstdlib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zstdlib
3
- Version: 0.0.6
3
+ Version: 0.0.9
4
4
  Summary: A set of useful python utilities
5
5
  License: GPLv3
6
6
  Project-URL: Homepage, https://github.com/zwimer/zstdlib
@@ -17,16 +17,25 @@ class TestCuteFormatter(LeftBase, unittest.TestCase):
17
17
  msg = self.messages[log][0].rsplit("|", 1)[-1]
18
18
  self.assertEqual(f" {color.code}test{Color.RESET}", msg)
19
19
 
20
- def test_name_width(self) -> None:
21
- width = 123
20
+ def test_width(self) -> None:
22
21
  color = Color.red
23
- name = "TestCuteFormatter.name_width"
24
- with self.hijack(name, fmt=CuteFormatter(colors={name: color}, name_width=width)) as log:
22
+ name = "TestCuteFormatter.test_width"
23
+ cw = {
24
+ "cute_levelname": 300,
25
+ "cute_asctime": 200,
26
+ "cute_name": 100,
27
+ "cute_message": 400,
28
+ }
29
+ fmt = CuteFormatter(fmt="|".join(f"%({i})s" for i in cw), colors={name: color}, cute_widths=cw)
30
+ with self.hijack(name, fmt=fmt) as log:
25
31
  log.debug("test")
26
- lvl, _, nam, msg = self.messages[log][0].split("|")
27
- self.assertEqual("DEBUG", lvl.strip())
28
- self.assertEqual(f" {color(name.ljust(width))} ", nam)
29
- self.assertEqual(f" {color('test')}", msg)
32
+ lvl, date, nam, msg = self.messages[log][0].split("|")
33
+ self.assertEqual("DEBUG".ljust(cw["cute_levelname"]), lvl)
34
+ self.assertEqual(cw["cute_asctime"], len(date))
35
+ self.assertEqual(f"{color(name.ljust(cw['cute_name']))}", nam)
36
+ self.assertEqual(f"{color('test'.ljust(cw['cute_message']))}", msg)
37
+ with self.assertRaises(ValueError):
38
+ CuteFormatter(cute_widths={"name": 123})
30
39
 
31
40
  def test_no_color(self) -> None:
32
41
  name = "TestCuteFormatter.test_no_color"
@@ -69,6 +78,28 @@ class TestCuteFormatter(LeftBase, unittest.TestCase):
69
78
  self.assertEqual(Color.bright_red_bg_yellow("CRITICAL".ljust(8)), l_name(5))
70
79
  self.assertEqual(Color.bright_red_bg_yellow("Level 60".ljust(8)), l_name(6))
71
80
 
81
+ def test_custom_dim_level(self) -> None:
82
+ name = "TestCuteFormatter.test_dim_level"
83
+ msg = "test"
84
+ with self.hijack(name, fmt=CuteFormatter(dim_level=5)) as log:
85
+ log.log(4, msg)
86
+ log.log(5, msg)
87
+ self.assertEqual(2, len(self.messages[log]))
88
+ l_name = lambda idx: self.messages[log][idx].split("|")[0].strip()
89
+ self.assertEqual(Color.dim("Level 4".ljust(8)), l_name(0))
90
+ self.assertEqual("Level 5", l_name(1))
91
+
92
+ def test_custom_level_color(self) -> None:
93
+ name = "TestCuteFormatter.test_custom_level_color"
94
+ msg = "test"
95
+ with self.hijack(name, fmt=CuteFormatter(level_colors={15: Color.bright_red_bg_yellow})) as log:
96
+ log.log(14, msg)
97
+ log.log(15, msg)
98
+ self.assertEqual(2, len(self.messages[log]))
99
+ l_name = lambda idx: self.messages[log][idx].split("|")[0].strip()
100
+ self.assertEqual("Level 14".ljust(8), l_name(0))
101
+ self.assertEqual(Color.bright_red_bg_yellow("Level 15".ljust(8)), l_name(1))
102
+
72
103
  def test_exception(self) -> None:
73
104
  name = "TestCuteFormatter.test_exception"
74
105
  with self.hijack(name, fmt=CuteFormatter()) as log:
@@ -1,4 +1,4 @@
1
- __version__ = "0.0.6"
1
+ __version__ = "0.0.9"
2
2
 
3
3
  from .not_set import NotSetType, NotSet
4
4
  from .frozen import Freezable, frozen
@@ -107,6 +107,12 @@ class Color(metaclass=_ColorMeta):
107
107
  raise TypeError("Cannot add non-Color to Color")
108
108
  return type(self)(code=f"{self.code[:-1]};{other.code[len(_PREFIX):]}")
109
109
 
110
+ def __eq__(self, other: object) -> bool:
111
+ """
112
+ :return: Whether the two colors are equal
113
+ """
114
+ return isinstance(other, type(self)) and self.code == other.code
115
+
110
116
  def __repr__(self) -> str:
111
117
  """
112
118
  :return: The ansi color code this object represents
@@ -0,0 +1,104 @@
1
+ from __future__ import annotations
2
+ from logging import CRITICAL, ERROR, WARNING, INFO, DEBUG, Formatter
3
+ from collections import defaultdict
4
+ from typing import TYPE_CHECKING
5
+ from zlib import adler32
6
+ from copy import copy
7
+
8
+ from ..ansi import PureColor, RawColor, Color
9
+
10
+ if TYPE_CHECKING:
11
+ from logging import LogRecord
12
+
13
+
14
+ class CuteFormatter(Formatter):
15
+ """
16
+ A log formatter that can print log messages with colors.
17
+ """
18
+
19
+ __slots__ = ("colored", "_color", "_cmap", "_lvl_cmap", "_dim_level", "_name_width")
20
+ DEFAULT_CUTE_WIDTHS: dict[str, int] = {"cute_levelname": 8, "cute_time": 23, "cute_name": 12}
21
+ DEFAULT_LEVEL_COLORS: dict[int, Color] = {
22
+ INFO: Color.blue,
23
+ WARNING: Color.yellow,
24
+ ERROR: Color.red,
25
+ CRITICAL: Color.bright_red_bg_yellow,
26
+ }
27
+
28
+ # pylint: disable=dangerous-default-value,keyword-arg-before-vararg,too-many-arguments
29
+ def __init__(
30
+ self,
31
+ fmt="%(cute_levelname)s | %(cute_asctime)s | %(cute_name)s | %(cute_message)s",
32
+ *args,
33
+ colored: bool = True,
34
+ dim_level: int = DEBUG,
35
+ colors: dict[str, Color] = {},
36
+ level_colors: dict[int, Color] = {},
37
+ cute_widths: dict[str, int] = {},
38
+ **kwargs,
39
+ ):
40
+ """
41
+ log_colors may be overridden, for example, trace logs are printed dimly
42
+ Do not modify cute_ parameters in the fmt string; they might have special formatting that is not visible
43
+ Ex. %(cute_name)-8s should be done via cute_widths["cute_name"] = 8
44
+ This is because cute_widths takes into account 0-width color codes when padding
45
+ Level colors used are: DEFAULT_LEVEL_COLORS | level_colors
46
+ Dimming of log messages is done for levels < dim_level
47
+ :param fmt: The format string to use for the log message; do not modify cute_ parameters
48
+ :param args: Passed to logging.Formatter
49
+ :param colored: If False, no colors will be used regardless of the colors parameter
50
+ :param colors: The colors to use for the given loggers, automatic for non-specified loggers
51
+ :param level_colors: The colors to use >= the given levels, automatic for non-specified loggers
52
+ :param cute_widths: The widths of the cute_ columns in the log message
53
+ :param kwargs: Passed to logging.Formatter
54
+ """
55
+ super().__init__(fmt, *args, **kwargs)
56
+ self._dim_level: int = dim_level
57
+ self._cmap: dict[str, Color] = dict(colors)
58
+ self._lvl_cmap: dict[int, Color] = self.DEFAULT_LEVEL_COLORS | level_colors
59
+ self._widths = defaultdict(int, self.DEFAULT_CUTE_WIDTHS | cute_widths)
60
+ if any(not i.startswith("cute_") for i in self._widths):
61
+ raise ValueError("cute_widths must only contain cute_ parameters")
62
+ self.colored: bool = colored
63
+
64
+ def update(self, colors: dict[str, Color]):
65
+ """
66
+ Set the colors for all loggers; enables colors if disabled
67
+ """
68
+ self._cmap |= colors
69
+
70
+ def format(self, record: LogRecord) -> str:
71
+ levelname: str = record.levelname.ljust(self._widths["cute_levelname"])
72
+ asctime = self.formatTime(record, self.datefmt).ljust(self._widths["cute_asctime"])
73
+ name: str = record.name.ljust(self._widths["cute_name"])
74
+ message: str = record.getMessage().ljust(self._widths["cute_message"])
75
+ if self.colored:
76
+ # Color level
77
+ opts = tuple(i for i in self._lvl_cmap if i <= record.levelno)
78
+ col: Color | None = self._lvl_cmap[max(opts)] if opts else None
79
+ if record.levelno < self._dim_level:
80
+ col = Color.dim if col is None else (col + Color.dim)
81
+ if col is not None:
82
+ levelname = col(levelname)
83
+ # Color text
84
+ if (col := self._cmap.get(record.name, None)) is None:
85
+ c: int = adler32(record.name.encode()) % 7
86
+ col = Color(RawColor(PureColor.black.value + c)) if c != 0 else Color.default
87
+ if record.levelno < self._dim_level:
88
+ col += Color.dim
89
+ message = col(message)
90
+ name = col(name)
91
+ # Color timestamp
92
+ if record.levelno < self._dim_level:
93
+ asctime = Color.dim(asctime)
94
+ # Create an updated record then format that
95
+ new = copy(record)
96
+ new.__dict__.update(
97
+ {
98
+ "cute_levelname": levelname,
99
+ "cute_asctime": asctime,
100
+ "cute_name": name,
101
+ "cute_message": message,
102
+ }
103
+ )
104
+ return super().format(new)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zstdlib
3
- Version: 0.0.6
3
+ Version: 0.0.9
4
4
  Summary: A set of useful python utilities
5
5
  License: GPLv3
6
6
  Project-URL: Homepage, https://github.com/zwimer/zstdlib
@@ -1,92 +0,0 @@
1
- from __future__ import annotations
2
- from logging import CRITICAL, ERROR, WARNING, INFO, DEBUG, Formatter
3
- from traceback import format_exception
4
- from typing import TYPE_CHECKING
5
- from zlib import adler32
6
- from copy import copy
7
-
8
- from ..ansi import PureColor, RawColor, Color
9
-
10
- if TYPE_CHECKING:
11
- from logging import LogRecord
12
-
13
-
14
- class CuteFormatter(Formatter):
15
- """
16
- A log formatter that can print log messages with colors.
17
- """
18
-
19
- __slots__ = ("colored", "_color", "_cmap", "_name_width")
20
-
21
- def __init__(
22
- self,
23
- colors: dict[str, Color] | None = None,
24
- *,
25
- colored: bool = True,
26
- name_width: int = 12,
27
- fmt="%(cute_levelname)s | %(cute_time)s | %(cute_name)s | %(cute_message)s%(cute_exc)s",
28
- **kwargs,
29
- ):
30
- """
31
- log_colors may be overridden, for example, trace logs are printed dimly
32
- Do not modify cute_ parameters in the fmt string; they might have special formatting that is not visible
33
- Ex. %(cute_name)-8s should be done via name_width, that takes into account 0-width color codes
34
- :param colors: The colors to use for the given loggers, automatic for non-specified loggers
35
- :param colored: If False, no colors will be used regardless of the colors parameter
36
- :param fmt: The format string to use for the log message; do not modify cute_ parameters
37
- :param name_width: How wide the column containing the logger name should be (minus padding)
38
- :param kwargs: Passed to logging.Formatter
39
- """
40
- super().__init__(fmt=fmt, **kwargs)
41
- self._cmap: dict[str, Color] = {}
42
- if colors is not None:
43
- self.update(colors)
44
- self._name_width = name_width
45
- self.colored: bool = colored
46
-
47
- def update(self, colors: dict[str, Color]):
48
- """
49
- Set the colors for all loggers; enables colors if disabled
50
- """
51
- self._cmap.update(colors)
52
-
53
- def format(self, record: LogRecord) -> str:
54
- level: str = record.levelname.ljust(8)
55
- when = self.formatTime(record, self.datefmt).ljust(23)
56
- name: str = record.name.ljust(self._name_width)
57
- message: str = record.getMessage()
58
- if self.colored:
59
- # Color level
60
- if record.levelno >= CRITICAL:
61
- level = Color.bright_red_bg_yellow(level)
62
- elif record.levelno >= ERROR:
63
- level = Color.red(level)
64
- elif record.levelno >= WARNING:
65
- level = Color.yellow(level)
66
- elif record.levelno >= INFO:
67
- level = Color.blue(level)
68
- elif record.levelno < DEBUG:
69
- level = Color.dim(level)
70
- # Color text
71
- if (col := self._cmap.get(record.name, None)) is None:
72
- c: int = adler32(record.name.encode()) % 7
73
- col = Color(RawColor(PureColor.black.value + c)) if c != 0 else Color.default
74
- if record.levelno < DEBUG:
75
- col += Color.dim
76
- message = col(message)
77
- name = col(name)
78
- # Color timestamp
79
- if record.levelno < DEBUG:
80
- when = Color.dim(when)
81
- # Create an updated record then format that
82
- new = copy(record)
83
- new.__dict__.update(
84
- {
85
- "cute_levelname": level,
86
- "cute_time": when,
87
- "cute_name": name,
88
- "cute_message": message,
89
- "cute_exc": ("\n" + "".join(format_exception(*new.exc_info))[:-1]) if new.exc_info else "",
90
- }
91
- )
92
- return super().format(new)
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
File without changes
File without changes
File without changes
File without changes
File without changes