private-attribute-cpp 1.3.8__tar.gz → 1.4.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 1.3.8
3
+ Version: 1.4.0
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,6 +250,7 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
250
250
  - One class defined in another class cannot use another class's private attribute.
251
251
  - One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
252
252
  - CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
253
+ - `private_attribute.register_metaclass` must be called with the metaclass which support weakref.
253
254
 
254
255
  ## License
255
256
 
@@ -231,6 +231,7 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
231
231
  - One class defined in another class cannot use another class's private attribute.
232
232
  - One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
233
233
  - CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
234
+ - `private_attribute.register_metaclass` must be called with the metaclass which support weakref.
234
235
 
235
236
  ## License
236
237
 
@@ -140,6 +140,7 @@ namespace {
140
140
  static std::shared_mutex all_register_new_metaclass_mutex;
141
141
  static std::vector<PyTypeObject*> all_register_new_metaclass;
142
142
  static std::unordered_set<uintptr_t> all_register_new_metaclass_id;
143
+ static std::unordered_map<uintptr_t, PyObject*> all_register_type_weak_ref;
143
144
  };
144
145
  };
145
146
 
@@ -155,13 +156,11 @@ struct FinalObject
155
156
  int status = 0;
156
157
  FinalObject(PyObject* result)
157
158
  : result(result) {
158
- Py_INCREF(result);
159
+ Py_XINCREF(result);
159
160
  }
160
161
  FinalObject(int status): status(status) {}
161
162
  ~FinalObject() {
162
- if (result) {
163
- Py_DECREF(result);
164
- }
163
+ Py_XDECREF(result);
165
164
  }
166
165
  };
167
166
 
@@ -185,18 +184,39 @@ is_class_code(uintptr_t typ_id, PyCodeObject* code)
185
184
  }
186
185
 
187
186
  static bool
