private-attribute-cpp 1.4.10__tar.gz → 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {private_attribute_cpp-1.4.10/private_attribute_cpp.egg-info → private_attribute_cpp-2.0.0}/PKG-INFO +2 -1
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/README.md +1 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/private_attribute.cpp +416 -419
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/private_attribute.pyi +1 -1
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0/private_attribute_cpp.egg-info}/PKG-INFO +2 -1
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/setup.py +1 -1
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/LICENSE +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/MANIFEST.in +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/picosha2.h +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/private_attribute_cpp.egg-info/SOURCES.txt +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/private_attribute_cpp.egg-info/dependency_links.txt +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/private_attribute_cpp.egg-info/not-zip-safe +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/private_attribute_cpp.egg-info/top_level.txt +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/setup.cfg +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_class_private_attrs.py +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_private_abc.py +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_private_attrs.py +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_private_func.py +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_private_inheritance.py +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_private_method.py +0 -0
- {private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_private_wrap.py +0 -0
{private_attribute_cpp-1.4.10/private_attribute_cpp.egg-info → private_attribute_cpp-2.0.0}/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.0
|
|
4
4
|
Summary: A Python package that provides a way to define private attributes in C++ implementation.
|
|
5
5
|
Home-page: https://github.com/Locked-chess-official/private_attribute_cpp
|
|
6
6
|
Author: HuangHaoHua
|
|
@@ -247,6 +247,7 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
|
|
|
247
247
|
- All of the object that is the instance of the class "PrivateAttrBase" or its subclass are default to be unable to be pickled.
|
|
248
248
|
- Finally the attributes' names in `__private_attrs__` will be change to a tuple with two hash.
|
|
249
249
|
- Finally the `_PrivateWrap` object will be recoveried to the original object.
|
|
250
|
+
- Don't use a decorator which will return the `_PrivateWrap` in `PrivateWrapProxy` which will raise `TypeError`.
|
|
250
251
|
- One class defined in another class cannot use another class's private attribute.
|
|
251
252
|
- One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
|
|
252
253
|
- CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
|
|
@@ -228,6 +228,7 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
|
|
|
228
228
|
- All of the object that is the instance of the class "PrivateAttrBase" or its subclass are default to be unable to be pickled.
|
|
229
229
|
- Finally the attributes' names in `__private_attrs__` will be change to a tuple with two hash.
|
|
230
230
|
- Finally the `_PrivateWrap` object will be recoveried to the original object.
|
|
231
|
+
- Don't use a decorator which will return the `_PrivateWrap` in `PrivateWrapProxy` which will raise `TypeError`.
|
|
231
232
|
- One class defined in another class cannot use another class's private attribute.
|
|
232
233
|
- One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
|
|
233
234
|
- CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
|
|
@@ -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!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ";
|
|
@@ -271,10 +262,7 @@ default_random_string(uintptr_t obj_id, const std::string& attr_name) noexcept
|
|
|
271
262
|
result = it->second;
|
|
272
263
|
return result;
|
|
273
264
|
}
|
|
274
|
-
while (
|
|
275
|
-
if (::AllData::all_exist_name.find(result) == ::AllData::all_exist_name.end()) {
|
|
276
|
-
break;
|
|
277
|
-
}
|
|
265
|
+
while (::AllData::all_exist_name.find(result) != ::AllData::all_exist_name.end()) {
|
|
278
266
|
result = original_result + "_" + std::to_string(i);
|
|
279
267
|
i++;
|
|
280
268
|
}
|
|
@@ -328,12 +316,77 @@ public:
|
|
|
328
316
|
type = value = traceback = nullptr;
|
|
329
317
|
}
|
|
330
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
|
+
|
|
331
376
|
private:
|
|
332
377
|
PyObject* type = nullptr;
|
|
333
378
|
PyObject* value = nullptr;
|
|
334
379
|
PyObject* traceback = nullptr;
|
|
380
|
+
mutable std::string msg_;
|
|
335
381
|
};
|
|
336
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
|
+
|
|
337
390
|
static std::string
|
|
338
391
|
custom_random_string(uintptr_t obj_id, const std::string& attr_name, PyObject* func)
|
|
339
392
|
{
|
|
@@ -372,10 +425,7 @@ custom_random_string(uintptr_t obj_id, const std::string& attr_name, PyObject* f
|
|
|
372
425
|
result = it->second;
|
|
373
426
|
return result;
|
|
374
427
|
}
|
|
375
|
-
while (
|
|
376
|
-
if (::AllData::all_exist_name.find(result) == ::AllData::all_exist_name.end()) {
|
|
377
|
-
break;
|
|
378
|
-
}
|
|
428
|
+
while (::AllData::all_exist_name.find(result) != ::AllData::all_exist_name.end()) {
|
|
379
429
|
result = original_result + "_" + std::to_string(i);
|
|
380
430
|
i++;
|
|
381
431
|
}
|
|
@@ -395,6 +445,10 @@ custom_random_string(uintptr_t obj_id, const std::string& attr_name, PyObject* f
|
|
|
395
445
|
return result;
|
|
396
446
|
}
|
|
397
447
|
|
|
448
|
+
#ifdef _MSC_VER
|
|
449
|
+
#pragma warning(pop)
|
|
450
|
+
#endif
|
|
451
|
+
|
|
398
452
|
static void
|
|
399
453
|
clear_obj(uintptr_t obj_id) noexcept
|
|
400
454
|
{
|
|
@@ -883,17 +937,11 @@ static PrivateWrapObject* PrivateWrap_New(PyObject *decorator, PyObject *func, P
|
|
|
883
937
|
static void PrivateWrap_dealloc(PrivateWrapObject *self) noexcept;
|
|
884
938
|
static PyObject* PrivateWrap_call(PrivateWrapObject *self, PyObject *args, PyObject *kw) noexcept;
|
|
885
939
|
|
|
886
|
-
static
|
|
887
|
-
|
|
888
|
-
{
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
PyObject *res = ((PrivateWrapObject*)obj)->result;
|
|
894
|
-
Py_INCREF(res);
|
|
895
|
-
return res;
|
|
896
|
-
}
|
|
940
|
+
static PyMemberDef PrivateWrap_members[] = {
|
|
941
|
+
{"result", T_OBJECT, offsetof(PrivateWrapObject, result), READONLY, "The result object"},
|
|
942
|
+
{"__wrapped__", T_OBJECT, offsetof(PrivateWrapObject, result), READONLY, "The result object"},
|
|
943
|
+
{NULL}
|
|
944
|
+
};
|
|
897
945
|
|
|
898
946
|
static PyObject *
|
|
899
947
|
PrivateWrap_funcs(PyObject *obj, void* /*closure*/) noexcept
|
|
@@ -909,7 +957,7 @@ static PyObject*
|
|
|
909
957
|
PrivateWrap_doc(PyObject *obj, void* /*closure*/) noexcept
|
|
910
958
|
{
|
|
911
959
|
if (!obj) {
|
|
912
|
-
return
|
|
960
|
+
return PyUnicode_InternFromString("PrivateWrap");
|
|
913
961
|
}
|
|
914
962
|
PyObject* doc = PyObject_GetAttrString(((PrivateWrapObject*)obj)->result, "__doc__");
|
|
915
963
|
if (!doc) {
|
|
@@ -923,26 +971,26 @@ static PyObject*
|
|
|
923
971
|
PrivateWrap_module(PyObject *obj, void* /*closure*/) noexcept
|
|
924
972
|
{
|
|
925
973
|
if (!obj) {
|
|
926
|
-
return
|
|
974
|
+
return PyUnicode_InternFromString("private_attribute");
|
|
927
975
|
}
|
|
928
976
|
PyObject* module = PyObject_GetAttrString(((PrivateWrapObject*)obj)->result, "__module__");
|
|
929
977
|
if (!module){
|
|
930
978
|
PyErr_Clear();
|
|
931
|
-
return
|
|
979
|
+
return PyUnicode_InternFromString("private_attribute");
|
|
932
980
|
}
|
|
933
981
|
return module;
|
|
934
982
|
}
|
|
935
983
|
|
|
936
984
|
static PyObject*
|
|
937
|
-
|
|
985
|
+
PrivateWrap_name(PyObject* obj, void* /*closure*/) noexcept
|
|
938
986
|
{
|
|
939
987
|
if (!obj) {
|
|
940
|
-
return
|
|
988
|
+
return PyUnicode_InternFromString("_PrivateWrap");
|
|
941
989
|
}
|
|
942
990
|
PyObject* name = PyObject_GetAttrString(((PrivateWrapObject*)obj)->result, "__name__");
|
|
943
991
|
if (!name) {
|
|
944
992
|
PyErr_Clear();
|
|
945
|
-
return
|
|
993
|
+
return PyUnicode_InternFromString("_PrivateWrap");
|
|
946
994
|
}
|
|
947
995
|
return name;
|
|
948
996
|
}
|
|
@@ -951,12 +999,12 @@ static PyObject*
|
|
|
951
999
|
PrivateWrap_qualname(PyObject* obj, void* /*closure*/) noexcept
|
|
952
1000
|
{
|
|
953
1001
|
if (!obj) {
|
|
954
|
-
return
|
|
1002
|
+
return PyUnicode_InternFromString("_PrivateWrap");
|
|
955
1003
|
}
|
|
956
1004
|
PyObject* qualname = PyObject_GetAttrString(((PrivateWrapObject*)obj)->result, "__qualname__");
|
|
957
1005
|
if (!qualname) {
|
|
958
1006
|
PyErr_Clear();
|
|
959
|
-
return
|
|
1007
|
+
return PyUnicode_InternFromString("_PrivateWrap");
|
|
960
1008
|
}
|
|
961
1009
|
return qualname;
|
|
962
1010
|
}
|
|
@@ -991,34 +1039,76 @@ PrivateWrap_type_params(PyObject* obj, void* /*closure*/) noexcept
|
|
|
991
1039
|
return type_params;
|
|
992
1040
|
}
|
|
993
1041
|
|
|
994
|
-
static const char* PrivateWrap_result_doc = "the final result of decorating";
|
|
995
1042
|
static const char* PrivateWrap_funcs_doc = "the original functions";
|
|
996
1043
|
|
|
997
1044
|
static PyGetSetDef PrivateWrap_getset[] = {
|
|
998
|
-
{"result", (getter)PrivateWrap_result, NULL, PrivateWrap_result_doc, NULL},
|
|
999
1045
|
{"funcs", (getter)PrivateWrap_funcs, NULL, PrivateWrap_funcs_doc, NULL},
|
|
1000
|
-
{"__wrapped__", (getter)PrivateWrap_result, NULL, NULL, NULL},
|
|
1001
1046
|
{"__doc__", (getter)PrivateWrap_doc, NULL, NULL, NULL},
|
|
1002
1047
|
{"__module__", (getter)PrivateWrap_module, NULL, NULL, NULL},
|
|
1003
|
-
{"__name__", (getter)
|
|
1048
|
+
{"__name__", (getter)PrivateWrap_name, NULL, NULL, NULL},
|
|
1004
1049
|
{"__qualname__", (getter)PrivateWrap_qualname, NULL, NULL, NULL},
|
|
1005
1050
|
{"__annotate__", (getter)PrivateWrap_annotate, NULL, NULL, NULL},
|
|
1006
1051
|
{"__type_params__", (getter)PrivateWrap_type_params, NULL, NULL, NULL},
|
|
1007
1052
|
{NULL}
|
|
1008
1053
|
};
|
|
1009
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
|
+
|
|
1010
1061
|
static PyObject *
|
|
1011
1062
|
PrivateWrap_getattro(PyObject *obj, PyObject *name) noexcept
|
|
1012
1063
|
{
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
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;
|
|
1016
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
|
+
}
|
|
1017
1089
|
|
|
1018
|
-
|
|
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
|
+
}
|
|
1019
1101
|
|
|
1020
|
-
|
|
1021
|
-
|
|
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
|
+
}
|
|
1022
1112
|
}
|
|
1023
1113
|
|
|
1024
1114
|
static PyTypeObject PrivateWrapType = {
|
|
@@ -1042,7 +1132,7 @@ static PyTypeObject PrivateWrapType = {
|
|
|
1042
1132
|
0, // tp_setattro
|
|
1043
1133
|
0, // tp_as_buffer
|
|
1044
1134
|
Py_TPFLAGS_DEFAULT, // tp_flags
|
|
1045
|
-
"_PrivateWrap",
|
|
1135
|
+
"private_attribute._PrivateWrap", // tp_doc
|
|
1046
1136
|
0, // tp_traverse
|
|
1047
1137
|
0, // tp_clear
|
|
1048
1138
|
0, // tp_richcompare
|
|
@@ -1050,21 +1140,29 @@ static PyTypeObject PrivateWrapType = {
|
|
|
1050
1140
|
0, // tp_iter
|
|
1051
1141
|
0, // tp_iternext
|
|
1052
1142
|
0, // tp_methods
|
|
1053
|
-
|
|
1143
|
+
PrivateWrap_members, // tp_members
|
|
1054
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
|
|
1055
1149
|
};
|
|
1056
1150
|
|
|
1057
1151
|
static PrivateWrapObject*
|
|
1058
1152
|
PrivateWrap_New(PyObject *decorator, PyObject *func, PyObject *list) noexcept
|
|
1059
1153
|
{
|
|
1060
|
-
PrivateWrapObject *self =
|
|
1061
|
-
PyObject_New(PrivateWrapObject, &PrivateWrapType);
|
|
1062
1154
|
PyObject *wrapped = PyObject_CallFunctionObjArgs(decorator, func, NULL);
|
|
1063
1155
|
if (!wrapped) {
|
|
1064
|
-
|
|
1156
|
+
return NULL;
|
|
1157
|
+
}
|
|
1158
|
+
if (PyObject_TypeCheck(wrapped, &PrivateWrapType)) {
|
|
1159
|
+
PyErr_SetString(PyExc_TypeError, "decorator returned a '_PrivateWrap' object which is not allowed");
|
|
1160
|
+
Py_DECREF(wrapped);
|
|
1065
1161
|
return NULL;
|
|
1066
1162
|
}
|
|
1067
1163
|
|
|
1164
|
+
PrivateWrapObject *self =
|
|
1165
|
+
PyObject_New(PrivateWrapObject, &PrivateWrapType);
|
|
1068
1166
|
self->func_list = list;
|
|
1069
1167
|
Py_INCREF(list);
|
|
1070
1168
|
|
|
@@ -1824,12 +1922,17 @@ need_analyse_type(PyObject* type) noexcept
|
|
|
1824
1922
|
}
|
|
1825
1923
|
#if PY_VERSION_HEX < 0x030D0000
|
|
1826
1924
|
PyObject* metaclass = PyWeakref_GET_OBJECT(metaclassref);
|
|
1925
|
+
if (type == metaclass) continue;
|
|
1827
1926
|
if (PyObject_IsInstance(type, metaclass)) {
|
|
1828
1927
|
return true;
|
|
1829
1928
|
}
|
|
1830
1929
|
#else
|
|
1831
1930
|
PyObject* metaclass;
|
|
1832
1931
|
if (PyWeakref_GetRef(metaclassref, &metaclass) == 1) {
|
|
1932
|
+
if (type == metaclass) {
|
|
1933
|
+
Py_DECREF(metaclass);
|
|
1934
|
+
continue;
|
|
1935
|
+
}
|
|
1833
1936
|
if (PyObject_IsInstance(type, metaclass)) {
|
|
1834
1937
|
Py_DECREF(metaclass);
|
|
1835
1938
|
return true;
|
|
@@ -1841,157 +1944,6 @@ need_analyse_type(PyObject* type) noexcept
|
|
|
1841
1944
|
return false;
|
|
1842
1945
|
}
|
|
1843
1946
|
|
|
1844
|
-
static void
|
|
1845
|
-
get_getattribute_and_getattr(PyTypeObject* cls, PyObject** getattribute, PyObject** getattr) noexcept
|
|
1846
|
-
{
|
|
1847
|
-
bool has_getattribute = false;
|
|
1848
|
-
bool has_getattr = false;
|
|
1849
|
-
if (PyDict_ContainsString(cls->tp_dict, "__getattribute__")) {
|
|
1850
|
-
*getattribute = PyDict_GetItemString(cls->tp_dict, "__getattribute__");
|
|
1851
|
-
has_getattribute = true;
|
|
1852
|
-
}
|
|
1853
|
-
if (PyDict_ContainsString(cls->tp_dict, "__getattr__")) {
|
|
1854
|
-
*getattr = PyDict_GetItemString(cls->tp_dict, "__getattr__");
|
|
1855
|
-
has_getattr = true;
|
|
1856
|
-
}
|
|
1857
|
-
if (has_getattribute && has_getattr) {
|
|
1858
|
-
return;
|
|
1859
|
-
}
|
|
1860
|
-
for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
|
|
1861
|
-
if (!has_getattribute && PyDict_ContainsString(base->tp_dict, "__getattribute__")) {
|
|
1862
|
-
*getattribute = PyDict_GetItemString(base->tp_dict, "__getattribute__");
|
|
1863
|
-
has_getattribute = true;
|
|
1864
|
-
}
|
|
1865
|
-
if (!has_getattr && PyDict_ContainsString(base->tp_dict, "__getattr__")) {
|
|
1866
|
-
*getattr = PyDict_GetItemString(base->tp_dict, "__getattr__");
|
|
1867
|
-
has_getattr = true;
|
|
1868
|
-
}
|
|
1869
|
-
if (has_getattribute && has_getattr) {
|
|
1870
|
-
return;
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
static void
|
|
1876
|
-
get_setattr_and_delattr(PyTypeObject* cls, PyObject** setattr, PyObject** delattr) noexcept
|
|
1877
|
-
{
|
|
1878
|
-
bool has_setattr = false;
|
|
1879
|
-
bool has_delattr = false;
|
|
1880
|
-
if (PyDict_ContainsString(cls->tp_dict, "__setattr__")) {
|
|
1881
|
-
*setattr = PyDict_GetItemString(cls->tp_dict, "__setattr__");
|
|
1882
|
-
has_setattr = true;
|
|
1883
|
-
}
|
|
1884
|
-
if (PyDict_ContainsString(cls->tp_dict, "__delattr__")) {
|
|
1885
|
-
*delattr = PyDict_GetItemString(cls->tp_dict, "__delattr__");
|
|
1886
|
-
has_delattr = true;
|
|
1887
|
-
}
|
|
1888
|
-
if (has_setattr && has_delattr) {
|
|
1889
|
-
return;
|
|
1890
|
-
}
|
|
1891
|
-
for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
|
|
1892
|
-
if (!has_setattr && PyDict_ContainsString(base->tp_dict, "__setattr__")) {
|
|
1893
|
-
*setattr = PyDict_GetItemString(base->tp_dict, "__setattr__");
|
|
1894
|
-
has_setattr = true;
|
|
1895
|
-
}
|
|
1896
|
-
if (!has_delattr && PyDict_ContainsString(base->tp_dict, "__delattr__")) {
|
|
1897
|
-
*delattr = PyDict_GetItemString(base->tp_dict, "__delattr__");
|
|
1898
|
-
has_delattr = true;
|
|
1899
|
-
}
|
|
1900
|
-
if (has_setattr && has_delattr) {
|
|
1901
|
-
return;
|
|
1902
|
-
}
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
|
|
1906
|
-
static void
|
|
1907
|
-
get_del(PyTypeObject* cls, PyObject** del) noexcept
|
|
1908
|
-
{
|
|
1909
|
-
if (PyDict_ContainsString(cls->tp_dict, "__del__")) {
|
|
1910
|
-
*del = PyDict_GetItemString(cls->tp_dict, "__del__");
|
|
1911
|
-
return;
|
|
1912
|
-
}
|
|
1913
|
-
for (PyTypeObject* base = cls->tp_base; base != NULL && base != &PyBaseObject_Type; base = base->tp_base) {
|
|
1914
|
-
if (PyDict_ContainsString(base->tp_dict, "__del__")) {
|
|
1915
|
-
*del = PyDict_GetItemString(base->tp_dict, "__del__");
|
|
1916
|
-
return;
|
|
1917
|
-
}
|
|
1918
|
-
}
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
|
-
static PyObject*
|
|
1922
|
-
python_original_tp_getattro(PyObject* self, PyObject* name) noexcept
|
|
1923
|
-
{
|
|
1924
|
-
PyObject* getattriute = NULL;
|
|
1925
|
-
PyObject* getattr = NULL;
|
|
1926
|
-
get_getattribute_and_getattr((PyTypeObject*)self->ob_type, &getattriute, &getattr);
|
|
1927
|
-
PyObject* res = NULL;
|
|
1928
|
-
if (getattriute) {
|
|
1929
|
-
res = PyObject_CallFunctionObjArgs(getattriute, self, name, NULL);
|
|
1930
|
-
} else {
|
|
1931
|
-
res = PyObject_GenericGetAttr(self, name);
|
|
1932
|
-
}
|
|
1933
|
-
if (!res && getattr) {
|
|
1934
|
-
// check if the exception is AttributeError
|
|
1935
|
-
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
|
1936
|
-
return NULL;
|
|
1937
|
-
}
|
|
1938
|
-
PyErr_Clear();
|
|
1939
|
-
res = PyObject_CallFunctionObjArgs(getattr, self, name, NULL);
|
|
1940
|
-
}
|
|
1941
|
-
return res;
|
|
1942
|
-
}
|
|
1943
|
-
|
|
1944
|
-
static int
|
|
1945
|
-
python_original_tp_setattro(PyObject* self, PyObject* name, PyObject* value) noexcept
|
|
1946
|
-
{
|
|
1947
|
-
PyObject* setattr = NULL;
|
|
1948
|
-
PyObject* delattr = NULL;
|
|
1949
|
-
get_setattr_and_delattr((PyTypeObject*)self->ob_type, &setattr, &delattr);
|
|
1950
|
-
if (value && setattr) {
|
|
1951
|
-
PyObject* res = PyObject_CallFunctionObjArgs(setattr, self, name, value, NULL);
|
|
1952
|
-
if (!res) {
|
|
1953
|
-
return -1;
|
|
1954
|
-
}
|
|
1955
|
-
Py_DECREF(res);
|
|
1956
|
-
return 0;
|
|
1957
|
-
} else if (!value && delattr) {
|
|
1958
|
-
PyObject* res = PyObject_CallFunctionObjArgs(delattr, self, name, NULL);
|
|
1959
|
-
if (!res) {
|
|
1960
|
-
return -1;
|
|
1961
|
-
}
|
|
1962
|
-
Py_DECREF(res);
|
|
1963
|
-
return 0;
|
|
1964
|
-
}
|
|
1965
|
-
return PyObject_GenericSetAttr(self, name, value);
|
|
1966
|
-
}
|
|
1967
|
-
|
|
1968
|
-
static void
|
|
1969
|
-
python_original_tp_finalize(PyObject* self) noexcept
|
|
1970
|
-
{
|
|
1971
|
-
PyObject* del = NULL;
|
|
1972
|
-
get_del((PyTypeObject*)self->ob_type, &del);
|
|
1973
|
-
if (del) {
|
|
1974
|
-
PyObject *exc_type = NULL, *exc_value = NULL, *exc_tb = NULL;
|
|
1975
|
-
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
|
|
1976
|
-
PyObject *result = PyObject_CallFunctionObjArgs(del, self, NULL);
|
|
1977
|
-
if (result == NULL) {
|
|
1978
|
-
// python < 3.13 use PyErr_WriteUnraisable, python >= 3.13 use PyErr_FormatUnraisable
|
|
1979
|
-
# if PY_VERSION_HEX >= 0x030D0000
|
|
1980
|
-
PyErr_FormatUnraisable("Exception ignored while "
|
|
1981
|
-
"calling deallocator %R", del);
|
|
1982
|
-
# else
|
|
1983
|
-
PyErr_WriteUnraisable(del);
|
|
1984
|
-
# endif
|
|
1985
|
-
}
|
|
1986
|
-
else {
|
|
1987
|
-
Py_DECREF(result);
|
|
1988
|
-
}
|
|
1989
|
-
if (exc_type != NULL) {
|
|
1990
|
-
PyErr_Restore(exc_type, exc_value, exc_tb);
|
|
1991
|
-
}
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
1947
|
static bool
|
|
1996
1948
|
PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationData& data) noexcept
|
|
1997
1949
|
{
|
|
@@ -2233,67 +2185,55 @@ ensure_tp(PyTypeObject* type_instance) noexcept
|
|
|
2233
2185
|
uintptr_t type_id = (uintptr_t)(type_instance);
|
|
2234
2186
|
{
|
|
2235
2187
|
if (type_instance->tp_getattro != PrivateAttr_tp_getattro) {
|
|
2236
|
-
if (!type_instance->tp_getattro) {
|
|
2188
|
+
if (!type_instance->tp_getattro && ::AllData::all_type_getattro.find(type_id) == ::AllData::all_type_getattro.end()) {
|
|
2237
2189
|
::AllData::all_type_getattro[type_id] = get_need_tp_getattro(type_instance);
|
|
2238
2190
|
} else {
|
|
2239
2191
|
::AllData::all_type_getattro[type_id] = type_instance->tp_getattro;
|
|
2240
2192
|
}
|
|
2241
2193
|
type_instance->tp_getattro = PrivateAttr_tp_getattro;
|
|
2242
|
-
} else {
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
::AllData::all_type_getattro[type_id] = ::AllData::all_type_getattro[base_id];
|
|
2250
|
-
} else if (base && base->tp_getattro && base->tp_getattro != PrivateAttr_tp_getattro) {
|
|
2251
|
-
::AllData::all_type_getattro[type_id] = base->tp_getattro;
|
|
2252
|
-
}
|
|
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;
|
|
2253
2201
|
}
|
|
2254
2202
|
}
|
|
2255
2203
|
}
|
|
2256
2204
|
{
|
|
2257
2205
|
if (type_instance->tp_setattro != PrivateAttr_tp_setattro) {
|
|
2258
|
-
if (!type_instance->tp_setattro) {
|
|
2206
|
+
if (!type_instance->tp_setattro && ::AllData::all_type_setattro.find(type_id) == ::AllData::all_type_setattro.end()) {
|
|
2259
2207
|
::AllData::all_type_setattro[type_id] = get_need_tp_setattro(type_instance);
|
|
2260
2208
|
} else {
|
|
2261
2209
|
::AllData::all_type_setattro[type_id] = type_instance->tp_setattro;
|
|
2262
2210
|
}
|
|
2263
2211
|
type_instance->tp_setattro = PrivateAttr_tp_setattro;
|
|
2264
|
-
} else {
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
::AllData::all_type_setattro[type_id] = ::AllData::all_type_setattro[base_id];
|
|
2272
|
-
} else if (base && base->tp_setattro && base->tp_setattro != PrivateAttr_tp_setattro) {
|
|
2273
|
-
::AllData::all_type_setattro[type_id] = base->tp_setattro;
|
|
2274
|
-
}
|
|
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;
|
|
2275
2219
|
}
|
|
2276
2220
|
}
|
|
2277
2221
|
}
|
|
2278
2222
|
{
|
|
2279
2223
|
if (type_instance->tp_finalize != PrivateAttr_tp_finalize) {
|
|
2280
|
-
if (!type_instance->tp_finalize) {
|
|
2224
|
+
if (!type_instance->tp_finalize && ::AllData::all_type_finalize.find(type_id) == ::AllData::all_type_finalize.end()) {
|
|
2281
2225
|
::AllData::all_type_finalize[type_id] = get_need_tp_finalize(type_instance);
|
|
2282
2226
|
} else {
|
|
2283
2227
|
::AllData::all_type_finalize[type_id] = type_instance->tp_finalize;
|
|
2284
2228
|
}
|
|
2285
2229
|
type_instance->tp_finalize = PrivateAttr_tp_finalize;
|
|
2286
|
-
} else {
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
::AllData::all_type_finalize[type_id] = ::AllData::all_type_finalize[base_id];
|
|
2294
|
-
} else if (base && base->tp_finalize && base->tp_finalize != PrivateAttr_tp_finalize) {
|
|
2295
|
-
::AllData::all_type_finalize[type_id] = base->tp_finalize;
|
|
2296
|
-
}
|
|
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;
|
|
2297
2237
|
}
|
|
2298
2238
|
}
|
|
2299
2239
|
}
|
|
@@ -2302,40 +2242,16 @@ ensure_tp(PyTypeObject* type_instance) noexcept
|
|
|
2302
2242
|
static void
|
|
2303
2243
|
ensure_subclass_tp(PyTypeObject* type_instance) noexcept
|
|
2304
2244
|
{
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
}
|
|
2313
|
-
// check all values in the dict. It should be a weakref to a type. If not, continue.
|
|
2314
|
-
PyObject* key, *value;
|
|
2315
|
-
Py_ssize_t pos = 0;
|
|
2316
|
-
while (PyDict_Next(type_subclasses, &pos, &key, &value)) {
|
|
2317
|
-
if (!value || !PyWeakref_CheckRef(value)) {
|
|
2318
|
-
continue;
|
|
2319
|
-
}
|
|
2320
|
-
// python<3.13 use PyWeakref_GetObject, python>=3.13 use PyWeakref_GetRef
|
|
2321
|
-
#if PY_VERSION_HEX < 0x030D0000
|
|
2322
|
-
PyObject* subclass = PyWeakref_GetObject(value);
|
|
2323
|
-
if (!subclass || !PyType_Check(subclass)) {
|
|
2324
|
-
continue;
|
|
2325
|
-
}
|
|
2326
|
-
ensure_tp((PyTypeObject*)subclass);
|
|
2327
|
-
#else
|
|
2328
|
-
PyObject* subclass;
|
|
2329
|
-
if (PyWeakref_GetRef(value, (PyObject**)&subclass) != 1) {
|
|
2330
|
-
continue;
|
|
2331
|
-
}
|
|
2332
|
-
if (!subclass || !PyType_Check(subclass)) {
|
|
2333
|
-
continue;
|
|
2334
|
-
}
|
|
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;
|
|
2335
2252
|
ensure_tp((PyTypeObject*)subclass);
|
|
2336
|
-
Py_XDECREF(subclass);
|
|
2337
|
-
#endif
|
|
2338
2253
|
}
|
|
2254
|
+
Py_DECREF(subclasses);
|
|
2339
2255
|
}
|
|
2340
2256
|
|
|
2341
2257
|
static bool
|
|
@@ -2358,15 +2274,6 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data) n
|
|
|
2358
2274
|
}
|
|
2359
2275
|
|
|
2360
2276
|
ensure_tp(type_instance);
|
|
2361
|
-
if (PyDict_ContainsString(type_instance->tp_dict, "__getattribute__") || PyDict_ContainsString(type_instance->tp_dict, "__getattr__")) {
|
|
2362
|
-
::AllData::all_type_getattro[type_id] = AllSlots::original_getattro;
|
|
2363
|
-
}
|
|
2364
|
-
if (PyDict_ContainsString(type_instance->tp_dict, "__setattr__") || PyDict_ContainsString(type_instance->tp_dict, "__delattr__")) {
|
|
2365
|
-
::AllData::all_type_setattro[type_id] = AllSlots::original_setattro;
|
|
2366
|
-
}
|
|
2367
|
-
if (PyDict_ContainsString(type_instance->tp_dict, "__del__")) {
|
|
2368
|
-
::AllData::all_type_finalize[type_id] = AllSlots::original_finalize;
|
|
2369
|
-
}
|
|
2370
2277
|
|
|
2371
2278
|
::AllData::type_attr_dict[type_id] = {};
|
|
2372
2279
|
::AllData::all_type_attr_set[type_id] = data.private_attrs_set;
|
|
@@ -2520,21 +2427,93 @@ PrivateAttrType_getattr(PyObject* cls, PyObject* name) noexcept
|
|
|
2520
2427
|
return result;
|
|
2521
2428
|
}
|
|
2522
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
|
+
|
|
2523
2481
|
static int
|
|
2524
2482
|
init_all_slots() noexcept
|
|
2525
2483
|
{
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
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
|
+
((PyTypeObject*)metaclass)->tp_setattro = new_type_tp_setattro;
|
|
2509
|
+
}
|
|
2510
|
+
Py_DECREF(all_metaclasses);
|
|
2529
2511
|
return 0;
|
|
2530
2512
|
}
|
|
2531
2513
|
|
|
2532
2514
|
static getattrofunc
|
|
2533
2515
|
get_need_tp_getattro(PyTypeObject* cls) noexcept
|
|
2534
2516
|
{
|
|
2535
|
-
if (PyDict_ContainsString(cls->tp_dict, "__getattribute__") || PyDict_ContainsString(cls->tp_dict, "__getattr__")) {
|
|
2536
|
-
return AllSlots::original_getattro;
|
|
2537
|
-
}
|
|
2538
2517
|
PyTypeObject* base = cls->tp_base;
|
|
2539
2518
|
while (base) {
|
|
2540
2519
|
if (base->tp_getattro != PrivateAttr_tp_getattro) {
|
|
@@ -2554,9 +2533,6 @@ get_need_tp_getattro(PyTypeObject* cls) noexcept
|
|
|
2554
2533
|
static setattrofunc
|
|
2555
2534
|
get_need_tp_setattro(PyTypeObject* cls) noexcept
|
|
2556
2535
|
{
|
|
2557
|
-
if (PyDict_ContainsString(cls->tp_dict, "__setattr__") || PyDict_ContainsString(cls->tp_dict, "__delattr__")) {
|
|
2558
|
-
return AllSlots::original_setattro;
|
|
2559
|
-
}
|
|
2560
2536
|
PyTypeObject* base = cls->tp_base;
|
|
2561
2537
|
while (base) {
|
|
2562
2538
|
if (base->tp_setattro != PrivateAttr_tp_setattro) {
|
|
@@ -2576,9 +2552,6 @@ get_need_tp_setattro(PyTypeObject* cls) noexcept
|
|
|
2576
2552
|
static destructor
|
|
2577
2553
|
get_need_tp_finalize(PyTypeObject* cls) noexcept
|
|
2578
2554
|
{
|
|
2579
|
-
if (PyDict_ContainsString(cls->tp_dict, "__del__")) {
|
|
2580
|
-
return AllSlots::original_finalize;
|
|
2581
|
-
}
|
|
2582
2555
|
PyTypeObject* base = cls->tp_base;
|
|
2583
2556
|
while (base) {
|
|
2584
2557
|
if (base->tp_finalize != PrivateAttr_tp_finalize) {
|
|
@@ -2595,64 +2568,6 @@ get_need_tp_finalize(PyTypeObject* cls) noexcept
|
|
|
2595
2568
|
return NULL;
|
|
2596
2569
|
}
|
|
2597
2570
|
|
|
2598
|
-
static void
|
|
2599
|
-
type_change_all_slots(PyTypeObject* cls, const char* name) noexcept
|
|
2600
|
-
{
|
|
2601
|
-
if (strcmp(name, "__getattribute__") == 0 || strcmp(name, "__getattr__") == 0) {
|
|
2602
|
-
cls->tp_getattro = PrivateAttr_tp_getattro;
|
|
2603
|
-
::AllData::all_type_getattro[(uintptr_t)cls] = get_need_tp_getattro(cls);
|
|
2604
|
-
} else if (strcmp(name, "__setattr__") == 0 || strcmp(name, "__delattr__") == 0) {
|
|
2605
|
-
cls->tp_setattro = PrivateAttr_tp_setattro;
|
|
2606
|
-
::AllData::all_type_setattro[(uintptr_t)cls] = get_need_tp_setattro(cls);
|
|
2607
|
-
} else if (strcmp(name, "__del__") == 0) {
|
|
2608
|
-
cls->tp_finalize = PrivateAttr_tp_finalize;
|
|
2609
|
-
::AllData::all_type_finalize[(uintptr_t)cls] = get_need_tp_finalize(cls);
|
|
2610
|
-
}
|
|
2611
|
-
}
|
|
2612
|
-
|
|
2613
|
-
static void
|
|
2614
|
-
subtype_change_all_slots(PyTypeObject* cls, const char* name) noexcept
|
|
2615
|
-
{
|
|
2616
|
-
// tp_subclasses: {id(type): weakref.ref(type)}
|
|
2617
|
-
PyObject* tp_subclasses = (PyObject*)cls->tp_subclasses;
|
|
2618
|
-
if (!tp_subclasses) {
|
|
2619
|
-
return;
|
|
2620
|
-
}
|
|
2621
|
-
if (!PyDict_Check(tp_subclasses)) {
|
|
2622
|
-
return;
|
|
2623
|
-
}
|
|
2624
|
-
PyObject* key;
|
|
2625
|
-
PyObject* value;
|
|
2626
|
-
Py_ssize_t pos = 0;
|
|
2627
|
-
while (PyDict_Next(tp_subclasses, &pos, &key, &value)) {
|
|
2628
|
-
if (!PyWeakref_Check(value)) {
|
|
2629
|
-
continue;
|
|
2630
|
-
}
|
|
2631
|
-
#if PY_VERSION_HEX < 0x030D0000
|
|
2632
|
-
PyObject* obj = PyWeakref_GET_OBJECT(value);
|
|
2633
|
-
if (!obj) {
|
|
2634
|
-
continue;
|
|
2635
|
-
}
|
|
2636
|
-
#else
|
|
2637
|
-
PyObject* obj;
|
|
2638
|
-
if (PyWeakref_GetRef(value, &obj) != 1) {
|
|
2639
|
-
continue;
|
|
2640
|
-
}
|
|
2641
|
-
if (!obj) {
|
|
2642
|
-
continue;
|
|
2643
|
-
}
|
|
2644
|
-
#endif
|
|
2645
|
-
if (!PyType_Check(obj)) {
|
|
2646
|
-
continue;
|
|
2647
|
-
}
|
|
2648
|
-
PyTypeObject* sub_cls = (PyTypeObject*)obj;
|
|
2649
|
-
type_change_all_slots(sub_cls, name);
|
|
2650
|
-
#if PY_VERSION_HEX >= 0x030D0000
|
|
2651
|
-
Py_XDECREF(obj);
|
|
2652
|
-
#endif
|
|
2653
|
-
}
|
|
2654
|
-
}
|
|
2655
|
-
|
|
2656
2571
|
static int
|
|
2657
2572
|
PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value) noexcept
|
|
2658
2573
|
{
|
|
@@ -2679,42 +2594,12 @@ PrivateAttrType_setattr(PyObject* cls, PyObject* name, PyObject* value) noexcept
|
|
|
2679
2594
|
return type_setattr(cls, name_str, value);
|
|
2680
2595
|
}
|
|
2681
2596
|
Py_XDECREF(now_code);
|
|
2682
|
-
// if name in __getattribute__, __setattr__, __delattr__, __del__, just set to tp_dict
|
|
2683
|
-
if (strcmp(name_str.c_str(), "__getattribute__") == 0 ||
|
|
2684
|
-
strcmp(name_str.c_str(), "__getattr__") == 0 ||
|
|
2685
|
-
strcmp(name_str.c_str(), "__setattr__") == 0 ||
|
|
2686
|
-
strcmp(name_str.c_str(), "__delattr__") == 0 ||
|
|
2687
|
-
strcmp(name_str.c_str(), "__del__") == 0) {
|
|
2688
|
-
PyObject* tp_dict = ((PyTypeObject*)cls)->tp_dict;
|
|
2689
|
-
if (!tp_dict) {
|
|
2690
|
-
PyErr_SetString(PyExc_TypeError, "type has no tp_dict");
|
|
2691
|
-
return -1;
|
|
2692
|
-
}
|
|
2693
|
-
if (!value) {
|
|
2694
|
-
if (PyDict_DelItem(tp_dict, name) < 0) {
|
|
2695
|
-
PyErr_Format(PyExc_AttributeError, "type object '%.100s' has no attribute '%U'", ((PyTypeObject*)cls)->tp_name, name);
|
|
2696
|
-
return -1;
|
|
2697
|
-
}
|
|
2698
|
-
type_change_all_slots((PyTypeObject*)cls, name_str.c_str());
|
|
2699
|
-
subtype_change_all_slots((PyTypeObject*)cls, name_str.c_str());
|
|
2700
|
-
return 0;
|
|
2701
|
-
}
|
|
2702
|
-
if (PyDict_SetItem(tp_dict, name, value) < 0) {
|
|
2703
|
-
return -1;
|
|
2704
|
-
}
|
|
2705
|
-
type_change_all_slots((PyTypeObject*)cls, name_str.c_str());
|
|
2706
|
-
subtype_change_all_slots((PyTypeObject*)cls, name_str.c_str());
|
|
2707
|
-
return 0;
|
|
2708
|
-
}
|
|
2709
2597
|
PyTypeObject* base = Py_TYPE(cls)->tp_base;
|
|
2710
2598
|
while (base && base->tp_base && base->tp_setattro == PrivateAttrType_setattr) {
|
|
2711
2599
|
base = base->tp_base;
|
|
2712
2600
|
}
|
|
2713
2601
|
if (!base) {
|
|
2714
|
-
|
|
2715
|
-
ensure_tp((PyTypeObject*)cls);
|
|
2716
|
-
ensure_subclass_tp((PyTypeObject*)cls);
|
|
2717
|
-
return result;
|
|
2602
|
+
return new_type_tp_setattro(cls, name, value);
|
|
2718
2603
|
}
|
|
2719
2604
|
int result = base->tp_setattro(cls, name, value);
|
|
2720
2605
|
ensure_tp((PyTypeObject*)cls);
|
|
@@ -2800,7 +2685,7 @@ static const char* PrivateAttrBase_doc = "The class to help to create private at
|
|
|
2800
2685
|
static PyObject*
|
|
2801
2686
|
create_private_attr_base_simple(void) noexcept
|
|
2802
2687
|
{
|
|
2803
|
-
PyObject* name =
|
|
2688
|
+
PyObject* name = PyUnicode_InternFromString("PrivateAttrBase");
|
|
2804
2689
|
if (!name) return NULL;
|
|
2805
2690
|
PyObject* bases = PyTuple_New(0);
|
|
2806
2691
|
if (!bases) {
|
|
@@ -2822,8 +2707,8 @@ create_private_attr_base_simple(void) noexcept
|
|
|
2822
2707
|
}
|
|
2823
2708
|
PyDict_SetItemString(dict, "__private_attrs__", private_attrs);
|
|
2824
2709
|
PyDict_SetItemString(dict, "__slots__", private_attrs);
|
|
2825
|
-
PyDict_SetItemString(dict, "__doc__",
|
|
2826
|
-
PyDict_SetItemString(dict, "__module__",
|
|
2710
|
+
PyDict_SetItemString(dict, "__doc__", PyUnicode_InternFromString(PrivateAttrBase_doc));
|
|
2711
|
+
PyDict_SetItemString(dict, "__module__", PyUnicode_InternFromString("private_attribute"));
|
|
2827
2712
|
PyObject *args = PyTuple_Pack(3, name, bases, dict);
|
|
2828
2713
|
PyObject* base_type;
|
|
2829
2714
|
if (args) {
|
|
@@ -2915,7 +2800,7 @@ PrivateTempObject_dealloc(PyObject* self) noexcept
|
|
|
2915
2800
|
|
|
2916
2801
|
static PyTypeObject PrivateTempType = {
|
|
2917
2802
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
2918
|
-
"
|
|
2803
|
+
"private_attribute._PrivateTemp", // tp_name
|
|
2919
2804
|
sizeof(PrivateTempObject), // tp_basicsize
|
|
2920
2805
|
0, //tp_itemsize
|
|
2921
2806
|
PrivateTempObject_dealloc, //tp_dealloc
|
|
@@ -3031,8 +2916,40 @@ static PyMethodDef weakref_callback_def = {
|
|
|
3031
2916
|
NULL
|
|
3032
2917
|
};
|
|
3033
2918
|
|
|
2919
|
+
static bool
|
|
2920
|
+
is_class_of_registed_type(PyObject* metaclass) noexcept
|
|
2921
|
+
{
|
|
2922
|
+
std::shared_lock lock(::AllData::all_register_new_metaclass_mutex);
|
|
2923
|
+
for (auto& [id, instanceref]: ::AllData::all_register_type_weak_ref){
|
|
2924
|
+
if (!PyWeakref_CheckRef(instanceref)) {
|
|
2925
|
+
continue;
|
|
2926
|
+
}
|
|
2927
|
+
#if PY_VERSION_HEX < 0x030D0000
|
|
2928
|
+
PyObject* instance = PyWeakref_GET_OBJECT(instanceref);
|
|
2929
|
+
if (instance == metaclass) continue;
|
|
2930
|
+
if (PyObject_IsInstance(instance, metaclass)) {
|
|
2931
|
+
return true;
|
|
2932
|
+
}
|
|
2933
|
+
#else
|
|
2934
|
+
PyObject* instance;
|
|
2935
|
+
if (PyWeakref_GetRef(instanceref, &instance) == 1) {
|
|
2936
|
+
if (instance == metaclass) {
|
|
2937
|
+
Py_DECREF(instance);
|
|
2938
|
+
continue;
|
|
2939
|
+
}
|
|
2940
|
+
if (PyObject_IsInstance(instance, metaclass)) {
|
|
2941
|
+
Py_DECREF(instance);
|
|
2942
|
+
return true;
|
|
2943
|
+
}
|
|
2944
|
+
Py_DECREF(instance);
|
|
2945
|
+
}
|
|
2946
|
+
#endif
|
|
2947
|
+
}
|
|
2948
|
+
return false;
|
|
2949
|
+
}
|
|
2950
|
+
|
|
3034
2951
|
static PyObject*
|
|
3035
|
-
|
|
2952
|
+
register_metaclass_head(PyObject* metaclass) noexcept
|
|
3036
2953
|
{
|
|
3037
2954
|
if (!PyType_Check(metaclass)) {
|
|
3038
2955
|
PyErr_SetString(PyExc_TypeError, "metaclass must be a type");
|
|
@@ -3042,6 +2959,18 @@ register_metaclass(PyObject* /*self*/, PyObject* metaclass) noexcept
|
|
|
3042
2959
|
PyErr_SetString(PyExc_TypeError, "metaclass must be a metatype");
|
|
3043
2960
|
return NULL;
|
|
3044
2961
|
}
|
|
2962
|
+
if (metaclass == (PyObject*)&PyType_Type) {
|
|
2963
|
+
PyErr_SetString(PyExc_ValueError, "cannot register type itself");
|
|
2964
|
+
return NULL;
|
|
2965
|
+
}
|
|
2966
|
+
if (need_analyse_type(metaclass)) {
|
|
2967
|
+
PyErr_SetString(PyExc_ValueError, "cannot register type that is the instance of 'PrivateAttrType' or registed type");
|
|
2968
|
+
return NULL;
|
|
2969
|
+
}
|
|
2970
|
+
if (is_class_of_registed_type(metaclass)) {
|
|
2971
|
+
PyErr_SetString(PyExc_ValueError, "cannot register type that is the class of registed type");
|
|
2972
|
+
return NULL;
|
|
2973
|
+
}
|
|
3045
2974
|
uintptr_t id = (uintptr_t)metaclass;
|
|
3046
2975
|
|
|
3047
2976
|
std::unique_lock lock(::AllData::all_register_new_metaclass_mutex);
|
|
@@ -3072,6 +3001,27 @@ register_metaclass(PyObject* /*self*/, PyObject* metaclass) noexcept
|
|
|
3072
3001
|
Py_RETURN_NONE;
|
|
3073
3002
|
}
|
|
3074
3003
|
|
|
3004
|
+
static PyObject*
|
|
3005
|
+
register_metaclass(PyObject* /*self*/, PyObject* metaclass) noexcept
|
|
3006
|
+
{
|
|
3007
|
+
if (!register_metaclass_head(metaclass)) return NULL;
|
|
3008
|
+
PyObject* subclasses = PyObject_CallMethod((PyObject*)&PyType_Type, "__subclasses__", "O", metaclass);
|
|
3009
|
+
if (!subclasses) {
|
|
3010
|
+
PyErr_Clear();
|
|
3011
|
+
Py_RETURN_NONE;
|
|
3012
|
+
}
|
|
3013
|
+
Py_ssize_t list_len = PyList_GET_SIZE(subclasses);
|
|
3014
|
+
for (Py_ssize_t i = 0; i < list_len; i++) {
|
|
3015
|
+
PyObject* subclass = PyList_GET_ITEM(subclasses, i);
|
|
3016
|
+
if (!register_metaclass(0, subclass)) {
|
|
3017
|
+
Py_DECREF(subclasses);
|
|
3018
|
+
return NULL;
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
Py_DECREF(subclasses);
|
|
3022
|
+
Py_RETURN_NONE;
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3075
3025
|
static PyObject*
|
|
3076
3026
|
ensure_type_tp(PyObject* /*self*/, PyObject* type) noexcept
|
|
3077
3027
|
{
|
|
@@ -3154,8 +3104,16 @@ PrivateModule_dir(PyObject* self, PyObject* /*args*/) noexcept
|
|
|
3154
3104
|
return result;
|
|
3155
3105
|
}
|
|
3156
3106
|
|
|
3107
|
+
#define PrivateModule_GETATTRO_CASE(name) \
|
|
3108
|
+
do {\
|
|
3109
|
+
if (strcmp(name_cstr, #name) == 0) {\
|
|
3110
|
+
PyObject* attr = PrivateModule_get_##name(NULL, NULL);\
|
|
3111
|
+
return attr;\
|
|
3112
|
+
}\
|
|
3113
|
+
} while (0)
|
|
3114
|
+
|
|
3157
3115
|
static int
|
|
3158
|
-
PrivateModule_setattro(PyObject*
|
|
3116
|
+
PrivateModule_setattro(PyObject* self, PyObject* name, PyObject* value) noexcept
|
|
3159
3117
|
{
|
|
3160
3118
|
// if name is "__class__" it do nothing and return success
|
|
3161
3119
|
if (PyUnicode_Check(name)) {
|
|
@@ -3163,8 +3121,25 @@ PrivateModule_setattro(PyObject* cls, PyObject* name, PyObject* value) noexcept
|
|
|
3163
3121
|
if (name_cstr && strcmp(name_cstr, "__class__") == 0) {
|
|
3164
3122
|
return 0;
|
|
3165
3123
|
}
|
|
3124
|
+
static const char* unsetable_attrs[] = {
|
|
3125
|
+
"PrivateWrapProxy",
|
|
3126
|
+
"PrivateAttrType",
|
|
3127
|
+
"PrivateAttrBase",
|
|
3128
|
+
"prepare",
|
|
3129
|
+
"postprocess",
|
|
3130
|
+
"register_metaclass",
|
|
3131
|
+
"ensure_type",
|
|
3132
|
+
"ensure_metaclass"
|
|
3133
|
+
};
|
|
3134
|
+
const size_t num_attrs = sizeof(unsetable_attrs) / sizeof(unsetable_attrs[0]);
|
|
3135
|
+
for (size_t i = 0; i < num_attrs; ++i) {
|
|
3136
|
+
if (strcmp(name_cstr, unsetable_attrs[i]) == 0) {
|
|
3137
|
+
PyErr_Format(PyExc_AttributeError, "attribute '%s' of 'private_attribute_module' objects is not writable", name_cstr);
|
|
3138
|
+
return -1;
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3166
3141
|
}
|
|
3167
|
-
return
|
|
3142
|
+
return PyModule_Type.tp_setattro(self, name, value);
|
|
3168
3143
|
}
|
|
3169
3144
|
|
|
3170
3145
|
static const char* prepare_and_postprocess_doc = R"(function for custom metaclass to create private attributes class.
|
|
@@ -3261,38 +3236,60 @@ static PyMethodDef PrivateModule_methods_def[] = {
|
|
|
3261
3236
|
{NULL} // Sentinel
|
|
3262
3237
|
};
|
|
3263
3238
|
|
|
3239
|
+
static PyObject*
|
|
3240
|
+
PrivateModule_getattro(PyObject* self, PyObject* name) noexcept
|
|
3241
|
+
{
|
|
3242
|
+
if (!PyUnicode_Check(name)) {
|
|
3243
|
+
PyErr_SetString(PyExc_TypeError, "attribute name must be a string");
|
|
3244
|
+
return NULL;
|
|
3245
|
+
}
|
|
3246
|
+
const char* name_cstr = PyUnicode_AsUTF8(name);
|
|
3247
|
+
if (!name_cstr) {
|
|
3248
|
+
return NULL;
|
|
3249
|
+
}
|
|
3250
|
+
PrivateModule_GETATTRO_CASE(PrivateWrapProxy);
|
|
3251
|
+
PrivateModule_GETATTRO_CASE(PrivateAttrType);
|
|
3252
|
+
PrivateModule_GETATTRO_CASE(PrivateAttrBase);
|
|
3253
|
+
PrivateModule_GETATTRO_CASE(prepare);
|
|
3254
|
+
PrivateModule_GETATTRO_CASE(postprocess);
|
|
3255
|
+
PrivateModule_GETATTRO_CASE(register_metaclass);
|
|
3256
|
+
PrivateModule_GETATTRO_CASE(ensure_type);
|
|
3257
|
+
PrivateModule_GETATTRO_CASE(ensure_metaclass);
|
|
3258
|
+
return PyModule_Type.tp_getattro(self, name);
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3264
3261
|
static PyTypeObject PrivateModuleType = {
|
|
3265
3262
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
3266
|
-
"private_attribute_module", //tp_name
|
|
3267
|
-
PyModule_Type.tp_basicsize + 8,
|
|
3268
|
-
0,
|
|
3269
|
-
0,
|
|
3270
|
-
0,
|
|
3271
|
-
0,
|
|
3272
|
-
0,
|
|
3273
|
-
0,
|
|
3274
|
-
0,
|
|
3275
|
-
0,
|
|
3276
|
-
0,
|
|
3277
|
-
0,
|
|
3278
|
-
0,
|
|
3279
|
-
0,
|
|
3280
|
-
0,
|
|
3281
|
-
|
|
3282
|
-
(setattrofunc)PrivateModule_setattro,
|
|
3283
|
-
0,
|
|
3284
|
-
Py_TPFLAGS_DEFAULT,
|
|
3285
|
-
0,
|
|
3286
|
-
0,
|
|
3287
|
-
0,
|
|
3288
|
-
0,
|
|
3289
|
-
0,
|
|
3290
|
-
0,
|
|
3291
|
-
0,
|
|
3292
|
-
PrivateModule_methods_def,
|
|
3293
|
-
0,
|
|
3294
|
-
PrivateModule_getsetters,
|
|
3295
|
-
&PyModule_Type,
|
|
3263
|
+
"private_attribute.private_attribute_module", //tp_name
|
|
3264
|
+
PyModule_Type.tp_basicsize + 8, //tp_basicsize size of module object + 8 bytes for basicsize to avoid changing attribute '__class__'
|
|
3265
|
+
0, //tp_itemsize
|
|
3266
|
+
0, //tp_dealloc
|
|
3267
|
+
0, //tp_print
|
|
3268
|
+
0, //tp_getattr
|
|
3269
|
+
0, //tp_setattr
|
|
3270
|
+
0, //tp_compare
|
|
3271
|
+
0, //tp_repr
|
|
3272
|
+
0, //tp_as_number
|
|
3273
|
+
0, //tp_as_sequence
|
|
3274
|
+
0, //tp_as_mapping
|
|
3275
|
+
0, //tp_hash
|
|
3276
|
+
0, //tp_call
|
|
3277
|
+
0, //tp_str
|
|
3278
|
+
(getattrofunc)PrivateModule_getattro, //tp_getattro
|
|
3279
|
+
(setattrofunc)PrivateModule_setattro, //tp_setattro
|
|
3280
|
+
0, //tp_as_buffer
|
|
3281
|
+
Py_TPFLAGS_DEFAULT, //tp_flags
|
|
3282
|
+
0, //tp_doc
|
|
3283
|
+
0, //tp_traverse
|
|
3284
|
+
0, //tp_clear
|
|
3285
|
+
0, //tp_richcompare
|
|
3286
|
+
0, //tp_weaklistoffset
|
|
3287
|
+
0, //tp_iter
|
|
3288
|
+
0, //tp_iternext
|
|
3289
|
+
PrivateModule_methods_def, //tp_methods
|
|
3290
|
+
0, //tp_members
|
|
3291
|
+
PrivateModule_getsetters, //tp_getset
|
|
3292
|
+
&PyModule_Type, //tp_base
|
|
3296
3293
|
};
|
|
3297
3294
|
|
|
3298
3295
|
static const char* module_doc = R"(
|
|
@@ -76,7 +76,7 @@ class PrivateWrapProxy:
|
|
|
76
76
|
class PrivateAttrType(type):
|
|
77
77
|
"metaclass for private attributes"
|
|
78
78
|
def __new__(cls, name: str, bases: tuple,
|
|
79
|
-
attrs: _PrivateAttrDict, /,
|
|
79
|
+
attrs: _PrivateAttrDict, /, *,
|
|
80
80
|
private_func: Callable[[int, str], str]|None = None) -> PrivateAttrType: ...
|
|
81
81
|
|
|
82
82
|
class PrivateAttrBase(metaclass=PrivateAttrType):
|
{private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0/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.0
|
|
4
4
|
Summary: A Python package that provides a way to define private attributes in C++ implementation.
|
|
5
5
|
Home-page: https://github.com/Locked-chess-official/private_attribute_cpp
|
|
6
6
|
Author: HuangHaoHua
|
|
@@ -247,6 +247,7 @@ TypeError: Can't instantiate abstract class MyClass without an implementation fo
|
|
|
247
247
|
- All of the object that is the instance of the class "PrivateAttrBase" or its subclass are default to be unable to be pickled.
|
|
248
248
|
- Finally the attributes' names in `__private_attrs__` will be change to a tuple with two hash.
|
|
249
249
|
- Finally the `_PrivateWrap` object will be recoveried to the original object.
|
|
250
|
+
- Don't use a decorator which will return the `_PrivateWrap` in `PrivateWrapProxy` which will raise `TypeError`.
|
|
250
251
|
- One class defined in another class cannot use another class's private attribute.
|
|
251
252
|
- One parent class defined an attribute which not in `__private_attrs__` or not a `PrivateAttrType` instance, the child class shouldn't contain the attribute in its `__private_attrs__`.
|
|
252
253
|
- CPython may change "tp_getattro", "tp_setattro" and so on when you change the attribute "\_\_getattribute\_\_", "\_\_setattr\_\_" and so on. If you are fear about it, you can use `ensure_type` to reset those tp slots. For the other metaclasses, you can use `ensure_metaclass` to reset those tp slots. Also, don't set those methods on these classes in your code.
|
|
@@ -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.0',
|
|
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
|
{private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_class_private_attrs.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{private_attribute_cpp-1.4.10 → private_attribute_cpp-2.0.0}/tests/test_private_inheritance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|