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.
- {zstdlib-0.9.0 → zstdlib-0.10.0}/PKG-INFO +1 -1
- zstdlib-0.10.0/tests/test_exc_capture.py +70 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/__init__.py +4 -1
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/ansi.py +11 -6
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/enum.py +4 -2
- zstdlib-0.10.0/zstdlib/exc_capture.py +69 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/io.py +2 -2
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/PKG-INFO +1 -1
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/SOURCES.txt +2 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/LICENSE +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/README.md +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/pyproject.toml +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/setup.cfg +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/__init__.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/log/__init__.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/log/base.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/log/test_cute.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/log/test_trace.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_ansi.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_enum.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_frozen.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_io.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_lazy.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_not_set.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/tests/test_singleton.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/frozen.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/lazy.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/log/__init__.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/log/cute.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/log/trace.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/macos.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/not_set.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/py.typed +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/signal_cm.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib/singleton.py +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/dependency_links.txt +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/requires.txt +0 -0
- {zstdlib-0.9.0 → zstdlib-0.10.0}/zstdlib.egg-info/top_level.txt +0 -0
|
@@ -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.
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
177
|
+
"""
|
|
178
|
+
Args:
|
|
174
179
|
foreground: The foreground color
|
|
175
180
|
background: The background color
|
|
176
|
-
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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"""
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|