zstdlib 0.0.2__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.
Files changed (28) hide show
  1. {zstdlib-0.0.2/zstdlib.egg-info → zstdlib-0.0.4}/PKG-INFO +1 -1
  2. {zstdlib-0.0.2 → zstdlib-0.0.4}/tests/log/test_cute.py +2 -2
  3. {zstdlib-0.0.2 → zstdlib-0.0.4}/tests/test_enum.py +1 -1
  4. zstdlib-0.0.4/tests/test_frozen.py +109 -0
  5. {zstdlib-0.0.2 → zstdlib-0.0.4}/tests/test_singleton.py +1 -1
  6. zstdlib-0.0.4/zstdlib/__init__.py +6 -0
  7. zstdlib-0.0.4/zstdlib/frozen.py +87 -0
  8. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib/singleton.py +4 -6
  9. {zstdlib-0.0.2 → zstdlib-0.0.4/zstdlib.egg-info}/PKG-INFO +1 -1
  10. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib.egg-info/SOURCES.txt +2 -0
  11. zstdlib-0.0.2/zstdlib/__init__.py +0 -5
  12. {zstdlib-0.0.2 → zstdlib-0.0.4}/LICENSE +0 -0
  13. {zstdlib-0.0.2 → zstdlib-0.0.4}/README.md +0 -0
  14. {zstdlib-0.0.2 → zstdlib-0.0.4}/pyproject.toml +0 -0
  15. {zstdlib-0.0.2 → zstdlib-0.0.4}/setup.cfg +0 -0
  16. {zstdlib-0.0.2 → zstdlib-0.0.4}/tests/__init__.py +0 -0
  17. {zstdlib-0.0.2 → zstdlib-0.0.4}/tests/log/__init__.py +0 -0
  18. {zstdlib-0.0.2 → zstdlib-0.0.4}/tests/log/base.py +0 -0
  19. {zstdlib-0.0.2 → zstdlib-0.0.4}/tests/log/test_trace.py +0 -0
  20. {zstdlib-0.0.2 → zstdlib-0.0.4}/tests/test_ansi.py +0 -0
  21. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib/ansi.py +0 -0
  22. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib/enum.py +0 -0
  23. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib/log/__init__.py +0 -0
  24. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib/log/cute.py +0 -0
  25. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib/log/trace.py +0 -0
  26. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib/py.typed +0 -0
  27. {zstdlib-0.0.2 → zstdlib-0.0.4}/zstdlib.egg-info/dependency_links.txt +0 -0
  28. {zstdlib-0.0.2 → zstdlib-0.0.4}/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.2
3
+ Version: 0.0.4
4
4
  Summary: A set of useful python utilities
5
5
  License: GPLv3
6
6
  Project-URL: Homepage, https://github.com/zwimer/zstdlib
@@ -77,7 +77,7 @@ class TestCuteFormatter(LeftBase, unittest.TestCase):
77
77
  except ValueError:
78
78
  log.error("test", exc_info=True)
79
79
  spt = self.messages[log][0].split("\n")
80
- self.assertTrue(len(spt) > 2)
80
+ self.assertGreater(len(spt), 2)
81
81
  self.assertEqual("Traceback (most recent call last):", spt[1].strip())
82
82
  self.assertEqual("raise ValueError(name)", spt[-2].strip())
83
83
  self.assertEqual(f"ValueError: {name}", spt[-1].strip())
@@ -91,7 +91,7 @@ class TestCuteFormatter(LeftBase, unittest.TestCase):
91
91
  log.info(base)
92
92
  messages.add(self.messages[log][0].rsplit("|", 1)[-1].strip())
93
93
  cols = ("red", "green", "yellow", "blue", "magenta", "cyan", "default")
94
- self.assertEqual({getattr(Color, i)(base) for i in cols}, messages)
94
+ self.assertSetEqual({getattr(Color, i)(base) for i in cols}, messages)
95
95
 
96
96
 
97
97
  if __name__ == "__main__":
@@ -1,7 +1,7 @@
1
1
  # pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring,unused-variable
2
2
  import unittest
3
3
 
4
- from zstdlib import EnumType, Enum
4
+ from zstdlib.enum import EnumType, Enum
5
5
 
6
6
 
7
7
  class TestEnumType(unittest.TestCase):
