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.
- {private_attribute_cpp-1.4.4/private_attribute_cpp.egg-info → private_attribute_cpp-1.4.6}/PKG-INFO +3 -2
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/README.md +2 -1
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute.cpp +11 -9
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute.pyi +1 -1
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6/private_attribute_cpp.egg-info}/PKG-INFO +3 -2
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute_cpp.egg-info/SOURCES.txt +8 -1
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/setup.py +1 -2
- private_attribute_cpp-1.4.6/tests/test_class_private_attrs.py +23 -0
- private_attribute_cpp-1.4.6/tests/test_private_abc.py +55 -0
- private_attribute_cpp-1.4.6/tests/test_private_attrs.py +51 -0
- private_attribute_cpp-1.4.6/tests/test_private_func.py +27 -0
- private_attribute_cpp-1.4.6/tests/test_private_inheritance.py +40 -0
- private_attribute_cpp-1.4.6/tests/test_private_method.py +30 -0
- private_attribute_cpp-1.4.6/tests/test_private_wrap.py +55 -0
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/LICENSE +0 -0
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/MANIFEST.in +0 -0
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/picosha2.h +0 -0
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute_cpp.egg-info/dependency_links.txt +0 -0
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute_cpp.egg-info/not-zip-safe +0 -0
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/private_attribute_cpp.egg-info/top_level.txt +0 -0
- {private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6}/setup.cfg +0 -0
{private_attribute_cpp-1.4.4/private_attribute_cpp.egg-info → private_attribute_cpp-1.4.6}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: private_attribute_cpp
|
|
3
|
-
Version: 1.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
|
|
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
|
|
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
|
|
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"
|
{private_attribute_cpp-1.4.4 → private_attribute_cpp-1.4.6/private_attribute_cpp.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: private_attribute_cpp
|
|
3
|
-
Version: 1.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
|
|
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.
|
|
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()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|