188
- is_subclass_code(uintptr_t typ_id, PyCodeObject* code)
187
+ is_type_private(uintptr_t typ_id, std::string name)
189
188
  {
190
- std::vector<uintptr_t> parent_ids;
191
- if (::AllData::all_type_parent_id.find(typ_id) != ::AllData::all_type_parent_id.end()){
192
- parent_ids = ::AllData::all_type_parent_id[typ_id];
193
- for (auto& parent_id : parent_ids){
194
- if (is_class_code(parent_id, code)){
189
+ if (::AllData::all_type_attr_set.find(typ_id) != ::AllData::all_type_attr_set.end()){
190
+ auto& attr_set = ::AllData::all_type_attr_set[typ_id];
191
+ TwoStringTuple key = get_string_hash_tuple2(name);
192
+ if (attr_set.find(key) != attr_set.end()){
193
+ return true;
194
+ }
195
+ }
196
+ return false;
197
+ }
198
+
199
+ static bool
200
+ attr_classify(uintptr_t typ_id, std::string name, PyCodeObject* code)
201
+ {
202
+ if (is_class_code(typ_id, code)) {
203
+ return true;
204
+ }
205
+ if (is_type_private(typ_id, name)) {
206
+ return false;
207
+ }
208
+ if (::AllData::all_type_parent_id.find(typ_id) != ::AllData::all_type_parent_id.end()) {
209
+ std::vector<uintptr_t> parent_ids = ::AllData::all_type_parent_id[typ_id];
210
+ for (auto& parent_id : parent_ids) {
211
+ if (is_class_code(parent_id, code)) {
195
212
  return true;
196
213
  }
214
+ if (is_type_private(parent_id, name)) {
215
+ return false;
216
+ }
197
217
  }
198
218
  }
199
- return false;
219
+ return true;
200
220
  }
201
221
 
202
222
  static std::string
@@ -404,6 +424,9 @@ get_name_from_tp_name(PyTypeObject* typ)
404
424
  return final_name;
405
425
  }
406
426
 
427
+ static void ensure_tp(PyTypeObject* type_instance);
428
+ static void ensure_subclass_tp(PyTypeObject* type_instance);
429
+
407
430
  static PyObject*
408
431
  id_getattr(std::string attr_name, PyObject* obj, PyObject* typ)
409
432
  {
@@ -451,21 +474,23 @@ id_getattr(std::string attr_name, PyObject* obj, PyObject* typ)
451
474
  if (final_object.status != -1) {
452
475
  result = final_object.result;
453
476
  }
454
- PyObject* result_typ = nullptr;
477
+ PyTypeObject* result_typ = nullptr;
455
478
 
456
479
  if (result) {
457
- result_typ = PyObject_Type(result);
480
+ result_typ = Py_TYPE(result);
458
481
  if (!result_typ) return NULL;
459
482
  }
460
- int has_get = 0;
461
- int has_set = 0;
483
+ bool has_get = false;
484
+ bool has_set = false;
462
485
  if (result_typ) {
463
- has_get = PyObject_HasAttrString(result_typ, "__get__");
464
- has_set = PyObject_HasAttrString(result_typ, "__set__");
486
+ has_get = result_typ->tp_descr_get != NULL;
487
+ has_set = result_typ->tp_descr_set != NULL;
465
488
  }
466
489
  if (has_get && has_set) {
467
- PyObject* python_result = PyObject_CallMethod(result, "__get__", "(OO)", obj, typ);
468
- return python_result;
490
+ PyObject* final_result = result_typ->tp_descr_get(result, obj, typ);
491
+ ensure_tp((PyTypeObject*)typ);
492
+ ensure_subclass_tp((PyTypeObject*)typ);
493
+ return final_result;
469
494
  }
470
495
 
471
496
  {
@@ -477,10 +502,12 @@ id_getattr(std::string attr_name, PyObject* obj, PyObject* typ)
477
502
  return NULL;
478
503
  }
479
504
  // if obj is a type, call result.__get__(None, obj)
480
- if (PyType_Check(obj) && PyObject_HasAttrString((PyObject*)PyObject_Type(python_obj), "__get__")) {
481
- lock.unlock();
482
- PyObject* python_result = PyObject_CallMethod(python_obj, "__get__", "(OO)", Py_None, obj);
483
- return python_result;
505
+ if (PyType_Check(obj)) {
506
+ PyTypeObject* obj_type = Py_TYPE(python_obj);
507
+ if (obj_type->tp_descr_get != NULL) {
508
+ lock.unlock();
509
+ return obj_type->tp_descr_get(python_obj, Py_None, obj);
510
+ }
484
511
  }
485
512
  Py_XINCREF(python_obj);
486
513
  return python_obj;
@@ -488,8 +515,10 @@ id_getattr(std::string attr_name, PyObject* obj, PyObject* typ)
488
515
  }
489
516
 
490
517
  if (has_get) {
491
- PyObject* python_result = PyObject_CallMethod(result, "__get__", "(OO)", obj, typ);
492
- return python_result;
518
+ PyObject* final_result = result_typ->tp_descr_get(result, obj, typ);
519
+ ensure_tp((PyTypeObject*)typ);
520
+ ensure_subclass_tp((PyTypeObject*)typ);
521
+ return final_result;
493
522
  }
494
523
  if (result) {
495
524
  Py_INCREF(result);
@@ -518,9 +547,12 @@ type_getattr(PyObject* typ, std::string attr_name)
518
547
  result = final_object.result;
519
548
  }
520
549
  if (result) {
521
- if (PyObject_HasAttrString((PyObject*)PyObject_Type(result), "__get__")) {
522
- PyObject* python_result = PyObject_CallMethod(result, "__get__", "OO", Py_None, typ);
523
- return python_result;
550
+ PyTypeObject* type = Py_TYPE(result);
551
+ if (type->tp_descr_get != NULL) {
552
+ PyObject* final_result = type->tp_descr_get(result, Py_None, (PyObject*)type);
553
+ ensure_tp((PyTypeObject*)type);
554
+ ensure_subclass_tp((PyTypeObject*)type);
555
+ return final_result;
524
556
  } else {
525
557
  Py_INCREF(result);
526
558
  return result;
@@ -531,7 +563,7 @@ type_getattr(PyObject* typ, std::string attr_name)
531
563
  return NULL;
532
564
  }
533
565
  std::string string_type_name = type_name;
534
- std::string message = "type '" + string_type_name + "' has no attribute '" + attr_name + "'";
566
+ std::string message = "type object '" + string_type_name + "' has no attribute '" + attr_name + "'";
535
567
  PyErr_SetString(PyExc_AttributeError, message.c_str());
536
568
  return NULL;
537
569
  }
@@ -584,13 +616,14 @@ id_setattr(std::string attr_name, PyObject* obj, PyObject* typ, PyObject* value)
584
616
  if (final_object.status != -1) {
585
617
  result = final_object.result;
586
618
  }
587
- if (result && PyObject_HasAttrString((PyObject*)PyObject_Type(result), "__set__")) {
588
- PyObject* python_result = PyObject_CallMethod(result, "__set__", "(OO)", obj, value);
589
- if (!python_result) {
590
- return -1;
619
+ if (result) {
620
+ PyTypeObject* type = Py_TYPE(result);
621
+ if (type->tp_descr_set != NULL) {
622
+ if (type->tp_descr_set(result, obj, value) < 0) {
623
+ return -1;
624
+ }
625
+ return 0;
591
626
  }
592
- Py_DECREF(python_result);
593
- return 0;
594
627
  }
595
628
 
596
629
  // second: set attribute on obj
@@ -727,13 +760,14 @@ id_delattr(std::string attr_name, PyObject* obj, PyObject* typ)
727
760
  if (final_object.status == 0) {
728
761
  result = final_object.result;
729
762
  }
730
- if (result && PyObject_HasAttrString(result, "__delete__")) {
731
- PyObject* delete_result = PyObject_CallMethod(result, "__delete__", "(O)", result);
732
- if (delete_result == NULL) {
733
- return -1;
763
+ if (result) {
764
+ PyTypeObject* type = Py_TYPE(result);
765
+ if (type->tp_descr_set != NULL) {
766
+ if (type->tp_descr_set(result, result, NULL) < 0) {
767
+ return -1;
768
+ }
769
+ return 0;
734
770
  }
735
- Py_XDECREF(delete_result);
736
- return 0;
737
771
  }
738
772
  // second: delete attribute on obj
739
773
  {
@@ -797,7 +831,7 @@ type_delattr(PyObject* typ, std::string attr_name)
797
831
  return -1;
798
832
  }
799
833
  std::string string_type_name = type_name;
800
- std::string message = "type '" + string_type_name + "' has no attribute '" + attr_name + "'";
834
+ std::string message = "type object '" + string_type_name + "' has no attribute '" + attr_name + "'";
801
835
  PyErr_SetString(PyExc_AttributeError, message.c_str());
802
836
  return -1;
803
837
  }
@@ -825,7 +859,7 @@ type_delattr(PyObject* typ, std::string attr_name)
825
859
  return -1;
826
860
  }
827
861
  std::string string_type_name = type_name;
828
- std::string message = "type '" + string_type_name + "' has no attribute '" + attr_name + "'";
862
+ std::string message = "type object '" + string_type_name + "' has no attribute '" + attr_name + "'";
829
863
  PyErr_SetString(PyExc_AttributeError, message.c_str());
830
864
  return -1;
831
865
  }
@@ -1210,8 +1244,6 @@ typedef struct {
1210
1244
  } PrivateAttrTypeObject;
1211
1245
 
1212
1246
  static void PrivateAttr_object_init_private_dict(uintptr_t obj_id, uintptr_t type_id);
1213
- static void ensure_tp(PyTypeObject* type_instance);
1214
- static void ensure_subclass_tp(PyTypeObject* type_instance);
1215
1247
  static int PrivateAttr_tp_setattro(PyObject* self, PyObject* name, PyObject* value);
1216
1248
  static void PrivateAttr_tp_finalize(PyObject* self);
1217
1249
 
@@ -1224,7 +1256,7 @@ PrivateAttr_tp_getattro(PyObject* self, PyObject* name)
1224
1256
  std::string name_str = PyUnicode_AsUTF8(name);
1225
1257
  auto code = get_now_code();
1226
1258
  if (type_private_attr(type_id, name_str)) {
1227
- if (!code || (!is_class_code(type_id, code) && !is_subclass_code(type_id, code))){
1259
+ if (!code || !attr_classify(type_id, name_str, code)){
1228
1260
  Py_XDECREF(code);
1229
1261
  PyErr_SetString(PyExc_AttributeError, "private attribute");
1230
1262
  return NULL;
@@ -1256,7 +1288,7 @@ PrivateAttr_tp_setattro(PyObject* self, PyObject* name, PyObject* value)
1256
1288
  std::string name_str(c_name);
1257
1289
  auto code = get_now_code();
1258
1290
  if (type_private_attr(typ_id, name_str)) {
1259
- if (!code || (!is_class_code(typ_id, code) && !is_subclass_code(typ_id, code))){
1291
+ if (!code || !attr_classify(typ_id, name_str, code)){
1260
1292
  PyErr_SetString(PyExc_AttributeError, "private attribute");
1261
1293
  Py_XDECREF(code);
1262
1294
  return -1;
@@ -1765,10 +1797,25 @@ need_analyse_type(PyObject* type)
1765
1797
  return true;
1766
1798
  }
1767
1799
  std::shared_lock lock(::AllData::all_register_new_metaclass_mutex);
1768
- for (auto i: ::AllData::all_register_new_metaclass) {
1769
- if (i && PyObject_IsInstance(type, (PyObject*)i)) {
1800
+ for (auto& [id, metaclassref]: ::AllData::all_register_type_weak_ref){
1801
+ if (!PyWeakref_CheckRef(metaclassref)) {
1802
+ continue;
1803
+ }
1804
+ #if PY_VERSION_HEX < 0x030D0000
1805
+ PyObject* metaclass = PyWeakref_GET_OBJECT(metaclassref);
1806
+ if (metaclass == (PyObject*)Py_TYPE(type)) {
1770
1807
  return true;
1771
1808
  }
1809
+ #else
1810
+ PyObject* metaclass;
1811
+ if (PyWeakref_GetRef(metaclassref, &metaclass) == 1) {
1812
+ if (PyObject_IsInstance(type, metaclass)) {
1813
+ Py_DECREF(metaclass);
1814
+ return true;
1815
+ }
1816
+ Py_DECREF(metaclass);
1817
+ }
1818
+ #endif
1772
1819
  }
1773
1820
  return false;
1774
1821
  }
@@ -2250,7 +2297,7 @@ ensure_subclass_tp(PyTypeObject* type_instance)
2250
2297
  ensure_tp((PyTypeObject*)subclass);
2251
2298
  #else
2252
2299
  PyObject* subclass;
2253
- if (PyWeakref_GetRef(value, (PyObject**)&subclass) != 0) {
2300
+ if (PyWeakref_GetRef(value, (PyObject**)&subclass) == 0) {
2254
2301
  continue;
2255
2302
  }
2256
2303
  if (!subclass || !PyType_Check(subclass)) {
@@ -2414,7 +2461,7 @@ PrivateAttrType_getattr(PyObject* cls, PyObject* name)
2414
2461
  std::string name_str = PyUnicode_AsUTF8(name);
2415
2462
  PyCodeObject* now_code = get_now_code();
2416
2463
  if (type_private_attr(typ_id, name_str)) {
2417
- if (!now_code || (!is_class_code(typ_id, now_code) && !is_subclass_code(typ_id, now_code))) {
2464
+ if (!now_code || !attr_classify(typ_id, name_str, now_code)) {
2418
2465
  PyErr_SetString(PyExc_AttributeError, "private attribute");
2419
2466
  Py_XDECREF(now_code);
2420
2467
  return NULL;
@@ -2585,7 +2632,7 @@ PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value)
2585
2632
  }
2586
2633
  PyCodeObject* now_code = get_now_code();
2587
2634
  if (type_private_attr(typ_id, name_str)) {
2588
- if (!now_code || (!is_class_code(typ_id, now_code) && !is_subclass_code(typ_id, now_code))) {
2635
+ if (!now_code || !attr_classify(typ_id, name_str, now_code)) {
2589
2636
  PyErr_SetString(PyExc_AttributeError, "private attribute");
2590
2637
  Py_XDECREF(now_code);
2591
2638
  return -1;
@@ -2920,6 +2967,34 @@ register_finalize(PyObject* cls)
2920
2967
  PrivateAttrType_finalize(cls);
2921
2968
  }
2922
2969
 
2970
+
2971
+ static PyObject*
2972
+ metaclass_weakref_callback(PyObject* self, PyObject* /*weakref*/)
2973
+ {
2974
+ void* pointer = PyCapsule_GetPointer(self, "metaclass_id");
2975
+ if (!pointer) {
2976
+ Py_RETURN_NONE;
2977
+ }
2978
+ uintptr_t id = (uintptr_t)pointer;
2979
+
2980
+ std::unique_lock lock(::AllData::all_register_new_metaclass_mutex);
2981
+
2982
+ auto it = ::AllData::all_register_type_weak_ref.find(id);
2983
+ if (it != ::AllData::all_register_type_weak_ref.end()) {
2984
+ Py_DECREF(it->second);
2985
+ ::AllData::all_register_type_weak_ref.erase(it);
2986
+ }
2987
+
2988
+ Py_RETURN_NONE;
2989
+ }
2990
+
2991
+ static PyMethodDef weakref_callback_def = {
2992
+ "metaclass_weakref_callback",
2993
+ (PyCFunction)metaclass_weakref_callback,
2994
+ METH_O,
2995
+ NULL
2996
+ };
2997
+
2923
2998
  static PyObject*
2924
2999
  register_metaclass(PyObject* /*self*/, PyObject* metaclass)
2925
3000
  {
@@ -2931,12 +3006,30 @@ register_metaclass(PyObject* /*self*/, PyObject* metaclass)
2931
3006
  PyErr_SetString(PyExc_TypeError, "metaclass must be a metatype");
2932
3007
  return NULL;
2933
3008
  }
2934
- Py_INCREF(metaclass);
2935
3009
  uintptr_t id = (uintptr_t)metaclass;
3010
+
2936
3011
  std::unique_lock lock(::AllData::all_register_new_metaclass_mutex);
2937
- if (::AllData::all_register_new_metaclass_id.find(id) != ::AllData::all_register_new_metaclass_id.end()) Py_RETURN_NONE;
2938
- ::AllData::all_register_new_metaclass_id.insert(id);
2939
- ::AllData::all_register_new_metaclass.push_back((PyTypeObject*)metaclass);
3012
+ if (::AllData::all_register_type_weak_ref.find(id) != ::AllData::all_register_type_weak_ref.end()) {
3013
+ Py_RETURN_NONE;
3014
+ }
3015
+
3016
+ PyObject* capsule = PyCapsule_New((void*)metaclass, "metaclass_id", NULL);
3017
+ if (!capsule) {
3018
+ return NULL;
3019
+ }
3020
+
3021
+ PyObject* callback = PyCFunction_New(&weakref_callback_def, capsule);
3022
+ if (!callback) {
3023
+ Py_DECREF(capsule);
3024
+ return NULL;
3025
+ }
3026
+ PyObject* ref = PyWeakref_NewRef(metaclass, callback);
3027
+ if (!ref) {
3028
+ Py_DECREF(callback);
3029
+ Py_DECREF(capsule);
3030
+ return NULL;
3031
+ }
3032
+ ::AllData::all_register_type_weak_ref[id] = ref;
2940
3033
  ((PyTypeObject*)metaclass)->tp_getattro = PrivateAttrType_getattr;
2941
3034
  ((PyTypeObject*)metaclass)->tp_setattro = PrivateAttrType_setattr;
2942
3035
  ((PyTypeObject*)metaclass)->tp_finalize = register_finalize;
@@ -2962,7 +3055,7 @@ static PyObject*
2962
3055
  ensure_metaclass_tp(PyObject* /*self*/, PyObject* metaclass)
2963
3056
  {
2964
3057
  uintptr_t id = (uintptr_t)metaclass;
2965
- if (::AllData::all_register_new_metaclass_id.find(id) != ::AllData::all_register_new_metaclass_id.end()) {
3058
+ if (::AllData::all_register_type_weak_ref.find(id) != ::AllData::all_register_type_weak_ref.end()) {
2966
3059
  ((PyTypeObject*)metaclass)->tp_getattro = PrivateAttrType_getattr;
2967
3060
  ((PyTypeObject*)metaclass)->tp_setattro = PrivateAttrType_setattr;
2968
3061
  ((PyTypeObject*)metaclass)->tp_finalize = register_finalize;
@@ -2970,10 +3063,6 @@ ensure_metaclass_tp(PyObject* /*self*/, PyObject* metaclass)
2970
3063
  Py_RETURN_NONE;
2971
3064
  }
2972
3065
 
2973
- typedef struct PrivateModule {
2974
- PyObject_HEAD
2975
- }PrivateModule;
2976
-
2977
3066
  static PyObject*
2978
3067
  PrivateModule_get_PrivateWrapProxy(PyObject* /*self*/, void* /*closure*/)
2979
3068
  {
@@ -3006,7 +3095,7 @@ PrivateModule_get_PrivateAttrBase(PyObject* /*self*/, void* /*closure*/)
3006
3095
  }
3007
3096
 
3008
3097
  static PyObject*
3009
- PrivateModule_dir(PyObject* self)
3098
+ PrivateModule_dir(PyObject* self, PyObject* /*args*/)
3010
3099
  {
3011
3100
  PyObject* parent_dir = PyObject_CallMethod((PyObject*)&PyModule_Type, "__dir__", "O", self);
3012
3101
  if (!parent_dir) return NULL;
@@ -3089,18 +3178,18 @@ def ensure_metaclass(metaclass: type) -> None:
3089
3178
 
3090
3179
  static PyMethodDef PrivateModule_methods[] = {
3091
3180
  {"__dir__", (PyCFunction)PrivateModule_dir, METH_NOARGS, NULL},
3092
- {"prepare", (PyCFunction)prepare_for_PrivateAttr, METH_VARARGS | METH_KEYWORDS, prepare_and_postprocess_doc},
3093
- {"postprocess", (PyCFunction)postprocess_for_PrivateAttr, METH_VARARGS, prepare_and_postprocess_doc},
3094
- {"register_metaclass", (PyCFunction)register_metaclass, METH_O, prepare_and_postprocess_doc},
3095
- {"ensure_type", (PyCFunction)ensure_type_tp, METH_O, ensure_type_doc},
3096
- {"ensure_metaclass", (PyCFunction)ensure_metaclass_tp, METH_O, ensure_metaclass_doc},
3181
+ {"prepare", (PyCFunction)prepare_for_PrivateAttr, METH_VARARGS | METH_KEYWORDS | METH_STATIC, prepare_and_postprocess_doc},
3182
+ {"postprocess", (PyCFunction)postprocess_for_PrivateAttr, METH_VARARGS | METH_STATIC, prepare_and_postprocess_doc},
3183
+ {"register_metaclass", (PyCFunction)register_metaclass, METH_O | METH_STATIC, prepare_and_postprocess_doc},
3184
+ {"ensure_type", (PyCFunction)ensure_type_tp, METH_O | METH_STATIC, ensure_type_doc},
3185
+ {"ensure_metaclass", (PyCFunction)ensure_metaclass_tp, METH_O | METH_STATIC, ensure_metaclass_doc},
3097
3186
  {NULL} // Sentinel
3098
3187
  };
3099
3188
 
3100
3189
  static PyTypeObject PrivateModuleType = {
3101
3190
  PyVarObject_HEAD_INIT(NULL, 0)
3102
3191
  "private_attribute_module", //tp_name
3103
- sizeof(PrivateModule), //tp_basicsize
3192
+ PyModule_Type.tp_basicsize + 8, //tp_basicsize size of module object + 8 bytes for flag to avoid change attribute '__class__'
3104
3193
  0, //tp_itemsize
3105
3194
  0, //tp_dealloc
3106
3195
  0, //tp_print
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 1.3.8
3
+ Version: 1.4.0
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,6 +250,7 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
250
250
  - One class defined in another class cannot use another class's private attribute.
251
251
  - One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
252
252
  - CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
253
+ - `private_attribute.register_metaclass` must be called with the metaclass which support weakref.
253
254
 
254
255
  ## License
255
256
 
@@ -19,7 +19,7 @@ readme = open('README.md').read()
19
19
 
20
20
  setup(
21
21
  name='private_attribute_cpp',
22
- version='1.3.8',
22
+ version='1.4.0',
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.',