private-attribute-cpp 1.3.6__tar.gz → 1.3.8__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.6
3
+ Version: 1.3.8
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
@@ -21,6 +21,21 @@
21
21
  #include <memory>
22
22
  #include <algorithm>
23
23
 
24
+ // python under 3.13 doesn't has PyDict_ContainsString, so we implement it ourselves
25
+ #if PY_VERSION_HEX < 0x030D0000
26
+ static int
27
+ PyDict_ContainsString(PyObject *op, const char *key)
28
+ {
29
+ PyObject *key_obj = PyUnicode_FromString(key);
30
+ if (key_obj == NULL) {
31
+ return -1;
32
+ }
33
+ int res = PyDict_Contains(op, key_obj);
34
+ Py_DECREF(key_obj);
35
+ return res;
36
+ }
37
+ #endif
38
+
24
39
  static const auto module_running_time = std::chrono::system_clock::now();
25
40
 
26
41
  static std::string
@@ -128,6 +143,12 @@ namespace {
128
143
  };
129
144
  };
130
145
 
146
+ namespace AllSlots {
147
+ static getattrofunc original_getattro = nullptr;
148
+ static setattrofunc original_setattro = nullptr;
149
+ static destructor original_finalize = nullptr;
150
+ }
151
+
131
152
  struct FinalObject
132
153
  {
133
154
  PyObject* result = NULL;
@@ -1191,6 +1212,8 @@ typedef struct {
1191
1212
  static void PrivateAttr_object_init_private_dict(uintptr_t obj_id, uintptr_t type_id);
1192
1213
  static void ensure_tp(PyTypeObject* type_instance);
1193
1214
  static void ensure_subclass_tp(PyTypeObject* type_instance);
1215
+ static int PrivateAttr_tp_setattro(PyObject* self, PyObject* name, PyObject* value);
1216
+ static void PrivateAttr_tp_finalize(PyObject* self);
1194
1217
 
1195
1218
  static PyObject*
1196
1219
  PrivateAttr_tp_getattro(PyObject* self, PyObject* name)
@@ -1212,8 +1235,11 @@ PrivateAttr_tp_getattro(PyObject* self, PyObject* name)
1212
1235
  }
1213
1236
  Py_XDECREF(code);
1214
1237
  if (::AllData::all_type_getattro.find(type_id) != ::AllData::all_type_getattro.end()){
1215
- PyObject* result = ::AllData::all_type_getattro[type_id](self, name);
1216
- return result;
1238
+ if (::AllData::all_type_getattro[type_id]) {
1239
+ PyObject* result = ::AllData::all_type_getattro[type_id](self, name);
1240
+ ensure_tp(typ);
1241
+ return result;
1242
+ }
1217
1243
  }
1218
1244
  return PyObject_GenericGetAttr(self, name);
1219
1245
  }
@@ -1245,6 +1271,7 @@ PrivateAttr_tp_setattro(PyObject* self, PyObject* name, PyObject* value)
1245
1271
  Py_XDECREF(code);
1246
1272
  if (::AllData::all_type_setattro.find(typ_id) != ::AllData::all_type_setattro.end()){
1247
1273
  int result = ::AllData::all_type_setattro[typ_id](self, name, value);
1274
+ ensure_tp(typ);
1248
1275
  return result;
1249
1276
  }
1250
1277
  return PyObject_GenericSetAttr(self, name, value);
@@ -1258,7 +1285,10 @@ PrivateAttr_tp_finalize(PyObject* self)
1258
1285
  uintptr_t typ_id = (uintptr_t)typ;
1259
1286
  Py_ssize_t original_ref = Py_REFCNT(self);
1260
1287
  if (::AllData::all_type_finalize.find(typ_id) != ::AllData::all_type_finalize.end()){
1261
- ::AllData::all_type_finalize[typ_id](self);
1288
+ if (::AllData::all_type_finalize[typ_id]) {
1289
+ ::AllData::all_type_finalize[typ_id](self);
1290
+ ensure_tp(typ);
1291
+ }
1262
1292
  }
1263
1293
  if (original_ref != Py_REFCNT(self)) {
1264
1294
  return;
@@ -1743,6 +1773,157 @@ need_analyse_type(PyObject* type)
1743
1773
  return false;
1744
1774
  }
1745
1775
 
