wrapt 2.3.0rc1__tar.gz → 2.4.0.dev1__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 (152) hide show
  1. {wrapt-2.3.0rc1/src/wrapt.egg-info → wrapt-2.4.0.dev1}/PKG-INFO +1 -1
  2. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/__init__.py +1 -1
  3. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/_wrappers.c +97 -19
  4. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1/src/wrapt.egg-info}/PKG-INFO +1 -1
  5. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_object_proxy.py +49 -0
  6. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/LICENSE +0 -0
  7. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/MANIFEST.in +0 -0
  8. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/README.md +0 -0
  9. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/RELEASE.rst +0 -0
  10. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/pyproject.toml +0 -0
  11. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/setup.cfg +0 -0
  12. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/setup.py +0 -0
  13. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/__wrapt__.py +0 -0
  14. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/arguments.py +0 -0
  15. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/caching.py +0 -0
  16. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/decorators.py +0 -0
  17. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/importer.py +0 -0
  18. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/patches.py +0 -0
  19. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/proxies.py +0 -0
  20. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/signature.py +0 -0
  21. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/synchronization.py +0 -0
  22. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/weakrefs.py +0 -0
  23. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt/wrappers.py +0 -0
  24. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt-stubs/__init__.pyi +0 -0
  25. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt.egg-info/SOURCES.txt +0 -0
  26. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt.egg-info/dependency_links.txt +0 -0
  27. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt.egg-info/not-zip-safe +0 -0
  28. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt.egg-info/requires.txt +0 -0
  29. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/src/wrapt.egg-info/top_level.txt +0 -0
  30. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/conftest.py +0 -0
  31. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/compat.py +0 -0
  32. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/module1.py +0 -0
  33. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/module2.py +0 -0
  34. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_adapter.py +0 -0
  35. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_adapter_annotations.py +0 -0
  36. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_adapter_kwonly.py +0 -0
  37. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_annotations.py +0 -0
  38. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_attribute_wrapper.py +0 -0
  39. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_auto_object_proxy.py +0 -0
  40. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_callable_binding_no_args.py +0 -0
  41. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_callable_object_proxy.py +0 -0
  42. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_class.py +0 -0
  43. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_class_mro_entries.py +0 -0
  44. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_copy.py +0 -0
  45. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_decorator_state.py +0 -0
  46. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_decorators.py +0 -0
  47. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_deferred_patching.py +0 -0
  48. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_descriptor_get_class_access.py +0 -0
  49. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_descriptors.py +0 -0
  50. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_enabled_bool_error.py +0 -0
  51. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_entry_points.py +0 -0
  52. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_formatargspec.py +0 -0
  53. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_function.py +0 -0
  54. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_function_wrapper.py +0 -0
  55. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_inheritance.py +0 -0
  56. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_inner_classmethod.py +0 -0
  57. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_inner_staticmethod.py +0 -0
  58. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_inplace_operators.py +0 -0
  59. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_instancemethod.py +0 -0
  60. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_lazy_object_proxy.py +0 -0
  61. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_lru_cache.py +0 -0
  62. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_memoize.py +0 -0
  63. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_monkey_patching.py +0 -0
  64. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_nested_function.py +0 -0
  65. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_object_proxy_hook.py +0 -0
  66. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_object_proxy_self_dict.py +0 -0
  67. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_object_proxy_type_checks.py +0 -0
  68. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_outer_classmethod.py +0 -0
  69. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_outer_staticmethod.py +0 -0
  70. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_pickle.py +0 -0
  71. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_post_import_hooks.py +0 -0
  72. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_pyerr_clear_propagation.py +0 -0
  73. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_resolve_path.py +0 -0
  74. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_runtime_type_hints.py +0 -0
  75. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_synchronized_async.py +0 -0
  76. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_synchronized_lock.py +0 -0
  77. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_synchronized_markers.py +0 -0
  78. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_type_module_attribute.py +0 -0
  79. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_update_attributes.py +0 -0
  80. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_weak_function_proxy.py +0 -0
  81. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/core/test_with_signature.py +0 -0
  82. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_auto_object_proxy_t1.out +0 -0
  83. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_auto_object_proxy_t1.py +0 -0
  84. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_decorator_t1.out +0 -0
  85. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_decorator_t1.py +0 -0
  86. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t1.out +0 -0
  87. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t1.py +0 -0
  88. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t2.out +0 -0
  89. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t2.py +0 -0
  90. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t3.out +0 -0
  91. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t3.py +0 -0
  92. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t4.out +0 -0
  93. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t4.py +0 -0
  94. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t5.out +0 -0
  95. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t5.py +0 -0
  96. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t6.out +0 -0
  97. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t6.py +0 -0
  98. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t7.out +0 -0
  99. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t7.py +0 -0
  100. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t8.out +0 -0
  101. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_cls_t8.py +0 -0
  102. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t1.out +0 -0
  103. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t1.py +0 -0
  104. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t2.out +0 -0
  105. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t2.py +0 -0
  106. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t3.out +0 -0
  107. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t3.py +0 -0
  108. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t4.out +0 -0
  109. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t4.py +0 -0
  110. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t5.out +0 -0
  111. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t5.py +0 -0
  112. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t6.out +0 -0
  113. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t6.py +0 -0
  114. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t7.out +0 -0
  115. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_function_wrapper_fn_t7.py +0 -0
  116. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_object_proxy_arithmetic_t1.out +0 -0
  117. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_object_proxy_arithmetic_t1.py +0 -0
  118. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_object_proxy_container_t1.out +0 -0
  119. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_object_proxy_container_t1.py +0 -0
  120. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_object_proxy_context_t1.out +0 -0
  121. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_object_proxy_context_t1.py +0 -0
  122. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_partial_callable_t1.out +0 -0
  123. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_partial_callable_t1.py +0 -0
  124. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_patch_function_wrapper_t1.out +0 -0
  125. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_patch_function_wrapper_t1.py +0 -0
  126. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_patching_primitives_t1.out +0 -0
  127. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_patching_primitives_t1.py +0 -0
  128. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_post_import_hooks_t1.out +0 -0
  129. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_post_import_hooks_t1.py +0 -0
  130. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_synchronized_lock_t1.out +0 -0
  131. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_synchronized_lock_t1.py +0 -0
  132. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_transient_function_wrapper_t1.out +0 -0
  133. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_transient_function_wrapper_t1.py +0 -0
  134. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_weak_function_proxy_t1.out +0 -0
  135. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_weak_function_proxy_t1.py +0 -0
  136. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t1.out +0 -0
  137. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t1.py +0 -0
  138. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t2.out +0 -0
  139. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t2.py +0 -0
  140. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t3.out +0 -0
  141. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t3.py +0 -0
  142. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t4.out +0 -0
  143. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t4.py +0 -0
  144. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t5.out +0 -0
  145. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t5.py +0 -0
  146. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t6.out +0 -0
  147. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t6.py +0 -0
  148. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t7.out +0 -0
  149. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t7.py +0 -0
  150. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t8.out +0 -0
  151. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tests/mypy/mypy_wrap_function_wrapper_t8.py +0 -0
  152. {wrapt-2.3.0rc1 → wrapt-2.4.0.dev1}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wrapt
