private-attribute-cpp 2.0.2__tar.gz → 2.0.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.
Files changed (21) hide show
  1. {private_attribute_cpp-2.0.2/private_attribute_cpp.egg-info → private_attribute_cpp-2.0.4}/PKG-INFO +1 -1
  2. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/private_attribute.cpp +146 -126
  3. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4/private_attribute_cpp.egg-info}/PKG-INFO +1 -1
  4. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/setup.py +1 -1
  5. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/LICENSE +0 -0
  6. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/MANIFEST.in +0 -0
  7. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/README.md +0 -0
  8. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/picosha2.h +0 -0
  9. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/private_attribute.pyi +0 -0
  10. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/private_attribute_cpp.egg-info/SOURCES.txt +0 -0
  11. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/private_attribute_cpp.egg-info/dependency_links.txt +0 -0
  12. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/private_attribute_cpp.egg-info/not-zip-safe +0 -0
  13. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/private_attribute_cpp.egg-info/top_level.txt +0 -0
  14. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/setup.cfg +0 -0
  15. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/tests/test_class_private_attrs.py +0 -0
  16. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/tests/test_private_abc.py +0 -0
  17. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/tests/test_private_attrs.py +0 -0
  18. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/tests/test_private_func.py +0 -0
  19. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/tests/test_private_inheritance.py +0 -0
  20. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/tests/test_private_method.py +0 -0
  21. {private_attribute_cpp-2.0.2 → private_attribute_cpp-2.0.4}/tests/test_private_wrap.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 2.0.2
3
+ Version: 2.0.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
@@ -115,6 +115,56 @@ namespace std {
115
115
  };
116
116
  }
117
117
 