@@ -0,0 +1,109 @@
1
+ # pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring,unused-variable,attribute-defined-outside-init
2
+ import unittest
3
+
4
+ from zstdlib.frozen import Freezable, frozen
5
+
6
+
7
+ class TestFreezable(unittest.TestCase):
8
+
9
+ def test_unfrozen(self):
10
+ class F1(Freezable):
11
+ pass
12
+
13
+ f1 = F1()
14
+ f1.a = 1
15
+ self.assertEqual(f1.a, 1)
16
+ del f1.a
17
+ self.assertIs(getattr(f1, "a", None), None)
18
+
19
+ def test_frozen(self):
20
+ class F1(Freezable):
21
+ pass
22
+
23
+ f1 = F1()
24
+ f1.a = 1
25
+ f1.freeze()
26
+ self.assertEqual(f1.a, 1)
27
+ with self.assertRaises(AttributeError):
28
+ f1.a = 2
29
+ with self.assertRaises(AttributeError):
30
+ del f1.a
31
+
32
+ def test_thaw(self):
33
+ class F1(Freezable):
34
+ pass
35
+
36
+ f1 = F1()
37
+ f1.a = 1
38
+ f1.freeze()
39
+ self.assertEqual(f1.a, 1)
40
+ f1.thaw()
41
+ f1.a = 2
42
+ self.assertEqual(f1.a, 2)
43
+ del f1.a
44
+ self.assertIs(getattr(f1, "a", None), None)
45
+
46
+ def test_permanent_freeze(self):
47
+ class F1(Freezable):
48
+ pass
49
+
50
+ f1 = F1()
51
+ f1.a = 1
52
+ f1.freeze(permanent=True)
53
+ self.assertEqual(f1.a, 1)
54
+ with self.assertRaises(RuntimeError):
55
+ f1.thaw()
56
+ with self.assertRaises(AttributeError):
57
+ f1.a = 1
58
+
59
+
60
+ class TestFrozen(unittest.TestCase):
61
+
62
+ def test_frozen(self):
63
+ @frozen
64
+ class F1:
65
+ def __init__(self):
66
+ self.a = 1
67
+ self.b = 1
68
+ del self.b
69
+
70
+ f1 = F1()
71
+ self.assertEqual(f1.a, 1)
72
+ self.assertIs(getattr(f1, "b", None), None)
73
+ with self.assertRaises(AttributeError):
74
+ f1.a = 1
75
+ with self.assertRaises(AttributeError):
76
+ del f1.a
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
+
107
+
108
+ if __name__ == "__main__":
109
+ unittest.main()
@@ -3,7 +3,7 @@ from threading import Thread, Lock
3
3
  from time import sleep
4
4
  import unittest
5
5
 
6
- from zstdlib import SingletonType, Singleton
6
+ from zstdlib.singleton import SingletonType, Singleton
7
7
 
8
8
 
9
9
  class TestSingletonType(unittest.TestCase):
@@ -0,0 +1,6 @@
1
+ __version__ = "0.0.4"
2
+
3
+ from .frozen import Freezable, frozen
4
+ from .singleton import Singleton
5
+ from .enum import Enum
6
+ from . import log
@@ -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__")
@@ -7,10 +7,8 @@ class SingletonType(type):
7
7
  A thread-safe singleton metaclass
8
8
  """
9
9
 
10
- _seen: set[type] = (
11
- set()
12
- ) # Objects in this have been seen by singleton before and should not be constructed again
13
- _instances: dict[type, Any] = {} # Fully constructed singleton objects
10
+ _seen: set[type] = set() # Types that should not be constructed again
11
+ _instances: dict[type, Any] = {} # Fully constructed and initialized singleton types
14
12
  _lock = Condition()
15
13
  # For preventing subclassing of Singletons
16
14
  _types: list[type] = []
@@ -21,7 +19,7 @@ class SingletonType(type):
21
19
  Intercept all class definitions to prevent subclassing singleton types except for Singleton
22
20
  """
23
21
  if "__init_subclass__" in attrs:
24
- raise NotImplementedError("Singleton's should not be subclassed")
22
+ raise NotImplementedError("Singleton's should not be subclassed or implement __init_subclass__")
25
23
 
26
24
  def _init_subclass(cls):
27
25
  with mcs._types_lock:
@@ -46,7 +44,7 @@ class SingletonType(type):
46
44
  cls._lock.wait_for(lambda: cls in cls._instances)
47
45
  return cls._instances[cls]
48
46
  cls._seen.add(cls)
49
- # The object has not been constructed before, create it outside of any lock to avoid delays
47
+ # The object has not been constructed before, create it outside any lock to avoid delays
50
48
  obj = super().__call__(*args, **kwargs)
51
49
  with cls._lock:
52
50
  cls._instances[cls] = obj
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zstdlib
3
- Version: 0.0.2
3
+ Version: 0.0.4
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_frozen.py
7
8
  tests/test_singleton.py
8
9
  tests/log/__init__.py
9
10
  tests/log/base.py
@@ -12,6 +13,7 @@ tests/log/test_trace.py
12
13
  zstdlib/__init__.py
13
14
  zstdlib/ansi.py
14
15
  zstdlib/enum.py
16
+ zstdlib/frozen.py
15
17
  zstdlib/py.typed
16
18
  zstdlib/singleton.py
17
19
  zstdlib.egg-info/PKG-INFO
@@ -1,5 +0,0 @@
1
- __version__ = "0.0.2"
2
-
3
- from .singleton import SingletonType, Singleton
4
- from .enum import EnumType, Enum
5
- from . import log
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