private-attribute-cpp 1.3.3__tar.gz → 1.3.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.
@@ -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.3
3
+ Version: 1.3.5
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
@@ -816,11 +816,10 @@ type_delattr(PyObject* typ, std::string attr_name)
816
816
  // ================================================================
817
817
  // _PrivateWrap
818
818
  // ================================================================
819
- typedef struct PrivateWrapObject {
819
+ typedef struct {
820
820
  PyObject_HEAD
821
821
  PyObject *result;
822
822
  PyObject *func_list;
823
- PyObject *decorator;
824
823
  } PrivateWrapObject;
825
824
 
826
825
  static PrivateWrapObject* PrivateWrap_New(PyObject *decorator, PyObject *func, PyObject *list);
@@ -935,16 +934,19 @@ PrivateWrap_type_params(PyObject* obj, void* /*closure*/)
935
934
  return type_params;
936
935
  }
937
936
 
937
+ static const char* PrivateWrap_result_doc = "the final result of decorating";
938
+ static const char* PrivateWrap_funcs_doc = "the original functions";
939
+
938
940
  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},
941
+ {"result", (getter)PrivateWrap_result, NULL, PrivateWrap_result_doc, NULL},
942
+ {"funcs", (getter)PrivateWrap_funcs, NULL, PrivateWrap_funcs_doc, NULL},
943
+ {"__wrapped__", (getter)PrivateWrap_result, NULL, NULL, NULL},
944
+ {"__doc__", (getter)PrivateWrap_doc, NULL, NULL, NULL},
945
+ {"__module__", (getter)PrivateWrap_module, NULL, NULL, NULL},
946
+ {"__name__", (getter)PrivateWarp_name, NULL, NULL, NULL},
947
+ {"__qualname__", (getter)PrivateWrap_qualname, NULL, NULL, NULL},
948
+ {"__annotate__", (getter)PrivateWrap_annotate, NULL, NULL, NULL},
949
+ {"__type_params__", (getter)PrivateWrap_type_params, NULL, NULL, NULL},
948
950
  {NULL}
949
951
  };
950
952
 
@@ -1006,9 +1008,6 @@ PrivateWrap_New(PyObject *decorator, PyObject *func, PyObject *list)
1006
1008
  return NULL;
1007
1009
  }
1008
1010
 
1009
- self->decorator = decorator;
1010
- Py_INCREF(decorator);
1011
-
1012
1011
  self->func_list = list;
1013
1012
  Py_INCREF(list);
1014
1013
 
@@ -1022,7 +1021,6 @@ PrivateWrap_dealloc(PrivateWrapObject *self)
1022
1021
  {
1023
1022
  Py_XDECREF(self->result);
1024
1023
  Py_XDECREF(self->func_list);
1025
- Py_XDECREF(self->decorator);
1026
1024
  Py_TYPE(self)->tp_free((PyObject *)self);
1027
1025
  }
1028
1026
 
