private-attribute-cpp 1.4.4__tar.gz → 1.4.6__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 (21) hide show
  1. {private_attribute_cpp-1.4.4/private_attribute_cpp.egg-info → private_attribute_cpp-1.4.6}/PKG-INFO +3 -2
  2. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/README.md +2 -1
  3. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute.cpp +11 -9
  4. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute.pyi +1 -1
  5. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6/private_attribute_cpp.egg-info}/PKG-INFO +3 -2
  6. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute_cpp.egg-info/SOURCES.txt +8 -1
  7. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/setup.py +1 -2
  8. private_attribute_cpp-1.4.6/tests/test_class_private_attrs.py +23 -0
  9. private_attribute_cpp-1.4.6/tests/test_private_abc.py +55 -0
  10. private_attribute_cpp-1.4.6/tests/test_private_attrs.py +51 -0
  11. private_attribute_cpp-1.4.6/tests/test_private_func.py +27 -0
  12. private_attribute_cpp-1.4.6/tests/test_private_inheritance.py +40 -0
  13. private_attribute_cpp-1.4.6/tests/test_private_method.py +30 -0
  14. private_attribute_cpp-1.4.6/tests/test_private_wrap.py +55 -0
  15. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/LICENSE +0 -0
  16. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/MANIFEST.in +0 -0
  17. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/picosha2.h +0 -0
  18. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute_cpp.egg-info/dependency_links.txt +0 -0
  19. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute_cpp.egg-info/not-zip-safe +0 -0
  20. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute_cpp.egg-info/top_level.txt +0 -0
  21. {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 1.4.4
3
+ Version: 1.4.6
4
4
  Summary: A Python package that provides a way to define private attributes in C++ implementation.
5
5
  Home-page: https://github.com/Locked-chess-official/private_attribute_cpp
6
6
  Author: HuangHaoHua
@@ -250,7 +250,8 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
250
250
  - One class defined in another class cannot use another class's private attribute.
251
251
  - One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
252
252
  - CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
253
- - `private_attribute.register_metaclass` must be called with the metaclass which support weakref.
253
+ - `private_attribute.register_metaclass` must be called with the metaclass which supports weakref.
254
+ - Don't set `__static_attributes__` in private attribute class, or it will be removed.
254
255
 
255
256
  ## License
256
257
 
@@ -231,7 +231,8 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
231
231
  - One class defined in another class cannot use another class's private attribute.
232
232
  - One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
233
233
  - CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
234
- - `private_attribute.register_metaclass` must be called with the metaclass which support weakref.
234
+ - `private_attribute.register_metaclass` must be called with the metaclass which supports weakref.
235
+ - Don't set `__static_attributes__` in private attribute class, or it will be removed.
235
236
 
236
237
  ## License
237
238
 
@@ -21,7 +21,7 @@
21
21
  #include <memory>
22
22
  #include <algorithm>
23
23
 
24
- // python under 3.13 doesn't has PyDict_ContainsString, so we implement it ourselves
24
+ // python under 3.13 doesn't have PyDict_ContainsString, so we implement it ourselves
25
25
  #if PY_VERSION_HEX < 0x030D0000
26
26
  static int
27
27
  PyDict_ContainsString(PyObject *op, const char *key)
@@ -2127,6 +2127,11 @@ PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationDa
2127
2127
  return (uintptr_t)0;
2128
2128
  };
2129
2129
 
2130
+ // forbidden to have "__static_attributes__" in attrs, because it exposes the private attributes name.
2131
+ if (PyDict_ContainsString(data.attrs_copy, "__static_attributes__")) {
2132
+ PyDict_DelItemString(data.attrs_copy, "__static_attributes__");
2133
+ }
2134
+
2130
2135
  {
2131
2136
  Py_ssize_t pos = 0;
2132
2137
  PyObject* key, *value;
@@ -2335,6 +2340,10 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data)
2335
2340
 
