wrapt 2.0.0__cp314-cp314t-macosx_11_0_arm64.whl → 2.0.1__cp314-cp314t-macosx_11_0_arm64.whl

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.
wrapt/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  Wrapt is a library for decorators, wrappers and monkey patching.
3
3
  """
4
4
 
5
- __version_info__ = ("2", "0", "0")
5
+ __version_info__ = ("2", "0", "1")
6
6
  __version__ = ".".join(__version_info__)
7
7
 
8
8
  from .__wrapt__ import (
@@ -53,6 +53,7 @@ __all__ = (
53
53
  "when_imported",
54
54
  "apply_patch",
55
55
  "function_wrapper",
56
+ "lazy_import",
56
57
  "patch_function_wrapper",
57
58
  "resolve_path",
58
59
  "transient_function_wrapper",
wrapt/__init__.pyi CHANGED
@@ -37,12 +37,16 @@ if sys.version_info >= (3, 10):
37
37
  # LazyObjectProxy
38
38
 
39
39
  class LazyObjectProxy(AutoObjectProxy[T]):
40
- def __init__(self, callback: Callable[[], T] | None) -> None: ...
40
+ def __init__(
41
+ self, callback: Callable[[], T] | None, *, interface: Any = ...
42
+ ) -> None: ...
41
43
 
42
44
  @overload
43
45
  def lazy_import(name: str) -> LazyObjectProxy[ModuleType]: ...
44
46
  @overload
45
- def lazy_import(name: str, attribute: str) -> LazyObjectProxy[Any]: ...
47
+ def lazy_import(
48
+ name: str, attribute: str, *, interface: Any = ...
49
+ ) -> LazyObjectProxy[Any]: ...
46
50
 
47
51
  # CallableObjectProxy
48
52
 
Binary file
wrapt/proxies.py CHANGED
@@ -1,5 +1,8 @@
1
1
  """Variants of ObjectProxy for different use cases."""
2
2
 
3
+ from collections.abc import Callable
4
+ from types import ModuleType
5
+
3
6
  from .__wrapt__ import BaseObjectProxy
4
7
  from .decorators import synchronized
5
8
 
@@ -30,7 +33,12 @@ class ObjectProxy(BaseObjectProxy):
30
33
  # object and add special dunder methods.
31
34
 
32
35
 
33
- def __wrapper_call__(self, *args, **kwargs):
36
+ def __wrapper_call__(*args, **kwargs):
37
+ def _unpack_self(self, *args):
38
+ return self, args
39
+
40
+ self, args = _unpack_self(*args)
41
+
34
42
  return self.__wrapped__(*args, **kwargs)
35
43
 
36
44
 
@@ -136,7 +144,7 @@ class AutoObjectProxy(BaseObjectProxy):
136
144
  if cls is AutoObjectProxy:
137
145
  name = BaseObjectProxy.__name__
138
146
 
139
- return super().__new__(type(name, (cls,), namespace))
147
+ return super(AutoObjectProxy, cls).__new__(type(name, (cls,), namespace))
140
148
 
141
149
  def __wrapped_setattr_fixups__(self):
142
150
  """Adjusts special dunder methods on the class as needed based on the
@@ -218,10 +226,64 @@ class LazyObjectProxy(AutoObjectProxy):
218
226
  when it is first needed.