118
+ struct PyObjectStorage
119
+ {
120
+ PyObject* obj = NULL;
121
+
122
+ PyObjectStorage() noexcept = default;
123
+ PyObjectStorage(PyObject* obj) noexcept : obj(obj) {
124
+ Py_XINCREF(obj);
125
+ }
126
+ PyObjectStorage(const PyObjectStorage& other) noexcept : obj(other.obj) {
127
+ Py_XINCREF(obj);
128
+ }
129
+ PyObjectStorage(PyObjectStorage&& other) noexcept : obj(other.obj) {
130
+ other.obj = NULL;
131
+ }
132
+ PyObjectStorage& operator=(const PyObjectStorage& other) noexcept {
133
+ if (this == &other) {
134
+ return *this;
135
+ }
136
+ PyObject* new_obj = other.obj;
137
+ Py_XINCREF(new_obj);
138
+ Py_XDECREF(obj);
139
+ obj = new_obj;
140
+ return *this;
141
+ }
142
+ PyObjectStorage& operator=(PyObjectStorage&& other) noexcept {
143
+ if (this != &other) {
144
+ Py_XDECREF(obj);
145
+ obj = other.obj;
146
+ other.obj = NULL;
147
+ }
148
+ return *this;
149
+ }
150
+ PyObjectStorage& operator=(PyObject* new_obj) noexcept {
151
+ Py_XINCREF(new_obj);
152
+ Py_XDECREF(obj);
153
+ obj = new_obj;
154
+ return *this;
155
+ }
156
+ ~PyObjectStorage() noexcept {
157
+ Py_XDECREF(obj);
158
+ }
159
+
160
+ operator PyObject*() const noexcept {
161
+ return obj;
162
+ }
163
+ PyObject* get() const noexcept {
164
+ return obj;
165
+ }
166
+ };
167
+
118
168
  namespace {
119
169
  namespace AllData {
120
170
  static std::unordered_map<AllPyobjectAttrCacheKey, std::string> cache;
@@ -122,7 +172,7 @@ namespace {
122
172
  static std::unordered_map<uintptr_t, std::vector<AllPyobjectAttrCacheKey>> obj_attr_keys;
123
173
  static std::shared_mutex cache_mutex;
124
174
  namespace {
125
- static std::unordered_map<uintptr_t, std::unordered_map<std::string, PyObject*>> type_attr_dict;
175
+ static std::unordered_map<uintptr_t, std::unordered_map<std::string, PyObjectStorage>> type_attr_dict;
126
176
  };
127
177
  static std::unordered_map<uintptr_t, std::unordered_map<uintptr_t, PyCodeObject*>> type_allowed_code_map;
128
178
  static std::unordered_map<uintptr_t, std::shared_ptr<std::shared_mutex>> all_type_mutex;
@@ -130,7 +180,7 @@ namespace {
130
180
  static std::unordered_map<uintptr_t, std::unordered_set<TwoStringTuple>> all_type_attr_set;
131
181
  namespace {
132
182
  static std::unordered_map<uintptr_t, std::unordered_map<uintptr_t,
133
- std::unordered_map<std::string, PyObject*>>> all_object_attr, all_type_subclass_attr;
183
+ std::unordered_map<std::string, PyObjectStorage>>> all_object_attr, all_type_subclass_attr;
134
184
  };
135
185
  static std::unordered_map<uintptr_t, std::unordered_map<uintptr_t, std::shared_ptr<std::shared_mutex>>>
136
186
  all_object_mutex, all_type_subclass_mutex;
@@ -149,16 +199,12 @@ namespace {
149
199
 
150
200
  struct FinalObject
151
201
  {
152
- PyObject* result = NULL;
202
+ PyObjectStorage result;
153
203
  int status = 0;
154
- FinalObject(PyObject* result) noexcept
155
- : result(result) {
156
- Py_XINCREF(result);
157
- }
158
- FinalObject(int status) noexcept: status(status) {}
159
- ~FinalObject() noexcept {
160
- Py_XDECREF(result);
161
- }
204
+ FinalObject() noexcept = default;
205
+ FinalObject(PyObject* result) noexcept : result(result) {}
206
+ FinalObject(PyObjectStorage result) noexcept : result(std::move(result)) {}
207
+ FinalObject(int status) noexcept : status(status) {}
162
208
  };
163
209
 
164
210
  static TwoStringTuple get_string_hash_tuple2(const std::string& name) noexcept;
@@ -476,9 +522,7 @@ id_getattr(const std::string& attr_name, PyObject* obj, PyObject* typ) noexcept
476
522
  if (type_name == NULL) {
477
523
  return NULL;
478
524
  }
479
- std::string string_type_name = type_name;
480
- std::string exception_information = "'" + string_type_name + "' objects has no attribute '" + attr_name + "'";
481
- PyErr_SetString(PyExc_AttributeError, exception_information.c_str());
525
+ PyErr_Format(PyExc_AttributeError, "'%s' object has no attribute '%s'", type_name, attr_name.c_str());
482
526
  return NULL;
483
527
  }
484
528
 
@@ -510,9 +554,7 @@ type_getattr(PyObject* typ, const std::string& attr_name) noexcept
510
554
  if (type_name == NULL) {
511
555
  return NULL;
512
556
  }
513
- std::string string_type_name = type_name;
514
- std::string message = "type object '" + string_type_name + "' has no attribute '" + attr_name + "'";
515
- PyErr_SetString(PyExc_AttributeError, message.c_str());
557
+ PyErr_Format(PyExc_AttributeError, "'%s' object has no attribute '%s'", type_name, attr_name.c_str());
516
558
  return NULL;
517
559
  }
518
560
 
@@ -574,12 +616,8 @@ id_setattr(const std::string& attr_name, PyObject* obj, PyObject* typ, PyObject*
574
616
  }
575
617
 
576
618
  // second: set attribute on obj
577
- Py_INCREF(value);
578
619
  {
579
620
  std::unique_lock<std::shared_mutex> lock(*::AllData::all_object_mutex[final_id][obj_id]);
580
- if (::AllData::all_object_attr[final_id][obj_id].find(obj_private_name) != ::AllData::all_object_attr[final_id][obj_id].end()) {
581
- Py_XDECREF(::AllData::all_object_attr[final_id][obj_id][obj_private_name]);
582
- }
583
621
  ::AllData::all_object_attr[final_id][obj_id][obj_private_name] = value;
584
622
  }
585
623
  return 0;
@@ -625,11 +663,7 @@ type_setattr(PyObject* typ, const std::string& attr_name, PyObject* value) noexc
625
663
  }
626
664
  {
627
665
  std::unique_lock<std::shared_mutex> lock(*::AllData::all_type_mutex[typ_id]);
628
- if (::AllData::type_attr_dict[typ_id].find(final_key) != ::AllData::type_attr_dict[typ_id].end()) {
629
- Py_XDECREF(::AllData::type_attr_dict[typ_id][final_key]);
630
- }
631
666
  ::AllData::type_attr_dict[typ_id][final_key] = value;
632
- Py_INCREF(value);
633
667
  }
634
668
  return 0;
635
669
  } else {
@@ -648,11 +682,7 @@ type_setattr(PyObject* typ, const std::string& attr_name, PyObject* value) noexc
648
682
  }
649
683
  {
650
684
  std::unique_lock<std::shared_mutex> lock(*::AllData::all_type_subclass_mutex[final_id][typ_id]);
651
- if (::AllData::all_type_subclass_attr[final_id][typ_id].find(final_key) != ::AllData::all_type_subclass_attr[final_id][typ_id].end()) {
652
- Py_XDECREF(::AllData::all_type_subclass_attr[final_id][typ_id][final_key]);
653
- }
654
685
  ::AllData::all_type_subclass_attr[final_id][typ_id][final_key] = value;
655
- Py_INCREF(value);
656
686
  return 0;
657
687
  }
658
688
  }