1776
+ static void
1777
+ get_getattribute_and_getattr(PyTypeObject* cls, PyObject** getattribute, PyObject** getattr)
1778
+ {
1779
+ bool has_getattribute = false;
1780
+ bool has_getattr = false;
1781
+ if (PyDict_ContainsString(cls->tp_dict, "__getattribute__")) {
1782
+ *getattribute = PyDict_GetItemString(cls->tp_dict, "__getattribute__");
1783
+ has_getattribute = true;
1784
+ }
1785
+ if (PyDict_ContainsString(cls->tp_dict, "__getattr__")) {
1786
+ *getattr = PyDict_GetItemString(cls->tp_dict, "__getattr__");
1787
+ has_getattr = true;
1788
+ }
1789
+ if (has_getattribute && has_getattr) {
1790
+ return;
1791
+ }
1792
+ for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
1793
+ if (!has_getattribute && PyDict_ContainsString(base->tp_dict, "__getattribute__")) {
1794
+ *getattribute = PyDict_GetItemString(base->tp_dict, "__getattribute__");
1795
+ has_getattribute = true;
1796
+ }
1797
+ if (!has_getattr && PyDict_ContainsString(base->tp_dict, "__getattr__")) {
1798
+ *getattr = PyDict_GetItemString(base->tp_dict, "__getattr__");
1799
+ has_getattr = true;
1800
+ }
1801
+ if (has_getattribute && has_getattr) {
1802
+ return;
1803
+ }
1804
+ }
1805
+ }
1806
+
1807
+ static void
1808
+ get_setattr_and_delattr(PyTypeObject* cls, PyObject** setattr, PyObject** delattr)
1809
+ {
1810
+ bool has_setattr = false;
1811
+ bool has_delattr = false;
1812
+ if (PyDict_ContainsString(cls->tp_dict, "__setattr__")) {
1813
+ *setattr = PyDict_GetItemString(cls->tp_dict, "__setattr__");
1814
+ has_setattr = true;
1815
+ }
1816
+ if (PyDict_ContainsString(cls->tp_dict, "__delattr__")) {
1817
+ *delattr = PyDict_GetItemString(cls->tp_dict, "__delattr__");
1818
+ has_delattr = true;
1819
+ }
1820
+ if (has_setattr && has_delattr) {
1821
+ return;
1822
+ }
1823
+ for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
1824
+ if (!has_setattr && PyDict_ContainsString(base->tp_dict, "__setattr__")) {
1825
+ *setattr = PyDict_GetItemString(base->tp_dict, "__setattr__");
1826
+ has_setattr = true;
1827
+ }
1828
+ if (!has_delattr && PyDict_ContainsString(base->tp_dict, "__delattr__")) {
1829
+ *delattr = PyDict_GetItemString(base->tp_dict, "__delattr__");
1830
+ has_delattr = true;
1831
+ }
1832
+ if (has_setattr && has_delattr) {
1833
+ return;
1834
+ }
1835
+ }
1836
+ }
1837
+
1838
+ static void
1839
+ get_del(PyTypeObject* cls, PyObject** del)
1840
+ {
1841
+ if (PyDict_ContainsString(cls->tp_dict, "__del__")) {
1842
+ *del = PyDict_GetItemString(cls->tp_dict, "__del__");
1843
+ return;
1844
+ }
1845
+ for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
1846
+ if (PyDict_ContainsString(base->tp_dict, "__del__")) {
1847
+ *del = PyDict_GetItemString(base->tp_dict, "__del__");
1848
+ return;
1849
+ }
1850
+ }
1851
+ }
1852
+
1853
+ static PyObject*
1854
+ python_original_tp_getattro(PyObject* self, PyObject* name)
1855
+ {
1856
+ PyObject* getattriute = NULL;
1857
+ PyObject* getattr = NULL;
1858
+ get_getattribute_and_getattr((PyTypeObject*)self->ob_type, &getattriute, &getattr);
1859
+ PyObject* res = NULL;
1860
+ if (getattriute) {
1861
+ res = PyObject_CallFunctionObjArgs(getattriute, self, name, NULL);
1862
+ } else {
1863
+ res = PyObject_GenericGetAttr(self, name);
1864
+ }
1865
+ if (!res && getattr) {
1866
+ // check if the exception is AttributeError
1867
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
1868
+ return NULL;
1869
+ }
1870
+ PyErr_Clear();
1871
+ res = PyObject_CallFunctionObjArgs(getattr, self, name, NULL);
1872
+ }
1873
+ return res;
1874
+ }
1875
+
1876
+ static int
1877
+ python_original_tp_setattro(PyObject* self, PyObject* name, PyObject* value)
1878
+ {
1879
+ PyObject* setattr = NULL;
1880
+ PyObject* delattr = NULL;
1881
+ get_setattr_and_delattr((PyTypeObject*)self->ob_type, &setattr, &delattr);
1882
+ if (value && setattr) {
1883
+ PyObject* res = PyObject_CallFunctionObjArgs(setattr, self, name, value, NULL);
1884
+ if (!res) {
1885
+ return -1;
1886
+ }
1887
+ Py_DECREF(res);
1888
+ return 0;
1889
+ } else if (!value && delattr) {
1890
+ PyObject* res = PyObject_CallFunctionObjArgs(delattr, self, name, NULL);
1891
+ if (!res) {
1892
+ return -1;
1893
+ }
1894
+ Py_DECREF(res);
1895
+ return 0;
1896
+ }
1897
+ return PyObject_GenericSetAttr(self, name, value);
1898
+ }
1899
+
1900
+ static void
1901
+ python_original_tp_finalize(PyObject* self)
1902
+ {
1903
+ PyObject* del = NULL;
1904
+ get_del((PyTypeObject*)self->ob_type, &del);
1905
+ if (del) {
1906
+ PyObject *exc_type = NULL, *exc_value = NULL, *exc_tb = NULL;
1907
+ PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
1908
+ PyObject *result = PyObject_CallFunctionObjArgs(del, self, NULL);
1909
+ if (result == NULL) {
1910
+ // python < 3.13 use PyErr_WriteUnraisable, python >= 3.13 use PyErr_FormatUnraisable
1911
+ # if PY_VERSION_HEX >= 0x030D0000
1912
+ PyErr_FormatUnraisable("Exception ignored while "
1913
+ "calling deallocator %R", del);
1914
+ # else
1915
+ PyErr_WriteUnraisable(del);
1916
+ # endif
1917
+ }
1918
+ else {
1919
+ Py_DECREF(result);
1920
+ }
1921
+ if (exc_type != NULL) {
1922
+ PyErr_Restore(exc_type, exc_value, exc_tb);
1923
+ }
1924
+ }
1925
+ }
1926
+
1746
1927
  static bool
