private-attribute-cpp 1.3.2__tar.gz → 1.3.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.
@@ -0,0 +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,18 +1,20 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 1.3.2
3
+ Version: 1.3.4
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
7
7
  Author-email: 13140752715@example.com
8
8
  License: MIT
9
9
  Description-Content-Type: text/markdown
10
+ License-File: LICENSE
10
11
  Dynamic: author
11
12
  Dynamic: author-email
12
13
  Dynamic: description
13
14
  Dynamic: description-content-type
14
15
  Dynamic: home-page
15
16
  Dynamic: license
17
+ Dynamic: license-file
16
18
  Dynamic: summary
17
19
 
18
20
  # Private Attribute (c++ implementation)
@@ -247,7 +249,6 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
247
249
  - Finally the `_PrivateWrap` object will be recoveried to the original object.
248
250
  - One class defined in another class cannot use another class's private attribute.
249
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__`.
250
- - When combine with other metaclass, be ensure that the parent metaclass has no classmethod that can set subclasses' attributes. If it has, it will fail on new metaclass because the new metaclass you defined and registered will be immutable.
251
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.
252
253
 
253
254
  ## License
@@ -230,7 +230,6 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
230
230
  - Finally the `_PrivateWrap` object will be recoveried to the original object.
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
- - When combine with other metaclass, be ensure that the parent metaclass has no classmethod that can set subclasses' attributes. If it has, it will fail on new metaclass because the new metaclass you defined and registered will be immutable.
234
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.
235
234
 
236
235
  ## License
@@ -477,7 +477,7 @@ id_getattr(std::string attr_name, PyObject* obj, PyObject* typ)
477
477
  return NULL;
478
478
  }
479
479
  std::string string_type_name = type_name;
480
- std::string exception_information = "'" + string_type_name + "' object has no attribute '" + attr_name + "'";
480
+ std::string exception_information = "'" + string_type_name + "' objects has no attribute '" + attr_name + "'";
481
481
  PyErr_SetString(PyExc_AttributeError, exception_information.c_str());
482
482
  return NULL;
483
483
  }
@@ -722,7 +722,7 @@ id_delattr(std::string attr_name, PyObject* obj, PyObject* typ)
722
722
  return -1;
723
723
  }
724
724
  std::string string_type_name = type_name;
725
- std::string exception_information = "'" + string_type_name + "' object has no attribute '" + attr_name + "'";
725
+ std::string exception_information = "'" + string_type_name + "' objects has no attribute '" + attr_name + "'";
726
726
  PyErr_SetString(PyExc_AttributeError, exception_information.c_str());
727
727
  return -1;
728
728
  }
@@ -935,16 +935,19 @@ PrivateWrap_type_params(PyObject* obj, void* /*closure*/)
935
935
  return type_params;
936
936
  }
937
937
 
938
+ static const char* PrivateWrap_result_doc = "the final result of decorating";
939
+ static const char* PrivateWrap_funcs_doc = "the original functions";
940
+
938
941
  static PyGetSetDef PrivateWrap_getset[] = {
939
- {"result", (getter)PrivateWrap_result, NULL, "final result", NULL},
940
- {"funcs", (getter)PrivateWrap_funcs, NULL, "funcs", NULL},
941
- {"__wrapped__", (getter)PrivateWrap_result, NULL, "final result", NULL},
942
- {"__doc__", (getter)PrivateWrap_doc, NULL, "doc", NULL},
943
- {"__module__", (getter)PrivateWrap_module, NULL, "module", NULL},
944
- {"__name__", (getter)PrivateWarp_name, NULL, "name", NULL},
945
- {"__qualname__", (getter)PrivateWrap_qualname, NULL, "qualname", NULL},
946
- {"__annotate__", (getter)PrivateWrap_annotate, NULL, "annotate", NULL},
947
- {"__type_params__", (getter)PrivateWrap_type_params, NULL, "type_params", NULL},
942
+ {"result", (getter)PrivateWrap_result, NULL, PrivateWrap_result_doc, NULL},
943
+ {"funcs", (getter)PrivateWrap_funcs, NULL, PrivateWrap_funcs_doc, NULL},
944
+ {"__wrapped__", (getter)PrivateWrap_result, NULL, NULL, NULL},
945
+ {"__doc__", (getter)PrivateWrap_doc, NULL, NULL, NULL},
946
+ {"__module__", (getter)PrivateWrap_module, NULL, NULL, NULL},
947
+ {"__name__", (getter)PrivateWarp_name, NULL, NULL, NULL},
948
+ {"__qualname__", (getter)PrivateWrap_qualname, NULL, NULL, NULL},
949
+ {"__annotate__", (getter)PrivateWrap_annotate, NULL, NULL, NULL},
950
+ {"__type_params__", (getter)PrivateWrap_type_params, NULL, NULL, NULL},
948
951
  {NULL}
949
952
  };
950
953
 
@@ -1041,30 +1044,8 @@ typedef struct {
1041
1044
  PyObject *func_list; // _func_list
1042
1045
  } PrivateWrapProxyObject;
1043
1046
 
1044
- static int
1045
- PrivateWrapProxy_init(PrivateWrapProxyObject *self, PyObject *args, PyObject *kwds)
1046
- {
1047
- PyObject *decorator;
1048
- PyObject *orig = NULL;
1049
-
1050
- if (!PyArg_ParseTuple(args, "O|O", &decorator, &orig))
1051
- return -1;
1052
-
1053
- self->decorator = decorator;
1054
- Py_INCREF(decorator);
1055
-
1056
- if (orig && PyObject_TypeCheck(orig, &PrivateWrapType)) {
1057
- self->func_list = ((PrivateWrapObject*)orig)->func_list;
1058
- Py_INCREF(self->func_list);
1059
- }
1060
- else {
1061
- self->func_list = PyList_New(0);
1062
- }
1063
- return 0;
1064
- }
1065
-
1066
1047
  static PyObject*
1067
- PrivateWrapProxy_call(PrivateWrapProxyObject *self, PyObject *args, PyObject * /*kwgs */)
1048
+ PrivateWrapProxy_call(PrivateWrapProxyObject *self, PyObject *args, PyObject* /*kwgs */)
1068
1049
  {
1069
1050
  PyObject *func;
1070
1051
  if (!PyArg_ParseTuple(args, "O", &func)) return NULL;
@@ -1091,6 +1072,36 @@ PrivateWrapProxy_call(PrivateWrapProxyObject *self, PyObject *args, PyObject * /
1091
1072
  }
1092
1073
 
1093
1074
  static void PrivateWrapProxy_dealloc(PrivateWrapProxyObject *self);
1075
+ static PyObject* PrivateWrapProxy_New(PyTypeObject *type, PyObject *args, PyObject *kwds);
1076
+ static const char* PrivateWrapProxy_doc = R"(
1077
+ PrivateWrapProxy is a proxy for private attributes.
1078
+ Usage:
1079
+ ```
1080
+ from private_attribute import PrivateWrapProxy, PrivateAttrBase
1081
+
1082
+ class MyClass(PrivateAttrBase):
1083
+ __private_attrs__ = ()
1084
+ @PrivateWrapProxy(decorator)
1085
+ def my_method(self): ...
1086
+
1087
+ @PrivateWrapProxy(decorator)
1088
+ def my_method2(self): ...
1089
+ ```
1090
+ It returned a '_PrivateWrap' object.
1091
+
1092
+ If you need to decorate more function, use like this:
1093
+ ```
1094
+ from private_attribute import PrivateWrapProxy, PrivateAttrBase
1095
+
1096
+ class MyClass(PrivateAttrBase):
1097
+ __private_attrs__ = ()
1098
+ @PrivateWrapProxy(decorator)
1099
+ def my_method(self): ...
1100
+
1101
+ @PrivateWrapProxy(my_method.some_decorator, my_method)
1102
+ def my_method(self): ...
1103
+ ```
1104
+ )";
1094
1105
 
1095
1106
  static PyTypeObject PrivateWrapProxyType = {
1096
1107
  PyVarObject_HEAD_INIT(NULL, 0)
@@ -1113,7 +1124,7 @@ static PyTypeObject PrivateWrapProxyType = {
1113
1124
  0, // tp_setattro
1114
1125
  0, // tp_as_buffer
1115
1126
  Py_TPFLAGS_DEFAULT, // tp_flags
1116
- "PrivateWrapProxy", // tp_doc
1127
+ PrivateWrapProxy_doc, // tp_doc
1117
1128
  0, // tp_traverse
1118
1129
  0, // tp_clear
1119
1130
  0, // tp_richcompare
@@ -1128,11 +1139,43 @@ static PyTypeObject PrivateWrapProxyType = {
1128
1139
  0, // tp_descr_get
1129
1140
  0, // tp_descr_set
1130
1141
  0, // tp_dictoffset
1131
- (initproc)PrivateWrapProxy_init, // tp_init
1142
+ 0, // tp_init
1132
1143
  0, // tp_alloc
1133
- PyType_GenericNew, // tp_new
1144
+ PrivateWrapProxy_New, // tp_new
1134
1145
  };
1135
1146
 
1147
+ static PyObject*
1148
+ PrivateWrapProxy_New(PyTypeObject *type, PyObject *args, PyObject* /*kwds*/)
1149
+ {
1150
+ PrivateWrapProxyObject *self;
1151
+ PyObject *decorator;
1152
+ PyObject *orig = NULL;
1153
+
1154
+ if (!PyArg_ParseTuple(args, "O|O", &decorator, &orig))
1155
+ return NULL;
1156
+
1157
+ self = (PrivateWrapProxyObject*)type->tp_alloc(type, 0);
1158
+ if (self == NULL)
1159
+ return NULL;
1160
+
1161
+ Py_INCREF(decorator);
1162
+ self->decorator = decorator;
1163
+
1164
+ if (orig && PyObject_TypeCheck(orig, &PrivateWrapType)) {
1165
+ self->func_list = ((PrivateWrapObject*)orig)->func_list;
1166
+ Py_INCREF(self->func_list);
1167
+ }
1168
+ else {
1169
+ self->func_list = PyList_New(0);
1170
+ if (self->func_list == NULL) {
1171
+ Py_DECREF(self);
1172
+ return NULL;
1173
+ }
1174
+ }
1175
+
1176
+ return (PyObject*)self;
1177
+ }
1178
+
1136
1179
  static void
1137
1180
  PrivateWrapProxy_dealloc(PrivateWrapProxyObject *self)
1138
1181
  {
@@ -1296,66 +1339,45 @@ static PyObject* PrivateAttrType_getattr(PyObject* cls, PyObject* name);
1296
1339
  static int PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value);
1297
1340
  static void PrivateAttrType_del(PyObject* cls);
1298
1341
 
1299
- static int
1300
- PrivateAttrType_init(PyObject* self, PyObject* args, PyObject* kwds)
1301
- {
1302
- PyTypeObject* base = Py_TYPE(self);
1303
- while (base->tp_init == PrivateAttrType_init) {
1304
- base = base->tp_base;
1305
- }
1306
- if (base->tp_init == NULL) {
1307
- int result = PyType_Type.tp_init(self, args, kwds);
1308
- if (result == 0) {
1309
- ensure_tp((PyTypeObject*)self);
1310
- }
1311
- return result;
1312
- }
1313
- int result = base->tp_init(self, args, kwds);
1314
- if (result == 0) {
1315
- ensure_tp((PyTypeObject*)self);
1316
- }
1317
- return result;
1318
- }
1319
-
1320
1342
  static PyTypeObject PrivateAttrType = {
1321
1343
  PyVarObject_HEAD_INIT(NULL, 0)
1322
- "private_attribute.PrivateAttrType", // tp_name
1323
- sizeof(PrivateAttrTypeObject), // tp_basicsize
1324
- 0, // tp_itemsize
1325
- (destructor)PrivateAttrType_del, // tp_dealloc
1326
- 0, // tp_print
1327
- 0, // tp_getattr
1328
- 0, // tp_setattr
1329
- 0, // tp_reserved
1330
- 0, // tp_repr
1331
- 0, // tp_as_number
1332
- 0, // tp_as_sequence
1333
- 0, // tp_as_mapping
1334
- 0, // tp_hash
1335
- 0, // tp_call
1336
- 0, // tp_str
1337
- (getattrofunc)PrivateAttrType_getattr, // tp_getattro
1338
- (setattrofunc)PrivateAttrType_setattr, // tp_setattro
1339
- 0, // tp_as_buffer
1340
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
1341
- "metaclass for private attributes", // tp_doc
1342
- 0, // tp_travers
1343
- 0, // tp_clear
1344
- 0, // tp_richcompare
1345
- 0, // tp_weaklistoffset
1346
- 0, // tp_iter
1347
- 0, // tp_iternext
1348
- 0, // tp_methods
1349
- 0, // tp_members
1350
- 0, // tp_getset
1351
- &PyType_Type, // tp_base
1352
- 0, // tp_dict
1353
- 0, // tp_descr_get
1354
- 0, // tp_descr_set
1355
- 0, // tp_dictoffset
1356
- PrivateAttrType_init, // tp_init
1357
- 0, // tp_alloc
1358
- (newfunc)PrivateAttrType_new, // tp_new
1344
+ "private_attribute.PrivateAttrType", // tp_name
1345
+ sizeof(PrivateAttrTypeObject), // tp_basicsize
1346
+ 0, // tp_itemsize
1347
+ (destructor)PrivateAttrType_del, // tp_dealloc
1348
+ 0, // tp_print
1349
+ 0, // tp_getattr
1350
+ 0, // tp_setattr
1351
+ 0, // tp_reserved
1352
+ 0, // tp_repr
1353
+ 0, // tp_as_number
1354
+ 0, // tp_as_sequence
1355
+ 0, // tp_as_mapping
1356
+ 0, // tp_hash
1357
+ 0, // tp_call
1358
+ 0, // tp_str
1359
+ (getattrofunc)PrivateAttrType_getattr, // tp_getattro
1360
+ (setattrofunc)PrivateAttrType_setattr, // tp_setattro
1361
+ 0, // tp_as_buffer
1362
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
1363
+ "metaclass for private attributes", // tp_doc
1364
+ 0, // tp_travers
1365
+ 0, // tp_clear
1366
+ 0, // tp_richcompare
1367
+ 0, // tp_weaklistoffset
1368
+ 0, // tp_iter
1369
+ 0, // tp_iternext
1370
+ 0, // tp_methods
1371
+ 0, // tp_members
1372
+ 0, // tp_getset
1373
+ &PyType_Type, // tp_base
1374
+ 0, // tp_dict
1375
+ 0, // tp_descr_get
1376
+ 0, // tp_descr_set
1377
+ 0, // tp_dictoffset
1378
+ 0, // tp_init
1379
+ 0, // tp_alloc
1380
+ (newfunc)PrivateAttrType_new, // tp_new
1359
1381
  };
1360
1382
 
1361
1383
  static PyObject*
@@ -2016,6 +2038,7 @@ ensure_subclass_tp(PyTypeObject* type_instance)
2016
2038
  continue;
2017
2039
  }
2018
2040
  ensure_tp((PyTypeObject*)subclass);
2041
+ ensure_subclass_tp((PyTypeObject*)subclass);
2019
2042
  }
2020
2043
  Py_DECREF(type_subclasses);
2021
2044
  }
@@ -2292,6 +2315,9 @@ PrivateAttrType_del(PyObject* cls)
2292
2315
  (Py_TYPE(cls))->tp_free(cls);
2293
2316
  }
2294
2317
 
2318
+ static const char* PrivateAttrBase_doc = "The class to help to create private attribute. "
2319
+ "It does not have any special behavior, but it can be used as a base class for PrivateAttrType to avoid some conflicts with other metaclasses.";
2320
+
2295
2321
  // PrivateAttrBase
2296
2322
  static PyObject*
2297
2323
  create_private_attr_base_simple(void)
@@ -2318,6 +2344,7 @@ create_private_attr_base_simple(void)
2318
2344
  }
2319
2345
  PyDict_SetItemString(dict, "__private_attrs__", private_attrs);
2320
2346
  PyDict_SetItemString(dict, "__slots__", private_attrs);
2347
+ PyDict_SetItemString(dict, "__doc__", PyUnicode_FromString(PrivateAttrBase_doc));
2321
2348
  PyObject *args = PyTuple_Pack(3, name, bases, dict);
2322
2349
  PyObject* base_type;
2323
2350
  if (args) {
@@ -2395,10 +2422,10 @@ PrivateTempObject_kwds(PyObject* self, void* /*closure*/)
2395
2422
  }
2396
2423
 
2397
2424
  static PyGetSetDef PrivateTempObject_getsets[] = {
2398
- {"name", (getter)PrivateTempObject_name, NULL, NULL, NULL},
2399
- {"bases", (getter)PrivateTempObject_base, NULL, NULL, NULL},
2400
- {"attrs", (getter)PrivateTempObject_attrs, NULL, NULL, NULL},
2401
- {"kwds", (getter)PrivateTempObject_kwds, NULL, NULL, NULL},
2425
+ {"name", (getter)PrivateTempObject_name, NULL, "The name for submetaclass.__new__ argument 1", NULL},
2426
+ {"bases", (getter)PrivateTempObject_base, NULL, "The base classes for submetaclass.__new__ argument 2", NULL},
2427
+ {"attrs", (getter)PrivateTempObject_attrs, NULL, "The attributes for submetaclass.__new__ argument 3", NULL},
2428
+ {"kwds", (getter)PrivateTempObject_kwds, NULL, "The keyword arguments for submetaclass.__new__", NULL},
2402
2429
  {NULL}
2403
2430
  };
2404
2431
 
@@ -2515,7 +2542,6 @@ register_metaclass(PyObject* /*self*/, PyObject* metaclass)
2515
2542
  ((PyTypeObject*)metaclass)->tp_getattro = PrivateAttrType_getattr;
2516
2543
  ((PyTypeObject*)metaclass)->tp_setattro = PrivateAttrType_setattr;
2517
2544
  ((PyTypeObject*)metaclass)->tp_finalize = register_finalize;
2518
- ((PyTypeObject*)metaclass)->tp_init = PrivateAttrType_init;
2519
2545
  ((PyTypeObject*)metaclass)->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
2520
2546
  Py_RETURN_NONE;
2521
2547
  }
@@ -2543,7 +2569,6 @@ ensure_metaclass_tp(PyObject* /*self*/, PyObject* metaclass)
2543
2569
  ((PyTypeObject*)metaclass)->tp_getattro = PrivateAttrType_getattr;
2544
2570
  ((PyTypeObject*)metaclass)->tp_setattro = PrivateAttrType_setattr;
2545
2571
  ((PyTypeObject*)metaclass)->tp_finalize = register_finalize;
2546
- ((PyTypeObject*)metaclass)->tp_init = PrivateAttrType_init;
2547
2572
  }
2548
2573
  Py_RETURN_NONE;
2549
2574
  }
@@ -2627,13 +2652,52 @@ static PyGetSetDef PrivateModule_getsetters[] = {
2627
2652
  {NULL}
2628
2653
  };
2629
2654
 
2655
+ static const char* prepare_and_postprocess_doc = R"(function for custom metaclass to create private attributes class.
2656
+
2657
+ def prepare(name: str, bases: tuple, attrs: dict, **kwds) -> tempobject:
2658
+ the function to prepare for creating private attributes class. It will return a temporary object which has the same information as the arguments. The custom metaclass can call this function in its __prepare__ method to get the information for creating private attributes class.
2659
+
2660
+ def postprocess(type: type, tmp: tempobject) -> None:
2661
+ the function to postprocess for creating private attributes class. The custom metaclass can call this
2662
+
2663
+ def register_metaclass(metaclass: type) -> None:
2664
+ the function to register custom metaclass. The custom metaclass must call this function to register itself before creating any private attributes class, otherwise the private attributes class created by this custom metaclass will not work.
2665
+
2666
+ All usage of this module should be like:
2667
+ ```
2668
+ from abc import ABCMeta
2669
+ import private_attribute
2670
+
2671
+ class PrivateAbcMeta(ABCMeta):
2672
+ def __new__(cls, *args, **kwargs):
2673
+ temp = private_attribute.prepare(*args, **kwargs)
2674
+ typ = super().__new__(cls, temp.name, temp.bases, temp.attrs, **temp.kwds)
2675
+ private_attribute.postprocess(typ, temp)
2676
+ return typ
2677
+
2678
+
2679
+ private_attribute.register_metaclass(PrivateAbcMeta)
2680
+ ```
2681
+ )";
2682
+
2683
+ static const char* ensure_type_doc = R"(function for custom metaclass to ensure the type is a private attributes class.
2684
+
2685
+ def ensure_type(type: type) -> None:
2686
+ the function to ensure the type is a private attributes class `tp_getattro`, `tp_setattro` and `tp_finalizer`.
2687
+ )";
2688
+
2689
+ static const char* ensure_metaclass_doc = R"(function for custom metaclass to ensure the metaclass is registered.
2690
+ def ensure_metaclass(metaclass: type) -> None:
2691
+ the function to ensure the metaclass `tp_getattro`, `tp_setattro` and `tp_finalizer`.
2692
+ )";
2693
+
2630
2694
  static PyMethodDef PrivateModule_methods[] = {
2631
2695
  {"__dir__", (PyCFunction)PrivateModule_dir, METH_NOARGS, NULL},
2632
- {"prepare", (PyCFunction)prepare_for_PrivateAttr, METH_VARARGS | METH_KEYWORDS, NULL},
2633
- {"postprocess", (PyCFunction)postprocess_for_PrivateAttr, METH_VARARGS, NULL},
2634
- {"register_metaclass", (PyCFunction)register_metaclass, METH_O, NULL},
2635
- {"ensure_type", (PyCFunction)ensure_type_tp, METH_O, NULL},
2636
- {"ensure_metaclass", (PyCFunction)ensure_metaclass_tp, METH_O, NULL},
2696
+ {"prepare", (PyCFunction)prepare_for_PrivateAttr, METH_VARARGS | METH_KEYWORDS, prepare_and_postprocess_doc},
2697
+ {"postprocess", (PyCFunction)postprocess_for_PrivateAttr, METH_VARARGS, prepare_and_postprocess_doc},
2698
+ {"register_metaclass", (PyCFunction)register_metaclass, METH_O, prepare_and_postprocess_doc},
2699
+ {"ensure_type", (PyCFunction)ensure_type_tp, METH_O, ensure_type_doc},
2700
+ {"ensure_metaclass", (PyCFunction)ensure_metaclass_tp, METH_O, ensure_metaclass_doc},
2637
2701
  {NULL} // Sentinel
2638
2702
  };
2639
2703
 
@@ -2671,10 +2735,29 @@ static PyTypeObject PrivateModuleType = {
2671
2735
  &PyModule_Type, //tp_base
2672
2736
  };
2673
2737
 
2738
+ static const char* module_doc = R"(
2739
+ A module that provides a metaclass for creating classes with private attributes.
2740
+ Private attributes are defined in the `__private_attrs__` sequence and are only
2741
+ You can use the `PrivateAttrBase` metaclass to create classes with private attributes.
2742
+ The attributes which are private are not on the instance's `__dict__` and cannot be accessed outside
2743
+ but in the classmethods it is reachable.
2744
+ Usage example:
2745
+ ```python
2746
+ class MyClass(PrivateAttrBase):
2747
+ __private_attrs__ = ('_private_attr1',)
2748
+ def __init__(self):
2749
+ self._private_attr1 = 1
2750
+
2751
+ @property
2752
+ def public_attr1(self):
2753
+ return self._private_attr1
2754
+ ```
2755
+ )";
2756
+
2674
2757
  static PyModuleDef def = {
2675
2758
  PyModuleDef_HEAD_INIT,
2676
2759
  "private_attribute",
2677
- NULL,
2760
+ module_doc,
2678
2761
  0,
2679
2762
  NULL,
2680
2763
  NULL,
@@ -1,18 +1,20 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 1.3.2
3
+ Version: 1.3.4
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
7
7
  Author-email: 13140752715@example.com
8
8
  License: MIT
9
9
  Description-Content-Type: text/markdown
10
+ License-File: LICENSE
10
11
  Dynamic: author
11
12
  Dynamic: author-email
12
13
  Dynamic: description
13
14
  Dynamic: description-content-type
14
15
  Dynamic: home-page
15
16
  Dynamic: license
17
+ Dynamic: license-file
16
18
  Dynamic: summary
17
19
 
18
20
  # Private Attribute (c++ implementation)
@@ -247,7 +249,6 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
247
249
  - Finally the `_PrivateWrap` object will be recoveried to the original object.
248
250
  - One class defined in another class cannot use another class's private attribute.
249
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__`.
250
- - When combine with other metaclass, be ensure that the parent metaclass has no classmethod that can set subclasses' attributes. If it has, it will fail on new metaclass because the new metaclass you defined and registered will be immutable.
251
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.
252
253
 
253
254
  ## License
@@ -19,7 +19,7 @@ readme = open('README.md').read()
19
19
 
20
20
  setup(
21
21
  name='private_attribute_cpp',
22
- version='1.3.2',
22
+ version='1.3.4',
23
23
  author="HuangHaoHua",
24
24
  author_email="13140752715@example.com",
25
25
  description='A Python package that provides a way to define private attributes in C++ implementation.',