@@ -723,14 +753,9 @@ id_delattr(const std::string& attr_name, PyObject* obj, PyObject* typ) noexcept
723
753
  if (type_name == NULL) {
724
754
  return -1;
725
755
  }
726
- std::string string_type_name = type_name;
727
- std::string exception_information = "'" + string_type_name + "' objects has no attribute '" + attr_name + "'";
728
- PyErr_SetString(PyExc_AttributeError, exception_information.c_str());
729
- return -1;
756
+ PyErr_Format(PyExc_AttributeError, "'%s' object has no attribute '%s'", type_name, attr_name.c_str());
730
757
  }
731
- PyObject* delete_obj = ::AllData::all_object_attr[final_id][obj_id][obj_private_name];
732
758
  ::AllData::all_object_attr[final_id][obj_id].erase(obj_private_name);
733
- Py_XDECREF(delete_obj);
734
759
  }
735
760
  return 0;
736
761
  }
@@ -774,14 +799,10 @@ type_delattr(PyObject* typ, const std::string& attr_name) noexcept
774
799
  if (type_name == NULL) {
775
800
  return -1;
776
801
  }
777
- std::string string_type_name = type_name;
778
- std::string message = "type object '" + string_type_name + "' has no attribute '" + attr_name + "'";
779
- PyErr_SetString(PyExc_AttributeError, message.c_str());
802
+ PyErr_Format(PyExc_AttributeError, "type object '%s' has no attribute '%s'", type_name, attr_name.c_str());
780
803
  return -1;
781
804
  }
782
- PyObject* delete_obj = ::AllData::type_attr_dict[typ_id][final_key];
783
805
  ::AllData::type_attr_dict[typ_id].erase(final_key);
784
- Py_XDECREF(delete_obj);
785
806
  } else {
786
807
  if (::AllData::all_type_subclass_attr.find(final_id) == ::AllData::all_type_subclass_attr.end()) {
787
808
  ::AllData::all_type_subclass_attr[final_id] = {};
@@ -802,14 +823,10 @@ type_delattr(PyObject* typ, const std::string& attr_name) noexcept
802
823
  if (type_name == NULL) {
803
824
  return -1;
804
825
  }
805
- std::string string_type_name = type_name;
806
- std::string message = "type object '" + string_type_name + "' has no attribute '" + attr_name + "'";
807
- PyErr_SetString(PyExc_AttributeError, message.c_str());
826
+ PyErr_Format(PyExc_AttributeError, "type object '%s' has no attribute '%s'", type_name, attr_name.c_str());
808
827
  return -1;
809
828
  }
810
- PyObject* delete_obj = ::AllData::all_type_subclass_attr[final_id][typ_id][final_key];
811
829
  ::AllData::all_type_subclass_attr[final_id][typ_id].erase(final_key);
812
- Py_XDECREF(delete_obj);
813
830
  }