219
227
  """
220
228
 
221
- def __new__(cls, callback=None):
222
- return super().__new__(cls, None)
229
+ def __new__(cls, callback=None, *, interface=...):
230
+ """Injects special dunder methods into a dynamically created subclass
231
+ as needed based on the wrapped object.
232
+ """
233
+
234
+ if interface is ...:
235
+ interface = type(None)
236
+
237
+ namespace = {}
238
+
239
+ interface_attrs = dir(interface)
240
+ class_attrs = set(dir(cls))
241
+
242
+ if "__call__" in interface_attrs and "__call__" not in class_attrs:
243
+ namespace["__call__"] = __wrapper_call__
244
+
245
+ if "__iter__" in interface_attrs and "__iter__" not in class_attrs:
246
+ namespace["__iter__"] = __wrapper_iter__
247
+
248
+ if "__next__" in interface_attrs and "__next__" not in class_attrs:
249
+ namespace["__next__"] = __wrapper_next__
250
+
251
+ if "__aiter__" in interface_attrs and "__aiter__" not in class_attrs:
252
+ namespace["__aiter__"] = __wrapper_aiter__
253
+
254
+ if "__anext__" in interface_attrs and "__anext__" not in class_attrs:
255
+ namespace["__anext__"] = __wrapper_anext__
223
256
 
224
- def __init__(self, callback=None):
257
+ if (
258
+ "__length_hint__" in interface_attrs
259
+ and "__length_hint__" not in class_attrs
260
+ ):
261
+ namespace["__length_hint__"] = __wrapper_length_hint__
262
+
263
+ # Note that not providing compatibility with generator-based coroutines
264
+ # (PEP 342) here as they are removed in Python 3.11+ and were deprecated
265
+ # in 3.8.
266
+
267
+ if "__await__" in interface_attrs and "__await__" not in class_attrs:
268
+ namespace["__await__"] = __wrapper_await__
269
+
270
+ if "__get__" in interface_attrs and "__get__" not in class_attrs:
271
+ namespace["__get__"] = __wrapper_get__
272
+
273
+ if "__set__" in interface_attrs and "__set__" not in class_attrs:
274
+ namespace["__set__"] = __wrapper_set__
275
+
276
+ if "__delete__" in interface_attrs and "__delete__" not in class_attrs:
277
+ namespace["__delete__"] = __wrapper_delete__
278
+
279
+ if "__set_name__" in interface_attrs and "__set_name__" not in class_attrs:
280
+ namespace["__set_name__"] = __wrapper_set_name__
281
+
282
+ name = cls.__name__
283
+
284
+ return super(AutoObjectProxy, cls).__new__(type(name, (cls,), namespace))
285
+
286
+ def __init__(self, callback=None, *, interface=...):
225
287
  """Initialize the object proxy with wrapped object as `None` but due
226
288
  to presence of special `__wrapped_factory__` attribute addded first,
227
289
  this will actually trigger the deferred creation of the wrapped object
@@ -263,7 +325,7 @@ class LazyObjectProxy(AutoObjectProxy):
263
325
  return self.__wrapped__
264
326
 
265
327
 
266
- def lazy_import(name, attribute=None):
328
+ def lazy_import(name, attribute=None, *, interface=...):
267
329
  """Lazily imports the module `name`, returning a `LazyObjectProxy` which
268
330
  will import the module when it is first needed. When `name is a dotted name,
269
331
  then the full dotted name is imported and the last module is taken as the
@@ -271,6 +333,13 @@ def lazy_import(name, attribute=None):
271
333
  from the module.
272
334
  """
273
335
 
336
+ if attribute is not None:
337
+ if interface is ...:
338
+ interface = Callable
339
+ else:
340
+ if interface is ...:
341
+ interface = ModuleType
342
+
274
343
  def _import():
275
344
  module = __import__(name, fromlist=[""])
276
345
 
@@ -279,4 +348,4 @@ def lazy_import(name, attribute=None):
279
348
 
280
349
  return module
281
350
 
