zstdlib 0.0.3__tar.gz → 0.0.4__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.0.3/zstdlib.egg-info → zstdlib-0.0.4}/PKG-INFO +1 -1
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/test_frozen.py +29 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib/__init__.py +1 -1
- zstdlib-0.0.4/zstdlib/frozen.py +87 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4/zstdlib.egg-info}/PKG-INFO +1 -1
- zstdlib-0.0.3/zstdlib/frozen.py +0 -65
- {zstdlib-0.0.3 → zstdlib-0.0.4}/LICENSE +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/README.md +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/pyproject.toml +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/setup.cfg +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/__init__.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/log/__init__.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/log/base.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/log/test_cute.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/log/test_trace.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/test_ansi.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/test_enum.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/tests/test_singleton.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib/ansi.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib/enum.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib/log/__init__.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib/log/cute.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib/log/trace.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib/py.typed +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib/singleton.py +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib.egg-info/SOURCES.txt +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib.egg-info/dependency_links.txt +0 -0
- {zstdlib-0.0.3 → zstdlib-0.0.4}/zstdlib.egg-info/top_level.txt +0 -0
|
@@ -75,6 +75,35 @@ class TestFrozen(unittest.TestCase):
|
|
|
75
75
|
with self.assertRaises(AttributeError):
|
|
76
76
|
del f1.a
|
|
77
77
|
|
|
78
|
+
def test_metadata(self):
|
|
79
|
+
@frozen
|
|
80
|
+
class F2:
|
|
81
|
+
def __init__(self):
|
|
82
|
+
"""
|
|
83
|
+
init doc
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
f2 = F2()
|
|
87
|
+
self.assertEqual(f2.__init__.__doc__.strip(), "init doc")
|
|
88
|
+
self.assertEqual(f2.__init__.__name__, "__init__")
|
|
89
|
+
self.assertEqual(f2.__init__.__qualname__, "TestFrozen.test_metadata.<locals>.F2.__init__")
|
|
90
|
+
|
|
91
|
+
def test_frozen_custom(self):
|
|
92
|
+
@frozen("custom")
|
|
93
|
+
class F3:
|
|
94
|
+
def __init__(self):
|
|
95
|
+
self.a = 1
|
|
96
|
+
|
|
97
|
+
def custom(self):
|
|
98
|
+
self.a = 2
|
|
99
|
+
|
|
100
|
+
f3 = F3()
|
|
101
|
+
self.assertEqual(f3.a, 1)
|
|
102
|
+
f3.custom()
|
|
103
|
+
self.assertEqual(f3.a, 2)
|
|
104
|
+
with self.assertRaises(AttributeError):
|
|
105
|
+
f3.a = 1
|
|
106
|
+
|
|
78
107
|
|
|
79
108
|
if __name__ == "__main__":
|
|
80
109
|
unittest.main()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import TypeVar
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Freezable:
|
|
6
|
+
"""
|
|
7
|
+
A base class for objects that can be frozen
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
11
|
+
super().__init__(*args, **kwargs) # For MRO super classes
|
|
12
|
+
if hasattr(self, "_frozen") or hasattr(self, "_can_thaw"):
|
|
13
|
+
raise ValueError("Base class defines _frozen or _can_thaw")
|
|
14
|
+
self._can_thaw: bool = True
|
|
15
|
+
self._frozen: bool = False
|
|
16
|
+
|
|
17
|
+
def freeze(self, *, permanent: bool = False):
|
|
18
|
+
"""
|
|
19
|
+
Prevent further modifications to this object
|
|
20
|
+
"""
|
|
21
|
+
if permanent:
|
|
22
|
+
self._can_thaw = False
|
|
23
|
+
self._frozen = True
|
|
24
|
+
|
|
25
|
+
def thaw(self):
|
|
26
|
+
"""
|
|
27
|
+
Allow modifications to this object
|
|
28
|
+
"""
|
|
29
|
+
if not self._can_thaw:
|
|
30
|
+
raise RuntimeError("Cannot thaw permanently frozen object")
|
|
31
|
+
object.__setattr__(self, "_frozen", False)
|
|
32
|
+
|
|
33
|
+
def __setattr__(self, key: str, value) -> None:
|
|
34
|
+
if getattr(self, "_frozen", False):
|
|
35
|
+
raise AttributeError("Cannot modify frozen object")
|
|
36
|
+
super().__setattr__(key, value)
|
|
37
|
+
|
|
38
|
+
def __delattr__(self, item: str) -> None:
|
|
39
|
+
if getattr(self, "_frozen", False):
|
|
40
|
+
raise AttributeError("Cannot modify frozen object")
|
|
41
|
+
super().__delattr__(item)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_SELF = TypeVar("_SELF")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def frozen(arg: str | type[_SELF]):
|
|
48
|
+
"""
|
|
49
|
+
A class decorator to permanently freeze a class after some method, __init__ by default
|
|
50
|
+
If passed a string, will freeze after the method with that name
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def shim_method(cls: type[_SELF], name, new) -> None:
|
|
54
|
+
original = getattr(cls, name)
|
|
55
|
+
new.__qualname__ = original.__qualname__
|
|
56
|
+
new.__name__ = original.__name__
|
|
57
|
+
new.__doc__ = original.__doc__
|
|
58
|
+
setattr(cls, name, new)
|
|
59
|
+
|
|
60
|
+
def mk_frozen(cls: type[_SELF], method: str) -> type:
|
|
61
|
+
original_method: Callable = getattr(cls, method)
|
|
62
|
+
|
|
63
|
+
def new_method(self: _SELF, *args, **kwargs):
|
|
64
|
+
ret = original_method(self, *args, **kwargs)
|
|
65
|
+
# pylint: disable=protected-access
|
|
66
|
+
self._frozen = True # type: ignore[attr-defined]
|
|
67
|
+
return ret
|
|
68
|
+
|
|
69
|
+
def __setattr__(self: _SELF, key: str, value) -> None:
|
|
70
|
+
if getattr(self, "_frozen", False):
|
|
71
|
+
raise AttributeError("Cannot modify frozen object")
|
|
72
|
+
super(cls, self).__setattr__(key, value) # type: ignore[misc]
|
|
73
|
+
|
|
74
|
+
def __delattr__(self: _SELF, item: str) -> None:
|
|
75
|
+
if getattr(self, "_frozen", False):
|
|
76
|
+
raise AttributeError("Cannot modify frozen object")
|
|
77
|
+
super(cls, self).__delattr__(item) # type: ignore[misc]
|
|
78
|
+
|
|
79
|
+
# Update cls with the new methods
|
|
80
|
+
shim_method(cls, method, new_method)
|
|
81
|
+
shim_method(cls, "__delattr__", __delattr__)
|
|
82
|
+
shim_method(cls, "__setattr__", __setattr__)
|
|
83
|
+
return cls
|
|
84
|
+
|
|
85
|
+
if isinstance(arg, str):
|
|
86
|
+
return lambda cls: mk_frozen(cls, arg)
|
|
87
|
+
return mk_frozen(arg, "__init__")
|
zstdlib-0.0.3/zstdlib/frozen.py
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
class Freezable:
|
|
2
|
-
"""
|
|
3
|
-
A base class for objects that can be frozen
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
def __init__(self, *args, **kwargs) -> None:
|
|
7
|
-
super().__init__(*args, **kwargs) # For MRO super classes
|
|
8
|
-
if hasattr(self, "_frozen") or hasattr(self, "_can_thaw"):
|
|
9
|
-
raise ValueError("Base class defines _frozen or _can_thaw")
|
|
10
|
-
self._can_thaw: bool = True
|
|
11
|
-
self._frozen: bool = False
|
|
12
|
-
|
|
13
|
-
def freeze(self, *, permanent: bool = False):
|
|
14
|
-
"""
|
|
15
|
-
Prevent further modifications to this object
|
|
16
|
-
"""
|
|
17
|
-
if permanent:
|
|
18
|
-
self._can_thaw = False
|
|
19
|
-
self._frozen = True
|
|
20
|
-
|
|
21
|
-
def thaw(self):
|
|
22
|
-
"""
|
|
23
|
-
Allow modifications to this object
|
|
24
|
-
"""
|
|
25
|
-
if not self._can_thaw:
|
|
26
|
-
raise RuntimeError("Cannot thaw permanently frozen object")
|
|
27
|
-
object.__setattr__(self, "_frozen", False)
|
|
28
|
-
|
|
29
|
-
def __setattr__(self, key: str, value) -> None:
|
|
30
|
-
if getattr(self, "_frozen", False):
|
|
31
|
-
raise AttributeError("Cannot modify frozen object")
|
|
32
|
-
super().__setattr__(key, value)
|
|
33
|
-
|
|
34
|
-
def __delattr__(self, item: str) -> None:
|
|
35
|
-
if getattr(self, "_frozen", False):
|
|
36
|
-
raise AttributeError("Cannot modify frozen object")
|
|
37
|
-
super().__delattr__(item)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def frozen(cls):
|
|
41
|
-
"""
|
|
42
|
-
A class decorator to permanently freeze a class after __init__
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
def __setattr__(self, key: str, value) -> None:
|
|
46
|
-
if getattr(self, "_frozen", False):
|
|
47
|
-
raise AttributeError("Cannot modify frozen object")
|
|
48
|
-
super(cls, self).__setattr__(key, value)
|
|
49
|
-
|
|
50
|
-
def __delattr__(self, item: str) -> None:
|
|
51
|
-
if getattr(self, "_frozen", False):
|
|
52
|
-
raise AttributeError("Cannot modify frozen object")
|
|
53
|
-
super(cls, self).__delattr__(item)
|
|
54
|
-
|
|
55
|
-
init = cls.__init__
|
|
56
|
-
|
|
57
|
-
def __init__(self, *args, **kwargs):
|
|
58
|
-
init(self, *args, **kwargs)
|
|
59
|
-
self._frozen = True # pylint: disable=protected-access
|
|
60
|
-
|
|
61
|
-
# Update cls with the new methods
|
|
62
|
-
cls.__setattr__ = __setattr__
|
|
63
|
-
cls.__delattr__ = __delattr__
|
|
64
|
-
cls.__init__ = __init__
|
|
65
|
-
return cls
|
|
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
|