private-attribute-cpp 2.0.0__tar.gz → 2.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {private_attribute_cpp-2.0.0/private_attribute_cpp.egg-info → private_attribute_cpp-2.0.2}/PKG-INFO +1 -1
  2. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/private_attribute.cpp +68 -181
  3. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2/private_attribute_cpp.egg-info}/PKG-INFO +1 -1
  4. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/setup.py +1 -1
  5. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/LICENSE +0 -0
  6. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/MANIFEST.in +0 -0
  7. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/README.md +0 -0
  8. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/picosha2.h +0 -0
  9. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/private_attribute.pyi +0 -0
  10. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/private_attribute_cpp.egg-info/SOURCES.txt +0 -0
  11. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/private_attribute_cpp.egg-info/dependency_links.txt +0 -0
  12. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/private_attribute_cpp.egg-info/not-zip-safe +0 -0
  13. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/private_attribute_cpp.egg-info/top_level.txt +0 -0
  14. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/setup.cfg +0 -0
  15. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/tests/test_class_private_attrs.py +0 -0
  16. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/tests/test_private_abc.py +0 -0
  17. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/tests/test_private_attrs.py +0 -0
  18. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/tests/test_private_func.py +0 -0
  19. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/tests/test_private_inheritance.py +0 -0
  20. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/tests/test_private_method.py +0 -0
  21. {private_attribute_cpp-2.0.0 → private_attribute_cpp-2.0.2}/tests/test_private_wrap.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 2.0.0
3
+ Version: 2.0.2
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
@@ -33,6 +33,12 @@ PyDict_ContainsString(PyObject *op, const char *key) noexcept
33
33
  return res;
34
34
  }
35
35
  #endif
36
+
37
+ // python >= 3.15 has PyAnyDict_Check. Under 3.15 defined it as PyDict_Check
38
+ #if PY_VERSION_HEX < 0x030F0000
39
+ #define PyAnyDict_Check(op) PyDict_Check(op)
40
+ #endif
41
+
36
42
  static const auto module_running_time = std::chrono::system_clock::now();
37
43
 
38
44
  static std::string
@@ -277,178 +283,67 @@ default_random_string(uintptr_t obj_id, const std::string& attr_name) noexcept
277
283
  return result;
278
284
  }
279
285
 