2336
2341
  PyTypeObject* type_instance = (PyTypeObject*)new_type;
2337
2342
  uintptr_t type_id = (uintptr_t)(type_instance);
2343
+ if (PyDict_ContainsString(type_instance->tp_dict, "__static_attributes__")) {
2344
+ PyErr_SetString(PyExc_SystemError, "'__static_attributes__' will expose private attribute names and cannot be used in private attribute types");
2345
+ return false;
2346
+ }
2338
2347
 
2339
2348
  ensure_tp(type_instance);
2340
2349
  if (PyDict_ContainsString(type_instance->tp_dict, "__getattribute__") || PyDict_ContainsString(type_instance->tp_dict, "__getattr__")) {
@@ -2441,12 +2450,6 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data)
2441
2450
  }
2442
2451
  }
2443
2452
 
2444
- // Python >= 3.13, delete the attr "__static_attributes__"
2445
- #if PY_VERSION_HEX >= 0x030D0000
2446
- PyDict_DelItemString(type_instance->tp_dict, "__static_attributes__");
2447
- PyErr_Clear();
2448
- #endif
2449
-
2450
2453
  return true;
2451
2454
  }
2452
2455
 
@@ -2808,6 +2811,7 @@ create_private_attr_base_simple(void)
2808
2811
  PyDict_SetItemString(dict, "__private_attrs__", private_attrs);
2809
2812
  PyDict_SetItemString(dict, "__slots__", private_attrs);
2810
2813
  PyDict_SetItemString(dict, "__doc__", PyUnicode_FromString(PrivateAttrBase_doc));
2814
+ PyDict_SetItemString(dict, "__module__", PyUnicode_FromString("private_attribute"));
2811
2815
  PyObject *args = PyTuple_Pack(3, name, bases, dict);
2812
2816
  PyObject* base_type;
2813
2817
  if (args) {
@@ -2825,8 +2829,6 @@ create_private_attr_base_simple(void)
2825
2829
  if (!base_type) {
2826
2830
  return NULL;
2827
2831
  }
2828
- // set "__module__"
2829
- PyType_Type.tp_setattro(base_type, PyUnicode_FromString("__module__"), PyUnicode_FromString("private_attribute"));
2830
2832
  ((PyTypeObject*)base_type)->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
2831
2833
  return base_type;
2832
2834
  }