@@ -1070,6 +1068,35 @@ PrivateWrapProxy_call(PrivateWrapProxyObject *self, PyObject *args, PyObject* /*
1070
1068
 
1071
1069
  static void PrivateWrapProxy_dealloc(PrivateWrapProxyObject *self);
1072
1070
  static PyObject* PrivateWrapProxy_New(PyTypeObject *type, PyObject *args, PyObject *kwds);
1071
+ static const char* PrivateWrapProxy_doc = R"(
1072
+ PrivateWrapProxy is a proxy for private attributes.
1073
+ Usage:
1074
+ ```
1075
+ from private_attribute import PrivateWrapProxy, PrivateAttrBase
1076
+
1077
+ class MyClass(PrivateAttrBase):
1078
+ __private_attrs__ = ()
1079
+ @PrivateWrapProxy(decorator)
1080
+ def my_method(self): ...
1081
+
1082
+ @PrivateWrapProxy(decorator)
1083
+ def my_method2(self): ...
1084
+ ```
1085
+ It returned a '_PrivateWrap' object.
1086
+
1087
+ If you need to decorate more function, use like this:
1088
+ ```
1089
+ from private_attribute import PrivateWrapProxy, PrivateAttrBase
1090
+
1091
+ class MyClass(PrivateAttrBase):
1092
+ __private_attrs__ = ()
1093
+ @PrivateWrapProxy(decorator)
1094
+ def my_method(self): ...
1095
+
1096
+ @PrivateWrapProxy(my_method.some_decorator, my_method)
1097
+ def my_method(self): ...
1098
+ ```
1099
+ )";
1073
1100
 
1074
1101
  static PyTypeObject PrivateWrapProxyType = {
1075
1102
  PyVarObject_HEAD_INIT(NULL, 0)
@@ -1092,7 +1119,7 @@ static PyTypeObject PrivateWrapProxyType = {
1092
1119
  0, // tp_setattro
1093
1120
  0, // tp_as_buffer
1094
1121
  Py_TPFLAGS_DEFAULT, // tp_flags
1095
- "PrivateWrapProxy", // tp_doc
1122
+ PrivateWrapProxy_doc, // tp_doc
1096
1123
  0, // tp_traverse
1097
1124
  0, // tp_clear
1098
1125
  0, // tp_richcompare
@@ -1307,66 +1334,45 @@ static PyObject* PrivateAttrType_getattr(PyObject* cls, PyObject* name);
1307
1334
  static int PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value);
1308
1335
  static void PrivateAttrType_del(PyObject* cls);
1309
1336
 
1310
- static int
1311
- PrivateAttrType_init(PyObject* self, PyObject* args, PyObject* kwds)
1312
- {
1313
- PyTypeObject* base = Py_TYPE(self);
1314
- while (base->tp_init == PrivateAttrType_init) {
1315
- base = base->tp_base;
1316
- }
1317
- if (base->tp_init == NULL) {
1318
- int result = PyType_Type.tp_init(self, args, kwds);
1319
- if (result == 0) {
1320
- ensure_tp((PyTypeObject*)self);
1321
- }
1322
- return result;
1323
- }
1324
- int result = base->tp_init(self, args, kwds);
1325
- if (result == 0) {
1326
- ensure_tp((PyTypeObject*)self);
1327
- }
1328
- return result;
1329
- }
1330
-
1331
1337
  static PyTypeObject PrivateAttrType = {
1332
1338
  PyVarObject_HEAD_INIT(NULL, 0)
1333
- "private_attribute.PrivateAttrType", // tp_name
1334
- sizeof(PrivateAttrTypeObject), // tp_basicsize
1335
- 0, // tp_itemsize
1336
- (destructor)PrivateAttrType_del, // tp_dealloc
1337
- 0, // tp_print
1338
- 0, // tp_getattr
1339
- 0, // tp_setattr
1340
- 0, // tp_reserved
1341
- 0, // tp_repr
1342
- 0, // tp_as_number
1343
- 0, // tp_as_sequence
1344
- 0, // tp_as_mapping
1345
- 0, // tp_hash
1346
- 0, // tp_call
1347
- 0, // tp_str
1348
- (getattrofunc)PrivateAttrType_getattr, // tp_getattro
1349
- (setattrofunc)PrivateAttrType_setattr, // tp_setattro
1350
- 0, // tp_as_buffer
1351
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
1352
- "metaclass for private attributes", // tp_doc
1353
- 0, // tp_travers
1354
- 0, // tp_clear
1355
- 0, // tp_richcompare
1356
- 0, // tp_weaklistoffset
1357
- 0, // tp_iter
1358
- 0, // tp_iternext
1359
- 0, // tp_methods
1360
- 0, // tp_members
1361
- 0, // tp_getset
1362
- &PyType_Type, // tp_base
1363
- 0, // tp_dict
1364
- 0, // tp_descr_get
1365
- 0, // tp_descr_set
1366
- 0, // tp_dictoffset
1367
- PrivateAttrType_init, // tp_init
1368
- 0, // tp_alloc
1369
- (newfunc)PrivateAttrType_new, // tp_new
1339
+ "private_attribute.PrivateAttrType", // tp_name
1340
+ sizeof(PrivateAttrTypeObject), // tp_basicsize
1341
+ 0, // tp_itemsize
1342
+ (destructor)PrivateAttrType_del, // tp_dealloc
1343
+ 0, // tp_print
1344
+ 0, // tp_getattr
1345
+ 0, // tp_setattr
1346
+ 0, // tp_reserved
1347
+ 0, // tp_repr
1348
+ 0, // tp_as_number
1349
+ 0, // tp_as_sequence
1350
+ 0, // tp_as_mapping
1351
+ 0, // tp_hash
1352
+ 0, // tp_call
1353
+ 0, // tp_str
1354
+ (getattrofunc)PrivateAttrType_getattr, // tp_getattro
1355
+ (setattrofunc)PrivateAttrType_setattr, // tp_setattro
1356
+ 0, // tp_as_buffer
1357
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
1358
+ "metaclass for private attributes", // tp_doc
1359
+ 0, // tp_travers
1360
+ 0, // tp_clear
1361
+ 0, // tp_richcompare
1362
+ 0, // tp_weaklistoffset
1363
+ 0, // tp_iter
1364
+ 0, // tp_iternext
1365
+ 0, // tp_methods
1366
+ 0, // tp_members
1367
+ 0, // tp_getset
1368
+ &PyType_Type, // tp_base
1369
+ 0, // tp_dict
1370
+ 0, // tp_descr_get
1371
+ 0, // tp_descr_set
1372
+ 0, // tp_dictoffset
1373
+ 0, // tp_init
1374
+ 0, // tp_alloc
1375
+ (newfunc)PrivateAttrType_new, // tp_new
1370
1376
  };
1371
1377
 
1372
1378
  static PyObject*
@@ -2027,6 +2033,7 @@ ensure_subclass_tp(PyTypeObject* type_instance)
2027
2033
  continue;
2028
2034
  }
2029
2035
  ensure_tp((PyTypeObject*)subclass);
2036
+ ensure_subclass_tp((PyTypeObject*)subclass);
2030
2037
  }
2031
2038
  Py_DECREF(type_subclasses);
2032
2039
  }
@@ -2303,6 +2310,8 @@ PrivateAttrType_del(PyObject* cls)
2303
2310
  (Py_TYPE(cls))->tp_free(cls);
2304
2311
  }
2305
2312
 
2313
+ static const char* PrivateAttrBase_doc = "The class to help to create private attribute. It does not have any special behavior.";
2314
+
2306
2315
  // PrivateAttrBase
2307
2316
  static PyObject*
2308
2317
  create_private_attr_base_simple(void)
@@ -2329,6 +2338,7 @@ create_private_attr_base_simple(void)
2329
2338
  }
2330
2339
  PyDict_SetItemString(dict, "__private_attrs__", private_attrs);
2331
2340
  PyDict_SetItemString(dict, "__slots__", private_attrs);
2341
+ PyDict_SetItemString(dict, "__doc__", PyUnicode_FromString(PrivateAttrBase_doc));
2332
2342
  PyObject *args = PyTuple_Pack(3, name, bases, dict);
2333
2343
  PyObject* base_type;
2334
2344
  if (args) {
@@ -2362,7 +2372,7 @@ PrivateTempObject_name(PyObject* self, void* /*closure*/)
2362
2372
  {
2363
2373
  PyObject* name = ((PrivateTempObject*)self)->tmp->name;
2364
2374
  if (!name) {
2365
- PyErr_SetString(PyExc_RuntimeError, "object not init");
2375
+ PyErr_SetString(PyExc_RuntimeError, "object not init or have been used");
2366
2376
  return nullptr;
2367
2377
  }
2368
2378
  Py_INCREF(name);
@@ -2374,7 +2384,7 @@ PrivateTempObject_base(PyObject* self, void* /*closure*/)
2374
2384
  {
2375
2385
  PyObject* base = ((PrivateTempObject*)self)->tmp->bases;
2376
2386
  if (!base) {
2377
- PyErr_SetString(PyExc_RuntimeError, "object not init");
2387
+ PyErr_SetString(PyExc_RuntimeError, "object not init or have been used");
2378
2388
  return nullptr;
2379
2389
  }
2380
2390
  Py_INCREF(base);
@@ -2386,7 +2396,7 @@ PrivateTempObject_attrs(PyObject* self, void* /*closure*/)
2386
2396
  {
2387
2397
  PyObject* attrs = ((PrivateTempObject*)self)->tmp->attrs_copy;
2388
2398
  if (!attrs) {
2389
- PyErr_SetString(PyExc_RuntimeError, "object not init");
2399
+ PyErr_SetString(PyExc_RuntimeError, "object not init or have been used");
2390
2400
  return nullptr;
2391
2401
  }
2392
2402
  Py_INCREF(attrs);
@@ -2398,7 +2408,7 @@ PrivateTempObject_kwds(PyObject* self, void* /*closure*/)
2398
2408
  {
2399
2409
  PyObject* kwds = ((PrivateTempObject*)self)->tmp->base_kwds;
2400
2410
  if (!kwds) {
2401
- PyErr_SetString(PyExc_RuntimeError, "object not init");
2411
+ PyErr_SetString(PyExc_RuntimeError, "object not init or have been used");
2402
2412
  return nullptr;
2403
2413
  }
2404
2414
  Py_INCREF(kwds);
@@ -2406,10 +2416,10 @@ PrivateTempObject_kwds(PyObject* self, void* /*closure*/)
2406
2416
  }
2407
2417
 
2408
2418
  static PyGetSetDef PrivateTempObject_getsets[] = {
2409
- {"name", (getter)PrivateTempObject_name, NULL, NULL, NULL},
2410
- {"bases", (getter)PrivateTempObject_base, NULL, NULL, NULL},
2411
- {"attrs", (getter)PrivateTempObject_attrs, NULL, NULL, NULL},
2412
- {"kwds", (getter)PrivateTempObject_kwds, NULL, NULL, NULL},
2419
+ {"name", (getter)PrivateTempObject_name, NULL, "The name for submetaclass.__new__ argument 1", NULL},
2420
+ {"bases", (getter)PrivateTempObject_base, NULL, "The base classes for submetaclass.__new__ argument 2", NULL},
2421
+ {"attrs", (getter)PrivateTempObject_attrs, NULL, "The attributes for submetaclass.__new__ argument 3", NULL},
2422
+ {"kwds", (getter)PrivateTempObject_kwds, NULL, "The keyword arguments for submetaclass.__new__", NULL},
2413
2423
  {NULL}
2414
2424
  };
2415
2425
 
@@ -2457,15 +2467,19 @@ static PyTypeObject PrivateTempType = {
2457
2467
  static PyObject*
2458
2468
  prepare_for_PrivateAttr(PyObject* /*self*/, PyObject* args, PyObject* kwargs)
2459
2469
  {
2460
- PrivateTempObject* tmp = PyObject_New(PrivateTempObject, &PrivateTempType);
2461
- if (!tmp) {
2470
+ PrivateAttrCreationData* tmp_data = new PrivateAttrCreationData();
2471
+ if (!PrivateAttrType_preprocess(args, kwargs, *tmp_data)) {
2472
+ tmp_data->clear();
2473
+ delete tmp_data;
2462
2474
  return NULL;
2463
2475
  }
2464
- tmp->tmp = new PrivateAttrCreationData();
2465
- if (!PrivateAttrType_preprocess(args, kwargs, *(tmp->tmp))) {
2466
- Py_DECREF(tmp);
2476
+ PrivateTempObject* tmp = PyObject_New(PrivateTempObject, &PrivateTempType);
2477
+ if (!tmp) {
2478
+ tmp_data->clear();
2479
+ delete tmp_data;
2467
2480
  return NULL;
2468
2481
  }
2482
+ tmp->tmp = tmp_data;
2469
2483
  return (PyObject*)tmp;
2470
2484
  }
2471
2485
 
@@ -2526,8 +2540,6 @@ register_metaclass(PyObject* /*self*/, PyObject* metaclass)
2526
2540
  ((PyTypeObject*)metaclass)->tp_getattro = PrivateAttrType_getattr;
2527
2541
  ((PyTypeObject*)metaclass)->tp_setattro = PrivateAttrType_setattr;
2528
2542
  ((PyTypeObject*)metaclass)->tp_finalize = register_finalize;
2529
- ((PyTypeObject*)metaclass)->tp_init = PrivateAttrType_init;
2530
- ((PyTypeObject*)metaclass)->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
2531
2543
  Py_RETURN_NONE;
2532
2544
  }
2533
2545
 
@@ -2554,7 +2566,6 @@ ensure_metaclass_tp(PyObject* /*self*/, PyObject* metaclass)
2554
2566
  ((PyTypeObject*)metaclass)->tp_getattro = PrivateAttrType_getattr;
2555
2567
  ((PyTypeObject*)metaclass)->tp_setattro = PrivateAttrType_setattr;
2556
2568
  ((PyTypeObject*)metaclass)->tp_finalize = register_finalize;
2557
- ((PyTypeObject*)metaclass)->tp_init = PrivateAttrType_init;
2558
2569
  }
2559
2570
  Py_RETURN_NONE;
2560
2571
  }
@@ -2638,13 +2649,51 @@ static PyGetSetDef PrivateModule_getsetters[] = {
2638
2649
  {NULL}
2639
2650
  };
2640
2651
 
2652
+ static const char* prepare_and_postprocess_doc = R"(function for custom metaclass to create private attributes class.
2653
+
2654
+ def prepare(name: str, bases: tuple, attrs: dict, **kwds) -> tempobject:
2655
+ the function to prepare for creating private attributes class. It will return a temporary object which has the same information as the arguments.
2656
+
2657
+ def postprocess(type: type, tmp: tempobject) -> None:
2658
+ the function to postprocess for creating private attributes class. The custom metaclass can call this
2659
+
2660
+ def register_metaclass(metaclass: type) -> None:
2661
+ the function to register custom metaclass. The custom metaclass must call this function to register itself before creating any private attributes class,
2662
+ otherwise the private attributes class created by this custom metaclass will not work.
2663
+
2664
+ All usage of this module should be like:
2665
+ ```
2666
+ from abc import ABCMeta
2667
+ import private_attribute
2668
+
2669
+ class PrivateAbcMeta(ABCMeta):
2670
+ def __new__(cls, *args, **kwargs):
2671
+ temp = private_attribute.prepare(*args, **kwargs)
2672
+ typ = super().__new__(cls, temp.name, temp.bases, temp.attrs, **temp.kwds)
2673
+ private_attribute.postprocess(typ, temp)
2674
+ return typ
2675
+
2676
+ private_attribute.register_metaclass(PrivateAbcMeta)
2677
+ ```
2678
+ )";
2679
+
2680
+ static const char* ensure_type_doc = R"(function for custom metaclass to ensure the type is a private attributes class.
2681
+ def ensure_type(type: type) -> None:
2682
+ the function to ensure the type is a private attributes class `tp_getattro`, `tp_setattro` and `tp_finalizer`.
2683
+ )";
2684
+
2685
+ static const char* ensure_metaclass_doc = R"(function for custom metaclass to ensure the metaclass is working.
2686
+ def ensure_metaclass(metaclass: type) -> None:
2687
+ the function to ensure the metaclass `tp_getattro`, `tp_setattro` and `tp_finalizer`.
2688
+ )";
2689
+
2641
2690
  static PyMethodDef PrivateModule_methods[] = {
2642
2691
  {"__dir__", (PyCFunction)PrivateModule_dir, METH_NOARGS, NULL},
2643
- {"prepare", (PyCFunction)prepare_for_PrivateAttr, METH_VARARGS | METH_KEYWORDS, NULL},
2644
- {"postprocess", (PyCFunction)postprocess_for_PrivateAttr, METH_VARARGS, NULL},
2645
- {"register_metaclass", (PyCFunction)register_metaclass, METH_O, NULL},
2646
- {"ensure_type", (PyCFunction)ensure_type_tp, METH_O, NULL},
2647
- {"ensure_metaclass", (PyCFunction)ensure_metaclass_tp, METH_O, NULL},
2692
+ {"prepare", (PyCFunction)prepare_for_PrivateAttr, METH_VARARGS | METH_KEYWORDS, prepare_and_postprocess_doc},
2693
+ {"postprocess", (PyCFunction)postprocess_for_PrivateAttr, METH_VARARGS, prepare_and_postprocess_doc},
2694
+ {"register_metaclass", (PyCFunction)register_metaclass, METH_O, prepare_and_postprocess_doc},
2695
+ {"ensure_type", (PyCFunction)ensure_type_tp, METH_O, ensure_type_doc},
2696
+ {"ensure_metaclass", (PyCFunction)ensure_metaclass_tp, METH_O, ensure_metaclass_doc},
2648
2697
  {NULL} // Sentinel
2649
2698
  };