814
831
  return 0;
815
832
  }
@@ -1323,10 +1340,6 @@ PrivateAttr_tp_finalize(PyObject* self) noexcept
1323
1340
  if (::AllData::all_object_attr.find(typ_id) != ::AllData::all_object_attr.end()){
1324
1341
  auto& all_object_attr = ::AllData::all_object_attr[typ_id];
1325
1342
  if (all_object_attr.find(id_self) != all_object_attr.end()){
1326
- auto& all_object_attr_self = all_object_attr[id_self];
1327
- for (auto& attr : all_object_attr_self){
1328
- Py_XDECREF(attr.second);
1329
- }
1330
1343
  all_object_attr.erase(id_self);
1331
1344
  }
1332
1345
  }
@@ -1341,10 +1354,6 @@ PrivateAttr_tp_finalize(PyObject* self) noexcept
1341
1354
  if (::AllData::all_object_attr.find(parent_id) != ::AllData::all_object_attr.end()){
1342
1355
  auto& all_object_attr = ::AllData::all_object_attr[parent_id];
1343
1356
  if (all_object_attr.find(id_self) != all_object_attr.end()){
1344
- auto& all_object_attr_self = all_object_attr[id_self];
1345
- for (auto& attr : all_object_attr_self){
1346
- Py_XDECREF(attr.second);
1347
- }
1348
1357
  all_object_attr.erase(id_self);
1349
1358
  }
1350
1359
  }
@@ -1621,6 +1630,21 @@ get_now_code() noexcept
1621
1630
  return code;
1622
1631
  }
1623
1632
 
1633
+ static PyObject*
1634
+ try_get_attr_string(PyObject* obj, const char* name) noexcept
1635
+ {
1636
+ if (obj == NULL || name == NULL) {
1637
+ return NULL;
1638
+ }
1639
+ if (PyObject_HasAttrString(obj, name) <= 0) {
1640
+ if (PyErr_Occurred()) {
1641
+ PyErr_Clear();
1642
+ }
1643
+ return NULL;
1644
+ }
1645
+ return PyObject_GetAttrString(obj, name);
1646
+ }
1647
+
1624
1648
  static void
1625
1649
  analyse_all_code(PyObject* obj, std::unordered_map<uintptr_t, PyCodeObject*>& map, std::unordered_set<uintptr_t>& _seen) noexcept