3
- Version: 2.3.0rc1
3
+ Version: 2.4.0.dev1
4
4
  Summary: Module for decorators, wrappers and monkey patching.
5
5
  Author-email: Graham Dumpleton <Graham.Dumpleton@gmail.com>
6
6
  License-Expression: BSD-2-Clause
@@ -13,7 +13,7 @@ def _format_version(parts):
13
13
  )
14
14
 
15
15
 
16
- __version_info__ = ("2", "3", "0", "rc1")
16
+ __version_info__ = ("2", "4", "0", "dev1")
17
17
  __version__ = _format_version(__version_info__)
18
18
 
19
19
  from .__wrapt__ import (
@@ -153,6 +153,15 @@ static PyObject *PyType_GetModuleByDef(PyTypeObject *type,
153
153
  }
154
154
  #endif
155
155
 
156
+ /* Polyfill the critical section API for Python < 3.13. Free-threaded
157
+ * builds only exist on 3.13+, where the real macros are provided (and are
158
+ * no-ops on GIL builds), so expanding to plain blocks here is safe. */
159
+
160
+ #if PY_VERSION_HEX < 0x030D0000
161
+ #define Py_BEGIN_CRITICAL_SECTION(op) {
162
+ #define Py_END_CRITICAL_SECTION() }
163
+ #endif
164
+
156
165
  /* Polyfill PyObject_GetOptionalAttrString for Python < 3.13. Matches the
157
166
  * 3.13+ semantics: returns 1 if found, 0 if not found (AttributeError
158
167
  * only), -1 on other errors with exception set. */
@@ -446,8 +455,16 @@ static int WraptObjectProxy_raw_init(WraptObjectProxyObject *self,
446
455
  }
447
456
  }