2650
2699
 
@@ -2682,10 +2731,29 @@ static PyTypeObject PrivateModuleType = {
2682
2731
  &PyModule_Type, //tp_base
2683
2732
  };
2684
2733
 
2734
+ static const char* module_doc = R"(
2735
+ A module that provides a metaclass for creating classes with private attributes.
2736
+ Private attributes are defined in the `__private_attrs__` sequence and are only
2737
+ You can use the `PrivateAttrBase` metaclass to create classes with private attributes.
2738
+ The attributes which are private are not on the instance's `__dict__` and cannot be accessed outside
2739
+ but in the methods defined in class it is reachable.
2740
+ Usage example:
2741
+ ```python
2742
+ class MyClass(PrivateAttrBase):
2743
+ __private_attrs__ = ('_private_attr1',)
2744
+ def __init__(self):
2745
+ self._private_attr1 = 1
2746
+
2747
+ @property
2748
+ def public_attr1(self):
2749
+ return self._private_attr1
2750
+ ```
2751
+ )";
2752
+
2685
2753
  static PyModuleDef def = {
2686
2754
  PyModuleDef_HEAD_INIT,
2687
2755
  "private_attribute",
2688
- NULL,
2756
+ module_doc,
2689
2757
  0,
2690
2758
  NULL,
2691
2759
  NULL,
@@ -0,0 +1,200 @@
1
+ """A module that provides a metaclass for creating classes with private attributes.
2
+ Private attributes are defined in the `__private_attrs__` sequence and are only
3
+ You can use the `PrivateAttrBase` metaclass to create classes with private attributes.
4
+ The attributes which are private are not on the instance's `__dict__` and cannot be accessed outside
5
+ but in the methods defined in class it is reachable.
6
+ Usage example:
7
+ ```python
8
+ class MyClass(PrivateAttrBase):
9
+ __private_attrs__ = ('_private_attr1',)
10
+ def __init__(self):
11
+ self._private_attr1 = 1
12
+
13
+ @property
14
+ def public_attr1(self):
15
+ return self._private_attr1
16
+ ```
17
+ """
18
+ from typing import Any, TypeVar, Callable, TypedDict, Sequence, Generic
19
+ from types import FunctionType
20
+
21
+ # define the dict that must have a key "__private_attrs__" and value must be the sequence of strings
22
+ class PrivateAttrDict(TypedDict):
23
+ __private_attrs__: Sequence[str]
24
+
25
+ T = TypeVar('T')
26
+
27
+ class _PrivateWrap(Generic[T]):
28
+ @property
29
+ def result(self) -> T:
30
+ "the final result of decorating"
31
+ ...
32
+
33
+ @property
34
+ def funcs(self) -> tuple[FunctionType]:
35
+ "the original functions"
36
+ ...
37
+
38
+ def __getattr__(self, name: str) -> Any:
39
+ return getattr(self.result, name)
40
+
41
+ TVar = TypeVar('TVar')
42
+
43
+ class PrivateWrapProxy:
44
+ """
45
+ PrivateWrapProxy is a proxy for private attributes.
46
+ Usage:
47
+ ```
48
+ from private_attribute import PrivateWrapProxy, PrivateAttrBase
49
+
50
+ class MyClass(PrivateAttrBase):
51
+ __private_attrs__ = ()
52
+ @PrivateWrapProxy(decorator)
53
+ def my_method(self): ...
54
+
55
+ @PrivateWrapProxy(decorator)
56
+ def my_method2(self): ...
57
+ ```
58
+ It returned a '_PrivateWrap' object.
59
+
60
+ If you need to decorate more function, use like this:
61
+ ```
62
+ from private_attribute import PrivateWrapProxy, PrivateAttrBase
63
+
64
+ class MyClass(PrivateAttrBase):
65
+ __private_attrs__ = ()
66
+ @PrivateWrapProxy(decorator)
67
+ def my_method(self): ...
68
+
69
+ @PrivateWrapProxy(my_method.some_decorator, my_method)
70
+ def my_method(self): ...
71
+ ```
72
+ """
73
+ def __init__(self, decorator: Callable[[TVar], T], orig: _PrivateWrap[Any]|None = None, /) -> None: ...
74
+ def __call__(self, func: TVar, /) -> _PrivateWrap[T]: ...
75
+
76
+ class PrivateAttrType(type):
77
+ "metaclass for private attributes"
78
+ def __new__(cls, name: str, bases: tuple,
79
+ attrs: PrivateAttrDict, /,
80
+ private_func: Callable[[int, str], str]|None = None) -> PrivateAttrType: ...
81
+
82
+ class PrivateAttrBase(metaclass=PrivateAttrType):
83
+ "The class to help to create private attribute. It does not have any special behavior."
84
+ __slots__ = ()
85
+ __private_attrs__ = ()
86
+
87
+
88
+ class _PrivateTemp:
89
+ @property
90
+ def name(self) -> str: ...
91
+ @property
92
+ def bases(self) -> tuple[type]: ...
93
+ @property
94
+ def attrs(self) -> dict[str, Any]: ...
95
+ @property
96
+ def kwds(self) -> dict[str, Any]: ...
97
+
98
+ def prepare(name: str, bases: tuple, attrs: PrivateAttrDict, /, **kwds) -> _PrivateTemp:
99
+ """
100
+ function for custom metaclass to create private attributes class.
101
+
102
+ def prepare(name: str, bases: tuple, attrs: dict, **kwds) -> tempobject:
103
+ the function to prepare for creating private attributes class. It will return a temporary object which has the same information as the arguments.
104
+
105
+ def postprocess(type: type, tmp: tempobject) -> None:
106
+ the function to postprocess for creating private attributes class. The custom metaclass can call this
107
+
108
+ def register_metaclass(metaclass: type) -> None:
109
+ the function to register custom metaclass. The custom metaclass must call this function to register itself before creating any private attributes class,
110
+ otherwise the private attributes class created by this custom metaclass will not work.
111
+
112
+ All usage of this module should be like:
113
+ ```
114
+ from abc import ABCMeta
115
+ import private_attribute
116
+
117
+ class PrivateAbcMeta(ABCMeta):
118
+ def __new__(cls, *args, **kwargs):
119
+ temp = private_attribute.prepare(*args, **kwargs)
120
+ typ = super().__new__(cls, temp.name, temp.bases, temp.attrs, **temp.kwds)
121
+ private_attribute.postprocess(typ, temp)
122
+ return typ
123
+
124
+ private_attribute.register_metaclass(PrivateAbcMeta)
125
+ ```
126
+ """
127
+ ...
128
+
129
+ def postprocess(typ: type, temp: _PrivateTemp, /) -> None:
130
+ """
131
+ function for custom metaclass to create private attributes class.
132
+
133
+ def prepare(name: str, bases: tuple, attrs: dict, **kwds) -> tempobject:
134
+ the function to prepare for creating private attributes class. It will return a temporary object which has the same information as the arguments.
135
+
136
+ def postprocess(type: type, tmp: tempobject) -> None:
137
+ the function to postprocess for creating private attributes class. The custom metaclass can call this
138
+
139
+ def register_metaclass(metaclass: type) -> None:
140
+ the function to register custom metaclass. The custom metaclass must call this function to register itself before creating any private attributes class,
141
+ otherwise the private attributes class created by this custom metaclass will not work.
142
+
143
+ All usage of this module should be like:
144
+ ```
145
+ from abc import ABCMeta
146
+ import private_attribute
147
+
148
+ class PrivateAbcMeta(ABCMeta):
149
+ def __new__(cls, *args, **kwargs):
150
+ temp = private_attribute.prepare(*args, **kwargs)
151
+ typ = super().__new__(cls, temp.name, temp.bases, temp.attrs, **temp.kwds)
152
+ private_attribute.postprocess(typ, temp)
153
+ return typ
154
+
155
+ private_attribute.register_metaclass(PrivateAbcMeta)
156
+ ```
157
+ """
158
+ ...
159
+ def register_metaclass(typ: type, /) -> None:
160
+ """
161
+ function for custom metaclass to create private attributes class.
162
+
163
+ def prepare(name: str, bases: tuple, attrs: dict, **kwds) -> tempobject:
164
+ the function to prepare for creating private attributes class. It will return a temporary object which has the same information as the arguments.
165
+
166
+ def postprocess(type: type, tmp: tempobject) -> None:
167
+ the function to postprocess for creating private attributes class. The custom metaclass can call this
168
+
169
+ def register_metaclass(metaclass: type) -> None:
170
+ the function to register custom metaclass. The custom metaclass must call this function to register itself before creating any private attributes class,
171
+ otherwise the private attributes class created by this custom metaclass will not work.
172
+
173
+ All usage of this module should be like:
174
+ ```
175
+ from abc import ABCMeta
176
+ import private_attribute
177
+
178
+ class PrivateAbcMeta(ABCMeta):
179
+ def __new__(cls, *args, **kwargs):
180
+ temp = private_attribute.prepare(*args, **kwargs)
181
+ typ = super().__new__(cls, temp.name, temp.bases, temp.attrs, **temp.kwds)
182
+ private_attribute.postprocess(typ, temp)
183
+ return typ
184
+
185
+ private_attribute.register_metaclass(PrivateAbcMeta)
186
+ ```
187
+ """
188
+ ...
189
+ def ensure_type(typ: type, /) -> None:
190
+ """function for custom metaclass to ensure the type is a private attributes class.
191
+ def ensure_type(type: type) -> None:
192
+ the function to ensure the type is a private attributes class `tp_getattro`, `tp_setattro` and `tp_finalizer`.
193
+ """
194
+ ...
195
+ def ensure_metaclass(typ: type, /) -> None:
196
+ """function for custom metaclass to ensure the metaclass is working.
197
+ def ensure_metaclass(metaclass: type) -> None:
198
+ the function to ensure the metaclass `tp_getattro`, `tp_setattro` and `tp_finalizer`.
199
+ """
200
+ ...
@@ -1,18 +1,20 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 1.3.3
3
+ Version: 1.3.5
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.3',
22
+ version='1.3.5',
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.',
@@ -1,50 +0,0 @@
1
- from typing import Any, TypeVar, Callable, TypedDict, Sequence, Generic
2
- from types import FunctionType
3
-
4
- # define the dict that must have a key "__private_attrs__" and value must be the sequence of strings
5
- class PrivateAttrDict(TypedDict):
6
- __private_attrs__: Sequence[str]
7
-
8
- T = TypeVar('T')
9
-
10
- class _PrivateWrap(Generic[T]):
11
- @property
12
- def result(self) -> T: ...
13
-
14
- @property
15
- def funcs(self) -> tuple[FunctionType]: ...
16
-
17
- def __getattr__(self, name: str) -> Any:
18
- return getattr(self.result, name)
19
-
20
- TVar = TypeVar('TVar')
21
-
22
- class PrivateWrapProxy:
23
- def __init__(self, decorator: Callable[[TVar], T], orig: _PrivateWrap[Any]|None = None, /) -> None: ...
24
- def __call__(self, func: TVar, /) -> _PrivateWrap[T]: ...
25
-
26
- class PrivateAttrType(type):
27
- def __new__(cls, name: str, bases: tuple,
28
- attrs: PrivateAttrDict, /,
29
- private_func: Callable[[int, str], str]|None = None) -> PrivateAttrType: ...
30
-
31
- class PrivateAttrBase(metaclass=PrivateAttrType):
32
- __slots__ = ()
33
- __private_attrs__ = ()
34
-
35
-
36
- class _PrivateTemp:
37
- @property
38
- def name(self) -> str: ...
39
- @property
40
- def bases(self) -> tuple[type]: ...
41
- @property
42
- def attrs(self) -> dict[str, Any]: ...
43
- @property
44
- def kwds(self) -> dict[str, Any]: ...
45
-
46
- def prepare(name: str, bases: tuple, attrs: PrivateAttrDict, /, **kwds) -> _PrivateTemp: ...
47
- def postprocess(typ: type, temp: _PrivateTemp, /) -> None: ...
48
- def register_metaclass(typ: type, /) -> None: ...
49
- def ensure_type(typ: type, /) -> None: ...
50
- def ensure_metaclass(typ: type, /) -> None: ...