1626
1650
  {
@@ -1632,88 +1656,83 @@ analyse_all_code(PyObject* obj, std::unordered_map<uintptr_t, PyCodeObject*>& ma
1632
1656
  if (PyObject_TypeCheck(obj, &PyCode_Type)) {
1633
1657
  Py_INCREF(obj);
1634
1658
  map[(uintptr_t)obj] = (PyCodeObject*)obj;
1635
- PyObject* co_contain = PyObject_GetAttrString(obj, "co_consts");
1659
+ PyObject* co_contain = try_get_attr_string(obj, "co_consts");
1636
1660
  if (co_contain && PySequence_Check(co_contain)) {
1637
1661
  Py_ssize_t len = PySequence_Length(co_contain);
1638
- for (Py_ssize_t i = 0; i < len; i++) {
1639
- PyObject* item = PySequence_GetItem(co_contain, i);
1640
- if (item) {
1641
- analyse_all_code(item, map, _seen);
1642
- } else {
1643
- PyErr_Clear();
1662
+ if (len >= 0) {
1663
+ for (Py_ssize_t i = 0; i < len; i++) {
1664
+ PyObject* item = PySequence_GetItem(co_contain, i);
1665
+ if (item) {
1666
+ analyse_all_code(item, map, _seen);
1667
+ Py_DECREF(item);
1668
+ }
1644
1669
  }
1645
1670
  }
1646
1671
  }
1672
+ Py_XDECREF(co_contain);
1647
1673
  return;
1648
1674
  }
1649
1675
  if (PyObject_TypeCheck(obj, &PrivateWrapType)) {
1650
1676
  PyObject* func_list = ((PrivateWrapObject*)obj)->func_list;
1651
1677
  if (func_list && PySequence_Check(func_list)) {
1652
1678
  Py_ssize_t len = PySequence_Length(func_list);
1653
- for (Py_ssize_t i = 0; i < len; i++) {
1654
- PyObject* func = PySequence_GetItem(func_list, i);
1655
- if (func) {
1656
- analyse_all_code(func, map, _seen);
1657
- } else {
1658
- PyErr_Clear();
1679
+ if (len >= 0) {
1680
+ for (Py_ssize_t i = 0; i < len; i++) {
1681
+ PyObject* func = PySequence_GetItem(func_list, i);
1682
+ if (func) {
1683
+ analyse_all_code(func, map, _seen);
1684
+ Py_DECREF(func);
1685
+ }
1659
1686
  }
1660
1687
  }
1661
1688
  }
1662
1689
  return;
1663
1690
  }
1664
1691
  if (PyObject_TypeCheck(obj, &PyProperty_Type)) {
1665
- PyObject* fget = PyObject_GetAttrString(obj, "fget");
1692
+ PyObject* fget = try_get_attr_string(obj, "fget");
1666
1693
  if (fget) {
1667
1694
  analyse_all_code(fget, map, _seen);
1668
- } else {
1669
- PyErr_Clear();
1695
+ Py_DECREF(fget);
1670
1696
  }
1671
- PyObject* fset = PyObject_GetAttrString(obj, "fset");
1697
+ PyObject* fset = try_get_attr_string(obj, "fset");
1672
1698
  if (fset) {
1673
1699
  analyse_all_code(fset, map, _seen);
1700
+ Py_DECREF(fset);
1674
1701
  }
1675
- else {
1676
- PyErr_Clear();
1677
- }
1678
- PyObject* fdel = PyObject_GetAttrString(obj, "fdel");
1702
+ PyObject* fdel = try_get_attr_string(obj, "fdel");
1679
1703
  if (fdel) {
1680
1704
  analyse_all_code(fdel, map, _seen);
1681
- } else {
1682
- PyErr_Clear();
1705
+ Py_DECREF(fdel);
1683
1706
  }
1684
1707
  return;
1685
1708
  }
1686
1709
  if (PyObject_TypeCheck(obj, &PyClassMethod_Type) || PyObject_TypeCheck(obj, &PyStaticMethod_Type)) {
1687
- PyObject* func = PyObject_GetAttrString(obj, "__func__");
1710
+ PyObject* func = try_get_attr_string(obj, "__func__");
1688
1711
  if (func) {
1689
1712
  analyse_all_code(func, map, _seen);
1690
- } else {
1691
- PyErr_Clear();
1713
+ Py_DECREF(func);
1692
1714
  }
1693
1715
  return;
1694
1716
  }
1695
- PyObject* wrap = PyObject_GetAttrString(obj, "__wrapped__");
1717
+ PyObject* wrap = try_get_attr_string(obj, "__wrapped__");
1696
1718
  if (wrap) {
1697
1719
  if (wrap == obj) {
1698
- PyObject* code = PyObject_GetAttrString(obj, "__code__");
1720
+ PyObject* code = try_get_attr_string(obj, "__code__");
1699
1721
  if (code) {
1700
1722
  analyse_all_code(code, map, _seen);
1701
- } else {
1702
- PyErr_Clear();
1723
+ Py_DECREF(code);
1703
1724
  }
1725
+ Py_DECREF(wrap);
1704
1726
  return;
1705
1727
  }
1706
1728
  analyse_all_code(wrap, map, _seen);
1729
+ Py_DECREF(wrap);
1707
1730
  return;
1708
1731
  }
1709
- else {
1710
- PyErr_Clear();
1711
- }
1712
- PyObject* code = PyObject_GetAttrString(obj, "__code__");
1732
+ PyObject* code = try_get_attr_string(obj, "__code__");
1713
1733
  if (code) {
1714
1734
  analyse_all_code(code, map, _seen);
1715
- } else {
1716
- PyErr_Clear();
1735
+ Py_DECREF(code);
1717
1736
  }
1718
1737
  }
1719
1738
 
@@ -1735,8 +1754,8 @@ struct PrivateAttrCreationData
1735
1754
  std::unordered_set<TwoStringTuple> private_attrs_set;
1736
1755
  std::unordered_set<std::string> private_attrs_vector_string;
1737
1756
  std::vector<uintptr_t> all_need_analyse_base;
1738
- std::unordered_map<std::string, PyObject*> need_remove_itself;
1739
- std::unordered_map<uintptr_t, std::unordered_map<std::string, PyObject*>> need_remove_subclass;
1757
+ std::unordered_map<std::string, PyObjectStorage> need_remove_itself;
1758
+ std::unordered_map<uintptr_t, std::unordered_map<std::string, PyObjectStorage>> need_remove_subclass;
1740
1759
  PyObject* private_func = nullptr;
1741
1760
  PyObject* base_kwds = nullptr;
1742
1761
  PyObject* name = nullptr;
@@ -1777,16 +1796,7 @@ struct PrivateAttrCreationData
1777
1796
  base_kwds = nullptr;
1778
1797
  }
1779
1798
 
1780
- for (auto& pair : need_remove_itself) {
1781
- Py_XDECREF(pair.second);
1782
- }
1783
1799
  need_remove_itself.clear();
1784
-
1785
- for (auto& outer_pair : need_remove_subclass) {
1786
- for (auto& inner_pair : outer_pair.second) {
1787
- Py_XDECREF(inner_pair.second);
1788
- }
1789
- }
1790
1800
  need_remove_subclass.clear();
1791
1801
  cleared = true;
1792
1802
  }
@@ -1937,26 +1947,46 @@ PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationDa
1937
1947
 
1938
1948
  if (has_slots) {
1939
1949
  PyObject* all_slots = PyDict_GetItemString(data.attrs_copy, "__slots__");
1940
- PyObject* slot_seq = PySequence_Fast(all_slots, "__slots__ must be a sequence");
1941
- if (!slot_seq) {
1942
- return false;
1943
- }
1944
-
1945
- Py_ssize_t slot_len = PySequence_Fast_GET_SIZE(slot_seq);
1946
-
1947
- for (Py_ssize_t j = 0; j < slot_len; j++) {
1948
- PyObject* slot = PySequence_Fast_GET_ITEM(slot_seq, j);
1949
- if (PyUnicode_Check(slot)) {
1950
- const char* slot_cstr = PyUnicode_AsUTF8(slot);
1951
- if (data.private_attrs_vector_string.find((std::string)slot_cstr) != data.private_attrs_vector_string.end()){
1952
- std::string error_msg = "'__slots__' and '__private_attrs__' cannot have the same attribute name: '" + std::string(slot_cstr) + "'";
1953
- PyErr_SetString(PyExc_TypeError, error_msg.c_str());
1954
- Py_DECREF(slot_seq);
1950
+ if (!all_slots) {return false;}
1951
+ if (PyUnicode_Check(all_slots)) {
1952
+ const char* slot_cstr = PyUnicode_AsUTF8(all_slots);
1953
+ if (data.private_attrs_vector_string.find((std::string)slot_cstr) != data.private_attrs_vector_string.end()){
1954
+ std::string error_msg = "'__slots__' and '__private_attrs__' cannot have the same attribute name: '" + std::string(slot_cstr) + "'";
1955
+ PyErr_SetString(PyExc_TypeError, error_msg.c_str());
1956
+ return false;
1957
+ }
1958
+ } else {
1959
+ PyObject* slot_seq;
1960
+ if (PyAnyDict_Check(all_slots)) {
1961
+ // use the key of the dict as the slot name
1962
+ PyObject* keys = PyDict_Keys(all_slots);
1963
+ if (!keys) {
1955
1964
  return false;
1956
1965
  }
1966
+ slot_seq = keys;
1967
+ } else {
1968
+ slot_seq = PySequence_Fast(all_slots, "__slots__ must be a sequence");
1969
+ }
1970
+ if (!slot_seq) {
1971
+ return false;
1957
1972
  }
1973
+
1974
+ Py_ssize_t slot_len = PySequence_Fast_GET_SIZE(slot_seq);
1975
+
1976
+ for (Py_ssize_t j = 0; j < slot_len; j++) {
1977
+ PyObject* slot = PySequence_Fast_GET_ITEM(slot_seq, j);
1978
+ if (PyUnicode_Check(slot)) {
1979
+ const char* slot_cstr = PyUnicode_AsUTF8(slot);
1980
+ if (data.private_attrs_vector_string.find((std::string)slot_cstr) != data.private_attrs_vector_string.end()){
1981
+ std::string error_msg = "'__slots__' and '__private_attrs__' cannot have the same attribute name: '" + std::string(slot_cstr) + "'";
1982
+ PyErr_SetString(PyExc_TypeError, error_msg.c_str());
1983
+ Py_DECREF(slot_seq);
1984
+ return false;
1985
+ }
1986
+ }
1987
+ }
1988
+ Py_DECREF(slot_seq);
1958
1989
  }
1959
- Py_DECREF(slot_seq);
1960
1990
  }
1961
1991
 
1962
1992
  Py_ssize_t bases_len = PyTuple_GET_SIZE(data.bases);
@@ -2207,7 +2237,6 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data) n
2207
2237
  } else {
2208
2238
  final_key = default_random_string(type_id, key);
2209
2239
  }
2210
- Py_INCREF(value);
2211
2240
  ::AllData::type_attr_dict[type_id][final_key] = value;
2212
2241
  }
2213
2242
 
@@ -2235,7 +2264,6 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data) n
2235
2264
  } else {
2236
2265
  final_key = default_random_string(type_id, key);
2237
2266
  }
2238
- Py_INCREF(value);
2239
2267
  ::AllData::all_type_subclass_attr[i][type_id][final_key] = value;
2240
2268
  }
