private-attribute-cpp 2.0.3__tar.gz → 2.0.5__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-2.0.3 → private_attribute_cpp-2.0.5}/LICENSE +21 -21
  2. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/MANIFEST.in +2 -2
  3. {private_attribute_cpp-2.0.3/private_attribute_cpp.egg-info → private_attribute_cpp-2.0.5}/PKG-INFO +267 -267
  4. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/README.md +248 -248
  5. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/private_attribute.cpp +3967 -3267
  6. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/private_attribute.pyi +200 -200
  7. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5/private_attribute_cpp.egg-info}/PKG-INFO +267 -267
  8. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/private_attribute_cpp.egg-info/not-zip-safe +1 -1
  9. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/setup.cfg +4 -4
  10. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/setup.py +37 -37
  11. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/tests/test_class_private_attrs.py +23 -23
  12. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/tests/test_private_abc.py +55 -55
  13. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/tests/test_private_attrs.py +51 -51
  14. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/tests/test_private_func.py +27 -27
  15. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/tests/test_private_inheritance.py +40 -40
  16. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/tests/test_private_method.py +30 -30
  17. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/tests/test_private_wrap.py +55 -55
  18. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/picosha2.h +0 -0
  19. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/private_attribute_cpp.egg-info/SOURCES.txt +0 -0
  20. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/private_attribute_cpp.egg-info/dependency_links.txt +0 -0
  21. {private_attribute_cpp-2.0.3 → private_attribute_cpp-2.0.5}/private_attribute_cpp.egg-info/top_level.txt +0 -0
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Locked-chess-official
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Locked-chess-official
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,2 +1,2 @@
1
- include README.md
2
- include picosha2.h
1
+ include README.md
2
+ include picosha2.h
@@ -1,267 +1,267 @@
1
- Metadata-Version: 2.4
2
- Name: private_attribute_cpp
3
- Version: 2.0.3
4
- Summary: A Python package that provides a way to define private attributes in C++ implementation.
5
- Home-page: https://github.com/Locked-chess-official/private_attribute_cpp
6
- Author: HuangHaoHua
7
- Author-email: 13140752715@example.com
8
- License: MIT
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Dynamic: author
12
- Dynamic: author-email
13
- Dynamic: description
14
- Dynamic: description-content-type
15
- Dynamic: home-page
16
- Dynamic: license
17
- Dynamic: license-file
18
- Dynamic: summary
19
-
20
- # Private Attribute (c++ implementation)
21
-
22
- ## Introduction
23
-
24
- This package provide a way to create the private attribute like "C++" does.
25
-
26
- ## All Base API
27
-
28
- ```python
29
- from private_attribute import (PrivateAttrBase, PrivateWrapProxy) # 1 Import public API
30
-
31
- def my_generate_func(obj_id, attr_name): # 2 Optional: custom name generator
32
- return f"_hidden_{obj_id}_{attr_name}"
33
-
34
- class MyClass(PrivateAttrBase, private_func=my_generate_func): # 3 Inherit + optional custom generator
35
- __private_attrs__ = ['a', 'b', 'c', 'result', 'conflicted_name'] # 4 Must declare all private attrs
36
-
37
- def __init__(self):
38
- self.a = 1
39
- self.b = 2
40
- self.c = 3
41
- self.result = 42 # deliberately conflicts with internal names
42
-
43
- # Normal methods can freely access private attributes
44
- def public_way(self):
45
- print(self.a, self.b, self.c)
46
-
47
- # Real-world case: method wrapped by multiple decorators
48
- @PrivateWrapProxy(memoize()) # 5 Apply any decorator safely
49
- @PrivateWrapProxy(login_required()) # 5 Stack as many as needed
50
- @PrivateWrapProxy(rate_limit(calls=10)) # 5
51
- def expensive_api_call(self, x): # First definition (will be wrapped)
52
- def inner(...):
53
- return some_implementation(self.a, self.b, self.c, x)
54
- inner(...)
55
- return heavy_computation(self.a, self.b, self.c, x)
56
-
57
- # Fix decorator order + resolve name conflicts
58
- @PrivateWrapProxy(expensive_api_call.result.name2, expensive_api_call) # 6 Chain .result to push decorators down
59
- @PrivateWrapProxy(expensive_api_call.result.name1, expensive_api_call) # 6 Resolve conflict with internal names
60
- def expensive_api_call(self, x): # Final real implementation
61
- return heavy_computation(self.a, self.b, self.c, x)
62
-
63
-
64
- # ====================== Usage ======================
65
- obj = MyClass()
66
- obj.public_way() # prints: 1 2 3
67
-
68
- print(hasattr(obj, 'a')) # False – truly hidden from outside
69
- print(obj.expensive_api_call(10)) # works with all decorators applied
70
- ```
71
-
72
- | # | API | Purpose | Required? |
73
- | --- | ---------------------------------------- | ------------------------------------------------------- | ----------- |
74
- | 1 | PrivateAttrBase | Base class – must inherit | Yes |
75
- | 1 | PrivateWrapProxy | Decorator wrapper for arbitrary decorators | When needed |
76
- | 2 | private_func=callable | Custom hidden-name generator | Optional |
77
- | 3 | Pass private_func in class definition | Same as above | Optional |
78
- | 4 | \_\_private_attrs\_\_ list | Declare which attributes are private | Yes |
79
- | 5 | @PrivateWrapProxy(...) | Make any decorator compatible with private attributes | When needed |
80
- | 6 | method.result.xxx chain + dummy wrap | Fix decorator order and name conflicts | When needed |
81
-
82
- ## Usage
83
-
84
- This is a simple usage about the module:
85
-
86
- ```python
87
- from private_attribute import PrivateAttrBase
88
-
89
- class MyClass(PrivateAttrBase):
90
- __private_attrs__ = ['a', 'b', 'c']
91
- def __init__(self):
92
- self.a = 1
93
- self.b = 2
94
- self.c = 3
95
-
96
- def public_way(self):
97
- print(self.a, self.b, self.c)
98
-
99
- obj = MyClass()
100
- obj.public_way() # (1, 2, 3)
101
-
102
- print(hasattr(obj, 'a')) # False
103
- print(hasattr(obj, 'b')) # False
104
- print(hasattr(obj, 'c')) # False
105
- ```
106
-
107
- All of the attributes in `__private_attrs__` will be hidden from the outside world, and stored by another name.
108
-
109
- You can use your function to generate the name. It needs the id of the obj and the name of the attribute:
110
-
111
- ```python
112
- def my_generate_func(obj_id, attr_name):
113
- return some_string
114
-
115
- class MyClass(PrivateAttrBase, private_func=my_generate_func):
116
- __private_attrs__ = ['a', 'b', 'c']
117
- def __init__(self):
118
- self.a = 1
119
- self.b = 2
120
- self.c = 3
121
-
122
- def public_way(self):
123
- print(self.a, self.b, self.c)
124
-
125
- obj = MyClass()
126
- obj.public_way() # (1, 2, 3)
127
-
128
- ```
129
-
130
- If the method will be decorated, the `property`, `classmethod` and `staticmethod` will be supported.
131
- For the other, you can use the `PrivateWrapProxy` to wrap the function:
132
-
133
- ```python
134
- from private_attribute import PrivateAttrBase, PrivateWrapProxy
135
-
136
- class MyClass(PrivateAttrBase):
137
- __private_attrs__ = ['a', 'b', 'c']
138
- @PrivateWrapProxy(decorator1())
139
- @PrivateWrapProxy(decorator2())
140
- def method1(self):
141
- ...
142
-
143
- @PrivateWrapProxy(method1.attr_name, method1) # Use the argument "method1" to save old func
144
- def method1(self):
145
- ...
146
-
147
- @PrivateWrapProxy(decorator3())
148
- def method2(self):
149
- ...
150
-
151
- @PrivateWrapProxy(method2.attr_name, method2) # Use the argument "method2" to save old func
152
- def method2(self):
153
- ...
154
-
155
-
156
- ```
157
-
158
- The `PrivateWrapProxy` is a decorator, and it will wrap the function with the decorator. When it decorates the method, it returns a `_PrivateWrap` object.
159
-
160
- The `_PrivateWrap` has the public api `result` and `funcs`. `result` returns the original decoratored result and `funcs` returns the tuple of the original functions.
161
-
162
- ```python
163
- from private_attribute import PrivateAttrBase, PrivateWrapProxy
164
-
165
- class MyClass(PrivateAttrBase):
166
- __private_attrs__ = ['a', 'b', 'c']
167
- @PrivateWrapProxy(decorator1())
168
- @PrivateWrapProxy(decorator2())
169
- def method1(self):
170
- ...
171
-
172
- @PrivateWrapProxy(method1.result.conflict_attr_name1, method1) # Use the argument "method1" to save old func
173
- def method1(self):
174
- ...
175
-
176
- @PrivateWrapProxy(method1.result.conflict_attr_name2, method1)
177
- def method1(self):
178
- ...
179
-
180
- @PrivateWrapProxy(decorator3())
181
- def method2(self):
182
- ```
183
-
184
- ## Advanced API
185
-
186
- ### define your metaclass based on one metaclass
187
-
188
- You can define your metaclass based on one metaclass:
189
-
190
- ```python
191
- from abc import ABCMeta, abstractmethod
192
- import private_attribute
193
-
194
- class PrivateAbcMeta(ABCMeta):
195
- def __new__(cls, name, bases, attrs, **kwargs):
196
- temp = private_attribute.prepare(name, bases, attrs, **kwargs)
197
- typ = super().__new__(cls, temp.name, temp.bases, temp.attrs, **temp.kwds)
198
- private_attribute.postprocess(typ, temp)
199
- return typ
200
-
201
- private_attribute.register_metaclass(PrivateAbcMeta)
202
- ```
203
-
204
- By this way you create a metaclass both can behave as ABC and private attribute:
205
-
206
- ```python
207
- class MyClass(metaclass=PrivateAbcMeta):
208
- __private_attrs__ = ()
209
- __slots__ = ()
210
-
211
- @abstractmethod
212
- def my_function(self): ...
213
-
214
- class MyImplement(MyClass):
215
- __private_attrs__ = ("_a",)
216
- def __init__(self, value=1):
217
- self._a = value
218
-
219
- def my_function(self):
220
- return self._a
221
- ```
222
-
223
- Finally:
224
-
225
- ```python
226
- >>> a = MyImplement(1)
227
- >>> a.my_function()
228
- 1
229
- >>> a._a
230
- Traceback (most recent call last):
231
- File "<pyshell#2>", line 1, in <module>
232
- a._a
233
- AttributeError: private attribute
234
- >>> MyClass()
235
- Traceback (most recent call last):
236
- File "<pyshell#3>", line 1, in <module>
237
- MyClass()
238
- TypeError: Can't instantiate abstract class MyClass without an implementation for abstract method 'my_function'
239
- ```
240
-
241
- ## Notes
242
-
243
- - All of the private attributes class must contain the `__private_attrs__` attribute.
244
- - The `__private_attrs__` attribute must be a sequence of strings.
245
- - You cannot define the name which in `__slots__` to `__private_attrs__`.
246
- - When you define `__slots__` and `__private_attrs__` in one class, the attributes in `__private_attrs__` can also be defined in the methods, even though they are not in `__slots__`.
247
- - All of the object that is the instance of the class "PrivateAttrBase" or its subclass are default to be unable to be pickled.
248
- - Finally the attributes' names in `__private_attrs__` will be change to a tuple with two hash.
249
- - Finally the `_PrivateWrap` object will be recoveried to the original object.
250
- - Don't use a decorator which will return the `_PrivateWrap` in `PrivateWrapProxy` which will raise `TypeError`.
251
- - One class defined in another class cannot use another class's private attribute.
252
- - 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__`.
253
- - 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.
254
- - `private_attribute.register_metaclass` must be called with the metaclass which supports weakref.
255
- - Don't set `__static_attributes__` in private attribute class, or it will be removed.
256
-
257
- ## License
258
-
259
- MIT
260
-
261
- ## Requirement
262
-
263
- This package require the c++ module "[picosha2](https://github.com/okdshin/PicoSHA2)" to compute the sha256 hash.
264
-
265
- ## Support
266
-
267
- Now it doesn't support "PyPy".
1
+ Metadata-Version: 2.4
2
+ Name: private_attribute_cpp
3
+ Version: 2.0.5
4
+ Summary: A Python package that provides a way to define private attributes in C++ implementation.
5
+ Home-page: https://github.com/Locked-chess-official/private_attribute_cpp
6
+ Author: HuangHaoHua
7
+ Author-email: 13140752715@example.com
8
+ License: MIT
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Dynamic: author
12
+ Dynamic: author-email
13
+ Dynamic: description
14
+ Dynamic: description-content-type
15
+ Dynamic: home-page
16
+ Dynamic: license
17
+ Dynamic: license-file
18
+ Dynamic: summary
19
+
20
+ # Private Attribute (c++ implementation)
21
+
22
+ ## Introduction
23
+
24
+ This package provide a way to create the private attribute like "C++" does.
25
+
26
+ ## All Base API
27
+
28
+ ```python
29
+ from private_attribute import (PrivateAttrBase, PrivateWrapProxy) # 1 Import public API
30
+
31
+ def my_generate_func(obj_id, attr_name): # 2 Optional: custom name generator
32
+ return f"_hidden_{obj_id}_{attr_name}"
33
+
34
+ class MyClass(PrivateAttrBase, private_func=my_generate_func): # 3 Inherit + optional custom generator
35
+ __private_attrs__ = ['a', 'b', 'c', 'result', 'conflicted_name'] # 4 Must declare all private attrs
36
+
37
+ def __init__(self):
38
+ self.a = 1
39
+ self.b = 2
40
+ self.c = 3
41
+ self.result = 42 # deliberately conflicts with internal names
42
+
43
+ # Normal methods can freely access private attributes
44
+ def public_way(self):
45
+ print(self.a, self.b, self.c)
46
+
47
+ # Real-world case: method wrapped by multiple decorators
48
+ @PrivateWrapProxy(memoize()) # 5 Apply any decorator safely
49
+ @PrivateWrapProxy(login_required()) # 5 Stack as many as needed
50
+ @PrivateWrapProxy(rate_limit(calls=10)) # 5
51
+ def expensive_api_call(self, x): # First definition (will be wrapped)
52
+ def inner(...):
53
+ return some_implementation(self.a, self.b, self.c, x)
54
+ inner(...)
55
+ return heavy_computation(self.a, self.b, self.c, x)
56
+
57
+ # Fix decorator order + resolve name conflicts
58
+ @PrivateWrapProxy(expensive_api_call.result.name2, expensive_api_call) # 6 Chain .result to push decorators down
59
+ @PrivateWrapProxy(expensive_api_call.result.name1, expensive_api_call) # 6 Resolve conflict with internal names
60
+ def expensive_api_call(self, x): # Final real implementation
61
+ return heavy_computation(self.a, self.b, self.c, x)
62
+
63
+
64
+ # ====================== Usage ======================
65
+ obj = MyClass()
66
+ obj.public_way() # prints: 1 2 3
67
+
68
+ print(hasattr(obj, 'a')) # False – truly hidden from outside
69
+ print(obj.expensive_api_call(10)) # works with all decorators applied
70
+ ```
71
+
72
+ | # | API | Purpose | Required? |
73
+ | --- | ---------------------------------------- | ------------------------------------------------------- | ----------- |
74
+ | 1 | PrivateAttrBase | Base class – must inherit | Yes |
75
+ | 1 | PrivateWrapProxy | Decorator wrapper for arbitrary decorators | When needed |
76
+ | 2 | private_func=callable | Custom hidden-name generator | Optional |
77
+ | 3 | Pass private_func in class definition | Same as above | Optional |
78
+ | 4 | \_\_private_attrs\_\_ list | Declare which attributes are private | Yes |
79
+ | 5 | @PrivateWrapProxy(...) | Make any decorator compatible with private attributes | When needed |
80
+ | 6 | method.result.xxx chain + dummy wrap | Fix decorator order and name conflicts | When needed |
81
+
82
+ ## Usage
83
+
84
+ This is a simple usage about the module:
85
+
86
+ ```python
87
+ from private_attribute import PrivateAttrBase
88
+
89
+ class MyClass(PrivateAttrBase):
90
+ __private_attrs__ = ['a', 'b', 'c']
91
+ def __init__(self):
92
+ self.a = 1
93
+ self.b = 2
94
+ self.c = 3
95
+
96
+ def public_way(self):
97
+ print(self.a, self.b, self.c)
98
+
99
+ obj = MyClass()
100
+ obj.public_way() # (1, 2, 3)
101
+
102
+ print(hasattr(obj, 'a')) # False
103
+ print(hasattr(obj, 'b')) # False
104
+ print(hasattr(obj, 'c')) # False
105
+ ```
106
+
107
+ All of the attributes in `__private_attrs__` will be hidden from the outside world, and stored by another name.
108
+
109
+ You can use your function to generate the name. It needs the id of the obj and the name of the attribute:
110
+
111
+ ```python
112
+ def my_generate_func(obj_id, attr_name):
113
+ return some_string
114
+
115
+ class MyClass(PrivateAttrBase, private_func=my_generate_func):
116
+ __private_attrs__ = ['a', 'b', 'c']
117
+ def __init__(self):
118
+ self.a = 1
119
+ self.b = 2
120
+ self.c = 3
121
+
122
+ def public_way(self):
123
+ print(self.a, self.b, self.c)
124
+
125
+ obj = MyClass()
126
+ obj.public_way() # (1, 2, 3)
127
+
128
+ ```
129
+
130
+ If the method will be decorated, the `property`, `classmethod` and `staticmethod` will be supported.
131
+ For the other, you can use the `PrivateWrapProxy` to wrap the function:
132
+
133
+ ```python
134
+ from private_attribute import PrivateAttrBase, PrivateWrapProxy
135
+
136
+ class MyClass(PrivateAttrBase):
137
+ __private_attrs__ = ['a', 'b', 'c']
138
+ @PrivateWrapProxy(decorator1())
139
+ @PrivateWrapProxy(decorator2())
140
+ def method1(self):
141
+ ...
142
+
143
+ @PrivateWrapProxy(method1.attr_name, method1) # Use the argument "method1" to save old func
144
+ def method1(self):
145
+ ...
146
+
147
+ @PrivateWrapProxy(decorator3())
148
+ def method2(self):
149
+ ...
150
+
151
+ @PrivateWrapProxy(method2.attr_name, method2) # Use the argument "method2" to save old func
152
+ def method2(self):
153
+ ...
154
+
155
+
156
+ ```
157
+
158
+ The `PrivateWrapProxy` is a decorator, and it will wrap the function with the decorator. When it decorates the method, it returns a `_PrivateWrap` object.
159
+
160
+ The `_PrivateWrap` has the public api `result` and `funcs`. `result` returns the original decoratored result and `funcs` returns the tuple of the original functions.
161
+
162
+ ```python
163
+ from private_attribute import PrivateAttrBase, PrivateWrapProxy
164
+
165
+ class MyClass(PrivateAttrBase):
166
+ __private_attrs__ = ['a', 'b', 'c']
167
+ @PrivateWrapProxy(decorator1())
168
+ @PrivateWrapProxy(decorator2())
169
+ def method1(self):
170
+ ...
171
+
172
+ @PrivateWrapProxy(method1.result.conflict_attr_name1, method1) # Use the argument "method1" to save old func
173
+ def method1(self):
174
+ ...
175
+
176
+ @PrivateWrapProxy(method1.result.conflict_attr_name2, method1)
177
+ def method1(self):
178
+ ...
179
+
180
+ @PrivateWrapProxy(decorator3())
181
+ def method2(self):
182
+ ```
183
+
184
+ ## Advanced API
185
+
186
+ ### define your metaclass based on one metaclass
187
+
188
+ You can define your metaclass based on one metaclass:
189
+
190
+ ```python
191
+ from abc import ABCMeta, abstractmethod
192
+ import private_attribute
193
+
194
+ class PrivateAbcMeta(ABCMeta):
195
+ def __new__(cls, name, bases, attrs, **kwargs):
196
+ temp = private_attribute.prepare(name, bases, attrs, **kwargs)
197
+ typ = super().__new__(cls, temp.name, temp.bases, temp.attrs, **temp.kwds)
198
+ private_attribute.postprocess(typ, temp)
199
+ return typ
200
+
201
+ private_attribute.register_metaclass(PrivateAbcMeta)
202
+ ```
203
+
204
+ By this way you create a metaclass both can behave as ABC and private attribute:
205
+
206
+ ```python
207
+ class MyClass(metaclass=PrivateAbcMeta):
208
+ __private_attrs__ = ()
209
+ __slots__ = ()
210
+
211
+ @abstractmethod
212
+ def my_function(self): ...
213
+
214
+ class MyImplement(MyClass):
215
+ __private_attrs__ = ("_a",)
216
+ def __init__(self, value=1):
217
+ self._a = value
218
+
219
+ def my_function(self):
220
+ return self._a
221
+ ```
222
+
223
+ Finally:
224
+
225
+ ```python
226
+ >>> a = MyImplement(1)
227
+ >>> a.my_function()
228
+ 1
229
+ >>> a._a
230
+ Traceback (most recent call last):
231
+ File "<pyshell#2>", line 1, in <module>
232
+ a._a
233
+ AttributeError: private attribute
234
+ >>> MyClass()
235
+ Traceback (most recent call last):
236
+ File "<pyshell#3>", line 1, in <module>
237
+ MyClass()
238
+ TypeError: Can't instantiate abstract class MyClass without an implementation for abstract method 'my_function'
239
+ ```
240
+
241
+ ## Notes
242
+
243
+ - All of the private attributes class must contain the `__private_attrs__` attribute.
244
+ - The `__private_attrs__` attribute must be a sequence of strings.
245
+ - You cannot define the name which in `__slots__` to `__private_attrs__`.
246
+ - When you define `__slots__` and `__private_attrs__` in one class, the attributes in `__private_attrs__` can also be defined in the methods, even though they are not in `__slots__`.
247
+ - All of the object that is the instance of the class "PrivateAttrBase" or its subclass are default to be unable to be pickled.
248
+ - Finally the attributes' names in `__private_attrs__` will be change to a tuple with two hash.
249
+ - Finally the `_PrivateWrap` object will be recoveried to the original object.
250
+ - Don't use a decorator which will return the `_PrivateWrap` in `PrivateWrapProxy` which will raise `TypeError`.
251
+ - One class defined in another class cannot use another class's private attribute.
252
+ - 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__`.
253
+ - 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.
254
+ - `private_attribute.register_metaclass` must be called with the metaclass which supports weakref.
255
+ - Don't set `__static_attributes__` in private attribute class, or it will be removed.
256
+
257
+ ## License
258
+
259
+ MIT
260
+
261
+ ## Requirement
262
+
263
+ This package require the c++ module "[picosha2](https://github.com/okdshin/PicoSHA2)" to compute the sha256 hash.
264
+
265
+ ## Support
266
+
267
+ Now it doesn't support "PyPy".