282
- return LazyObjectProxy(_import)
351
+ return LazyObjectProxy(_import, interface=interface)
@@ -0,0 +1,216 @@
1
+ Metadata-Version: 2.4
2
+ Name: wrapt
3
+ Version: 2.0.1
4
+ Summary: Module for decorators, wrappers and monkey patching.
5
+ Home-page: https://github.com/GrahamDumpleton/wrapt
6
+ Author: Graham Dumpleton
7
+ Author-email: Graham Dumpleton <Graham.Dumpleton@gmail.com>
8
+ License: Copyright (c) 2013-2025, Graham Dumpleton
9
+ All rights reserved.
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are met:
13
+
14
+ * Redistributions of source code must retain the above copyright notice, this
15
+ list of conditions and the following disclaimer.
16
+
17
+ * Redistributions in binary form must reproduce the above copyright notice,
18
+ this list of conditions and the following disclaimer in the documentation
19
+ and/or other materials provided with the distribution.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ POSSIBILITY OF SUCH DAMAGE.
32
+
33
+ Project-URL: Homepage, https://github.com/GrahamDumpleton/wrapt
34
+ Project-URL: Bug Tracker, https://github.com/GrahamDumpleton/wrapt/issues/
35
+ Project-URL: Changelog, https://wrapt.readthedocs.io/en/latest/changes.html
36
+ Project-URL: Documentation, https://wrapt.readthedocs.io/
37
+ Keywords: wrapper,proxy,decorator
38
+ Platform: any
39
+ Classifier: Development Status :: 5 - Production/Stable
40
+ Classifier: Programming Language :: Python :: 3
41
+ Classifier: Programming Language :: Python :: 3.8
42
+ Classifier: Programming Language :: Python :: 3.9
43
+ Classifier: Programming Language :: Python :: 3.10
44
+ Classifier: Programming Language :: Python :: 3.11
45
+ Classifier: Programming Language :: Python :: 3.12
46
+ Classifier: Programming Language :: Python :: 3.13
47
+ Classifier: Programming Language :: Python :: 3.14
48
+ Classifier: Programming Language :: Python :: Implementation :: CPython
49
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
50
+ Requires-Python: >=3.8
51
+ Description-Content-Type: text/x-rst
52
+ License-File: LICENSE
53
+ Provides-Extra: dev
54
+ Requires-Dist: pytest; extra == "dev"
55
+ Requires-Dist: setuptools; extra == "dev"
56
+ Dynamic: license-file
57
+
58
+ wrapt
59
+ =====
60
+
61
+ |PyPI| |Documentation|
62
+
63
+ A Python module for decorators, wrappers and monkey patching.
64
+
65
+ Overview
66
+ --------
67
+
68
+ The **wrapt** module provides a transparent object proxy for Python, which can be used as the basis for the construction of function wrappers and decorator functions.
69
+
70
+ The **wrapt** module focuses very much on correctness. It goes way beyond existing mechanisms such as ``functools.wraps()`` to ensure that decorators preserve introspectability, signatures, type checking abilities etc. The decorators that can be constructed using this module will work in far more scenarios than typical decorators and provide more predictable and consistent behaviour.
71
+
72
+ To ensure that the overhead is as minimal as possible, a C extension module is used for performance critical components. An automatic fallback to a pure Python implementation is also provided where a target system does not have a compiler to allow the C extension to be compiled.
73
+
74
+ Key Features
75
+ ------------
76
+
77
+ * **Universal decorators** that work with functions, methods, classmethods, staticmethods, and classes
78
+ * **Transparent object proxies** for advanced wrapping scenarios
79
+ * **Monkey patching utilities** for safe runtime modifications
80
+ * **C extension** for optimal performance with Python fallback
81
+ * **Comprehensive introspection preservation** (signatures, annotations, etc.)
82
+ * **Thread-safe decorator implementations**
83
+
84
+ Installation
85
+ ------------
86
+
87
+ Install from PyPI using pip::
88
+
89
+ pip install wrapt
90
+
91
+ Supported Python Versions
92
+ --------------------------
93
+
94
+ * Python 3.8+
95
+ * CPython and PyPy implementations
96
+
97
+ Documentation
98
+ -------------
99
+
100
+ For comprehensive documentation, examples, and advanced usage patterns, visit:
101
+
102
+ * https://wrapt.readthedocs.io/
103
+
104
+ Quick Start
105
+ -----------
106
+
107
+ To implement your decorator you need to first define a wrapper function.
108
+ This will be called each time a decorated function is called. The wrapper
109
+ function needs to take four positional arguments:
110
+
111
+ * ``wrapped`` - The wrapped function which in turns needs to be called by your wrapper function.
112
+ * ``instance`` - The object to which the wrapped function was bound when it was called.
113
+ * ``args`` - The list of positional arguments supplied when the decorated function was called.
114
+ * ``kwargs`` - The dictionary of keyword arguments supplied when the decorated function was called.
115
+
116
+ The wrapper function would do whatever it needs to, but would usually in
117
+ turn call the wrapped function that is passed in via the ``wrapped``
118
+ argument.
119
+
120
+ The decorator ``@wrapt.decorator`` then needs to be applied to the wrapper
121
+ function to convert it into a decorator which can in turn be applied to
122
+ other functions.
123
+
124
+ .. code-block:: python
125
+
126
+ import wrapt
127
+
128
+ @wrapt.decorator
129
+ def pass_through(wrapped, instance, args, kwargs):
130
+ return wrapped(*args, **kwargs)
131
+
132
+ @pass_through
133
+ def function():
134
+ pass
135
+
136
+ If you wish to implement a decorator which accepts arguments, then wrap the
137
+ definition of the decorator in a function closure. Any arguments supplied
138
+ to the outer function when the decorator is applied, will be available to
139
+ the inner wrapper when the wrapped function is called.
140
+
141
+ .. code-block:: python
142
+
143
+ import wrapt
144
+
145
+ def with_arguments(myarg1, myarg2):
146
+ @wrapt.decorator
147
+ def wrapper(wrapped, instance, args, kwargs):
148
+ return wrapped(*args, **kwargs)
149
+ return wrapper
150
+
151
+ @with_arguments(1, 2)
152
+ def function():
153
+ pass
154
+
155
+ When applied to a normal function or static method, the wrapper function
156
+ when called will be passed ``None`` as the ``instance`` argument.
157
+
158
+ When applied to an instance method, the wrapper function when called will
159
+ be passed the instance of the class the method is being called on as the
160
+ ``instance`` argument. This will be the case even when the instance method
161
+ was called explicitly via the class and the instance passed as the first
162
+ argument. That is, the instance will never be passed as part of ``args``.
163
+
164
+ When applied to a class method, the wrapper function when called will be
165
+ passed the class type as the ``instance`` argument.
166
+
167
+ When applied to a class, the wrapper function when called will be passed
168
+ ``None`` as the ``instance`` argument. The ``wrapped`` argument in this
169
+ case will be the class.
170
+
171
+ The above rules can be summarised with the following example.
172
+
173
+ .. code-block:: python
174
+
175
+ import inspect
176
+
177
+ @wrapt.decorator
178
+ def universal(wrapped, instance, args, kwargs):
179
+ if instance is None:
180
+ if inspect.isclass(wrapped):
181
+ # Decorator was applied to a class.
182
+ return wrapped(*args, **kwargs)
183
+ else:
184
+ # Decorator was applied to a function or staticmethod.
185
+ return wrapped(*args, **kwargs)
186
+ else:
187
+ if inspect.isclass(instance):
188
+ # Decorator was applied to a classmethod.
189
+ return wrapped(*args, **kwargs)
190
+ else:
191
+ # Decorator was applied to an instancemethod.
192
+ return wrapped(*args, **kwargs)
193
+
194
+ Using these checks it is therefore possible to create a universal decorator
195
+ that can be applied in all situations. It is no longer necessary to create
196
+ different variants of decorators for normal functions and instance methods,
197
+ or use additional wrappers to convert a function decorator into one that
198
+ will work for instance methods.
199
+
200
+ In all cases, the wrapped function passed to the wrapper function is called
201
+ in the same way, with ``args`` and ``kwargs`` being passed. The
202
+ ``instance`` argument doesn't need to be used in calling the wrapped
203
+ function.
204
+
205
+ Links
206
+ -----
207
+
208
+ * **Documentation**: https://wrapt.readthedocs.io/
209
+ * **Source Code**: https://github.com/GrahamDumpleton/wrapt
210
+ * **Bug Reports**: https://github.com/GrahamDumpleton/wrapt/issues/
211
+ * **Changelog**: https://wrapt.readthedocs.io/en/latest/changes.html
212
+
213
+ .. |PyPI| image:: https://img.shields.io/pypi/v/wrapt.svg?logo=python&cacheSeconds=3600
214
+ :target: https://pypi.python.org/pypi/wrapt
215
+ .. |Documentation| image:: https://img.shields.io/badge/docs-wrapt.readthedocs.io-blue.svg
216
+ :target: https://wrapt.readthedocs.io/
@@ -1,17 +1,17 @@
1
- wrapt-2.0.0.dist-info/RECORD,,
2
- wrapt-2.0.0.dist-info/WHEEL,sha256=26nyvDx4qlf6NyRSh1NSNrXJDCQeX0hnJ7EH1bB1egM,137
3
- wrapt-2.0.0.dist-info/top_level.txt,sha256=Jf7kcuXtwjUJMwOL0QzALDg2WiSiXiH9ThKMjN64DW0,6
4
- wrapt-2.0.0.dist-info/METADATA,sha256=jpjEmta4CbxgBQ06tfPdJaxpwG-jyRMEzgDCsvqgfn0,8828
5
- wrapt-2.0.0.dist-info/licenses/LICENSE,sha256=mrxBqmuGkMB-3ptEt8YjPQFCkO0eO1zMN-KSKVtdBY8,1304
6
- wrapt/_wrappers.cpython-314t-darwin.so,sha256=MK2NGNqSUTjIPHXCNRRLkp25EE1ZF2OtXhomioJacaA,105184
1
+ wrapt-2.0.1.dist-info/RECORD,,
2
+ wrapt-2.0.1.dist-info/WHEEL,sha256=26nyvDx4qlf6NyRSh1NSNrXJDCQeX0hnJ7EH1bB1egM,137
3
+ wrapt-2.0.1.dist-info/top_level.txt,sha256=Jf7kcuXtwjUJMwOL0QzALDg2WiSiXiH9ThKMjN64DW0,6
4
+ wrapt-2.0.1.dist-info/METADATA,sha256=nbszIjJc0vsh_DVij7b9ct6R9G2VCzVTTPSke5imlvs,8979
5
+ wrapt-2.0.1.dist-info/licenses/LICENSE,sha256=mrxBqmuGkMB-3ptEt8YjPQFCkO0eO1zMN-KSKVtdBY8,1304
6
+ wrapt/_wrappers.cpython-314t-darwin.so,sha256=lZpxUGLoyhAFCAMG0P3-U7Xe_FoNaNe5-LXyzYzWG5c,105184
7
7
  wrapt/importer.py,sha256=E16XxhomZuX5jM_JEH4ZO-MYpNou1t5RZLJHWLCtsgM,12135