@@ -71,7 +71,7 @@ class PrivateWrapProxy:
71
71
  ```
72
72
  """
73
73
  def __init__(self, decorator: Callable[[_TVar], _T], orig: _PrivateWrap[Any]|None = None, /) -> None: ...
74
- def __call__(self, func: _TVar, /) -> _PrivateWrap[_T]: ...
74
+ def __call__(self, func: _TVar | _PrivateWrap[_TVar], /) -> _PrivateWrap[_T]: ...
75
75
 
76
76
  class PrivateAttrType(type):
77
77
  "metaclass for private attributes"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 1.4.4
3
+ Version: 1.4.6
4
4
  Summary: A Python package that provides a way to define private attributes in C++ implementation.
5
5
  Home-page: https://github.com/Locked-chess-official/private_attribute_cpp
6
6
  Author: HuangHaoHua
@@ -250,7 +250,8 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
250
250
  - One class defined in another class cannot use another class's private attribute.
251
251
  - One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
252
252
  - CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
253
- - `private_attribute.register_metaclass` must be called with the metaclass which support weakref.
253
+ - `private_attribute.register_metaclass` must be called with the metaclass which supports weakref.
254
+ - Don't set `__static_attributes__` in private attribute class, or it will be removed.
254
255
 
255
256
  ## License
256
257
 
@@ -9,4 +9,11 @@ private_attribute_cpp.egg-info/PKG-INFO
9
9
  private_attribute_cpp.egg-info/SOURCES.txt
10
10
  private_attribute_cpp.egg-info/dependency_links.txt
11
11
  private_attribute_cpp.egg-info/not-zip-safe
12
- private_attribute_cpp.egg-info/top_level.txt
12
+ private_attribute_cpp.egg-info/top_level.txt
13
+ tests/test_class_private_attrs.py
14
+ tests/test_private_abc.py
15
+ tests/test_private_attrs.py
16
+ tests/test_private_func.py
17
+ tests/test_private_inheritance.py
18
+ tests/test_private_method.py
19
+ tests/test_private_wrap.py
@@ -1,6 +1,5 @@
1
1
  from setuptools import setup, Extension
2
2
  import sys
3
- import sysconfig
4
3
 
5
4
  if sys.platform == "win32":
6
5
  extra_compile_args = ['/std:c++17']
@@ -19,7 +18,7 @@ readme = open('README.md').read()
19
18
 
20
19
  setup(
21
20
  name='private_attribute_cpp',
22
- version='1.4.4',
21
+ version='1.4.6',
23
22
  author="HuangHaoHua",
24
23
  author_email="13140752715@example.com",
25
24
  description='A Python package that provides a way to define private attributes in C++ implementation.',
@@ -0,0 +1,23 @@
1
+ import private_attribute
2
+ import unittest
3
+
4
+ class MyClass(private_attribute.PrivateAttrBase):
5
+ __private_attrs__ = ["_secret"]
6
+ _secret = 1
7
+
8
+ @classmethod
9
+ def get_secret(cls):
10
+ return cls._secret
11
+
12
+ class TestClassPrivateAttrs(unittest.TestCase):
13
+ def test_class_private_attrs(self):
14
+ self.assertEqual(MyClass.get_secret(), 1)
15
+ with self.assertRaises(AttributeError):
16
+ MyClass._secret = 2
17
+ a = MyClass()
18
+ with self.assertRaises(AttributeError):
19
+ a._secret = 2
20
+ self.assertEqual(a.get_secret(), 1)
21
+
22
+ if __name__ == "__main__":
23
+ unittest.main()
@@ -0,0 +1,55 @@
1
+ from abc import ABCMeta, abstractmethod, ABC
2
+ import private_attribute
3
+ import unittest
4
+
5
+
6
+ class PrivateAbcMeta(ABCMeta):
7
+ def __new__(cls, *args, **kwargs):
8
+ temp = private_attribute.prepare(*args, **kwargs)
9
+ typ = super().__new__(cls, temp.name, temp.bases, temp.attrs, **temp.kwds)
10
+ private_attribute.postprocess(typ, temp)
11
+ return typ
12
+
13
+
14
+ private_attribute.register_metaclass(PrivateAbcMeta)
15
+
16
+ class MyClass(ABC, metaclass=PrivateAbcMeta):
17
+ __private_attrs__ = ["_secret1"]
18
+ _secret1 = 10
19
+
20
+ @classmethod
21
+ def get_secret1(cls):
22
+ return cls._secret1
23
+
24
+ @abstractmethod
25
+ def public_method(self):
26
+ pass
27
+
28
+ class ConcreteClass(MyClass):
29
+ __private_attrs__ = ["_secret2"]
30
+
31
+ def __init__(self, secret1, secret2):
32
+ self._secret1 = secret1
33
+ self._secret2 = secret2
34
+
35
+ def public_method(self):
36
+ return self._secret1, self._secret2
37
+
38
+
39
+ class TestPrivateAbc(unittest.TestCase):
40
+ def test_private_abc(self):
41
+ c = ConcreteClass("secret1", "secret2")
42
+ self.assertEqual(c.public_method(), ("secret1", "secret2"))
43
+ with self.assertRaises(AttributeError):
44
+ c._secret1
45
+ with self.assertRaises(AttributeError):
46
+ c._secret2
47
+ with self.assertRaises(TypeError):
48
+ MyClass()
49
+ with self.assertRaises(AttributeError):
50
+ MyClass._secret1
51
+ self.assertEqual(MyClass.get_secret1(), 10)
52
+ self.assertEqual(ConcreteClass.get_secret1(), 10)
53
+
54
+ if __name__ == '__main__':
55
+ unittest.main()
@@ -0,0 +1,51 @@
1
+ import private_attribute
2
+ import unittest
3
+
4
+ class BaseClass(private_attribute.PrivateAttrBase):
5
+ __private_attrs__ = ["_a", "_b"]
6
+ __slots__ = ["c", "d"]
7
+
8
+ def __init__(self, a, b, c, d):
9
+ self._a = a
10
+ self._b = b
11
+ self.c = c
12
+ self.d = d
13
+
14
+ @property
15
+ def a(self):
16
+ return self._a
17
+
18
+ @property
19
+ def b(self):
20
+ return self._b
21
+
22
+ def public_has_a(self):
23
+ return hasattr(self, "_a")
24
+
25
+ def public_has_b(self):
26
+ return hasattr(self, "_b")
27
+
28
+ class TestPrivateAttributes(unittest.TestCase):
29
+ def __init__(self, *args, **kwargs):
30
+ super().__init__(*args, **kwargs)
31
+ self.base_obj = BaseClass(1, 2, 3, 4)
32
+
33
+ def test_private_attrs(self):
34
+ self.assertTrue(self.base_obj.public_has_a())
35
+ self.assertTrue(self.base_obj.public_has_b())
36
+ self.assertEqual(self.base_obj.a, 1)
37
+ self.assertEqual(self.base_obj.b, 2)
38
+ self.assertEqual(self.base_obj.c, 3)
39
+ self.assertEqual(self.base_obj.d, 4)
40
+ self.assertFalse(hasattr(self.base_obj, "_a"))
41
+ self.assertFalse(hasattr(self.base_obj, "_b"))
42
+ with self.assertRaises(AttributeError):
43
+ self.base_obj._a
44
+ with self.assertRaises(AttributeError):
45
+ self.base_obj._b
46
+ self.assertTrue(isinstance(self.base_obj.__private_attrs__, tuple))
47
+ for i in self.base_obj.__private_attrs__:
48
+ self.assertTrue(isinstance(i, tuple))
49
+
50
+ if __name__ == "__main__":
51
+ unittest.main()
@@ -0,0 +1,27 @@
1
+ import private_attribute
2
+ import unittest
3
+
4
+ def my_func(obj_id, attr):
5
+ return f"Object ID: {obj_id}, String: {attr}"
6
+
7
+ class MyClass(private_attribute.PrivateAttrBase, private_func=my_func):
8
+ __private_attrs__ = ["_secret"]
9
+ __slots__ = ["public_attr"]
10
+
11
+ def __init__(self, secret, public_attr):
12
+ self._secret = secret
13
+ self.public_attr = public_attr
14
+
15
+ def get_secret(self):
16
+ return self._secret
17
+
18
+ class TestPrivateFunc(unittest.TestCase):
19
+ def test_private_func(self):
20
+ obj = MyClass("12345", "public_value")
21
+ self.assertEqual(obj.get_secret(), "12345")
22
+ self.assertEqual(obj.public_attr, "public_value")
23
+ with self.assertRaises(AttributeError):
24
+ obj._secret
25
+
26
+ if __name__ == "__main__":
27
+ unittest.main()
@@ -0,0 +1,40 @@
1
+ import private_attribute
2
+ import unittest
3
+
4
+ class BaseClass(private_attribute.PrivateAttrBase):
5
+ __private_attrs__ = ["_value"]
6
+ __slots__ = []
7
+
8
+ def __init__(self, value):
9
+ super().__init__()
10
+ self._value = value
11
+
12
+ class SubClass(BaseClass):
13
+ __private_attrs__ = ["_other_value"]
14
+ __slots__ = []
15
+
16
+ def __init__(self, value, other_value):
17
+ super().__init__(value)
18
+ self._other_value = other_value
19
+
20
+ @property
21
+ def value(self):
22
+ return self._value
23
+
24
+ @property
25
+ def other_value(self):
26
+ return self._other_value
27
+
28
+
29
+ class TestPrivateInheritance(unittest.TestCase):
30
+ def test_private_inheritance(self):
31
+ obj = SubClass(1, 2)
32
+ self.assertEqual(obj.value, 1)
33
+ self.assertEqual(obj.other_value, 2)
34
+ with self.assertRaises(AttributeError):
35
+ obj._value
36
+ with self.assertRaises(AttributeError):
37
+ obj._other_value
38
+
39
+ if __name__ == "__main__":
40
+ unittest.main()
@@ -0,0 +1,30 @@
1
+ import private_attribute
2
+ import unittest
3
+
4
+ class PrivateMethodClass(private_attribute.PrivateAttrBase):
5
+ __private_attrs__ = ["_secret_method", "_a"]
6
+ __slots__ = ["public_attr"]
7
+
8
+ def __init__(self, a):
9
+ self._a = a
10
+ self.public_attr = "public_value"
11
+
12
+ def _secret_method(self):
13
+ return self._a
14
+
15
+ def public_method(self):
16
+ return self._secret_method()
17
+
18
+
19
+ class TestPrivateMethod(unittest.TestCase):
20
+ def test_private_method(self):
21
+ obj = PrivateMethodClass(1)
22
+ self.assertEqual(obj.public_method(), 1)
23
+ with self.assertRaises(AttributeError):
24
+ obj._secret_method()
25
+
26
+ with self.assertRaises(AttributeError):
27
+ obj._a
28
+
29
+ if __name__ == "__main__":
30
+ unittest.main()
@@ -0,0 +1,55 @@
1
+ import private_attribute
2
+ import unittest
3
+
4
+ class MyWrap:
5
+ def __init__(self, func):
6
+ self.func1 = func
7
+ self.index = 1
8
+
9
+ def add(self, func):
10
+ self.index += 1
11
+ setattr(self, f"func{self.index}", func)
12
+ return self
13
+
14
+ def __get__(self, instance, owner):
15
+ if instance is None:
16
+ return self
17
+ def wrapper(index, *args, **kwargs):
18
+ func = getattr(self, f"func{index}")
19
+ return func.__get__(instance, owner)(*args, **kwargs)
20
+ return wrapper
21
+
22
+ class MyClass(private_attribute.PrivateAttrBase):
23
+ __private_attrs__ = ["_secret1", "_secret2", "_secret3"]
24
+ def __init__(self, secret1, secret2, secret3):
25
+ self._secret1 = secret1
26
+ self._secret2 = secret2
27
+ self._secret3 = secret3
28
+
29
+ @private_attribute.PrivateWrapProxy(MyWrap)
30
+ def get_secret(self):
31
+ return self._secret1
32
+
33
+ @private_attribute.PrivateWrapProxy(get_secret.result.add, get_secret)
34
+ def get_secret(self):
35
+ return self._secret2
36
+
37
+ @private_attribute.PrivateWrapProxy(get_secret.result.add, get_secret)
38
+ def get_secret(self):
39
+ return self._secret3
40
+
41
+ class TestPrivateWrap(unittest.TestCase):
42
+ def test_private_wrap(self):
43
+ a = MyClass(1, 2, 3)
44
+ self.assertEqual(a.get_secret(1), 1)
45
+ self.assertEqual(a.get_secret(2), 2)
46
+ self.assertEqual(a.get_secret(3), 3)
47
+ with self.assertRaises(AttributeError):
48
+ a._secret1
49
+ with self.assertRaises(AttributeError):
50
+ a._secret2
51
+ with self.assertRaises(AttributeError):
52
+ a._secret3
53
+
54
+ if __name__ == "__main__":
55
+ unittest.main()