280
- class RestorePythonException : public std::exception
281
- {
282
- public:
283
- RestorePythonException(PyObject* type, PyObject* value, PyObject* traceback) noexcept
284
- : type(type), value(value), traceback(traceback) {
285
- }
286
-
287
- ~RestorePythonException() noexcept {
288
- Py_XDECREF(type);
289
- Py_XDECREF(value);
290
- Py_XDECREF(traceback);
291
- }
292
-
293
- RestorePythonException(const RestorePythonException&) = delete;
294
- RestorePythonException& operator=(RestorePythonException&& other) noexcept {
295
- if (this != &other) {
296
- type = other.type;
297
- value = other.value;
298
- traceback = other.traceback;
299
- other.type = nullptr;
300
- other.value = nullptr;
301
- other.traceback = nullptr;
302
- }
303
- return *this;
304
- }
305
-
306
- // Move constructor
307
- RestorePythonException(RestorePythonException&& other) noexcept
308
- : type(other.type), value(other.value), traceback(other.traceback) {
309
- other.type = nullptr;
310
- other.value = nullptr;
311
- other.traceback = nullptr;
312
- }
313
-
314
- void restore() noexcept {
315
- PyErr_Restore(type, value, traceback);
316
- type = value = traceback = nullptr;
317
- }
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
-
376
- private:
377
- PyObject* type = nullptr;
378
- PyObject* value = nullptr;
379
- PyObject* traceback = nullptr;
380
- mutable std::string msg_;
286
+ struct RestorePythonExceptionResult {
287
+ std::string value;
288
+ bool ok = true;
381
289
  };
382
290
 
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
-
390
- static std::string
391
- custom_random_string(uintptr_t obj_id, const std::string& attr_name, PyObject* func)
291
+ static RestorePythonExceptionResult
292
+ custom_random_string(uintptr_t obj_id, const std::string& attr_name, PyObject* func) noexcept
392
293
  {
294
+ RestorePythonExceptionResult result;
393
295
  AllPyobjectAttrCacheKey key(obj_id, attr_name);
394
- std::string result;
395
296
  {
396
297
  std::shared_lock<std::shared_mutex> lock(::AllData::cache_mutex);
397
298
  auto it = ::AllData::cache.find(key);
398
299
  if (it != ::AllData::cache.end()) {
399
- result = it->second;
300
+ result.value = it->second;
400
301
  return result;
401
302
  } else {
402
303
  lock.unlock();
403
- PyObject* args = PyTuple_New(2);
404
- PyTuple_SetItem(args, 0, PyLong_FromSize_t(static_cast<size_t>(obj_id)));
405
- PyTuple_SetItem(args, 1, PyUnicode_FromString(attr_name.c_str()));
406
-
407
- PyObject* python_result = PyObject_CallObject((PyObject*)func, args);
408
-
409
- Py_DECREF(args);
304
+ PyObject* python_result = PyObject_CallFunction(
305
+ func,
306
+ "ns",
307
+ static_cast<Py_ssize_t>(obj_id),
308
+ attr_name.c_str()
309
+ );
410
310
  if (python_result) {
411
311
  if (!PyUnicode_Check(python_result)) {
412
312
  Py_DECREF(python_result);
413
313
  PyErr_SetString(PyExc_TypeError, "private_func function must return a string");
414
- PyObject *type, *value, *traceback;
415
- PyErr_Fetch(&type, &value, &traceback);
416
- throw RestorePythonException(type, value, traceback);
314
+ result.ok = false;
315
+ result.value = "private_func function must return a string";
316
+ return result;
417
317
  }
418
- result = PyUnicode_AsUTF8(python_result);
318
+ result.value = PyUnicode_AsUTF8(python_result);
419
319
  Py_DECREF(python_result);
420
- std::string original_result = result;
320
+ std::string original_result = result.value;
421
321
  unsigned long long i = 1;
422
322
  std::unique_lock<std::shared_mutex> lock2(::AllData::cache_mutex);
423
323
  auto it = ::AllData::cache.find(key); // twice check
424
324
  if (it != ::AllData::cache.end()) {
425
- result = it->second;
325
+ result.value = it->second;
426
326
  return result;
427
327
  }
428
- while (::AllData::all_exist_name.find(result) != ::AllData::all_exist_name.end()) {
429
- result = original_result + "_" + std::to_string(i);
328
+ while (::AllData::all_exist_name.find(result.value) != ::AllData::all_exist_name.end()) {
329
+ result.value = original_result + "_" + std::to_string(i);
430
330
  i++;
431
331
  }
432
332
  if (::AllData::obj_attr_keys.find(obj_id) == ::AllData::obj_attr_keys.end()) {
433
333
  ::AllData::obj_attr_keys[obj_id] = {};
434
334
  }
435
335
  ::AllData::obj_attr_keys[obj_id].push_back(key);
436
- ::AllData::cache[key] = result;
437
- ::AllData::all_exist_name.insert(result);
336
+ ::AllData::cache[key] = result.value;
337
+ ::AllData::all_exist_name.insert(result.value);
438
338
  } else {
439
- PyObject *type, *value, *traceback;
440
- PyErr_Fetch(&type, &value, &traceback);
441
- throw RestorePythonException(type, value, traceback);
339
+ result.ok = false;
340
+ result.value = "python exception while calling private function";
442
341
  }
443
342
  }
444
343
  }
445
344
  return result;
446
345
  }
447
346
 
448
- #ifdef _MSC_VER
449
- #pragma warning(pop)
450
- #endif
451
-
452
347
  static void
453
348
  clear_obj(uintptr_t obj_id) noexcept
454
349
  {
@@ -500,12 +395,11 @@ id_getattr(const std::string& attr_name, PyObject* obj, PyObject* typ) noexcept
500
395
  obj_need_call = ::AllData::type_need_call[final_id];
501
396
  }
502
397
  if (obj_need_call) {
503
- try {
504
- obj_private_name = custom_random_string(obj_id, attr_name, obj_need_call);
505
- } catch (RestorePythonException& e) {
506
- e.restore();
398
+ auto private_name_result = custom_random_string(obj_id, attr_name, obj_need_call);
399
+ if (!private_name_result.ok) {
507
400
  return NULL;
508
401
  }
402
+ obj_private_name = private_name_result.value;
509
403
  } else {
510
404
  obj_private_name = default_random_string(obj_id, attr_name);
511
405
  }
@@ -641,12 +535,11 @@ id_setattr(const std::string& attr_name, PyObject* obj, PyObject* typ, PyObject*
641
535
  obj_need_call = ::AllData::type_need_call[final_id];
642
536
  }
643
537
  if (obj_need_call) {
644
- try {
645
- obj_private_name = custom_random_string(obj_id, attr_name, obj_need_call);
646
- } catch (RestorePythonException& e) {
647
- e.restore();
538
+ auto private_name_result = custom_random_string(obj_id, attr_name, obj_need_call);
539
+ if (!private_name_result.ok) {
648
540
  return -1;
649
541
  }
542
+ obj_private_name = private_name_result.value;
650
543
  } else {
651
544
  obj_private_name = default_random_string(obj_id, attr_name);
652
545
  }
@@ -710,12 +603,11 @@ type_setattr(PyObject* typ, const std::string& attr_name, PyObject* value) noexc
710
603
  type_need_call = NULL;
711
604
  }
712
605
  if (type_need_call) {
713
- try {
714
- final_key = custom_random_string(typ_id, attr_name, type_need_call);
715
- } catch (RestorePythonException& e) {
716
- e.restore();
606
+ auto private_name_result = custom_random_string(typ_id, attr_name, type_need_call);
607
+ if (!private_name_result.ok) {
717
608
  return -1;
718
609
  }
610
+ final_key = private_name_result.value;
719
611
  } else {
720
612
  final_key = default_random_string(typ_id, attr_name);
721
613
  }
@@ -785,12 +677,11 @@ id_delattr(const std::string& attr_name, PyObject* obj, PyObject* typ) noexcept
785
677
  obj_need_call = ::AllData::type_need_call[final_id];
786
678
  }
787
679
  if (obj_need_call) {
788
- try {
789
- obj_private_name = custom_random_string(obj_id, attr_name, obj_need_call);
790
- } catch (RestorePythonException& e) {
791
- e.restore();
680
+ auto private_name_result = custom_random_string(obj_id, attr_name, obj_need_call);
681
+ if (!private_name_result.ok) {
792
682
  return -1;
793
683
  }
684
+ obj_private_name = private_name_result.value;
794
685
  } else {
795
686
  obj_private_name = default_random_string(obj_id, attr_name);
796
687
  }
@@ -857,12 +748,11 @@ type_delattr(PyObject* typ, const std::string& attr_name) noexcept
857
748
  type_need_call = NULL;
858
749
  }
859
750
  if (type_need_call) {
860
- try {
861
- final_key = custom_random_string(typ_id, attr_name, type_need_call);
862
- } catch (RestorePythonException& e) {
863
- e.restore();
751
+ auto private_name_result = custom_random_string(typ_id, attr_name, type_need_call);
752
+ if (!private_name_result.ok) {
864
753
  return -1;
865
754
  }
755
+ final_key = private_name_result.value;
866
756
  } else {
867
757
  final_key = default_random_string(typ_id, attr_name);
868
758
  }
@@ -1577,12 +1467,11 @@ type_get_final_attr(uintptr_t type_id, const std::string& name) noexcept
1577
1467
  }
1578
1468
  std::string key;
1579
1469
  if (type_need_call != NULL) {
1580
- try {
1581
- key = custom_random_string(type_id, name, type_need_call);
1582
- } catch (RestorePythonException& e) {
1583
- e.restore();
1470
+ auto private_name_result = custom_random_string(type_id, name, type_need_call);
1471
+ if (!private_name_result.ok) {
1584
1472
  return -2; // -2 means exception
1585
1473
  }
1474
+ key = private_name_result.value;
1586
1475
  } else {
1587
1476
  key = default_random_string(type_id, name);
1588
1477
  }
@@ -1616,12 +1505,11 @@ type_get_final_attr(uintptr_t type_id, const std::string& name) noexcept
1616
1505
  if (::AllData::type_need_call.find(now_visited_id) != ::AllData::type_need_call.end()) {
1617
1506
  PyObject* func = ::AllData::type_need_call[now_visited_id];
1618
1507
  if (func != NULL) {
1619
- try {
1620
- key = custom_random_string(now_visited_id, name, func);
1621
- } catch (RestorePythonException& e) {
1622
- e.restore();
1508
+ auto private_name_result = custom_random_string(now_visited_id, name, func);
1509
+ if (!private_name_result.ok) {
1623
1510
  return -2; // -2 means exception
1624
1511
  }
1512
+ key = private_name_result.value;
1625
1513
  } else {
1626
1514
  key = default_random_string(now_visited_id, name);
1627
1515
  }
@@ -1647,12 +1535,11 @@ type_get_final_attr(uintptr_t type_id, const std::string& name) noexcept
1647
1535
  if (::AllData::type_need_call.find(parent_id) != ::AllData::type_need_call.end()) {
1648
1536
  PyObject* func = ::AllData::type_need_call[parent_id];
1649
1537
  if (func != NULL) {
1650
- try {
1651
- key = custom_random_string(parent_id, name, ::AllData::type_need_call[parent_id]);
1652
- } catch (RestorePythonException& e) {
1653
- e.restore();
1538
+ auto private_name_result = custom_random_string(parent_id, name, func);
1539
+ if (!private_name_result.ok) {
1654
1540
  return -2; // -2 means exception
1655
1541
  }
1542
+ key = private_name_result.value;
1656
1543
  } else {
1657
1544
  key = default_random_string(parent_id, name);
1658
1545
  }
@@ -1975,7 +1862,7 @@ PrivateAttrType_preprocess(PyObject* args, PyObject* kwds, PrivateAttrCreationDa
1975
1862
  return false;
1976
1863
  }
1977
1864
 
1978
- if (!PyDict_Check(data.attrs)) {
1865
+ if (!PyAnyDict_Check(data.attrs)) {
1979
1866
  PyErr_SetString(PyExc_TypeError, "attrs must be a dict");
1980
1867
  return false;
1981
1868
  }
@@ -2312,12 +2199,11 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data) n
2312
2199
  for (auto& [key, value]: data.need_remove_itself) {
2313
2200
  std::string final_key;
2314
2201
  if (data.private_func) {
2315
- try {
2316
- final_key = custom_random_string(type_id, key, data.private_func);
2317
- } catch (RestorePythonException& e) {
2318
- e.restore();
2202
+ auto private_name_result = custom_random_string(type_id, key, data.private_func);
2203
+ if (!private_name_result.ok) {
2319
2204
  return false;
2320
2205
  }
2206
+ final_key = private_name_result.value;
2321
2207
  } else {
2322
2208
  final_key = default_random_string(type_id, key);
2323
2209
  }
@@ -2341,12 +2227,11 @@ PrivateAttrType_postprocess(PyObject* new_type, PrivateAttrCreationData& data) n
2341
2227
  for (auto& [key, value]: map) {
2342
2228
  std::string final_key;
2343
2229
  if (data.private_func) {
2344
- try {
2345
- final_key = custom_random_string(type_id, key, data.private_func);
2346
- } catch (RestorePythonException& e) {
2347
- e.restore();
2230
+ auto private_name_result = custom_random_string(type_id, key, data.private_func);
2231
+ if (!private_name_result.ok) {
2348
2232
  return false;
2349
2233
  }
2234
+ final_key = private_name_result.value;
2350
2235
  } else {
2351
2236
  final_key = default_random_string(type_id, key);
2352
2237
  }
@@ -2505,7 +2390,9 @@ init_all_slots() noexcept
2505
2390
  for (Py_ssize_t i = 0; i < list_len; i++) {
2506
2391
  PyObject* metaclass = PyList_GET_ITEM(all_metaclasses, i);
2507
2392
  if (!PyType_Check(metaclass)) {continue;}
2508
- ((PyTypeObject*)metaclass)->tp_setattro = new_type_tp_setattro;
2393
+ if (((PyTypeObject*)metaclass)->tp_setattro == original_type_tp_setattro) {
2394
+ ((PyTypeObject*)metaclass)->tp_setattro = new_type_tp_setattro;
2395
+ }
2509
2396
  }
2510
2397
  Py_DECREF(all_metaclasses);
2511
2398
  return 0;
@@ -3134,7 +3021,7 @@ PrivateModule_setattro(PyObject* self, PyObject* name, PyObject* value) noexcept
3134
3021
  const size_t num_attrs = sizeof(unsetable_attrs) / sizeof(unsetable_attrs[0]);
3135
3022
  for (size_t i = 0; i < num_attrs; ++i) {
3136
3023
  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);
3024
+ PyErr_Format(PyExc_AttributeError, "attribute '%s' of 'private_attribute.private_attribute_module' objects is not writable", name_cstr);
3138
3025
  return -1;
3139
3026
  }
3140
3027
  }
@@ -3294,8 +3181,8 @@ static PyTypeObject PrivateModuleType = {
3294
3181
 
3295
3182
  static const char* module_doc = R"(
3296
3183
  A module that provides a metaclass for creating classes with private attributes.
3297
- Private attributes are defined in the `__private_attrs__` sequence and are only
3298
- You can use the `PrivateAttrBase` metaclass to create classes with private attributes.
3184
+ Private attributes are defined in the `__private_attrs__` sequence and are only visitable in class codes.
3185
+ You can use the `PrivateAttrBase` as the base class to create classes with private attributes.
3299
3186
  The attributes which are private are not on the instance's `__dict__` and cannot be accessed outside
3300
3187
  but in the methods defined in class it is reachable.
3301
3188
  Usage example:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: private_attribute_cpp
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: A Python package that provides a way to define private attributes in C++ implementation.
5
5
  Home-page: https://github.com/Locked-chess-official/private_attribute_cpp
6
6
  Author: HuangHaoHua
@@ -18,7 +18,7 @@ readme = open('README.md').read()
18
18
 
19
19
  setup(
20
20
  name='private_attribute_cpp',
21
- version='2.0.0',
21
+ version='2.0.2',
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.',