8
- wrapt/__init__.pyi,sha256=sEJ93UmAcYesuYzTdyhmqCX5dQWyfD5IIJKT-wox3R8,9316
8
+ wrapt/__init__.pyi,sha256=d3CBY392zYAgBJoUeaRzdOUDbwlHgCxiLROnd4LdSG8,9402
9
9
  wrapt/arguments.py,sha256=q4bxH7GoCXhTCgxy-AEyvSnOq0ovMSHjN7ru3HWxlhA,2548
10
- wrapt/__init__.py,sha256=p1RQbeOGbig53vlveTjL788KtGvADBMMUymrZQwgqmk,1521
10
+ wrapt/__init__.py,sha256=bAF7Gzqnf_vUBpf5KNFfIm5P9Drm7M0WYlt22W25Q4Y,1540
11
11
  wrapt/__wrapt__.py,sha256=E_Yo7fIk51_OjMzlqXKtIhvplbYbJIPcTGD20b0GWM8,1431
12
12
  wrapt/patches.py,sha256=WJAKwOEeozpqgLAq_BlEu2HWbjMg9yaR65szi8J4GRQ,9907
13
13
  wrapt/wrappers.py,sha256=btpuNklFXdpnWlQVrgib1cY08M5tm1vTSd_XEjfEgxs,34439
