private-attribute-cpp 1.4.11__tar.gz → 2.0.1__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.
- {private_attribute_cpp-1.4.11/private_attribute_cpp.egg-info → private_attribute_cpp-2.0.1}/PKG-INFO +1 -1
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/private_attribute.cpp +405 -396
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1/private_attribute_cpp.egg-info}/PKG-INFO +1 -1
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/setup.py +1 -1
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/LICENSE +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/MANIFEST.in +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/README.md +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/picosha2.h +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/private_attribute.pyi +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/private_attribute_cpp.egg-info/SOURCES.txt +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/private_attribute_cpp.egg-info/dependency_links.txt +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/private_attribute_cpp.egg-info/not-zip-safe +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/private_attribute_cpp.egg-info/top_level.txt +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/setup.cfg +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_class_private_attrs.py +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_private_abc.py +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_private_attrs.py +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_private_func.py +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_private_inheritance.py +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_private_method.py +0 -0
- {private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_private_wrap.py +0 -0
{private_attribute_cpp-1.4.11/private_attribute_cpp.egg-info → private_attribute_cpp-2.0.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: private_attribute_cpp
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.1
|
|
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
|
|
@@ -12,14 +12,12 @@
|
|
|
12
12
|
#include <ctime>
|
|
13
13
|
#include <iomanip>
|
|
14
14
|
#include <sstream>
|
|
15
|
-
#include <vector>
|
|
16
15
|
#include <random>
|
|
17
16
|
#include <mutex>
|
|
18
17
|
#include <shared_mutex>
|
|
19
18
|
#include "picosha2.h"
|
|
20
19
|
#include <functional>
|
|
21
20
|
#include <memory>
|
|
22
|
-
#include <algorithm>
|
|
23
21
|
|
|
24
22
|
// python under 3.13 doesn't have PyDict_ContainsString, so we implement it ourselves
|
|
25
23
|
#if PY_VERSION_HEX < 0x030D0000
|
|
@@ -35,7 +33,6 @@ PyDict_ContainsString(PyObject *op, const char *key) noexcept
|
|
|
35
33
|
return res;
|
|
36
34
|
}
|
|
37
35
|
#endif
|
|
38
|
-
|
|
39
36
|
static const auto module_running_time = std::chrono::system_clock::now();
|
|
40
37
|
|
|
41
38
|
static std::string
|
|
@@ -110,7 +107,7 @@ namespace std {
|
|
|
110
107
|
return key.gethash();
|
|
111
108
|
}
|
|
112
109
|
};
|
|
113
|
-
}
|
|
110
|
+
}
|
|
114
111
|
|
|
115
112
|
namespace {
|
|
116
113
|
namespace AllData {
|
|
@@ -144,12 +141,6 @@ namespace {
|
|
|
144
141
|
};
|
|
145
142
|
};
|
|
146
143
|
|
|
147
|
-
namespace AllSlots {
|
|
148
|
-
static getattrofunc original_getattro = nullptr;
|
|
149
|
-
static setattrofunc original_setattro = nullptr;
|
|
150
|
-
static destructor original_finalize = nullptr;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
144
|
struct FinalObject
|
|
154
145
|
{
|
|
155
146
|
PyObject* result = NULL;
|
|
@@ -227,7 +218,7 @@ generate_private_attr_name(uintptr_t obj_id, const std::string& attr_name) noexc
|
|
|
227
218
|
|
|
228
219
|
unsigned long long seed = std::stoul(hash_str.substr(0, 8), nullptr, 16);
|
|
229
220
|
|
|
230
|
-
std::mt19937 rng(seed);
|
|
221
|
+
std::mt19937 rng(static_cast<std::mt19937::result_type>(seed));
|
|
231
222
|
|
|
232
223
|
static const std::string printable_chars =
|
|
233
224
|
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ";
|
|
@@ -325,12 +316,77 @@ public:
|
|
|
325
316
|
type = value = traceback = nullptr;
|
|
326
317
|
}
|
|
327
318
|
|
|
319
|
+
const char* what() const noexcept override {
|
|
320
|
+
if (!msg_.empty())
|
|
321
|
+
return msg_.c_str();
|
|
322
|
+
|
|
323
|
+
if (!type || !value) {
|
|
324
|
+
msg_ = "cannot format this exception (missing type/value)";
|
|
325
|
+
return msg_.c_str();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
PyObject* tb_mod = PyImport_ImportModule("traceback");
|
|
329
|
+
if (!tb_mod) {
|
|
330
|
+
msg_ = "cannot format this exception (import traceback failed)";
|
|
331
|
+
return msg_.c_str();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
PyObject* format_exc = PyObject_GetAttrString(tb_mod, "format_exception");
|
|
335
|
+
Py_DECREF(tb_mod);
|
|
336
|
+
if (!format_exc) {
|
|
337
|
+
msg_ = "cannot format this exception (get format_exception failed)";
|
|
338
|
+
return msg_.c_str();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
PyObject* result = PyObject_CallFunctionObjArgs(
|
|
342
|
+
format_exc, type, value, traceback ? traceback : Py_None, nullptr);
|
|
343
|
+
Py_DECREF(format_exc);
|
|
344
|
+
|
|
345
|
+
if (!result) {
|
|
346
|
+
msg_ = "cannot format this exception (format_exception failed)";
|
|
347
|
+
return msg_.c_str();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
PyObject* empty = PyUnicode_FromString("");
|
|
351
|
+
if (!empty) {
|
|
352
|
+
Py_DECREF(result);
|
|
353
|
+
msg_ = "cannot format this exception (create empty string failed)";
|
|
354
|
+
return msg_.c_str();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
PyObject* joined = PyUnicode_Join(empty, result);
|
|
358
|
+
Py_DECREF(empty);
|
|
359
|
+
Py_DECREF(result);
|
|
360
|
+
|
|
361
|
+
if (!joined) {
|
|
362
|
+
msg_ = "cannot format this exception (join failed)";
|
|
363
|
+
return msg_.c_str();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const char* utf8 = PyUnicode_AsUTF8(joined);
|
|
367
|
+
if (utf8)
|
|
368
|
+
msg_ = utf8;
|
|
369
|
+
else
|
|
370
|
+
msg_ = "cannot format this exception (AsUTF8 failed)";
|
|
371
|
+
|
|
372
|
+
Py_DECREF(joined);
|
|
373
|
+
return msg_.c_str();
|
|
374
|
+
}
|
|
375
|
+
|
|
328
376
|
private:
|
|
329
377
|
PyObject* type = nullptr;
|
|
330
378
|
PyObject* value = nullptr;
|
|
331
379
|
PyObject* traceback = nullptr;
|
|
380
|
+
mutable std::string msg_;
|
|
332
381
|
};
|
|
333
382
|
|
|
383
|
+
// In MSVC, disable warning C5272
|
|
384
|
+
// The custom_random_string will throw RestorePythonException, which cannot be copied and will be caught anyway.
|
|
385
|
+
#ifdef _MSC_VER
|
|
386
|
+
#pragma warning(push)
|
|
387
|
+
#pragma warning(disable: 5272)
|
|
388
|
+
#endif
|
|
389
|
+
|
|
334
390
|
static std::string
|
|
335
391
|
custom_random_string(uintptr_t obj_id, const std::string& attr_name, PyObject* func)
|
|
336
392
|
{
|
|
@@ -389,6 +445,10 @@ custom_random_string(uintptr_t obj_id, const std::string& attr_name, PyObject* f
|
|
|
389
445
|
return result;
|
|
390
446
|
}
|
|
391
447
|
|
|
448
|
+
#ifdef _MSC_VER
|
|
449
|
+
#pragma warning(pop)
|
|
450
|
+
#endif
|
|
451
|
+
|
|
392
452
|
static void
|
|
393
453
|
clear_obj(uintptr_t obj_id) noexcept
|
|
394
454
|
{
|
|
@@ -897,7 +957,7 @@ static PyObject*
|
|
|
897
957
|
PrivateWrap_doc(PyObject *obj, void* /*closure*/) noexcept
|
|
898
958
|
{
|
|
899
959
|
if (!obj) {
|
|
900
|
-
return
|
|
960
|
+
return PyUnicode_InternFromString("PrivateWrap");
|
|
901
961
|
}
|
|
902
962
|
PyObject* doc = PyObject_GetAttrString(((PrivateWrapObject*)obj)->result, "__doc__");
|
|
903
963
|
if (!doc) {
|
|
@@ -911,26 +971,26 @@ static PyObject*
|
|
|
911
971
|
PrivateWrap_module(PyObject *obj, void* /*closure*/) noexcept
|
|
912
972
|
{
|
|
913
973
|
if (!obj) {
|
|
914
|
-
return
|
|
974
|
+
return PyUnicode_InternFromString("private_attribute");
|
|
915
975
|
}
|
|
916
976
|
PyObject* module = PyObject_GetAttrString(((PrivateWrapObject*)obj)->result, "__module__");
|
|
917
977
|
if (!module){
|
|
918
978
|
PyErr_Clear();
|
|
919
|
-
return
|
|
979
|
+
return PyUnicode_InternFromString("private_attribute");
|
|
920
980
|
}
|
|
921
981
|
return module;
|
|
922
982
|
}
|
|
923
983
|
|
|
924
984
|
static PyObject*
|
|
925
|
-
|
|
985
|
+
PrivateWrap_name(PyObject* obj, void* /*closure*/) noexcept
|
|
926
986
|
{
|
|
927
987
|
if (!obj) {
|
|
928
|
-
return
|
|
988
|
+
return PyUnicode_InternFromString("_PrivateWrap");
|
|
929
989
|
}
|
|
930
990
|
PyObject* name = PyObject_GetAttrString(((PrivateWrapObject*)obj)->result, "__name__");
|
|
931
991
|
if (!name) {
|
|
932
992
|
PyErr_Clear();
|
|
933
|
-
return
|
|
993
|
+
return PyUnicode_InternFromString("_PrivateWrap");
|
|
934
994
|
}
|
|
935
995
|
return name;
|
|
936
996
|
}
|
|
@@ -939,12 +999,12 @@ static PyObject*
|
|
|
939
999
|
PrivateWrap_qualname(PyObject* obj, void* /*closure*/) noexcept
|
|
940
1000
|
{
|
|
941
1001
|
if (!obj) {
|
|
942
|
-
return
|
|
1002
|
+
return PyUnicode_InternFromString("_PrivateWrap");
|
|
943
1003
|
}
|
|
944
1004
|
PyObject* qualname = PyObject_GetAttrString(((PrivateWrapObject*)obj)->result, "__qualname__");
|
|
945
1005
|
if (!qualname) {
|
|
946
1006
|
PyErr_Clear();
|
|
947
|
-
return
|
|
1007
|
+
return PyUnicode_InternFromString("_PrivateWrap");
|
|
948
1008
|
}
|
|
949
1009
|
return qualname;
|
|
950
1010
|
}
|
|
@@ -979,32 +1039,76 @@ PrivateWrap_type_params(PyObject* obj, void* /*closure*/) noexcept
|
|
|
979
1039
|
return type_params;
|
|
980
1040
|
}
|
|
981
1041
|
|
|
982
|
-
static const char* PrivateWrap_result_doc = "the final result of decorating";
|
|
983
1042
|
static const char* PrivateWrap_funcs_doc = "the original functions";
|
|
984
1043
|
|
|
985
1044
|
static PyGetSetDef PrivateWrap_getset[] = {
|
|
986
1045
|
{"funcs", (getter)PrivateWrap_funcs, NULL, PrivateWrap_funcs_doc, NULL},
|
|
987
1046
|
{"__doc__", (getter)PrivateWrap_doc, NULL, NULL, NULL},
|
|
988
1047
|
{"__module__", (getter)PrivateWrap_module, NULL, NULL, NULL},
|
|
989
|
-
{"__name__", (getter)
|
|
1048
|
+
{"__name__", (getter)PrivateWrap_name, NULL, NULL, NULL},
|
|
990
1049
|
{"__qualname__", (getter)PrivateWrap_qualname, NULL, NULL, NULL},
|
|
991
1050
|
{"__annotate__", (getter)PrivateWrap_annotate, NULL, NULL, NULL},
|
|
992
1051
|
{"__type_params__", (getter)PrivateWrap_type_params, NULL, NULL, NULL},
|
|
993
1052
|
{NULL}
|
|
994
1053
|
};
|
|
995
1054
|
|
|
1055
|
+
#define PrivateWrap_getattro_dunder(name) do {\
|
|
1056
|
+
if (strcmp(name_str, "__" #name "__") == 0) {\
|
|
1057
|
+
return PrivateWrap_##name(obj, NULL);\
|
|
1058
|
+
}\
|
|
1059
|
+
} while(0)
|
|
1060
|
+
|
|
996
1061
|
static PyObject *
|
|
997
1062
|
PrivateWrap_getattro(PyObject *obj, PyObject *name) noexcept
|
|
998
1063
|
{
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1064
|
+
PrivateWrapObject *self = (PrivateWrapObject *)obj;
|
|
1065
|
+
const char *name_str = PyUnicode_AsUTF8(name);
|
|
1066
|
+
if (!name_str) {
|
|
1067
|
+
PyErr_SetString(PyExc_TypeError, "attribute name must be a string");
|
|
1068
|
+
return NULL;
|
|
1002
1069
|
}
|
|
1070
|
+
if (strcmp(name_str, "__wrapped__") == 0 || strcmp(name_str, "result") == 0) {
|
|
1071
|
+
if (!self->result) {
|
|
1072
|
+
PyErr_SetString(PyExc_AttributeError, "attribute 'result' is invalid");
|
|
1073
|
+
return NULL;
|
|
1074
|
+
}
|
|
1075
|
+
Py_INCREF(self->result);
|
|
1076
|
+
return self->result;
|
|
1077
|
+
}
|
|
1078
|
+
if (strcmp(name_str, "funcs") == 0) {
|
|
1079
|
+
return PrivateWrap_funcs(obj, NULL);
|
|
1080
|
+
}
|
|
1081
|
+
PrivateWrap_getattro_dunder(doc);
|
|
1082
|
+
PrivateWrap_getattro_dunder(module);
|
|
1083
|
+
PrivateWrap_getattro_dunder(name);
|
|
1084
|
+
PrivateWrap_getattro_dunder(qualname);
|
|
1085
|
+
PrivateWrap_getattro_dunder(annotate);
|
|
1086
|
+
PrivateWrap_getattro_dunder(type_params);
|
|
1087
|
+
return PyObject_GetAttr(self->result, name);
|
|
1088
|
+
}
|
|
1003
1089
|
|
|
1004
|
-
|
|
1090
|
+
static PyObject*
|
|
1091
|
+
PrivateWrap_descrget(PyObject* obj, PyObject* name, PyObject* cls) noexcept
|
|
1092
|
+
{
|
|
1093
|
+
PyObject* result = ((PrivateWrapObject*)obj)->result;
|
|
1094
|
+
if (Py_TYPE(result)->tp_descr_get) {
|
|
1095
|
+
return Py_TYPE(result)->tp_descr_get(result, name, cls);
|
|
1096
|
+
} else {
|
|
1097
|
+
Py_INCREF(result);
|
|
1098
|
+
return result;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1005
1101
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1102
|
+
static int
|
|
1103
|
+
PrivateWrap_descrset(PyObject* obj, PyObject* name, PyObject* value) noexcept
|
|
1104
|
+
{
|
|
1105
|
+
PyObject* result = ((PrivateWrapObject*)obj)->result;
|
|
1106
|
+
if (Py_TYPE(result)->tp_descr_set) {
|
|
1107
|
+
return Py_TYPE(result)->tp_descr_set(result, name, value);
|
|
1108
|
+
} else {
|
|
1109
|
+
PyErr_SetString(PyExc_AttributeError, "attribute is not settable");
|
|
1110
|
+
return -1;
|
|
1111
|
+
}
|
|
1008
1112
|
}
|
|
1009
1113
|
|
|
1010
1114
|
static PyTypeObject PrivateWrapType = {
|
|
@@ -1028,7 +1132,7 @@ static PyTypeObject PrivateWrapType = {
|
|
|
1028
1132
|
0, // tp_setattro
|
|
1029
1133
|
0, // tp_as_buffer
|
|
1030
1134
|
Py_TPFLAGS_DEFAULT, // tp_flags
|
|
1031
|
-
"_PrivateWrap",
|
|
1135
|
+
"private_attribute._PrivateWrap", // tp_doc
|
|
1032
1136
|
0, // tp_traverse
|
|
1033
1137
|
0, // tp_clear
|
|
1034
1138
|
0, // tp_richcompare
|
|
@@ -1038,6 +1142,10 @@ static PyTypeObject PrivateWrapType = {
|
|
|
1038
1142
|
0, // tp_methods
|
|
1039
1143
|
PrivateWrap_members, // tp_members
|
|
1040
1144
|
PrivateWrap_getset, // tp_getset
|
|
1145
|
+
0, // tp_base
|
|
1146
|
+
0, // tp_dict
|
|
1147
|
+
PrivateWrap_descrget, // tp_descr_get
|
|
1148
|
+
PrivateWrap_descrset, // tp_descr_set
|
|
1041
1149
|
};
|
|
1042
1150
|
|
|
1043
1151
|
static PrivateWrapObject*
|
|
@@ -1814,12 +1922,17 @@ need_analyse_type(PyObject* type) noexcept
|
|
|
1814
1922
|
}
|
|
1815
1923
|
#if PY_VERSION_HEX < 0x030D0000
|
|
1816
1924
|
PyObject* metaclass = PyWeakref_GET_OBJECT(metaclassref);
|
|
1925
|
+
if (type == metaclass) continue;
|
|
1817
1926
|
if (PyObject_IsInstance(type, metaclass)) {
|
|
1818
1927
|
return true;
|
|
1819
1928
|
}
|
|
1820
1929
|
#else
|
|
1821
1930
|
PyObject* metaclass;
|
|
1822
1931
|
if (PyWeakref_GetRef(metaclassref, &metaclass) == 1) {
|
|
1932
|
+
if (type == metaclass) {
|
|
1933
|
+
Py_DECREF(metaclass);
|
|
1934
|
+
continue;
|
|
1935
|
+
}
|
|
1823
1936
|
if (PyObject_IsInstance(type, metaclass)) {
|
|
1824
1937
|
Py_DECREF(metaclass);
|
|
1825
1938
|
return true;
|
|
@@ -1831,157 +1944,6 @@ need_analyse_type(PyObject* type) noexcept
|
|
|
1831
1944
|
return false;
|
|
1832
1945
|
}
|
|
1833
1946
|
|
|
1834
|
-
static void
|
|
1835
|
-
get_getattribute_and_getattr(PyTypeObject* cls, PyObject** getattribute, PyObject** getattr) noexcept
|
|
1836
|
-
{
|
|
1837
|
-
bool has_getattribute = false;
|
|
1838
|
-
bool has_getattr = false;
|
|
1839
|
-
if (PyDict_ContainsString(cls->tp_dict, "__getattribute__")) {
|
|
1840
|
-
*getattribute = PyDict_GetItemString(cls->tp_dict, "__getattribute__");
|
|
1841
|
-
has_getattribute = true;
|
|
1842
|
-
}
|
|
1843
|
-
if (PyDict_ContainsString(cls->tp_dict, "__getattr__")) {
|
|
1844
|
-
*getattr = PyDict_GetItemString(cls->tp_dict, "__getattr__");
|
|
1845
|
-
has_getattr = true;
|
|
1846
|
-
}
|
|
1847
|
-
if (has_getattribute && has_getattr) {
|
|
1848
|
-
return;
|
|
1849
|
-
}
|
|
1850
|
-
for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
|
|
1851
|
-
if (!has_getattribute && PyDict_ContainsString(base->tp_dict, "__getattribute__")) {
|
|
1852
|
-
*getattribute = PyDict_GetItemString(base->tp_dict, "__getattribute__");
|
|
1853
|
-
has_getattribute = true;
|
|
1854
|
-
}
|
|
1855
|
-
if (!has_getattr && PyDict_ContainsString(base->tp_dict, "__getattr__")) {
|
|
1856
|
-
*getattr = PyDict_GetItemString(base->tp_dict, "__getattr__");
|
|
1857
|
-
has_getattr = true;
|
|
1858
|
-
}
|
|
1859
|
-
if (has_getattribute && has_getattr) {
|
|
1860
|
-
return;
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
|
|
1865
|
-
static void
|
|
1866
|
-
get_setattr_and_delattr(PyTypeObject* cls, PyObject** setattr, PyObject** delattr) noexcept
|
|
1867
|
-
{
|
|
1868
|
-
bool has_setattr = false;
|
|
1869
|
-
bool has_delattr = false;
|
|
1870
|
-
if (PyDict_ContainsString(cls->tp_dict, "__setattr__")) {
|
|
1871
|
-
*setattr = PyDict_GetItemString(cls->tp_dict, "__setattr__");
|
|
1872
|
-
has_setattr = true;
|
|
1873
|
-
}
|
|
1874
|
-
if (PyDict_ContainsString(cls->tp_dict, "__delattr__")) {
|
|
1875
|
-
*delattr = PyDict_GetItemString(cls->tp_dict, "__delattr__");
|
|
1876
|
-
has_delattr = true;
|
|
1877
|
-
}
|
|
1878
|
-
if (has_setattr && has_delattr) {
|
|
1879
|
-
return;
|
|
1880
|
-
}
|
|
1881
|
-
for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
|
|
1882
|
-
if (!has_setattr && PyDict_ContainsString(base->tp_dict, "__setattr__")) {
|
|
1883
|
-
*setattr = PyDict_GetItemString(base->tp_dict, "__setattr__");
|
|
1884
|
-
has_setattr = true;
|
|
1885
|
-
}
|
|
1886
|
-
if (!has_delattr && PyDict_ContainsString(base->tp_dict, "__delattr__")) {
|
|
1887
|
-
*delattr = PyDict_GetItemString(base->tp_dict, "__delattr__");
|
|
1888
|
-
has_delattr = true;
|
|
1889
|
-
}
|
|
1890
|
-
if (has_setattr && has_delattr) {
|
|
1891
|
-
return;
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
static void
|
|
1897
|
-
get_del(PyTypeObject* cls, PyObject** del) noexcept
|
|
1898
|
-
{
|
|
1899
|
-
if (PyDict_ContainsString(cls->tp_dict, "__del__")) {
|
|
1900
|
-
*del = PyDict_GetItemString(cls->tp_dict, "__del__");
|
|
1901
|
-
return;
|
|
1902
|
-
}
|
|
1903
|
-
for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
|
|
1904
|
-
if (PyDict_ContainsString(base->tp_dict, "__del__")) {
|
|
1905
|
-
*del = PyDict_GetItemString(base->tp_dict, "__del__");
|
|
1906
|
-
return;
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
static PyObject*
|
|
1912
|
-
python_original_tp_getattro(PyObject* self, PyObject* name) noexcept
|
|
1913
|
-
{
|
|
1914
|
-
PyObject* getattriute = NULL;
|
|
1915
|
-
PyObject* getattr = NULL;
|
|
1916
|
-
get_getattribute_and_getattr((PyTypeObject*)self->ob_type, &getattriute, &getattr);
|
|
1917
|
-
PyObject* res = NULL;
|
|
1918
|
-
if (getattriute) {
|
|
1919
|
-
res = PyObject_CallFunctionObjArgs(getattriute, self, name, NULL);
|
|
1920
|
-
} else {
|
|
1921
|
-
res = PyObject_GenericGetAttr(self, name);
|
|
1922
|
-
}
|
|
1923
|
-
if (!res && getattr) {
|
|
1924
|
-
// check if the exception is AttributeError
|
|
1925
|
-
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
|
1926
|
-
return NULL;
|
|
1927
|
-
}
|
|
1928
|
-
PyErr_Clear();
|
|
1929
|
-
res = PyObject_CallFunctionObjArgs(getattr, self, name, NULL);
|
|
1930
|
-
}
|
|
1931
|
-
return res;
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
static int
|
|
1935
|
-
python_original_tp_setattro(PyObject* self, PyObject* name, PyObject* value) noexcept
|
|
1936
|
-
{
|
|
1937
|
-
PyObject* setattr = NULL;
|
|
1938
|
-
PyObject* delattr = NULL;
|
|
1939
|
-
get_setattr_and_delattr((PyTypeObject*)self->ob_type, &setattr, &delattr);
|
|
1940
|
-
if (value && setattr) {
|
|
1941
|
-
PyObject* res = PyObject_CallFunctionObjArgs(setattr, self, name, value, NULL);
|
|
1942
|
-
if (!res) {
|
|
1943
|
-
return -1;
|
|
1944
|
-
}
|
|
1945
|
-
Py_DECREF(res);
|
|
1946
|
-
return 0;
|
|
1947
|
-
} else if (!value && delattr) {
|
|
1948
|
-
PyObject* res = PyObject_CallFunctionObjArgs(delattr, self, name, NULL);
|
|
1949
|
-
if (!res) {
|
|
1950
|
-
return -1;
|
|
1951
|
-
}
|
|
1952
|
-
Py_DECREF(res);
|
|
1953
|
-
return 0;
|
|
1954
|
-
}
|
|
1955
|
-
return PyObject_GenericSetAttr(self, name, value);
|
|
1956
|
-
}
|
|
1957
|
-
|
|
1958
|
-
static void
|
|
1959
|
-
python_original_tp_finalize(PyObject* self) noexcept
|
|
1960
|
-
{
|
|
1961
|
-
PyObject* del = NULL;
|
|
1962
|
-
get_del((PyTypeObject*)self->ob_type, &del);
|
|
1963
|
-
if (del) {
|
|
1964
|
-
PyObject *exc_type = NULL, *exc_value = NULL, *exc_tb = NULL;
|
|
1965
|
-
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
|
|
1966
|
-
PyObject *result = PyObject_CallFunctionObjArgs(del, self, NULL);
|
|
1967
|
-
if (result == NULL) {
|
|
1968
|
-
// python < 3.13 use PyErr_WriteUnraisable, python >= 3.13 use PyErr_FormatUnraisable
|
|
1969
|
-
# if PY_VERSION_HEX >= 0x030D0000
|
|
1970
|
-
PyErr_FormatUnraisable("Exception ignored while "
|
|
1971
|
-
"calling deallocator %R", del);
|
|
1972
|
-
# else
|
|
1973
|
-
PyErr_WriteUnraisable(del);
|
|
1974
|
-
# endif
|
|
1975
|
-
}
|
|
1976
|
-
else {
|
|
1977
|
-
Py_DECREF(result);
|
|
1978
|
-
}
|
|
1979
|
-
if (exc_type != NULL) {
|
|
1980
|
-
PyErr_Restore(exc_type, exc_value, exc_tb);
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
|
|
1985
1947
|
static bool
|
|
1986
1948
|
PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationData& data) noexcept
|
|
1987
1949
|
{
|
|
@@ -2223,67 +2185,55 @@ ensure_tp(PyTypeObject* type_instance) noexcept
|
|
|
2223
2185
|
uintptr_t type_id = (uintptr_t)(type_instance);
|
|
2224
2186
|
{
|
|
2225
2187
|
if (type_instance->tp_getattro != PrivateAttr_tp_getattro) {
|
|
2226
|
-
if (!type_instance->tp_getattro) {
|
|
2188
|
+
if (!type_instance->tp_getattro && ::AllData::all_type_getattro.find(type_id) == ::AllData::all_type_getattro.end()) {
|
|
2227
2189
|
::AllData::all_type_getattro[type_id] = get_need_tp_getattro(type_instance);
|
|
2228
2190
|
} else {
|
|
2229
2191
|
::AllData::all_type_getattro[type_id] = type_instance->tp_getattro;
|
|
2230
2192
|
}
|
|
2231
2193
|
type_instance->tp_getattro = PrivateAttr_tp_getattro;
|
|
2232
|
-
} else {
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
::AllData::all_type_getattro[type_id] = ::AllData::all_type_getattro[base_id];
|
|
2240
|
-
} else if (base && base->tp_getattro && base->tp_getattro != PrivateAttr_tp_getattro) {
|
|
2241
|
-
::AllData::all_type_getattro[type_id] = base->tp_getattro;
|
|
2242
|
-
}
|
|
2194
|
+
} else if (::AllData::all_type_getattro.find(type_id) == ::AllData::all_type_getattro.end()) {
|
|
2195
|
+
PyTypeObject* base = type_instance->tp_base;
|
|
2196
|
+
uintptr_t base_id = (uintptr_t)(base);
|
|
2197
|
+
if (::AllData::all_type_getattro.find(base_id) != ::AllData::all_type_getattro.end()) {
|
|
2198
|
+
::AllData::all_type_getattro[type_id] = ::AllData::all_type_getattro[base_id];
|
|
2199
|
+
} else if (base && base->tp_getattro && base->tp_getattro != PrivateAttr_tp_getattro) {
|
|
2200
|
+
::AllData::all_type_getattro[type_id] = base->tp_getattro;
|
|
2243
2201
|
}
|
|
2244
2202
|
}
|
|
2245
2203
|
}
|
|
2246
2204
|
{
|
|
2247
2205
|
if (type_instance->tp_setattro != PrivateAttr_tp_setattro) {
|
|
2248
|
-
if (!type_instance->tp_setattro) {
|
|
2206
|
+
if (!type_instance->tp_setattro && ::AllData::all_type_setattro.find(type_id) == ::AllData::all_type_setattro.end()) {
|
|
2249
2207
|
::AllData::all_type_setattro[type_id] = get_need_tp_setattro(type_instance);
|
|
2250
2208
|
} else {
|
|
2251
2209
|
::AllData::all_type_setattro[type_id] = type_instance->tp_setattro;
|
|
2252
2210
|
}
|
|
2253
2211
|
type_instance->tp_setattro = PrivateAttr_tp_setattro;
|
|
2254
|
-
} else {
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
::AllData::all_type_setattro[type_id] = ::AllData::all_type_setattro[base_id];
|
|
2262
|
-
} else if (base && base->tp_setattro && base->tp_setattro != PrivateAttr_tp_setattro) {
|
|
2263
|
-
::AllData::all_type_setattro[type_id] = base->tp_setattro;
|
|
2264
|
-
}
|
|
2212
|
+
} else if (::AllData::all_type_setattro.find(type_id) == ::AllData::all_type_setattro.end()){
|
|
2213
|
+
PyTypeObject* base = type_instance->tp_base;
|
|
2214
|
+
uintptr_t base_id = (uintptr_t)(base);
|
|
2215
|
+
if (::AllData::all_type_setattro.find(base_id) != ::AllData::all_type_setattro.end()) {
|
|
2216
|
+
::AllData::all_type_setattro[type_id] = ::AllData::all_type_setattro[base_id];
|
|
2217
|
+
} else if (base && base->tp_setattro && base->tp_setattro != PrivateAttr_tp_setattro) {
|
|
2218
|
+
::AllData::all_type_setattro[type_id] = base->tp_setattro;
|
|
2265
2219
|
}
|
|
2266
2220
|
}
|
|
2267
2221
|
}
|
|
2268
2222
|
{
|
|
2269
2223
|
if (type_instance->tp_finalize != PrivateAttr_tp_finalize) {
|
|
2270
|
-
if (!type_instance->tp_finalize) {
|
|
2224
|
+
if (!type_instance->tp_finalize && ::AllData::all_type_finalize.find(type_id) == ::AllData::all_type_finalize.end()) {
|
|
2271
2225
|
::AllData::all_type_finalize[type_id] = get_need_tp_finalize(type_instance);
|
|
2272
2226
|
} else {
|
|
2273
2227
|
::AllData::all_type_finalize[type_id] = type_instance->tp_finalize;
|
|
2274
2228
|
}
|
|
2275
2229
|
type_instance->tp_finalize = PrivateAttr_tp_finalize;
|
|
2276
|
-
} else {
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
::AllData::all_type_finalize[type_id] = ::AllData::all_type_finalize[base_id];
|
|
2284
|
-
} else if (base && base->tp_finalize && base->tp_finalize != PrivateAttr_tp_finalize) {
|
|
2285
|
-
::AllData::all_type_finalize[type_id] = base->tp_finalize;
|
|
2286
|
-
}
|
|
2230
|
+
} else if (::AllData::all_type_finalize.find(type_id) == ::AllData::all_type_finalize.end()) {
|
|
2231
|
+
PyTypeObject* base = type_instance->tp_base;
|
|
2232
|
+
uintptr_t base_id = (uintptr_t)(base);
|
|
2233
|
+
if (::AllData::all_type_finalize.find(base_id) != ::AllData::all_type_finalize.end()) {
|
|
2234
|
+
::AllData::all_type_finalize[type_id] = ::AllData::all_type_finalize[base_id];
|
|
2235
|
+
} else if (base && base->tp_finalize && base->tp_finalize != PrivateAttr_tp_finalize) {
|
|
2236
|
+
::AllData::all_type_finalize[type_id] = base->tp_finalize;
|
|
2287
2237
|
}
|
|
2288
2238
|
}
|
|
2289
2239
|
}
|
|
@@ -2292,40 +2242,16 @@ ensure_tp(PyTypeObject* type_instance) noexcept
|
|
|
2292
2242
|
static void
|
|
2293
2243
|
ensure_subclass_tp(PyTypeObject* type_instance) noexcept
|
|
2294
2244
|
{
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
}
|
|
2303
|
-
// check all values in the dict. It should be a weakref to a type. If not, continue.
|
|
2304
|
-
PyObject* key, *value;
|
|
2305
|
-
Py_ssize_t pos = 0;
|
|
2306
|
-
while (PyDict_Next(type_subclasses, &pos, &key, &value)) {
|
|
2307
|
-
if (!value || !PyWeakref_CheckRef(value)) {
|
|
2308
|
-
continue;
|
|
2309
|
-
}
|
|
2310
|
-
// python<3.13 use PyWeakref_GetObject, python>=3.13 use PyWeakref_GetRef
|
|
2311
|
-
#if PY_VERSION_HEX < 0x030D0000
|
|
2312
|
-
PyObject* subclass = PyWeakref_GetObject(value);
|
|
2313
|
-
if (!subclass || !PyType_Check(subclass)) {
|
|
2314
|
-
continue;
|
|
2315
|
-
}
|
|
2316
|
-
ensure_tp((PyTypeObject*)subclass);
|
|
2317
|
-
#else
|
|
2318
|
-
PyObject* subclass;
|
|
2319
|
-
if (PyWeakref_GetRef(value, (PyObject**)&subclass) != 1) {
|
|
2320
|
-
continue;
|
|
2321
|
-
}
|
|
2322
|
-
if (!subclass || !PyType_Check(subclass)) {
|
|
2323
|
-
continue;
|
|
2324
|
-
}
|
|
2245
|
+
PyObject* subclasses = PyObject_CallMethod((PyObject*)&PyType_Type, "__subclasses__", "O", (PyObject*)type_instance);
|
|
2246
|
+
assert(subclasses);
|
|
2247
|
+
assert(PyList_Check(subclasses));
|
|
2248
|
+
Py_ssize_t list_len = PyList_GET_SIZE(subclasses);
|
|
2249
|
+
for (Py_ssize_t i = 0; i < list_len; i++) {
|
|
2250
|
+
PyObject* subclass = PyList_GetItem(subclasses, i);
|
|
2251
|
+
if (!PyType_Check(subclass)) continue;
|
|
2325
2252
|
ensure_tp((PyTypeObject*)subclass);
|
|
2326
|
-
Py_XDECREF(subclass);
|
|
2327
|
-
#endif
|
|
2328
2253
|
}
|
|
2254
|
+
Py_DECREF(subclasses);
|
|
2329
2255
|
}
|
|
2330
2256
|
|
|
2331
2257
|
static bool
|
|
@@ -2348,15 +2274,6 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data) n
|
|
|
2348
2274
|
}
|
|
2349
2275
|
|
|
2350
2276
|
ensure_tp(type_instance);
|
|
2351
|
-
if (PyDict_ContainsString(type_instance->tp_dict, "__getattribute__") || PyDict_ContainsString(type_instance->tp_dict, "__getattr__")) {
|
|
2352
|
-
::AllData::all_type_getattro[type_id] = AllSlots::original_getattro;
|
|
2353
|
-
}
|
|
2354
|
-
if (PyDict_ContainsString(type_instance->tp_dict, "__setattr__") || PyDict_ContainsString(type_instance->tp_dict, "__delattr__")) {
|
|
2355
|
-
::AllData::all_type_setattro[type_id] = AllSlots::original_setattro;
|
|
2356
|
-
}
|
|
2357
|
-
if (PyDict_ContainsString(type_instance->tp_dict, "__del__")) {
|
|
2358
|
-
::AllData::all_type_finalize[type_id] = AllSlots::original_finalize;
|
|
2359
|
-
}
|
|
2360
2277
|
|
|
2361
2278
|
::AllData::type_attr_dict[type_id] = {};
|
|
2362
2279
|
::AllData::all_type_attr_set[type_id] = data.private_attrs_set;
|
|
@@ -2510,21 +2427,95 @@ PrivateAttrType_getattr(PyObject* cls, PyObject* name) noexcept
|
|
|
2510
2427
|
return result;
|
|
2511
2428
|
}
|
|
2512
2429
|
|
|
2430
|
+
static setattrofunc original_type_tp_setattro = 0;
|
|
2431
|
+
|
|
2432
|
+
static bool
|
|
2433
|
+
is_registed_type(PyObject* type) noexcept
|
|
2434
|
+
{
|
|
2435
|
+
uintptr_t typ_id = (uintptr_t)type;
|
|
2436
|
+
return (AllData::all_register_type_weak_ref.find(typ_id) != AllData::all_register_type_weak_ref.end());
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
static PyObject* ensure_metaclass_tp(PyObject* /*self*/, PyObject* metaclass) noexcept;
|
|
2440
|
+
|
|
2441
|
+
static int
|
|
2442
|
+
new_type_tp_setattro(PyObject* self, PyObject* name, PyObject* value) noexcept
|
|
2443
|
+
{
|
|
2444
|
+
std::vector<PyObject*> need_analyse_types_and_metaclasses;
|
|
2445
|
+
std::vector<PyObject*> registered_types_and_metaclasses;
|
|
2446
|
+
std::vector<PyObject*> all_subclasses;
|
|
2447
|
+
PyObject* subclasses = PyObject_CallMethod((PyObject*)&PyType_Type, "__subclasses__", "O", self);
|
|
2448
|
+
if (!subclasses) return -1;
|
|
2449
|
+
if (!PyList_Check(subclasses)) {
|
|
2450
|
+
PyErr_SetString(PyExc_TypeError, "subclasses of this class is not list");
|
|
2451
|
+
Py_DECREF(subclasses);
|
|
2452
|
+
return -1;
|
|
2453
|
+
}
|
|
2454
|
+
Py_ssize_t list_len = PyList_GET_SIZE(subclasses);
|
|
2455
|
+
for (Py_ssize_t i = 0; i < list_len; i++) {
|
|
2456
|
+
all_subclasses.push_back(PyList_GET_ITEM(subclasses, i));
|
|
2457
|
+
}
|
|
2458
|
+
if (need_analyse_type(self)) {
|
|
2459
|
+
need_analyse_types_and_metaclasses.push_back(self);
|
|
2460
|
+
} else if (is_registed_type(self)) {
|
|
2461
|
+
registered_types_and_metaclasses.push_back(self);
|
|
2462
|
+
}
|
|
2463
|
+
for (auto& i: all_subclasses) {
|
|
2464
|
+
if (need_analyse_type(i)) {
|
|
2465
|
+
need_analyse_types_and_metaclasses.push_back(i);
|
|
2466
|
+
} else if (is_registed_type(i)) {
|
|
2467
|
+
registered_types_and_metaclasses.push_back(i);
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
int result = original_type_tp_setattro(self, name, value);
|
|
2471
|
+
for (auto& i: need_analyse_types_and_metaclasses) {
|
|
2472
|
+
ensure_tp((PyTypeObject*)i);
|
|
2473
|
+
}
|
|
2474
|
+
for (auto& i: registered_types_and_metaclasses) {
|
|
2475
|
+
ensure_metaclass_tp(0, i);
|
|
2476
|
+
}
|
|
2477
|
+
Py_DECREF(subclasses);
|
|
2478
|
+
return result;
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2513
2481
|
static int
|
|
2514
2482
|
init_all_slots() noexcept
|
|
2515
2483
|
{
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2484
|
+
original_type_tp_setattro = PyType_Type.tp_setattro;
|
|
2485
|
+
PyObject* original_setattr = PyObject_GetAttrString((PyObject*)&PyType_Type, "__setattr__");
|
|
2486
|
+
if (!original_setattr) {return -1;}
|
|
2487
|
+
if (original_setattr && PyObject_IsInstance(original_setattr, (PyObject*)&PyWrapperDescr_Type)) {
|
|
2488
|
+
((PyWrapperDescrObject*)original_setattr)->d_wrapped = (void*)new_type_tp_setattro;
|
|
2489
|
+
}
|
|
2490
|
+
Py_DECREF(original_setattr);
|
|
2491
|
+
PyObject* original_delattr = PyObject_GetAttrString((PyObject*)&PyType_Type, "__delattr__");
|
|
2492
|
+
if (!original_delattr) {return -1;}
|
|
2493
|
+
if (original_delattr && PyObject_IsInstance(original_delattr, (PyObject*)&PyWrapperDescr_Type)) {
|
|
2494
|
+
((PyWrapperDescrObject*)original_delattr)->d_wrapped = (void*)new_type_tp_setattro;
|
|
2495
|
+
}
|
|
2496
|
+
Py_DECREF(original_delattr);
|
|
2497
|
+
PyType_Type.tp_setattro = new_type_tp_setattro;
|
|
2498
|
+
PyObject* all_metaclasses = PyObject_CallMethod((PyObject*)&PyType_Type, "__subclasses__", "O", (PyObject*)&PyType_Type);
|
|
2499
|
+
if (!all_metaclasses) {return -1;}
|
|
2500
|
+
if (!PyList_Check(all_metaclasses)) {
|
|
2501
|
+
Py_DECREF(all_metaclasses);
|
|
2502
|
+
return 0;
|
|
2503
|
+
}
|
|
2504
|
+
Py_ssize_t list_len = PyList_GET_SIZE(all_metaclasses);
|
|
2505
|
+
for (Py_ssize_t i = 0; i < list_len; i++) {
|
|
2506
|
+
PyObject* metaclass = PyList_GET_ITEM(all_metaclasses, i);
|
|
2507
|
+
if (!PyType_Check(metaclass)) {continue;}
|
|
2508
|
+
if (((PyTypeObject*)metaclass)->tp_setattro == original_type_tp_setattro) {
|
|
2509
|
+
((PyTypeObject*)metaclass)->tp_setattro = new_type_tp_setattro;
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
Py_DECREF(all_metaclasses);
|
|
2519
2513
|
return 0;
|
|
2520
2514
|
}
|
|
2521
2515
|
|
|
2522
2516
|
static getattrofunc
|
|
2523
2517
|
get_need_tp_getattro(PyTypeObject* cls) noexcept
|
|
2524
2518
|
{
|
|
2525
|
-
if (PyDict_ContainsString(cls->tp_dict, "__getattribute__") || PyDict_ContainsString(cls->tp_dict, "__getattr__")) {
|
|
2526
|
-
return AllSlots::original_getattro;
|
|
2527
|
-
}
|
|
2528
2519
|
PyTypeObject* base = cls->tp_base;
|
|
2529
2520
|
while (base) {
|
|
2530
2521
|
if (base->tp_getattro != PrivateAttr_tp_getattro) {
|
|
@@ -2544,9 +2535,6 @@ get_need_tp_getattro(PyTypeObject* cls) noexcept
|
|
|
2544
2535
|
static setattrofunc
|
|
2545
2536
|
get_need_tp_setattro(PyTypeObject* cls) noexcept
|
|
2546
2537
|
{
|
|
2547
|
-
if (PyDict_ContainsString(cls->tp_dict, "__setattr__") || PyDict_ContainsString(cls->tp_dict, "__delattr__")) {
|
|
2548
|
-
return AllSlots::original_setattro;
|
|
2549
|
-
}
|
|
2550
2538
|
PyTypeObject* base = cls->tp_base;
|
|
2551
2539
|
while (base) {
|
|
2552
2540
|
if (base->tp_setattro != PrivateAttr_tp_setattro) {
|
|
@@ -2566,9 +2554,6 @@ get_need_tp_setattro(PyTypeObject* cls) noexcept
|
|
|
2566
2554
|
static destructor
|
|
2567
2555
|
get_need_tp_finalize(PyTypeObject* cls) noexcept
|
|
2568
2556
|
{
|
|
2569
|
-
if (PyDict_ContainsString(cls->tp_dict, "__del__")) {
|
|
2570
|
-
return AllSlots::original_finalize;
|
|
2571
|
-
}
|
|
2572
2557
|
PyTypeObject* base = cls->tp_base;
|
|
2573
2558
|
while (base) {
|
|
2574
2559
|
if (base->tp_finalize != PrivateAttr_tp_finalize) {
|
|
@@ -2585,64 +2570,6 @@ get_need_tp_finalize(PyTypeObject* cls) noexcept
|
|
|
2585
2570
|
return NULL;
|
|
2586
2571
|
}
|
|
2587
2572
|
|
|
2588
|
-
static void
|
|
2589
|
-
type_change_all_slots(PyTypeObject* cls, const char* name) noexcept
|
|
2590
|
-
{
|
|
2591
|
-
if (strcmp(name, "__getattribute__") == 0 || strcmp(name, "__getattr__") == 0) {
|
|
2592
|
-
cls->tp_getattro = PrivateAttr_tp_getattro;
|
|
2593
|
-
::AllData::all_type_getattro[(uintptr_t)cls] = get_need_tp_getattro(cls);
|
|
2594
|
-
} else if (strcmp(name, "__setattr__") == 0 || strcmp(name, "__delattr__") == 0) {
|
|
2595
|
-
cls->tp_setattro = PrivateAttr_tp_setattro;
|
|
2596
|
-
::AllData::all_type_setattro[(uintptr_t)cls] = get_need_tp_setattro(cls);
|
|
2597
|
-
} else if (strcmp(name, "__del__") == 0) {
|
|
2598
|
-
cls->tp_finalize = PrivateAttr_tp_finalize;
|
|
2599
|
-
::AllData::all_type_finalize[(uintptr_t)cls] = get_need_tp_finalize(cls);
|
|
2600
|
-
}
|
|
2601
|
-
}
|
|
2602
|
-
|
|
2603
|
-
static void
|
|
2604
|
-
subtype_change_all_slots(PyTypeObject* cls, const char* name) noexcept
|
|
2605
|
-
{
|
|
2606
|
-
// tp_subclasses: {id(type): weakref.ref(type)}
|
|
2607
|
-
PyObject* tp_subclasses = (PyObject*)cls->tp_subclasses;
|
|
2608
|
-
if (!tp_subclasses) {
|
|
2609
|
-
return;
|
|
2610
|
-
}
|
|
2611
|
-
if (!PyDict_Check(tp_subclasses)) {
|
|
2612
|
-
return;
|
|
2613
|
-
}
|
|
2614
|
-
PyObject* key;
|
|
2615
|
-
PyObject* value;
|
|
2616
|
-
Py_ssize_t pos = 0;
|
|
2617
|
-
while (PyDict_Next(tp_subclasses, &pos, &key, &value)) {
|
|
2618
|
-
if (!PyWeakref_Check(value)) {
|
|
2619
|
-
continue;
|
|
2620
|
-
}
|
|
2621
|
-
#if PY_VERSION_HEX < 0x030D0000
|
|
2622
|
-
PyObject* obj = PyWeakref_GET_OBJECT(value);
|
|
2623
|
-
if (!obj) {
|
|
2624
|
-
continue;
|
|
2625
|
-
}
|
|
2626
|
-
#else
|
|
2627
|
-
PyObject* obj;
|
|
2628
|
-
if (PyWeakref_GetRef(value, &obj) != 1) {
|
|
2629
|
-
continue;
|
|
2630
|
-
}
|
|
2631
|
-
if (!obj) {
|
|
2632
|
-
continue;
|
|
2633
|
-
}
|
|
2634
|
-
#endif
|
|
2635
|
-
if (!PyType_Check(obj)) {
|
|
2636
|
-
continue;
|
|
2637
|
-
}
|
|
2638
|
-
PyTypeObject* sub_cls = (PyTypeObject*)obj;
|
|
2639
|
-
type_change_all_slots(sub_cls, name);
|
|
2640
|
-
#if PY_VERSION_HEX >= 0x030D0000
|
|
2641
|
-
Py_XDECREF(obj);
|
|
2642
|
-
#endif
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
|
|
2646
2573
|
static int
|
|
2647
2574
|
PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value) noexcept
|
|
2648
2575
|
{
|
|
@@ -2669,42 +2596,12 @@ PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value) noexcept
|
|
|
2669
2596
|
return type_setattr(cls, name_str, value);
|
|
2670
2597
|
}
|
|
2671
2598
|
Py_XDECREF(now_code);
|
|
2672
|
-
// if name in __getattribute__, __setattr__, __delattr__, __del__, just set to tp_dict
|
|
2673
|
-
if (strcmp(name_str.c_str(), "__getattribute__") == 0 ||
|
|
2674
|
-
strcmp(name_str.c_str(), "__getattr__") == 0 ||
|
|
2675
|
-
strcmp(name_str.c_str(), "__setattr__") == 0 ||
|
|
2676
|
-
strcmp(name_str.c_str(), "__delattr__") == 0 ||
|
|
2677
|
-
strcmp(name_str.c_str(), "__del__") == 0) {
|
|
2678
|
-
PyObject* tp_dict = ((PyTypeObject*)cls)->tp_dict;
|
|
2679
|
-
if (!tp_dict) {
|
|
2680
|
-
PyErr_SetString(PyExc_TypeError, "type has no tp_dict");
|
|
2681
|
-
return -1;
|
|
2682
|
-
}
|
|
2683
|
-
if (!value) {
|
|
2684
|
-
if (PyDict_DelItem(tp_dict, name) < 0) {
|
|
2685
|
-
PyErr_Format(PyExc_AttributeError, "type object '%.100s' has no attribute '%U'", ((PyTypeObject*)cls)->tp_name, name);
|
|
2686
|
-
return -1;
|
|
2687
|
-
}
|
|
2688
|
-
type_change_all_slots((PyTypeObject*)cls, name_str.c_str());
|
|
2689
|
-
subtype_change_all_slots((PyTypeObject*)cls, name_str.c_str());
|
|
2690
|
-
return 0;
|
|
2691
|
-
}
|
|
2692
|
-
if (PyDict_SetItem(tp_dict, name, value) < 0) {
|
|
2693
|
-
return -1;
|
|
2694
|
-
}
|
|
2695
|
-
type_change_all_slots((PyTypeObject*)cls, name_str.c_str());
|
|
2696
|
-
subtype_change_all_slots((PyTypeObject*)cls, name_str.c_str());
|
|
2697
|
-
return 0;
|
|
2698
|
-
}
|
|
2699
2599
|
PyTypeObject* base = Py_TYPE(cls)->tp_base;
|
|
2700
2600
|
while (base && base->tp_base && base->tp_setattro == PrivateAttrType_setattr) {
|
|
2701
2601
|
base = base->tp_base;
|
|
2702
2602
|
}
|
|
2703
2603
|
if (!base) {
|
|
2704
|
-
|
|
2705
|
-
ensure_tp((PyTypeObject*)cls);
|
|
2706
|
-
ensure_subclass_tp((PyTypeObject*)cls);
|
|
2707
|
-
return result;
|
|
2604
|
+
return new_type_tp_setattro(cls, name, value);
|
|
2708
2605
|
}
|
|
2709
2606
|
int result = base->tp_setattro(cls, name, value);
|
|
2710
2607
|
ensure_tp((PyTypeObject*)cls);
|
|
@@ -2790,7 +2687,7 @@ static const char* PrivateAttrBase_doc = "The class to help to create private at
|
|
|
2790
2687
|
static PyObject*
|
|
2791
2688
|
create_private_attr_base_simple(void) noexcept
|
|
2792
2689
|
{
|
|
2793
|
-
PyObject* name =
|
|
2690
|
+
PyObject* name = PyUnicode_InternFromString("PrivateAttrBase");
|
|
2794
2691
|
if (!name) return NULL;
|
|
2795
2692
|
PyObject* bases = PyTuple_New(0);
|
|
2796
2693
|
if (!bases) {
|
|
@@ -2812,8 +2709,8 @@ create_private_attr_base_simple(void) noexcept
|
|
|
2812
2709
|
}
|
|
2813
2710
|
PyDict_SetItemString(dict, "__private_attrs__", private_attrs);
|
|
2814
2711
|
PyDict_SetItemString(dict, "__slots__", private_attrs);
|
|
2815
|
-
PyDict_SetItemString(dict, "__doc__",
|
|
2816
|
-
PyDict_SetItemString(dict, "__module__",
|
|
2712
|
+
PyDict_SetItemString(dict, "__doc__", PyUnicode_InternFromString(PrivateAttrBase_doc));
|
|
2713
|
+
PyDict_SetItemString(dict, "__module__", PyUnicode_InternFromString("private_attribute"));
|
|
2817
2714
|
PyObject *args = PyTuple_Pack(3, name, bases, dict);
|
|
2818
2715
|
PyObject* base_type;
|
|
2819
2716
|
if (args) {
|
|
@@ -2905,7 +2802,7 @@ PrivateTempObject_dealloc(PyObject* self) noexcept
|
|
|
2905
2802
|
|
|
2906
2803
|
static PyTypeObject PrivateTempType = {
|
|
2907
2804
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
2908
|
-
"
|
|
2805
|
+
"private_attribute._PrivateTemp", // tp_name
|
|
2909
2806
|
sizeof(PrivateTempObject), // tp_basicsize
|
|
2910
2807
|
0, //tp_itemsize
|
|
2911
2808
|
PrivateTempObject_dealloc, //tp_dealloc
|
|
@@ -3021,8 +2918,40 @@ static PyMethodDef weakref_callback_def = {
|
|
|
3021
2918
|
NULL
|
|
3022
2919
|
};
|
|
3023
2920
|
|
|
2921
|
+
static bool
|
|
2922
|
+
is_class_of_registed_type(PyObject* metaclass) noexcept
|
|
2923
|
+
{
|
|
2924
|
+
std::shared_lock lock(::AllData::all_register_new_metaclass_mutex);
|
|
2925
|
+
for (auto& [id, instanceref]: ::AllData::all_register_type_weak_ref){
|
|
2926
|
+
if (!PyWeakref_CheckRef(instanceref)) {
|
|
2927
|
+
continue;
|
|
2928
|
+
}
|
|
2929
|
+
#if PY_VERSION_HEX < 0x030D0000
|
|
2930
|
+
PyObject* instance = PyWeakref_GET_OBJECT(instanceref);
|
|
2931
|
+
if (instance == metaclass) continue;
|
|
2932
|
+
if (PyObject_IsInstance(instance, metaclass)) {
|
|
2933
|
+
return true;
|
|
2934
|
+
}
|
|
2935
|
+
#else
|
|
2936
|
+
PyObject* instance;
|
|
2937
|
+
if (PyWeakref_GetRef(instanceref, &instance) == 1) {
|
|
2938
|
+
if (instance == metaclass) {
|
|
2939
|
+
Py_DECREF(instance);
|
|
2940
|
+
continue;
|
|
2941
|
+
}
|
|
2942
|
+
if (PyObject_IsInstance(instance, metaclass)) {
|
|
2943
|
+
Py_DECREF(instance);
|
|
2944
|
+
return true;
|
|
2945
|
+
}
|
|
2946
|
+
Py_DECREF(instance);
|
|
2947
|
+
}
|
|
2948
|
+
#endif
|
|
2949
|
+
}
|
|
2950
|
+
return false;
|
|
2951
|
+
}
|
|
2952
|
+
|
|
3024
2953
|
static PyObject*
|
|
3025
|
-
|
|
2954
|
+
register_metaclass_head(PyObject* metaclass) noexcept
|
|
3026
2955
|
{
|
|
3027
2956
|
if (!PyType_Check(metaclass)) {
|
|
3028
2957
|
PyErr_SetString(PyExc_TypeError, "metaclass must be a type");
|
|
@@ -3032,6 +2961,18 @@ register_metaclass(PyObject* /*self*/, PyObject* metaclass) noexcept
|
|
|
3032
2961
|
PyErr_SetString(PyExc_TypeError, "metaclass must be a metatype");
|
|
3033
2962
|
return NULL;
|
|
3034
2963
|
}
|
|
2964
|
+
if (metaclass == (PyObject*)&PyType_Type) {
|
|
2965
|
+
PyErr_SetString(PyExc_ValueError, "cannot register type itself");
|
|
2966
|
+
return NULL;
|
|
2967
|
+
}
|
|
2968
|
+
if (need_analyse_type(metaclass)) {
|
|
2969
|
+
PyErr_SetString(PyExc_ValueError, "cannot register type that is the instance of 'PrivateAttrType' or registed type");
|
|
2970
|
+
return NULL;
|
|
2971
|
+
}
|
|
2972
|
+
if (is_class_of_registed_type(metaclass)) {
|
|
2973
|
+
PyErr_SetString(PyExc_ValueError, "cannot register type that is the class of registed type");
|
|
2974
|
+
return NULL;
|
|
2975
|
+
}
|
|
3035
2976
|
uintptr_t id = (uintptr_t)metaclass;
|
|
3036
2977
|
|
|
3037
2978
|
std::unique_lock lock(::AllData::all_register_new_metaclass_mutex);
|
|
@@ -3062,6 +3003,27 @@ register_metaclass(PyObject* /*self*/, PyObject* metaclass) noexcept
|
|
|
3062
3003
|
Py_RETURN_NONE;
|
|
3063
3004
|
}
|
|
3064
3005
|
|
|
3006
|
+
static PyObject*
|
|
3007
|
+
register_metaclass(PyObject* /*self*/, PyObject* metaclass) noexcept
|
|
3008
|
+
{
|
|
3009
|
+
if (!register_metaclass_head(metaclass)) return NULL;
|
|
3010
|
+
PyObject* subclasses = PyObject_CallMethod((PyObject*)&PyType_Type, "__subclasses__", "O", metaclass);
|
|
3011
|
+
if (!subclasses) {
|
|
3012
|
+
PyErr_Clear();
|
|
3013
|
+
Py_RETURN_NONE;
|
|
3014
|
+
}
|
|
3015
|
+
Py_ssize_t list_len = PyList_GET_SIZE(subclasses);
|
|
3016
|
+
for (Py_ssize_t i = 0; i < list_len; i++) {
|
|
3017
|
+
PyObject* subclass = PyList_GET_ITEM(subclasses, i);
|
|
3018
|
+
if (!register_metaclass(0, subclass)) {
|
|
3019
|
+
Py_DECREF(subclasses);
|
|
3020
|
+
return NULL;
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
Py_DECREF(subclasses);
|
|
3024
|
+
Py_RETURN_NONE;
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3065
3027
|
static PyObject*
|
|
3066
3028
|
ensure_type_tp(PyObject* /*self*/, PyObject* type) noexcept
|
|
3067
3029
|
{
|
|
@@ -3144,8 +3106,16 @@ PrivateModule_dir(PyObject* self, PyObject* /*args*/) noexcept
|
|
|
3144
3106
|
return result;
|
|
3145
3107
|
}
|
|
3146
3108
|
|
|
3109
|
+
#define PrivateModule_GETATTRO_CASE(name) \
|
|
3110
|
+
do {\
|
|
3111
|
+
if (strcmp(name_cstr, #name) == 0) {\
|
|
3112
|
+
PyObject* attr = PrivateModule_get_##name(NULL, NULL);\
|
|
3113
|
+
return attr;\
|
|
3114
|
+
}\
|
|
3115
|
+
} while (0)
|
|
3116
|
+
|
|
3147
3117
|
static int
|
|
3148
|
-
PrivateModule_setattro(PyObject*
|
|
3118
|
+
PrivateModule_setattro(PyObject* self, PyObject* name, PyObject* value) noexcept
|
|
3149
3119
|
{
|
|
3150
3120
|
// if name is "__class__" it do nothing and return success
|
|
3151
3121
|
if (PyUnicode_Check(name)) {
|
|
@@ -3153,8 +3123,25 @@ PrivateModule_setattro(PyObject* cls, PyObject* name, PyObject* value) noexcept
|
|
|
3153
3123
|
if (name_cstr && strcmp(name_cstr, "__class__") == 0) {
|
|
3154
3124
|
return 0;
|
|
3155
3125
|
}
|
|
3126
|
+
static const char* unsetable_attrs[] = {
|
|
3127
|
+
"PrivateWrapProxy",
|
|
3128
|
+
"PrivateAttrType",
|
|
3129
|
+
"PrivateAttrBase",
|
|
3130
|
+
"prepare",
|
|
3131
|
+
"postprocess",
|
|
3132
|
+
"register_metaclass",
|
|
3133
|
+
"ensure_type",
|
|
3134
|
+
"ensure_metaclass"
|
|
3135
|
+
};
|
|
3136
|
+
const size_t num_attrs = sizeof(unsetable_attrs) / sizeof(unsetable_attrs[0]);
|
|
3137
|
+
for (size_t i = 0; i < num_attrs; ++i) {
|
|
3138
|
+
if (strcmp(name_cstr, unsetable_attrs[i]) == 0) {
|
|
3139
|
+
PyErr_Format(PyExc_AttributeError, "attribute '%s' of 'private_attribute_module' objects is not writable", name_cstr);
|
|
3140
|
+
return -1;
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3156
3143
|
}
|
|
3157
|
-
return
|
|
3144
|
+
return PyModule_Type.tp_setattro(self, name, value);
|
|
3158
3145
|
}
|
|
3159
3146
|
|
|
3160
3147
|
static const char* prepare_and_postprocess_doc = R"(function for custom metaclass to create private attributes class.
|
|
@@ -3251,44 +3238,66 @@ static PyMethodDef PrivateModule_methods_def[] = {
|
|
|
3251
3238
|
{NULL} // Sentinel
|
|
3252
3239
|
};
|
|
3253
3240
|
|
|
3241
|
+
static PyObject*
|
|
3242
|
+
PrivateModule_getattro(PyObject* self, PyObject* name) noexcept
|
|
3243
|
+
{
|
|
3244
|
+
if (!PyUnicode_Check(name)) {
|
|
3245
|
+
PyErr_SetString(PyExc_TypeError, "attribute name must be a string");
|
|
3246
|
+
return NULL;
|
|
3247
|
+
}
|
|
3248
|
+
const char* name_cstr = PyUnicode_AsUTF8(name);
|
|
3249
|
+
if (!name_cstr) {
|
|
3250
|
+
return NULL;
|
|
3251
|
+
}
|
|
3252
|
+
PrivateModule_GETATTRO_CASE(PrivateWrapProxy);
|
|
3253
|
+
PrivateModule_GETATTRO_CASE(PrivateAttrType);
|
|
3254
|
+
PrivateModule_GETATTRO_CASE(PrivateAttrBase);
|
|
3255
|
+
PrivateModule_GETATTRO_CASE(prepare);
|
|
3256
|
+
PrivateModule_GETATTRO_CASE(postprocess);
|
|
3257
|
+
PrivateModule_GETATTRO_CASE(register_metaclass);
|
|
3258
|
+
PrivateModule_GETATTRO_CASE(ensure_type);
|
|
3259
|
+
PrivateModule_GETATTRO_CASE(ensure_metaclass);
|
|
3260
|
+
return PyModule_Type.tp_getattro(self, name);
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3254
3263
|
static PyTypeObject PrivateModuleType = {
|
|
3255
3264
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
3256
|
-
"private_attribute_module", //tp_name
|
|
3257
|
-
PyModule_Type.tp_basicsize + 8,
|
|
3258
|
-
0,
|
|
3259
|
-
0,
|
|
3260
|
-
0,
|
|
3261
|
-
0,
|
|
3262
|
-
0,
|
|
3263
|
-
0,
|
|
3264
|
-
0,
|
|
3265
|
-
0,
|
|
3266
|
-
0,
|
|
3267
|
-
0,
|
|
3268
|
-
0,
|
|
3269
|
-
0,
|
|
3270
|
-
0,
|
|
3271
|
-
|
|
3272
|
-
(setattrofunc)PrivateModule_setattro,
|
|
3273
|
-
0,
|
|
3274
|
-
Py_TPFLAGS_DEFAULT,
|
|
3275
|
-
0,
|
|
3276
|
-
0,
|
|
3277
|
-
0,
|
|
3278
|
-
0,
|
|
3279
|
-
0,
|
|
3280
|
-
0,
|
|
3281
|
-
0,
|
|
3282
|
-
PrivateModule_methods_def,
|
|
3283
|
-
0,
|
|
3284
|
-
PrivateModule_getsetters,
|
|
3285
|
-
&PyModule_Type,
|
|
3265
|
+
"private_attribute.private_attribute_module", //tp_name
|
|
3266
|
+
PyModule_Type.tp_basicsize + 8, //tp_basicsize size of module object + 8 bytes for basicsize to avoid changing attribute '__class__'
|
|
3267
|
+
0, //tp_itemsize
|
|
3268
|
+
0, //tp_dealloc
|
|
3269
|
+
0, //tp_print
|
|
3270
|
+
0, //tp_getattr
|
|
3271
|
+
0, //tp_setattr
|
|
3272
|
+
0, //tp_compare
|
|
3273
|
+
0, //tp_repr
|
|
3274
|
+
0, //tp_as_number
|
|
3275
|
+
0, //tp_as_sequence
|
|
3276
|
+
0, //tp_as_mapping
|
|
3277
|
+
0, //tp_hash
|
|
3278
|
+
0, //tp_call
|
|
3279
|
+
0, //tp_str
|
|
3280
|
+
(getattrofunc)PrivateModule_getattro, //tp_getattro
|
|
3281
|
+
(setattrofunc)PrivateModule_setattro, //tp_setattro
|
|
3282
|
+
0, //tp_as_buffer
|
|
3283
|
+
Py_TPFLAGS_DEFAULT, //tp_flags
|
|
3284
|
+
0, //tp_doc
|
|
3285
|
+
0, //tp_traverse
|
|
3286
|
+
0, //tp_clear
|
|
3287
|
+
0, //tp_richcompare
|
|
3288
|
+
0, //tp_weaklistoffset
|
|
3289
|
+
0, //tp_iter
|
|
3290
|
+
0, //tp_iternext
|
|
3291
|
+
PrivateModule_methods_def, //tp_methods
|
|
3292
|
+
0, //tp_members
|
|
3293
|
+
PrivateModule_getsetters, //tp_getset
|
|
3294
|
+
&PyModule_Type, //tp_base
|
|
3286
3295
|
};
|
|
3287
3296
|
|
|
3288
3297
|
static const char* module_doc = R"(
|
|
3289
3298
|
A module that provides a metaclass for creating classes with private attributes.
|
|
3290
|
-
Private attributes are defined in the `__private_attrs__` sequence and are only
|
|
3291
|
-
You can use the `PrivateAttrBase`
|
|
3299
|
+
Private attributes are defined in the `__private_attrs__` sequence and are only visitable in class codes.
|
|
3300
|
+
You can use the `PrivateAttrBase` as the base class to create classes with private attributes.
|
|
3292
3301
|
The attributes which are private are not on the instance's `__dict__` and cannot be accessed outside
|
|
3293
3302
|
but in the methods defined in class it is reachable.
|
|
3294
3303
|
Usage example:
|
{private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1/private_attribute_cpp.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: private_attribute_cpp
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.1
|
|
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='
|
|
21
|
+
version='2.0.1',
|
|
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.',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_class_private_attrs.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{private_attribute_cpp-1.4.11 → private_attribute_cpp-2.0.1}/tests/test_private_inheritance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|