448
457
 
458
+ /* Serialise the swap for the same reason as in the __wrapped__ setter.
459
+ * Normally __init__ runs before the proxy is shared, but it can be
460
+ * re-invoked on an already published proxy, in which case concurrent
461
+ * callers on a free-threaded build could otherwise decref the same old
462
+ * wrapped object twice. */
463
+
449
464
  Py_INCREF(wrapped);
465
+ Py_BEGIN_CRITICAL_SECTION(self);
450
466
  Py_XSETREF(self->wrapped, wrapped);
467
+ Py_END_CRITICAL_SECTION();
451
468
 
452
469
  self->init_called = 1;
453
470
 
@@ -1061,7 +1078,16 @@ static PyObject *WraptObjectProxy_inplace_add(WraptObjectProxyObject *self,
1061
1078
  if (!object)
1062
1079
  return NULL;
1063
1080
 
1081
+ /* As in the __wrapped__ setter, serialise the swap so that concurrent
1082
+ * in-place operations on the same proxy cannot decref the same old
1083
+ * wrapped object twice on a free-threaded build. The wrapped object
1084
+ * was read before the operation ran, so a concurrent mutation can
1085
+ * still be lost, matching pure Python semantics. The same applies to
1086
+ * all of the in-place operators which follow. */
1087
+
1088
+ Py_BEGIN_CRITICAL_SECTION(self);
1064
1089
  Py_SETREF(self->wrapped, object);
1090
+ Py_END_CRITICAL_SECTION();
1065
1091
 
1066
1092
  Py_INCREF(self);
1067
1093
  return (PyObject *)self;
@@ -1143,7 +1169,9 @@ static PyObject *WraptObjectProxy_inplace_subtract(WraptObjectProxyObject *self,
1143
1169
  if (!object)
1144
1170
  return NULL;
1145
1171
 
1172
+ Py_BEGIN_CRITICAL_SECTION(self);
1146
1173
  Py_SETREF(self->wrapped, object);
1174
+ Py_END_CRITICAL_SECTION();
1147
1175
 
1148
1176
  Py_INCREF(self);
1149
1177
  return (PyObject *)self;
@@ -1225,7 +1253,9 @@ static PyObject *WraptObjectProxy_inplace_multiply(WraptObjectProxyObject *self,
1225
1253
  if (!object)
1226
1254
  return NULL;
1227
1255
 
1256
+ Py_BEGIN_CRITICAL_SECTION(self);
1228
1257
  Py_SETREF(self->wrapped, object);
1258
+ Py_END_CRITICAL_SECTION();
1229
1259
 
1230
1260
  Py_INCREF(self);
1231
1261
  return (PyObject *)self;
@@ -1308,7 +1338,9 @@ WraptObjectProxy_inplace_remainder(WraptObjectProxyObject *self,
1308
1338
  if (!object)
1309
1339
  return NULL;
1310
1340
 
1341
+ Py_BEGIN_CRITICAL_SECTION(self);
1311
1342
  Py_SETREF(self->wrapped, object);
1343
+ Py_END_CRITICAL_SECTION();
1312
1344
 
1313
1345
  Py_INCREF(self);
1314
1346
  return (PyObject *)self;
@@ -1391,7 +1423,9 @@ static PyObject *WraptObjectProxy_inplace_power(WraptObjectProxyObject *self,
1391
1423
  if (!object)
1392
1424
  return NULL;
1393
1425
 
1426
+ Py_BEGIN_CRITICAL_SECTION(self);
1394
1427
  Py_SETREF(self->wrapped, object);
1428
+ Py_END_CRITICAL_SECTION();
1395
1429
 
1396
1430
  Py_INCREF(self);
1397
1431
  return (PyObject *)self;
@@ -1473,7 +1507,9 @@ static PyObject *WraptObjectProxy_inplace_lshift(WraptObjectProxyObject *self,
1473
1507
  if (!object)
1474
1508
  return NULL;
1475
1509
 
1510
+ Py_BEGIN_CRITICAL_SECTION(self);
1476
1511
  Py_SETREF(self->wrapped, object);
1512
+ Py_END_CRITICAL_SECTION();
1477
1513
 
1478
1514
  Py_INCREF(self);
1479
1515
  return (PyObject *)self;
@@ -1555,7 +1591,9 @@ static PyObject *WraptObjectProxy_inplace_rshift(WraptObjectProxyObject *self,
1555
1591
  if (!object)
1556
1592
  return NULL;
1557
1593
 
1594
+ Py_BEGIN_CRITICAL_SECTION(self);
1558
1595
  Py_SETREF(self->wrapped, object);
1596
+ Py_END_CRITICAL_SECTION();
1559
1597
 
1560
1598
  Py_INCREF(self);
1561
1599
  return (PyObject *)self;
@@ -1637,7 +1675,9 @@ static PyObject *WraptObjectProxy_inplace_and(WraptObjectProxyObject *self,
1637
1675
  if (!object)
1638
1676
  return NULL;
1639
1677
 
1678
+ Py_BEGIN_CRITICAL_SECTION(self);
1640
1679
  Py_SETREF(self->wrapped, object);
1680
+ Py_END_CRITICAL_SECTION();
1641
1681
 
1642
1682
  Py_INCREF(self);
1643
1683
  return (PyObject *)self;
@@ -1719,7 +1759,9 @@ static PyObject *WraptObjectProxy_inplace_xor(WraptObjectProxyObject *self,
1719
1759
  if (!object)
1720
1760
  return NULL;
1721
1761
 
1762
+ Py_BEGIN_CRITICAL_SECTION(self);
1722
1763
  Py_SETREF(self->wrapped, object);
1764
+ Py_END_CRITICAL_SECTION();
1723
1765
 
1724
1766
  Py_INCREF(self);
1725
1767
  return (PyObject *)self;
@@ -1801,7 +1843,9 @@ static PyObject *WraptObjectProxy_inplace_or(WraptObjectProxyObject *self,
1801
1843
  if (!object)
1802
1844
  return NULL;
1803
1845
 
1846
+ Py_BEGIN_CRITICAL_SECTION(self);
1804
1847
  Py_SETREF(self->wrapped, object);
1848
+ Py_END_CRITICAL_SECTION();
1805
1849
 
1806
1850
  Py_INCREF(self);
1807
1851
  return (PyObject *)self;
@@ -1942,7 +1986,9 @@ WraptObjectProxy_inplace_floor_divide(WraptObjectProxyObject *self,
1942
1986
  if (!object)
1943
1987
  return NULL;
1944
1988
 
1989
+ Py_BEGIN_CRITICAL_SECTION(self);
1945
1990
  Py_SETREF(self->wrapped, object);
1991
+ Py_END_CRITICAL_SECTION();
1946
1992
 
1947
1993
  Py_INCREF(self);
1948
1994
  return (PyObject *)self;
@@ -2025,7 +2071,9 @@ WraptObjectProxy_inplace_true_divide(WraptObjectProxyObject *self,
2025
2071
  if (!object)
2026
2072
  return NULL;
2027
2073
 
2074
+ Py_BEGIN_CRITICAL_SECTION(self);
2028
2075
  Py_SETREF(self->wrapped, object);
2076
+ Py_END_CRITICAL_SECTION();
2029
2077
 
2030
2078
  Py_INCREF(self);
2031
2079
  return (PyObject *)self;
@@ -2149,7 +2197,9 @@ static PyObject *WraptObjectProxy_inplace_matrix_multiply(
2149
2197
  if (!object)
2150
2198
  return NULL;
2151
2199
 
2200
+ Py_BEGIN_CRITICAL_SECTION(self);
2152
2201
  Py_SETREF(self->wrapped, object);
2202
+ Py_END_CRITICAL_SECTION();
2153
2203
 
2154
2204
  Py_INCREF(self);
2155
2205
  return (PyObject *)self;
@@ -2450,7 +2500,8 @@ static PyObject *WraptObjectProxy_bytes(WraptObjectProxyObject *self,
2450
2500
  return NULL;
2451
2501
  }
2452
2502
 
2453
- return PyObject_Bytes(self->wrapped);
2503
+ return PyObject_CallFunctionObjArgs((PyObject *)&PyBytes_Type,
2504
+ self->wrapped, NULL);
2454
2505
  }
2455
2506
 
2456
2507
  /* ------------------------------------------------------------------------- */
@@ -2919,15 +2970,22 @@ static int WraptObjectProxy_set_dict(WraptObjectProxyObject *self,
2919
2970
 
2920
2971
  static PyObject *WraptObjectProxy_get_self_dict(WraptObjectProxyObject *self)
2921
2972
  {
2973
+ PyObject *result = NULL;
2974
+
2975
+ /* self->dict is only NULL after tp_clear has run. Perform the lazy
2976
+ * recreation and the reference acquisition inside a critical section
2977
+ * so that two threads racing here on a free-threaded build cannot both
2978
+ * create a dict, leaking one of them, or return a dict which the other
2979
+ * thread has already replaced. */
2980
+
2981
+ Py_BEGIN_CRITICAL_SECTION(self);
2922
2982
  if (!self->dict)
2923
- {
2924
2983
  self->dict = PyDict_New();
2925
- if (!self->dict)
2926
- return NULL;
2927
- }
2984
+ result = self->dict;
2985
+ Py_XINCREF(result);
2986
+ Py_END_CRITICAL_SECTION();
2928
2987
 
2929
- Py_INCREF(self->dict);
2930
- return self->dict;
2988
+ return result;
2931
2989
  }
2932
2990
 
2933
2991
  /* ------------------------------------------------------------------------- */
@@ -2972,8 +3030,16 @@ static int WraptObjectProxy_set_wrapped(WraptObjectProxyObject *self,
2972
3030
  return -1;
2973
3031
  }
2974
3032
 
3033
+ /* On free-threaded builds the swap must be serialised, otherwise two
3034
+ * threads assigning __wrapped__ on the same proxy can both read the same
3035
+ * old value and both decref it, releasing it twice. The critical section
3036
+ * covers only the swap; __wrapped_setattr_fixups__ below runs arbitrary
3037
+ * Python code and must stay outside it. */
3038
+
2975
3039
  Py_INCREF(value);
3040
+ Py_BEGIN_CRITICAL_SECTION(self);
2976
3041
  Py_XSETREF(self->wrapped, value);
3042
+ Py_END_CRITICAL_SECTION();
2977
3043
 
2978
3044
  fixups = PyObject_GetAttr((PyObject *)self, state->str_setattr_fixups);
2979
3045
 
@@ -3385,11 +3451,19 @@ static int WraptPartialCallableObjectProxy_raw_init(
3385
3451
 
3386
3452
  if (result == 0)
3387
3453
  {
3388
- Py_INCREF(args);
3389
- Py_XSETREF(self->args, args);
3454
+ /* Serialise the swaps for the same reason as in the __wrapped__
3455
+ * setter. Initialisation normally happens before the proxy is shared,
3456
+ * but __init__ can be re-invoked on an already published proxy, in
3457
+ * which case concurrent callers on a free-threaded build could
3458
+ * otherwise decref the same old args or kwargs twice. */
3390
3459
 
3460
+ Py_INCREF(args);
3391
3461
  Py_XINCREF(kwargs);
3462
+
3463
+ Py_BEGIN_CRITICAL_SECTION(self);
3464
+ Py_XSETREF(self->args, args);
3392
3465
  Py_XSETREF(self->kwargs, kwargs);
3466
+ Py_END_CRITICAL_SECTION();
3393
3467
  }
3394
3468
 
3395
3469
  return result;
@@ -3617,23 +3691,27 @@ static int WraptFunctionWrapperBase_raw_init(
3617
3691
 
3618
3692
  if (result == 0)
3619
3693
  {
3620
- Py_INCREF(instance);
3621
- Py_XSETREF(self->instance, instance);
3694
+ /* Serialise the swaps for the same reason as in the __wrapped__
3695
+ * setter. These fields have no setters, so re-invocation of __init__
3696
+ * on an already published wrapper is the only path by which
3697
+ * concurrent callers on a free-threaded build could otherwise decref
3698
+ * the same old field values twice. */
3622
3699
 
3700
+ Py_INCREF(instance);
3623
3701
  Py_INCREF(wrapper);
3624
- Py_XSETREF(self->wrapper, wrapper);
3625
-
3626
3702
  Py_INCREF(enabled);
3627
- Py_XSETREF(self->enabled, enabled);
3628
-
3629
3703
  Py_INCREF(binding);
3630
- Py_XSETREF(self->binding, binding);
3631
-
3632
3704
  Py_INCREF(parent);
3633
- Py_XSETREF(self->parent, parent);
3634
-
3635
3705
  Py_INCREF(owner);
3706
+
3707
+ Py_BEGIN_CRITICAL_SECTION(self);
3708
+ Py_XSETREF(self->instance, instance);
3709
+ Py_XSETREF(self->wrapper, wrapper);
3710
+ Py_XSETREF(self->enabled, enabled);
3711
+ Py_XSETREF(self->binding, binding);
3712
+ Py_XSETREF(self->parent, parent);
3636
3713
  Py_XSETREF(self->owner, owner);
3714
+ Py_END_CRITICAL_SECTION();
3637
3715
  }
3638
3716
 
3639
3717
  return result;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wrapt
3
- Version: 2.3.0rc1
3
+ Version: 2.4.0.dev1
4
4
  Summary: Module for decorators, wrappers and monkey patching.
5
5
  Author-email: Graham Dumpleton <Graham.Dumpleton@gmail.com>
6
6
  License-Expression: BSD-2-Clause
@@ -1932,6 +1932,55 @@ class SpecialMethods(unittest.TestCase):
1932
1932
 
1933
1933
  self.assertEqual(bytes(instance), bytes(proxy))
1934
1934
 
1935
+ def test_int_bytes(self):
1936
+ # bytes(proxy) should behave like bytes() on the wrapped object even
1937
+ # when it has no __bytes__ (e.g. an int, where bytes(n) yields a
1938
+ # zero-filled buffer of length n).
1939
+ instance = 3
1940
+
1941
+ proxy = wrapt.ObjectProxy(instance)
1942
+
1943
+ self.assertEqual(bytes(instance), bytes(proxy))
1944
+
1945
+ def test_index_bytes(self):
1946
+ # An object with __index__() but no __bytes__ converts like an int,
1947
+ # yielding a zero-filled buffer.
1948
+ class Class:
1949
+ def __index__(self):
1950
+ return 2
1951
+
1952
+ instance = Class()
1953
+
1954
+ proxy = wrapt.ObjectProxy(instance)
1955
+
1956
+ self.assertEqual(bytes(instance), bytes(proxy))
1957
+
1958
+ def test_buffer_bytes(self):
1959
+ # An object supporting the buffer protocol but no __bytes__.
1960
+ instance = bytearray(b"abcd")
1961
+
1962
+ proxy = wrapt.ObjectProxy(instance)
1963
+
1964
+ self.assertEqual(bytes(instance), bytes(proxy))
1965
+
1966
+ def test_iterable_bytes(self):
1967
+ # An iterable of ints, converted element by element.
1968
+ instance = [1, 2, 3]
1969
+
1970
+ proxy = wrapt.ObjectProxy(instance)
1971
+
1972
+ self.assertEqual(bytes(instance), bytes(proxy))
1973
+
1974
+ def test_str_bytes(self):
1975
+ # bytes() on a str without an encoding raises TypeError, and the
1976
+ # proxy should match rather than fall back to some other conversion.
1977
+ instance = "abcd"
1978
+
1979
+ proxy = wrapt.ObjectProxy(instance)
1980
+
1981
+ with self.assertRaises(TypeError):
1982
+ bytes(proxy)
1983
+
1935
1984
  def test_str_format(self):
1936
1985
  instance = "abcd"
1937
1986
 
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