14
- wrapt/proxies.py,sha256=x9mergCbZIW4pplUmACkSU6iH0iWy9xNadQUoSp3ksA,10018
14
+ wrapt/proxies.py,sha256=0-N74mBM3tsC_zEQ83to3Y5OMqdxEu4BhXs3Hq1GDCU,12517
15
15
  wrapt/weakrefs.py,sha256=5HehYcKOKsRIghxLwnCZ4EJ67rhc0z1GH__pRILRLDc,4630
16
16
  wrapt/py.typed,sha256=la67KBlbjXN-_-DfGNcdOcjYumVpKG_Tkw-8n5dnGB4,8
17
17
  wrapt/_wrappers.c,sha256=ux1b_-Me_8QpJ_QRWvCq9jt_1CZ-9TFA-cVSLqi4_Zg,115800
@@ -1,198 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: wrapt
3
- Version: 2.0.0
4
- Summary: Module for decorators, wrappers and monkey patching.
5
- Home-page: https://github.com/GrahamDumpleton/wrapt
6
- Author: Graham Dumpleton
7
- Author-email: Graham Dumpleton <Graham.Dumpleton@gmail.com>
8
- License: Copyright (c) 2013-2025, Graham Dumpleton
9
- All rights reserved.
10
-
11
- Redistribution and use in source and binary forms, with or without
12
- modification, are permitted provided that the following conditions are met:
13
-
14
- * Redistributions of source code must retain the above copyright notice, this
15
- list of conditions and the following disclaimer.
16
-
17
- * Redistributions in binary form must reproduce the above copyright notice,
18
- this list of conditions and the following disclaimer in the documentation
19
- and/or other materials provided with the distribution.
20
-
21
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
- POSSIBILITY OF SUCH DAMAGE.
32
-
33
- Project-URL: Homepage, https://github.com/GrahamDumpleton/wrapt
34
- Project-URL: Bug Tracker, https://github.com/GrahamDumpleton/wrapt/issues/
35
- Project-URL: Changelog, https://wrapt.readthedocs.io/en/latest/changes.html
36
- Project-URL: Documentation, https://wrapt.readthedocs.io/
37
- Keywords: wrapper,proxy,decorator
38
- Platform: any
39
- Classifier: Development Status :: 5 - Production/Stable
40
- Classifier: Programming Language :: Python :: 3
41
- Classifier: Programming Language :: Python :: 3.8
42
- Classifier: Programming Language :: Python :: 3.9
43
- Classifier: Programming Language :: Python :: 3.10
44
- Classifier: Programming Language :: Python :: 3.11
45
- Classifier: Programming Language :: Python :: 3.12
46
- Classifier: Programming Language :: Python :: 3.13
47
- Classifier: Programming Language :: Python :: 3.14
48
- Classifier: Programming Language :: Python :: Implementation :: CPython
49
- Classifier: Programming Language :: Python :: Implementation :: PyPy
50
- Requires-Python: >=3.8
51
- Description-Content-Type: text/markdown
52
- License-File: LICENSE
53
- Provides-Extra: dev
54
- Requires-Dist: pytest; extra == "dev"
55
- Requires-Dist: setuptools; extra == "dev"
56
- Dynamic: license-file
57
-
58
- # wrapt
59
-
60
- [![PyPI](https://img.shields.io/pypi/v/wrapt.svg?logo=python&cacheSeconds=3600)](https://pypi.python.org/pypi/wrapt)
61
- [![Documentation](https://img.shields.io/badge/docs-wrapt.readthedocs.io-blue.svg)](https://wrapt.readthedocs.io/)
62
- [![License](https://img.shields.io/badge/license-BSD-green.svg)](LICENSE)
63
-
64
- A Python module for decorators, wrappers and monkey patching.
65
-
66
- ## Overview
67
-
68
- The **wrapt** module provides a transparent object proxy for Python, which can be used as the basis for the construction of function wrappers and decorator functions.
69
-
70
- The **wrapt** module focuses very much on correctness. It goes way beyond existing mechanisms such as `functools.wraps()` to ensure that decorators preserve introspectability, signatures, type checking abilities etc. The decorators that can be constructed using this module will work in far more scenarios than typical decorators and provide more predictable and consistent behaviour.
71
-
72
- To ensure that the overhead is as minimal as possible, a C extension module is used for performance critical components. An automatic fallback to a pure Python implementation is also provided where a target system does not have a compiler to allow the C extension to be compiled.
73
-
74
- ## Features
75
-
76
- - **Universal decorators** that work with functions, methods, classmethods, staticmethods, and classes
77
- - **Transparent object proxies** for advanced wrapping scenarios
78
- - **Monkey patching utilities** for safe runtime modifications
79
- - **C extension** for optimal performance with Python fallback
80
- - **Comprehensive introspection preservation** (signatures, annotations, etc.)
81
- - **Thread-safe decorator implementations**
82
-
83
- ## Installation
84
-
85
- ```bash
86
- pip install wrapt
87
- ```
88
-
89
- ## Quick Start
90
-
91
- ### Basic Decorator
92
-
93
- ```python
94
- import wrapt
95
-
96
- @wrapt.decorator
97
- def pass_through(wrapped, instance, args, kwargs):
98
- return wrapped(*args, **kwargs)
99
-
100
- @pass_through
101
- def function():
102
- pass
103
- ```
104
-
105
- ### Decorator with Arguments
106
-
107
- ```python
108
- import wrapt
109
-
110
- def with_arguments(myarg1, myarg2):
111
- @wrapt.decorator
112
- def wrapper(wrapped, instance, args, kwargs):
113
- print(f"Arguments: {myarg1}, {myarg2}")
114
- return wrapped(*args, **kwargs)
115
- return wrapper
116
-
117
- @with_arguments(1, 2)
118
- def function():
119
- pass
120
- ```
121
-
122
- ### Universal Decorator
123
-
124
- ```python
125
- import inspect
126
- import wrapt
127
-
128
- @wrapt.decorator
129
- def universal(wrapped, instance, args, kwargs):
130
- if instance is None:
131
- if inspect.isclass(wrapped):
132
- # Decorator was applied to a class
133
- print("Decorating a class")
134
- else:
135
- # Decorator was applied to a function or staticmethod
136
- print("Decorating a function")
137
- else:
138
- if inspect.isclass(instance):
139
- # Decorator was applied to a classmethod
140
- print("Decorating a classmethod")
141
- else:
142
- # Decorator was applied to an instancemethod
143
- print("Decorating an instance method")
144
-
145
- return wrapped(*args, **kwargs)
146
- ```
147
-
148
- ## Documentation
149
-
150
- For comprehensive documentation, examples, and advanced usage patterns, visit:
151
-
152
- **[wrapt.readthedocs.io](https://wrapt.readthedocs.io/)**
153
-
154
- ## Supported Python Versions
155
-
156
- - Python 3.8+
157
- - CPython
158
- - PyPy
159
-
160
- ## Contributing
161
-
162
- We welcome contributions! This is a pretty casual process - if you're interested in suggesting changes, improvements, or have found a bug, please reach out via the [GitHub issue tracker](https://github.com/GrahamDumpleton/wrapt/issues/). Whether it's a small fix, new feature idea, or just a question about how something works, feel free to start a discussion.
163
-
164
- Please note that wrapt is now considered a mature project. We're not expecting any significant new developments or major feature additions. The primary focus is on ensuring that the package continues to work correctly with newer Python versions and maintaining compatibility as the Python ecosystem evolves.
165
-
166
- ### Testing
167
-
168
- For information about running tests, including Python version-specific test conventions and available test commands, see [TESTING.md](TESTING.md).
169
-
170
- ## License
171
-
172
- This project is licensed under the BSD License - see the [LICENSE](LICENSE) file for details.
173
-
174
- ## Links
175
-
176
- - **Documentation**: https://wrapt.readthedocs.io/
177
- - **PyPI**: https://pypi.python.org/pypi/wrapt
178
- - **Issues**: https://github.com/GrahamDumpleton/wrapt/issues/
179
- - **Changelog**: https://wrapt.readthedocs.io/en/latest/changes.html
180
-
181
- ## Related Blog Posts
182
-
183
- This repository also contains a series of blog posts explaining the design and implementation of wrapt:
184
-
185
- - [How you implemented your Python decorator is wrong](blog/01-how-you-implemented-your-python-decorator-is-wrong.md)
186
- - [The interaction between decorators and descriptors](blog/02-the-interaction-between-decorators-and-descriptors.md)
187
- - [Implementing a factory for creating decorators](blog/03-implementing-a-factory-for-creating-decorators.md)
188
- - [Implementing a universal decorator](blog/04-implementing-a-universal-decorator.md)
189
- - [Decorators which accept arguments](blog/05-decorators-which-accept-arguments.md)
190
- - [Maintaining decorator state using a class](blog/06-maintaining-decorator-state-using-a-class.md)
191
- - [The missing synchronized decorator](blog/07-the-missing-synchronized-decorator.md)
192
- - [The synchronized decorator as context manager](blog/08-the-synchronized-decorator-as-context-manager.md)
193
- - [Performance overhead of using decorators](blog/09-performance-overhead-of-using-decorators.md)
194
- - [Performance overhead when applying decorators to methods](blog/10-performance-overhead-when-applying-decorators-to-methods.md)
195
- - [Safely applying monkey patches in Python](blog/11-safely-applying-monkey-patches-in-python.md)
196
- - [Using wrapt to support testing of software](blog/12-using-wrapt-to-support-testing-of-software.md)
197
- - [Ordering issues when monkey patching in Python](blog/13-ordering-issues-when-monkey-patching-in-python.md)
198
- - [Automatic patching of Python applications](blog/14-automatic-patching-of-python-applications.md)
File without changes