1747
1928
  PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationData& data)
1748
1929
  {
@@ -1809,7 +1990,7 @@ PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationDa
1809
1990
  }
1810
1991
 
1811
1992
  if (!PyUnicode_Check(attr)) {
1812
- PyErr_SetString(PyExc_TypeError, "all items in '__private_attrs__' must be strings");
1993
+ PyErr_Format(PyExc_TypeError, "all items in '__private_attrs__' must be 'str', not '%.200s'", Py_TYPE(attr)->tp_name);
1813
1994
  return false;
1814
1995
  }
1815
1996
 
@@ -1821,7 +2002,7 @@ PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationDa
1821
2002
  std::string attr_str = real_class_name(attr_cstr, data.class_name);
1822
2003
 
1823
2004
  for (const char** p = invalid_name; *p != NULL; p++) {
1824
- if (attr_str == *p) {
2005
+ if (strcmp(attr_str.c_str(), *p) == 0) {
1825
2006
  std::string error_msg = "invalid attribute name: '" + std::string(*p) + "'";
1826
2007
  PyErr_SetString(PyExc_TypeError, error_msg.c_str());
1827
2008
  return false;
@@ -1842,10 +2023,10 @@ PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationDa
1842
2023
  return false;
1843
2024
  }
1844
2025
 
1845
- PyObject* all_slots = PyDict_GetItemString(data.attrs_copy, "__slots__");
1846
- bool has_slots = (all_slots != NULL);
2026
+ int has_slots = PyDict_ContainsString(data.attrs_copy, "__slots__");
1847
2027
 
1848
2028
  if (has_slots) {
2029
+ PyObject* all_slots = PyDict_GetItemString(data.attrs_copy, "__slots__");
1849
2030
  PyObject* slot_seq = PySequence_Fast(all_slots, "__slots__ must be a sequence");
1850
2031
  if (!slot_seq) {
1851
2032
  return false;
@@ -1866,8 +2047,6 @@ PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationDa
1866
2047
  }
1867
2048
  }
1868
2049
  Py_DECREF(slot_seq);
1869
- } else {
1870
- PyErr_Clear();
1871
2050
  }
1872
2051
 
1873
2052
  Py_ssize_t bases_len = PyTuple_GET_SIZE(data.bases);
@@ -1927,16 +2106,16 @@ PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationDa
1927
2106
 
1928
2107
  // get "private_func" from kwds
1929
2108
  if (kwds && PyDict_Check(kwds)) {
1930
- data.private_func = PyDict_GetItemString(kwds, "private_func");
1931
- if (data.private_func) {
2109
+ bool has_private_func = PyDict_ContainsString(kwds, "private_func");
2110
+ if (has_private_func) {
2111
+ data.private_func = PyDict_GetItemString(kwds, "private_func");
1932
2112
  Py_INCREF(data.private_func);
1933
2113
  }
1934
2114
  data.base_kwds = PyDict_Copy(kwds);
1935
2115
  if (!data.base_kwds) {
1936
2116
  return false;
1937
2117
  }
1938
- PyDict_DelItemString(data.base_kwds, "private_func");
1939
- PyErr_Clear();
2118
+ if (has_private_func) PyDict_DelItemString(data.base_kwds, "private_func");
1940
2119
  }
1941
2120
 
1942
2121
  return true;
@@ -1968,49 +2147,77 @@ PrivateAttrType_create(PyTypeObject* type, PrivateAttrCreationData& data)
1968
2147
  return new_type;
1969
2148
  }
1970
2149
 
2150
+ static getattrofunc get_need_tp_getattro(PyTypeObject* cls);
2151
+ static setattrofunc get_need_tp_setattro(PyTypeObject* cls);
2152
+ static destructor get_need_tp_finalize(PyTypeObject* cls);
2153
+
1971
2154
  static void
1972
2155
  ensure_tp(PyTypeObject* type_instance)
1973
2156
  {
1974
2157
  uintptr_t type_id = (uintptr_t)(type_instance);
1975
- if (type_instance->tp_getattro) {
2158
+ {
1976
2159
  if (type_instance->tp_getattro != PrivateAttr_tp_getattro) {
1977
- ::AllData::all_type_getattro[type_id] = type_instance->tp_getattro;
2160
+ if (!type_instance->tp_getattro) {
2161
+ ::AllData::all_type_getattro[type_id] = get_need_tp_getattro(type_instance);
2162
+ } else {
2163
+ ::AllData::all_type_getattro[type_id] = type_instance->tp_getattro;
2164
+ }
1978
2165
  type_instance->tp_getattro = PrivateAttr_tp_getattro;
1979
2166
  } else {
1980
- PyTypeObject* base = type_instance->tp_base;
1981
- uintptr_t base_id = (uintptr_t)(base);
1982
- if (::AllData::all_type_getattro.find(base_id) != ::AllData::all_type_getattro.end()) {
1983
- ::AllData::all_type_getattro[type_id] = ::AllData::all_type_getattro[base_id];
1984
- } else if (base && base->tp_getattro && base->tp_getattro != PrivateAttr_tp_getattro) {
1985
- ::AllData::all_type_getattro[type_id] = base->tp_getattro;
2167
+ if (PyDict_ContainsString(type_instance->tp_dict, "__getattribute__") || PyDict_ContainsString(type_instance->tp_dict, "__getattr__")) {
2168
+ ::AllData::all_type_getattro[type_id] = AllSlots::original_getattro;
2169
+ } else {
2170
+ PyTypeObject* base = type_instance->tp_base;
2171
+ uintptr_t base_id = (uintptr_t)(base);
2172
+ if (::AllData::all_type_getattro.find(base_id) != ::AllData::all_type_getattro.end()) {
2173
+ ::AllData::all_type_getattro[type_id] = ::AllData::all_type_getattro[base_id];
2174
+ } else if (base && base->tp_getattro && base->tp_getattro != PrivateAttr_tp_getattro) {
2175
+ ::AllData::all_type_getattro[type_id] = base->tp_getattro;
2176
+ }
1986
2177
  }
1987
2178
  }
1988
2179
  }
1989
- if (type_instance->tp_setattro) {
2180
+ {
1990
2181
  if (type_instance->tp_setattro != PrivateAttr_tp_setattro) {
1991
- ::AllData::all_type_setattro[type_id] = type_instance->tp_setattro;
2182
+ if (!type_instance->tp_setattro) {
2183
+ ::AllData::all_type_setattro[type_id] = get_need_tp_setattro(type_instance);
2184
+ } else {
2185
+ ::AllData::all_type_setattro[type_id] = type_instance->tp_setattro;
2186
+ }
1992
2187
  type_instance->tp_setattro = PrivateAttr_tp_setattro;
1993
2188
  } else {
1994
- PyTypeObject* base = type_instance->tp_base;
1995
- uintptr_t base_id = (uintptr_t)(base);
1996
- if (::AllData::all_type_setattro.find(base_id) != ::AllData::all_type_setattro.end()) {
1997
- ::AllData::all_type_setattro[type_id] = ::AllData::all_type_setattro[base_id];
1998
- } else if (base && base->tp_setattro && base->tp_setattro != PrivateAttr_tp_setattro) {
1999
- ::AllData::all_type_setattro[type_id] = base->tp_setattro;
2189
+ if (PyDict_ContainsString(type_instance->tp_dict, "__setattr__") || PyDict_ContainsString(type_instance->tp_dict, "__delattr__")) {
2190
+ ::AllData::all_type_setattro[type_id] = AllSlots::original_setattro;
2191
+ } else {
2192
+ PyTypeObject* base = type_instance->tp_base;
2193
+ uintptr_t base_id = (uintptr_t)(base);
2194
+ if (::AllData::all_type_setattro.find(base_id) != ::AllData::all_type_setattro.end()) {
2195
+ ::AllData::all_type_setattro[type_id] = ::AllData::all_type_setattro[base_id];
2196
+ } else if (base && base->tp_setattro && base->tp_setattro != PrivateAttr_tp_setattro) {
2197
+ ::AllData::all_type_setattro[type_id] = base->tp_setattro;
2198
+ }
2000
2199
  }
2001
2200
  }
2002
2201
  }
2003
- if (type_instance->tp_finalize) {
2202
+ {
2004
2203
  if (type_instance->tp_finalize != PrivateAttr_tp_finalize) {
2005
- ::AllData::all_type_finalize[type_id] = type_instance->tp_finalize;
2204
+ if (!type_instance->tp_finalize) {
2205
+ ::AllData::all_type_finalize[type_id] = get_need_tp_finalize(type_instance);
2206
+ } else {
2207
+ ::AllData::all_type_finalize[type_id] = type_instance->tp_finalize;
2208
+ }
2006
2209
  type_instance->tp_finalize = PrivateAttr_tp_finalize;
2007
2210
  } else {
2008
- PyTypeObject* base = type_instance->tp_base;
2009
- uintptr_t base_id = (uintptr_t)(base);
2010
- if (::AllData::all_type_finalize.find(base_id) != ::AllData::all_type_finalize.end()) {
2011
- ::AllData::all_type_finalize[type_id] = ::AllData::all_type_finalize[base_id];
2012
- } else if (base && base->tp_finalize && base->tp_finalize != PrivateAttr_tp_finalize) {
2013
- ::AllData::all_type_finalize[type_id] = base->tp_finalize;
2211
+ if (PyDict_ContainsString(type_instance->tp_dict, "__del__")) {
2212
+ ::AllData::all_type_finalize[type_id] = AllSlots::original_finalize;
2213
+ } else {
2214
+ PyTypeObject* base = type_instance->tp_base;
2215
+ uintptr_t base_id = (uintptr_t)(base);
2216
+ if (::AllData::all_type_finalize.find(base_id) != ::AllData::all_type_finalize.end()) {
2217
+ ::AllData::all_type_finalize[type_id] = ::AllData::all_type_finalize[base_id];
2218
+ } else if (base && base->tp_finalize && base->tp_finalize != PrivateAttr_tp_finalize) {
2219
+ ::AllData::all_type_finalize[type_id] = base->tp_finalize;
2220
+ }
2014
2221
  }
2015
2222
  }
2016
2223
  }
@@ -2022,23 +2229,37 @@ ensure_subclass_tp(PyTypeObject* type_instance)
2022
2229
  // type.__subclasses__
2023
2230
  PyObject* type_subclasses = (PyObject*)type_instance->tp_subclasses;
2024
2231
  if (!type_subclasses) {
2025
- PyErr_Clear();
2026
2232
  return;
2027
2233
  }
2028
- if (!PyList_Check(type_subclasses)) {
2029
- Py_DECREF(type_subclasses);
2234
+ if (!PyDict_Check(type_subclasses)) {
2030
2235
  return;
2031
2236
  }
2032
- Py_ssize_t subclasses_size = PyList_GET_SIZE(type_subclasses);
2033
- for (Py_ssize_t i = 0; i < subclasses_size; i++) {
2034
- PyObject* subclass = PyList_GET_ITEM(type_subclasses, i);
2237
+ // check all values in the dict. It should be a weakref to a type. If not, continue.
2238
+ PyObject* key, *value;
2239
+ Py_ssize_t pos = 0;
2240
+ while (PyDict_Next(type_subclasses, &pos, &key, &value)) {
2241
+ if (!value || !PyWeakref_CheckRef(value)) {
2242
+ continue;
2243
+ }
2244
+ // python<3.13 use PyWeakref_GetObject, python>=3.13 use PyWeakref_GetRef
2245
+ #if PY_VERSION_HEX < 0x030D0000
2246
+ PyObject* subclass = PyWeakref_GetObject(value);
2035
2247
  if (!subclass || !PyType_Check(subclass)) {
2036
2248
  continue;
2037
2249
  }
2038
2250
  ensure_tp((PyTypeObject*)subclass);
2039
- ensure_subclass_tp((PyTypeObject*)subclass);
2251
+ #else
2252
+ PyObject* subclass;
2253
+ if (PyWeakref_GetRef(value, (PyObject**)&subclass) != 0) {
2254
+ continue;
2255
+ }
2256
+ if (!subclass || !PyType_Check(subclass)) {
2257
+ continue;
2258
+ }
2259
+ ensure_tp((PyTypeObject*)subclass);
2260
+ Py_XDECREF(subclass);
2261
+ #endif
2040
2262
  }
2041
- Py_DECREF(type_subclasses);
2042
2263
  }
2043
2264
 
2044
2265
  static bool
@@ -2052,6 +2273,15 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data)
2052
2273
  uintptr_t type_id = (uintptr_t)(type_instance);
2053
2274
 
2054
2275
  ensure_tp(type_instance);
2276
+ if (PyDict_ContainsString(type_instance->tp_dict, "__getattribute__") || PyDict_ContainsString(type_instance->tp_dict, "__getattr__")) {
2277
+ ::AllData::all_type_getattro[type_id] = AllSlots::original_getattro;
2278
+ }
2279
+ if (PyDict_ContainsString(type_instance->tp_dict, "__setattr__") || PyDict_ContainsString(type_instance->tp_dict, "__delattr__")) {
2280
+ ::AllData::all_type_setattro[type_id] = AllSlots::original_setattro;
2281
+ }
2282
+ if (PyDict_ContainsString(type_instance->tp_dict, "__del__")) {
2283
+ ::AllData::all_type_finalize[type_id] = AllSlots::original_finalize;
2284
+ }
2055
2285
 
2056
2286
  ::AllData::type_attr_dict[type_id] = {};
2057
2287
  ::AllData::all_type_attr_set[type_id] = data.private_attrs_set;
@@ -2205,6 +2435,139 @@ PrivateAttrType_getattr(PyObject* cls, PyObject* name)
2205
2435
  return result;
2206
2436
  }
2207
2437
 
2438
+ static int
2439
+ init_all_slots()
2440
+ {
2441
+ AllSlots::original_getattro = python_original_tp_getattro;
2442
+ AllSlots::original_setattro = python_original_tp_setattro;
2443
+ AllSlots::original_finalize = python_original_tp_finalize;
2444
+ return 0;
2445
+ }
2446
+
2447
+ static getattrofunc
2448
+ get_need_tp_getattro(PyTypeObject* cls)
2449
+ {
2450
+ if (PyDict_ContainsString(cls->tp_dict, "__getattribute__") || PyDict_ContainsString(cls->tp_dict, "__getattr__")) {
2451
+ return AllSlots::original_getattro;
2452
+ }
2453
+ PyTypeObject* base = cls->tp_base;
2454
+ while (base) {
2455
+ if (base->tp_getattro != PrivateAttr_tp_getattro) {
2456
+ return base->tp_getattro;
2457
+ } else if (::AllData::all_type_getattro.find((uintptr_t)base) != ::AllData::all_type_getattro.end()) {
2458
+ if (::AllData::all_type_getattro[(uintptr_t)base]) {
2459
+ return ::AllData::all_type_getattro[(uintptr_t)base];
2460
+ }
2461
+ base = base->tp_base;
2462
+ } else {
2463
+ base = base->tp_base;
2464
+ }
2465
+ }
2466
+ return NULL;
2467
+ }
2468
+
2469
+ static setattrofunc
2470
+ get_need_tp_setattro(PyTypeObject* cls)
2471
+ {
2472
+ if (PyDict_ContainsString(cls->tp_dict, "__setattr__") || PyDict_ContainsString(cls->tp_dict, "__delattr__")) {
2473
+ return AllSlots::original_setattro;
2474
+ }
2475
+ PyTypeObject* base = cls->tp_base;
2476
+ while (base) {
2477
+ if (base->tp_setattro != PrivateAttr_tp_setattro) {
2478
+ return base->tp_setattro;
2479
+ } else if (::AllData::all_type_setattro.find((uintptr_t)base) != ::AllData::all_type_setattro.end()) {
2480
+ if (::AllData::all_type_setattro[(uintptr_t)base]) {
2481
+ return ::AllData::all_type_setattro[(uintptr_t)base];
2482
+ }
2483
+ base = base->tp_base;
2484
+ } else {
2485
+ base = base->tp_base;
2486
+ }
2487
+ }
2488
+ return NULL;
2489
+ }
2490
+
2491
+ static destructor
2492
+ get_need_tp_finalize(PyTypeObject* cls)
2493
+ {
2494
+ if (PyDict_ContainsString(cls->tp_dict, "__del__")) {
2495
+ return AllSlots::original_finalize;
2496
+ }
2497
+ PyTypeObject* base = cls->tp_base;
2498
+ while (base) {
2499
+ if (base->tp_finalize != PrivateAttr_tp_finalize) {
2500
+ return base->tp_finalize;
2501
+ } else if (::AllData::all_type_finalize.find((uintptr_t)base) != ::AllData::all_type_finalize.end()) {
2502
+ if (::AllData::all_type_finalize[(uintptr_t)base]) {
2503
+ return ::AllData::all_type_finalize[(uintptr_t)base];
2504
+ }
2505
+ base = base->tp_base;
2506
+ } else {
2507
+ base = base->tp_base;
2508
+ }
2509
+ }
2510
+ return NULL;
2511
+ }
2512
+
2513
+ static void
2514
+ type_change_all_slots(PyTypeObject* cls, const char* name)
2515
+ {
2516
+ if (strcmp(name, "__getattribute__") == 0 || strcmp(name, "__getattr__") == 0) {
2517
+ cls->tp_getattro = PrivateAttr_tp_getattro;
2518
+ ::AllData::all_type_getattro[(uintptr_t)cls] = get_need_tp_getattro(cls);
2519
+ } else if (strcmp(name, "__setattr__") == 0 || strcmp(name, "__delattr__") == 0) {
2520
+ cls->tp_setattro = PrivateAttr_tp_setattro;
2521
+ ::AllData::all_type_setattro[(uintptr_t)cls] = get_need_tp_setattro(cls);
2522
+ } else if (strcmp(name, "__del__") == 0) {
2523
+ cls->tp_finalize = PrivateAttr_tp_finalize;
2524
+ ::AllData::all_type_finalize[(uintptr_t)cls] = get_need_tp_finalize(cls);
2525
+ }
2526
+ }
2527
+
2528
+ static void
2529
+ subtype_change_all_slots(PyTypeObject* cls, const char* name)
2530
+ {
2531
+ // tp_subclasses: {id(type): weakref.ref(type)}
2532
+ PyObject* tp_subclasses = (PyObject*)cls->tp_subclasses;
2533
+ if (!tp_subclasses) {
2534
+ return;
2535
+ }
2536
+ if (!PyDict_Check(tp_subclasses)) {
2537
+ return;
2538
+ }
2539
+ PyObject* key;
2540
+ PyObject* value;
2541
+ Py_ssize_t pos = 0;
2542
+ while (PyDict_Next(tp_subclasses, &pos, &key, &value)) {
2543
+ if (!PyWeakref_Check(value)) {
2544
+ continue;
2545
+ }
2546
+ #if PY_VERSION_HEX < 0x030D0000
2547
+ PyObject* obj = PyWeakref_GET_OBJECT(value);
2548
+ if (!obj) {
2549
+ continue;
2550
+ }
2551
+ #else
2552
+ PyObject* obj;
2553
+ if (PyWeakref_GetRef(value, &obj) != 0) {
2554
+ continue;
2555
+ }
2556
+ if (!obj) {
2557
+ continue;
2558
+ }
2559
+ #endif
2560
+ if (!PyType_Check(obj)) {
2561
+ continue;
2562
+ }
2563
+ PyTypeObject* sub_cls = (PyTypeObject*)obj;
2564
+ type_change_all_slots(sub_cls, name);
2565
+ #if PY_VERSION_HEX >= 0x030D0000
2566
+ Py_XDECREF(obj);
2567
+ #endif
2568
+ }
2569
+ }
2570
+
2208
2571
  static int
2209
2572
  PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value)
2210
2573
  {
@@ -2231,6 +2594,33 @@ PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value)
2231
2594
  return type_setattr(cls, name_str, value);
2232
2595
  }
2233
2596
  Py_XDECREF(now_code);
2597
+ // if name in __getattribute__, __setattr__, __delattr__, __del__, just set to tp_dict
2598
+ if (strcmp(name_str.c_str(), "__getattribute__") == 0 ||
2599
+ strcmp(name_str.c_str(), "__getattr__") == 0 ||
2600
+ strcmp(name_str.c_str(), "__setattr__") == 0 ||
2601
+ strcmp(name_str.c_str(), "__delattr__") == 0 ||
2602
+ strcmp(name_str.c_str(), "__del__") == 0) {
2603
+ PyObject* tp_dict = ((PyTypeObject*)cls)->tp_dict;
2604
+ if (!tp_dict) {
2605
+ PyErr_SetString(PyExc_TypeError, "type has no tp_dict");
2606
+ return -1;
2607
+ }
2608
+ if (!value) {
2609
+ if (PyDict_DelItem(tp_dict, name) < 0) {
2610
+ PyErr_Format(PyExc_AttributeError, "type object '%.100s' has no attribute '%U'", ((PyTypeObject*)cls)->tp_name, name);
2611
+ return -1;
2612
+ }
2613
+ type_change_all_slots((PyTypeObject*)cls, name_str.c_str());
2614
+ subtype_change_all_slots((PyTypeObject*)cls, name_str.c_str());
2615
+ return 0;
2616
+ }
2617
+ if (PyDict_SetItem(tp_dict, name, value) < 0) {
2618
+ return -1;
2619
+ }
2620
+ type_change_all_slots((PyTypeObject*)cls, name_str.c_str());
2621
+ subtype_change_all_slots((PyTypeObject*)cls, name_str.c_str());
2622
+ return 0;
2623
+ }
2234
2624
  PyTypeObject* base = Py_TYPE(cls)->tp_base;
2235
2625
  while (base && base->tp_base && base->tp_setattro == PrivateAttrType_setattr) {
2236
2626
  base = base->tp_base;
@@ -2316,7 +2706,7 @@ static void
2316
2706
  PrivateAttrType_del(PyObject* cls)
2317
2707
  {
2318
2708
  PrivateAttrType_finalize(cls);
2319
- (Py_TYPE(cls))->tp_free(cls);
2709
+ PyType_Type.tp_dealloc(cls);
2320
2710
  }
2321
2711
 
2322
2712
  static const char* PrivateAttrBase_doc = "The class to help to create private attribute. It does not have any special behavior.";
@@ -2775,7 +3165,8 @@ static PyModuleDef def = {
2775
3165
  PyMODINIT_FUNC
2776
3166
  PyInit_private_attribute(void)
2777
3167
  {
2778
- if (PyType_Ready(&PrivateWrapType) < 0 ||
3168
+ if (init_all_slots() <0 ||
3169
+ PyType_Ready(&PrivateWrapType) < 0 ||
2779
3170
  PyType_Ready(&PrivateWrapProxyType) < 0 ||
2780
3171
  PyType_Ready(&PrivateAttrType) < 0 ||
2781
3172
  PyType_Ready(&PrivateModuleType) < 0 ||
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 1.3.6
3
+ Version: 1.3.8
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
@@ -19,7 +19,7 @@ readme = open('README.md').read()
19
19
 
20
20
  setup(
21
21
  name='private_attribute_cpp',
22
- version='1.3.6',
22
+ version='1.3.8',
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.',