2241
2269
  }
@@ -2513,10 +2541,6 @@ PrivateAttrType_finalize(PyObject* cls) noexcept
2513
2541
  ::AllData::type_need_call.erase(typ_id);
2514
2542
  }
2515
2543
  if (::AllData::type_attr_dict.find(typ_id) != ::AllData::type_attr_dict.end()) {
2516
- auto& private_attrs = ::AllData::type_attr_dict[typ_id];
2517
- for (auto& attr : private_attrs) {
2518
- Py_XDECREF(attr.second);
2519
- }
2520
2544
  ::AllData::type_attr_dict.erase(typ_id);
2521
2545
  }
2522
2546
  if (::AllData::all_type_subclass_attr.find(typ_id) != ::AllData::all_type_subclass_attr.end()) {
@@ -2533,10 +2557,6 @@ PrivateAttrType_finalize(PyObject* cls) noexcept
2533
2557
  for (auto& parent_id : parent_ids) {
2534
2558
  if (::AllData::all_type_subclass_attr.find(parent_id) != ::AllData::all_type_subclass_attr.end()) {
2535
2559
  if (::AllData::all_type_subclass_attr[parent_id].find(typ_id) != ::AllData::all_type_subclass_attr[parent_id].end()) {
2536
- auto& private_attrs = ::AllData::all_type_subclass_attr[parent_id][typ_id];
2537
- for (auto& attr : private_attrs) {
2538
- Py_XDECREF(attr.second);
2539
- }
2540
2560
  ::AllData::all_type_subclass_attr[parent_id].erase(typ_id);
2541
2561
  }
2542
2562
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 2.0.2
3
+ Version: 2.0.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
@@ -18,7 +18,7 @@ readme = open('README.md').read()
18
18
 
19
19
  setup(
20
20
  name='private_attribute_cpp',
21
- version='2.0.2',
21
+ version='2.0.4',
22
22
  author="HuangHaoHua",
23
23
  author_email="13140752715@example.com",
24
24
  description='A Python package that provides a way to define private attributes in C++ implementation.',