zstdlib 0.9.0__tar.gz → 0.10.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.
Files changed (38) hide show
  1. {zstdlib-0.9.0 → zstdlib-0.10.0}/PKG-INFO +1 -1
  2. zstdlib-0.10.0/tests/test_exc_capture.py +70 -0
  3. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/__init__.py +4 -1
  4. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/ansi.py +11 -6
  5. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/enum.py +4 -2
  6. zstdlib-0.10.0/zstdlib/exc_capture.py +69 -0
  7. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/io.py +2 -2
  8. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/PKG-INFO +1 -1
  9. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/SOURCES.txt +2 -0
  10. {zstdlib-0.9.0 → zstdlib-0.10.0}/LICENSE +0 -0
  11. {zstdlib-0.9.0 → zstdlib-0.10.0}/README.md +0 -0
  12. {zstdlib-0.9.0 → zstdlib-0.10.0}/pyproject.toml +0 -0
  13. {zstdlib-0.9.0 → zstdlib-0.10.0}/setup.cfg +0 -0
  14. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/__init__.py +0 -0
  15. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/log/__init__.py +0 -0
  16. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/log/base.py +0 -0
  17. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/log/test_cute.py +0 -0
  18. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/log/test_trace.py +0 -0
  19. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_ansi.py +0 -0
  20. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_enum.py +0 -0
  21. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_frozen.py +0 -0
  22. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_io.py +0 -0
  23. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_lazy.py +0 -0
  24. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_not_set.py +0 -0
  25. {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_singleton.py +0 -0
  26. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/frozen.py +0 -0
  27. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/lazy.py +0 -0
  28. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/log/__init__.py +0 -0
  29. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/log/cute.py +0 -0
  30. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/log/trace.py +0 -0
  31. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/macos.py +0 -0
  32. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/not_set.py +0 -0
  33. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/py.typed +0 -0
  34. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/signal_cm.py +0 -0
  35. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/singleton.py +0 -0
  36. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/dependency_links.txt +0 -0
  37. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/requires.txt +0 -0
  38. {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zstdlib
3
- Version: 0.9.0
3
+ Version: 0.10.0
4
4
  Summary: A set of useful python utilities
5
5
  License: GPLv3
6
6
  Project-URL: Homepage, https://github.com/zwimer/zstdlib
@@ -0,0 +1,70 @@
1
+ # pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
2
+ import unittest
3
+
4
+ from zstdlib import ExcCapture, ExcDelay
5
+
6
+
7
+ class TestLazy(unittest.TestCase):
8
+
9
+ def test_capture(self) -> None:
10
+ # Capture nothing
11
+ rt = ExcCapture(RuntimeError)
12
+ with rt.capture():
13
+ pass
14
+ self.assertEqual(len(rt.errors), 0)
15
+ # Capture only Runtime
16
+ with rt.capture():
17
+ raise RuntimeError()
18
+ self.assertEqual(len(rt.errors), 1)
19
+ with self.assertRaises(ValueError), rt.capture():
20
+ raise ValueError()
21
+ self.assertEqual(len(rt.errors), 1)
22
+ # capture's exc_t
23
+ rt = ExcCapture(RuntimeError)
24
+ with self.assertRaises(RuntimeError), rt.capture(ValueError):
25
+ raise RuntimeError()
26
+ self.assertEqual(len(rt.errors), 0)
27
+ with rt.capture(ValueError):
28
+ raise ValueError()
29
+ self.assertEqual(len(rt.errors), 1)
30
+ del rt
31
+ # exc_t = None
32
+ non = ExcCapture()
33
+ with self.assertRaises(RuntimeError), non.capture(ValueError):
34
+ raise RuntimeError()
35
+ self.assertEqual(len(non.errors), 0)
36
+ with self.assertRaises(ValueError), non.capture():
37
+ pass
38
+ self.assertEqual(len(non.errors), 0)
39
+ with non.capture(RuntimeError):
40
+ raise RuntimeError()
41
+ self.assertEqual(len(non.errors), 1)
42
+
43
+ def test_delay(self) -> None:
44
+ # No raise
45
+ with ExcDelay("msg", RuntimeError) as capture, capture():
46
+ pass
47
+ # Raise
48
+ ed = ExcDelay("msg", RuntimeError)
49
+ try:
50
+ with ed as capture:
51
+ with capture():
52
+ raise RuntimeError()
53
+ with capture():
54
+ raise RuntimeError()
55
+ self.assertTrue(False)
56
+ except BaseExceptionGroup as grp:
57
+ self.assertIsInstance(grp, ExceptionGroup) # Test auto-conversion
58
+ self.assertEqual(len(grp.exceptions), 2)
59
+ self.assertEqual(len(ed.errors), 2)
60
+ # No block error
61
+ with self.assertRaises(ValueError), ExcDelay("msg", RuntimeError) as capture, capture():
62
+ raise ValueError()
63
+ with self.assertRaises(ValueError), ExcDelay("msg", RuntimeError) as capture:
64
+ with capture():
65
+ raise RuntimeError()
66
+ raise ValueError()
67
+
68
+
69
+ if __name__ == "__main__":
70
+ unittest.main()
@@ -1,5 +1,6 @@
1
- __version__ = "0.9.0"
1
+ __version__ = "0.10.0"
2
2
 
3
+ from .exc_capture import ExcCapture, ExcDelay
3
4
  from .not_set import NotSetType, NotSet
4
5
  from .frozen import Freezable, frozen
5
6
  from .singleton import Singleton
@@ -9,6 +10,8 @@ from . import macos, lazy, log, io
9
10
 
10
11
  __all__ = (
11
12
  "Enum",
13
+ "ExcCapture",
14
+ "ExcDelay",
12
15
  "Freezable",
13
16
  "NotSet",
14
17
  "NotSetType",
@@ -117,7 +117,8 @@ class Color(metaclass=_ColorMeta):
117
117
  self.code = RawColor._parse_color(fmt) if isinstance(fmt, str) else fmt.code
118
118
 
119
119
  def __call__(self, string: str) -> str:
120
- """Args:
120
+ """
121
+ Args:
121
122
  string: The string to color
122
123
 
123
124
  Returns:
@@ -126,7 +127,8 @@ class Color(metaclass=_ColorMeta):
126
127
  return f"{self.code}{string}{self.RESET}"
127
128
 
128
129
  def __add__(self, other: Self) -> Self:
129
- """Args:
130
+ """
131
+ Args:
130
132
  other: The other string to color
131
133
 
132
134
  Returns:
@@ -137,7 +139,8 @@ class Color(metaclass=_ColorMeta):
137
139
  return type(self)(code=f"{self.code[:-1]};{other.code[len(_PREFIX):]}")
138
140
 
139
141
  def __eq__(self, other: object) -> bool:
140
- """Args:
142
+ """
143
+ Args:
141
144
  other: The color to compare against
142
145
 
143
146
  Returns:
@@ -156,7 +159,8 @@ class Color(metaclass=_ColorMeta):
156
159
  def factory(
157
160
  cls, *, foreground: RawColor | None = None, background: RawColor | None = None, **modifiers: bool
158
161
  ) -> Self:
159
- """Args:
162
+ """
163
+ Args:
160
164
  foreground: The foreground color
161
165
  background: The background color
162
166
  **modifiers: Color modifiers to apply
@@ -170,10 +174,11 @@ class Color(metaclass=_ColorMeta):
170
174
  def _generate_code(
171
175
  foreground: RawColor | None, background: RawColor | None, modifiers: dict[str, bool]
172
176
  ) -> str:
173
- """Args:
177
+ """
178
+ Args:
174
179
  foreground: The foreground color
175
180
  background: The background color
176
- **modifiers: Color modifiers to apply
181
+ modifiers: Color modifiers to apply
177
182
 
178
183
  Returns:
179
184
  The Ansi given the chosen color and various modifiers
@@ -136,7 +136,8 @@ class Enum(metaclass=EnumType, empty_ok=True):
136
136
 
137
137
 
138
138
  def entries(enum: EnumType) -> dict[str, tuple[type | None, Any]]:
139
- """Args:
139
+ """
140
+ Args:
140
141
  enum: A class whose metaclass is EnumType
141
142
 
142
143
  Returns:
@@ -149,7 +150,8 @@ def entries(enum: EnumType) -> dict[str, tuple[type | None, Any]]:
149
150
 
150
151
 
151
152
  def values(enum: Any) -> tuple[Any, ...]:
152
- """Args:
153
+ """
154
+ Args:
153
155
  enum: A class whose metaclass is EnumType
154
156
 
155
157
  Returns:
@@ -0,0 +1,69 @@
1
+ from contextlib import AbstractContextManager, contextmanager
2
+ from collections.abc import Iterator
3
+ from typing import Protocol
4
+
5
+ __all__ = ("ExcCapture", "ExcDelay")
6
+
7
+
8
+ type EXC_T = type[BaseException] | tuple[type[BaseException]]
9
+
10
+
11
+ class CaptureFType(Protocol):
12
+ """The type of the capture function (used for type checking)"""
13
+
14
+ def __call__(self, exc_t: EXC_T | None = None) -> AbstractContextManager[None]: ...
15
+
16
+
17
+ class ExcCapture:
18
+ """A class that exposes a context manager which captures and suppresses any raised exception of a given type / tuple of types"""
19
+
20
+ __slots__ = ("errors", "exc_t")
21
+
22
+ def __init__(self, exc_t: EXC_T | None = None) -> None:
23
+ """
24
+ Args:
25
+ msg: The exception group message
26
+ exc_t: The exception type the capture function should capture, if None it must be passed to the capture function directly
27
+ """
28
+ self.exc_t: EXC_T | None = exc_t
29
+ self.errors: list[BaseException] = []
30
+
31
+ @contextmanager
32
+ def capture(self, exc_t: EXC_T | None = None) -> Iterator[None]:
33
+ """Capture and suppress any exception if type/tuple of types exc_t (self.exc_t if None)"""
34
+ exc_t = self.exc_t if exc_t is None else exc_t
35
+ if exc_t is None:
36
+ raise ValueError("No exception type provided here nor during construction")
37
+ try:
38
+ yield
39
+ except exc_t as e:
40
+ self.errors.append(e)
41
+
42
+
43
+ class ExcDelay(ExcCapture):
44
+ """A context manager subclass of ExcCapture that raises on exit if errors are captured"""
45
+
46
+ __slots__ = ("_msg",)
47
+
48
+ def __init__(
49
+ self,
50
+ msg: str,
51
+ exc_t: type[BaseException] | None = None,
52
+ ) -> None:
53
+ """
54
+ Args:
55
+ exc_t: The exception type the capture function should capture, if None it must be passed to the capture function directly
56
+ msg: The exception group message
57
+ """
58
+ super().__init__(exc_t)
59
+ self._msg = msg
60
+
61
+ def __enter__(self) -> CaptureFType:
62
+ """Return the capture function to use"""
63
+ return self.capture
64
+
65
+ def __exit__(self, type_: type[BaseException] | None, *_: object) -> None:
66
+ """Raise an ExceptionGroup (or BaseExceptionGroup depending on exc_t) if self.errors"""
67
+ if type_ is None and self.errors:
68
+ # Auto-converts to ExceptionGroup if all items are Exceptions
69
+ raise BaseExceptionGroup(self._msg, self.errors)
@@ -41,8 +41,8 @@ class _IOWrapperBase[T: (str, bytes)]:
41
41
  """
42
42
 
43
43
  __slots__ = ("_buffer", "_eof", "f", "lock")
44
- _instances: WeakKeyDictionary[IOBase, Self] = WeakKeyDictionary()
45
- _wr_lock = RLock()
44
+ _instances: WeakKeyDictionary[IOBase, Self] = WeakKeyDictionary() # noqa: RUF012
45
+ _wr_lock: RLock = RLock()
46
46
 
47
47
  def __new__(cls, f: IOBase) -> Self:
48
48
  """Create a new instance of cls for raw, or return an existing instance if one exists"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zstdlib
3
- Version: 0.9.0
3
+ Version: 0.10.0
4
4
  Summary: A set of useful python utilities
5
5
  License: GPLv3
6
6
  Project-URL: Homepage, https://github.com/zwimer/zstdlib
@@ -4,6 +4,7 @@ pyproject.toml
4
4
  tests/__init__.py
5
5
  tests/test_ansi.py
6
6
  tests/test_enum.py
7
+ tests/test_exc_capture.py
7
8
  tests/test_frozen.py
8
9
  tests/test_io.py
9
10
  tests/test_lazy.py
@@ -16,6 +17,7 @@ tests/log/test_trace.py
16
17
  zstdlib/__init__.py
17
18
  zstdlib/ansi.py
18
19
  zstdlib/enum.py
20
+ zstdlib/exc_capture.py
19
21
  zstdlib/frozen.py
20
22
  zstdlib/io.py
21
23
  zstdlib/lazy.py
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
File without changes
File without changes
File without changes