wrapt 2.0.0rc2__cp314-cp314t-win_arm64.whl → 2.0.1__cp314-cp314t-win_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.
Binary file
wrapt/decorators.py CHANGED
@@ -8,12 +8,7 @@ from functools import partial
8
8
  from inspect import isclass, signature
9
9
  from threading import Lock, RLock
10
10
 
11
- from .__wrapt__ import (
12
- BoundFunctionWrapper,
13
- CallableObjectProxy,
14
- FunctionWrapper,
15
- ObjectProxy,
16
- )
11
+ from .__wrapt__ import BoundFunctionWrapper, CallableObjectProxy, FunctionWrapper
17
12
  from .arguments import formatargspec
18
13
 
19
14
  # Adapter wrapper for the wrapped function which will overlay certain
wrapt/importer.py CHANGED
@@ -9,7 +9,7 @@ import threading
9
9
  from importlib.util import find_spec
10
10
  from typing import Callable, Dict, List
11
11
 
12
- from .__wrapt__ import ObjectProxy
12
+ from .__wrapt__ import BaseObjectProxy
13
13
 
14
14
  # The dictionary registering any post import hooks to be triggered once
15
15
  # the target module has been imported. Once a module has been imported
@@ -166,7 +166,7 @@ class _ImportHookLoader:
166
166
  return module
167
167
 
168
168
 
169
- class _ImportHookChainedLoader(ObjectProxy):
169
+ class _ImportHookChainedLoader(BaseObjectProxy):
170
170
 
171
171
  def __init__(self, loader):
172
172
  super(_ImportHookChainedLoader, self).__init__(loader)
wrapt/proxies.py ADDED
@@ -0,0 +1,351 @@
1
+ """Variants of ObjectProxy for different use cases."""
2
+
3
+ from collections.abc import Callable
4
+ from types import ModuleType
5
+
6
+ from .__wrapt__ import BaseObjectProxy
7
+ from .decorators import synchronized
8
+
9
+ # Define ObjectProxy which for compatibility adds `__iter__()` support which
10
+ # has been removed from `BaseObjectProxy`.
11
+
12
+
13
+ class ObjectProxy(BaseObjectProxy):
14
+ """A generic object proxy which forwards special methods as needed.
15
+ For backwards compatibility this class adds support for `__iter__()`. If
16
+ you don't need backward compatibility for `__iter__()` support then it is
17
+ preferable to use `BaseObjectProxy` directly. If you want automatic
18
+ support for special dunder methods for callables, iterators, and async,
19
+ then use `AutoObjectProxy`."""
20
+
21
+ @property
22
+ def __object_proxy__(self):
23
+ return ObjectProxy
24
+
25
+ def __new__(cls, *args, **kwargs):
26
+ return super().__new__(cls)
27
+
28
+ def __iter__(self):
29
+ return iter(self.__wrapped__)
30
+
31
+
32
+ # Define variant of ObjectProxy which can automatically adjust to the wrapped
33
+ # object and add special dunder methods.
34
+
35
+
36
+ def __wrapper_call__(*args, **kwargs):
37
+ def _unpack_self(self, *args):
38
+ return self, args
39
+
40
+ self, args = _unpack_self(*args)
41
+
42
+ return self.__wrapped__(*args, **kwargs)
43
+
44
+
45
+ def __wrapper_iter__(self):
46
+ return iter(self.__wrapped__)
47
+
48
+
49
+ def __wrapper_next__(self):
50
+ return self.__wrapped__.__next__()
51
+
52
+
53
+ def __wrapper_aiter__(self):
54
+ return self.__wrapped__.__aiter__()
55
+
56
+
57
+ async def __wrapper_anext__(self):
58
+ return await self.__wrapped__.__anext__()
59
+
60
+
61
+ def __wrapper_length_hint__(self):
62
+ return self.__wrapped__.__length_hint__()
63
+
64
+
65
+ def __wrapper_await__(self):
66
+ return (yield from self.__wrapped__.__await__())
67
+
68
+
69
+ def __wrapper_get__(self, instance, owner):
70
+ return self.__wrapped__.__get__(instance, owner)
71
+
72
+
73
+ def __wrapper_set__(self, instance, value):
74
+ return self.__wrapped__.__set__(instance, value)
75
+
76
+
77
+ def __wrapper_delete__(self, instance):
78
+ return self.__wrapped__.__delete__(instance)
79
+
80
+
81
+ def __wrapper_set_name__(self, owner, name):
82
+ return self.__wrapped__.__set_name__(owner, name)
83
+
84
+
85
+ class AutoObjectProxy(BaseObjectProxy):
86
+ """An object proxy which can automatically adjust to the wrapped object
87
+ and add special dunder methods as needed. Note that this creates a new
88
+ class for each instance, so it has much higher memory overhead than using
89
+ `BaseObjectProxy` directly. If you know what special dunder methods you need
90
+ then it is preferable to use `BaseObjectProxy` directly and add them to a
91
+ subclass as needed. If you only need `__iter__()` support for backwards
92
+ compatibility then use `ObjectProxy` instead.
93
+ """
94
+
95
+ def __new__(cls, wrapped):
96
+ """Injects special dunder methods into a dynamically created subclass
97
+ as needed based on the wrapped object.
98
+ """
99
+
100
+ namespace = {}
101
+
102
+ wrapped_attrs = dir(wrapped)
103
+ class_attrs = set(dir(cls))
104
+
105
+ if callable(wrapped) and "__call__" not in class_attrs:
106
+ namespace["__call__"] = __wrapper_call__
107
+
108
+ if "__iter__" in wrapped_attrs and "__iter__" not in class_attrs:
109
+ namespace["__iter__"] = __wrapper_iter__
110
+
111
+ if "__next__" in wrapped_attrs and "__next__" not in class_attrs:
112
+ namespace["__next__"] = __wrapper_next__
113
+
114
+ if "__aiter__" in wrapped_attrs and "__aiter__" not in class_attrs:
115
+ namespace["__aiter__"] = __wrapper_aiter__
116
+
117
+ if "__anext__" in wrapped_attrs and "__anext__" not in class_attrs:
118
+ namespace["__anext__"] = __wrapper_anext__
119
+
120
+ if "__length_hint__" in wrapped_attrs and "__length_hint__" not in class_attrs:
121
+ namespace["__length_hint__"] = __wrapper_length_hint__
122
+
123
+ # Note that not providing compatibility with generator-based coroutines
124
+ # (PEP 342) here as they are removed in Python 3.11+ and were deprecated
125
+ # in 3.8.
126
+
127
+ if "__await__" in wrapped_attrs and "__await__" not in class_attrs:
128
+ namespace["__await__"] = __wrapper_await__
129
+
130
+ if "__get__" in wrapped_attrs and "__get__" not in class_attrs:
131
+ namespace["__get__"] = __wrapper_get__
132
+
133
+ if "__set__" in wrapped_attrs and "__set__" not in class_attrs:
134
+ namespace["__set__"] = __wrapper_set__
135
+
136
+ if "__delete__" in wrapped_attrs and "__delete__" not in class_attrs:
137
+ namespace["__delete__"] = __wrapper_delete__
138
+
139
+ if "__set_name__" in wrapped_attrs and "__set_name__" not in class_attrs:
140
+ namespace["__set_name__"] = __wrapper_set_name__
141
+
142
+ name = cls.__name__
143
+
144
+ if cls is AutoObjectProxy:
145
+ name = BaseObjectProxy.__name__
146
+
147
+ return super(AutoObjectProxy, cls).__new__(type(name, (cls,), namespace))
148
+
149
+ def __wrapped_setattr_fixups__(self):
150
+ """Adjusts special dunder methods on the class as needed based on the
151
+ wrapped object, when `__wrapped__` is changed.
152
+ """
153
+
154
+ cls = type(self)
155
+ class_attrs = set(dir(cls))
156
+
157
+ if callable(self.__wrapped__):
158
+ if "__call__" not in class_attrs:
159
+ cls.__call__ = __wrapper_call__
160
+ elif getattr(cls, "__call__", None) is __wrapper_call__:
161
+ delattr(cls, "__call__")
162
+
163
+ if hasattr(self.__wrapped__, "__iter__"):
164
+ if "__iter__" not in class_attrs:
165
+ cls.__iter__ = __wrapper_iter__
166
+ elif getattr(cls, "__iter__", None) is __wrapper_iter__:
167
+ delattr(cls, "__iter__")
168
+
169
+ if hasattr(self.__wrapped__, "__next__"):
170
+ if "__next__" not in class_attrs:
171
+ cls.__next__ = __wrapper_next__
172
+ elif getattr(cls, "__next__", None) is __wrapper_next__:
173
+ delattr(cls, "__next__")
174
+
175
+ if hasattr(self.__wrapped__, "__aiter__"):
176
+ if "__aiter__" not in class_attrs:
177
+ cls.__aiter__ = __wrapper_aiter__
178
+ elif getattr(cls, "__aiter__", None) is __wrapper_aiter__:
179
+ delattr(cls, "__aiter__")
180
+
181
+ if hasattr(self.__wrapped__, "__anext__"):
182
+ if "__anext__" not in class_attrs:
183
+ cls.__anext__ = __wrapper_anext__
184
+ elif getattr(cls, "__anext__", None) is __wrapper_anext__:
185
+ delattr(cls, "__anext__")
186
+
187
+ if hasattr(self.__wrapped__, "__length_hint__"):
188
+ if "__length_hint__" not in class_attrs:
189
+ cls.__length_hint__ = __wrapper_length_hint__
190
+ elif getattr(cls, "__length_hint__", None) is __wrapper_length_hint__:
191
+ delattr(cls, "__length_hint__")
192
+
193
+ if hasattr(self.__wrapped__, "__await__"):
194
+ if "__await__" not in class_attrs:
195
+ cls.__await__ = __wrapper_await__
196
+ elif getattr(cls, "__await__", None) is __wrapper_await__:
197
+ delattr(cls, "__await__")
198
+
199
+ if hasattr(self.__wrapped__, "__get__"):
200
+ if "__get__" not in class_attrs:
201
+ cls.__get__ = __wrapper_get__
202
+ elif getattr(cls, "__get__", None) is __wrapper_get__:
203
+ delattr(cls, "__get__")
204
+
205
+ if hasattr(self.__wrapped__, "__set__"):
206
+ if "__set__" not in class_attrs:
207
+ cls.__set__ = __wrapper_set__
208
+ elif getattr(cls, "__set__", None) is __wrapper_set__:
209
+ delattr(cls, "__set__")
210
+
211
+ if hasattr(self.__wrapped__, "__delete__"):
212
+ if "__delete__" not in class_attrs:
213
+ cls.__delete__ = __wrapper_delete__
214
+ elif getattr(cls, "__delete__", None) is __wrapper_delete__:
215
+ delattr(cls, "__delete__")
216
+
217
+ if hasattr(self.__wrapped__, "__set_name__"):
218
+ if "__set_name__" not in class_attrs:
219
+ cls.__set_name__ = __wrapper_set_name__
220
+ elif getattr(cls, "__set_name__", None) is __wrapper_set_name__:
221
+ delattr(cls, "__set_name__")
222
+
223
+
224
+ class LazyObjectProxy(AutoObjectProxy):
225
+ """An object proxy which can generate/create the wrapped object on demand
226
+ when it is first needed.
227
+ """
228
+
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__
256
+
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=...):
287
+ """Initialize the object proxy with wrapped object as `None` but due
288
+ to presence of special `__wrapped_factory__` attribute addded first,
289
+ this will actually trigger the deferred creation of the wrapped object
290
+ when first needed.
291
+ """
292
+
293
+ if callback is not None:
294
+ self.__wrapped_factory__ = callback
295
+
296
+ super().__init__(None)
297
+
298
+ __wrapped_initialized__ = False
299
+
300
+ def __wrapped_factory__(self):
301
+ return None
302
+
303
+ def __wrapped_get__(self):
304
+ """Gets the wrapped object, creating it if necessary."""
305
+
306
+ # We synchronize on the class type, which will be unique to this instance
307
+ # since we inherit from `AutoObjectProxy` which creates a new class
308
+ # for each instance. If we synchronize on `self` or the method then
309
+ # we can end up in infinite recursion via `__getattr__()`.
310
+
311
+ with synchronized(type(self)):
312
+ # We were called because `__wrapped__` was not set, but because of
313
+ # multiple threads we may find that it has been set by the time
314
+ # we get the lock. So check again now whether `__wrapped__` is set.
315
+ # If it is then just return it, otherwise call the factory to
316
+ # create it.
317
+
318
+ if self.__wrapped_initialized__:
319
+ return self.__wrapped__
320
+
321
+ self.__wrapped__ = self.__wrapped_factory__()
322
+
323
+ self.__wrapped_initialized__ = True
324
+
325
+ return self.__wrapped__
326
+
327
+
328
+ def lazy_import(name, attribute=None, *, interface=...):
329
+ """Lazily imports the module `name`, returning a `LazyObjectProxy` which
330
+ will import the module when it is first needed. When `name is a dotted name,
331
+ then the full dotted name is imported and the last module is taken as the
332
+ target. If `attribute` is provided then it is used to retrieve an attribute
333
+ from the module.
334
+ """
335
+
336
+ if attribute is not None:
337
+ if interface is ...:
338
+ interface = Callable
339
+ else:
340
+ if interface is ...:
341
+ interface = ModuleType
342
+
343
+ def _import():
344
+ module = __import__(name, fromlist=[""])
345
+
346
+ if attribute is not None:
347
+ return getattr(module, attribute)
348
+
349
+ return module
350
+
351
+ return LazyObjectProxy(_import, interface=interface)
wrapt/weakrefs.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import functools
2
2
  import weakref
3
3
 
4
- from .__wrapt__ import ObjectProxy, _FunctionWrapperBase
4
+ from .__wrapt__ import BaseObjectProxy, _FunctionWrapperBase
5
5
 
6
6
  # A weak function proxy. This will work on instance methods, class
7
7
  # methods, static methods and regular functions. Special treatment is
@@ -27,7 +27,7 @@ def _weak_function_proxy_callback(ref, proxy, callback):
27
27
  callback(proxy)
28
28
 
29
29
 
30
- class WeakFunctionProxy(ObjectProxy):
30
+ class WeakFunctionProxy(BaseObjectProxy):
31
31
  """A weak function proxy."""
32
32
 
33
33
  __slots__ = ("_self_expired", "_self_instance")
wrapt/wrappers.py CHANGED
@@ -87,7 +87,26 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
87
87
  __slots__ = "__wrapped__"
88
88
 
89
89
  def __init__(self, wrapped):
90
- object.__setattr__(self, "__wrapped__", wrapped)
90
+ """Create an object proxy around the given object."""
91
+
92
+ if wrapped is None:
93
+ try:
94
+ callback = object.__getattribute__(self, "__wrapped_factory__")
95
+ except AttributeError:
96
+ callback = None
97
+
98
+ if callback is not None:
99
+ # If wrapped is none and class has a __wrapped_factory__
100
+ # method, then we don't set __wrapped__ yet and instead will
101
+ # defer creation of the wrapped object until it is first
102
+ # needed.
103
+
104
+ pass
105
+
106
+ else:
107
+ object.__setattr__(self, "__wrapped__", wrapped)
108
+ else:
109
+ object.__setattr__(self, "__wrapped__", wrapped)
91
110
 
92
111
  # Python 3.2+ has the __qualname__ attribute, but it does not
93
112
  # allow it to be overridden using a property and it must instead
@@ -106,6 +125,10 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
106
125
  except AttributeError:
107
126
  pass
108
127
 
128
+ @property
129
+ def __object_proxy__(self):
130
+ return ObjectProxy
131
+
109
132
  def __self_setattr__(self, name, value):
110
133
  object.__setattr__(self, name, value)
111
134
 
@@ -147,6 +170,10 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
147
170
  return round(self.__wrapped__, ndigits)
148
171
 
149
172
  def __mro_entries__(self, bases):
173
+ if not isinstance(self.__wrapped__, type) and hasattr(
174
+ self.__wrapped__, "__mro_entries__"
175
+ ):
176
+ return self.__wrapped__.__mro_entries__(bases)
150
177
  return (self.__wrapped__,)
151
178
 
152
179
  def __lt__(self, other):
@@ -182,6 +209,7 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
182
209
 
183
210
  elif name == "__wrapped__":
184
211
  object.__setattr__(self, name, value)
212
+
185
213
  try:
186
214
  object.__delattr__(self, "__qualname__")
187
215
  except AttributeError:
@@ -199,6 +227,13 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
199
227
  except AttributeError:
200
228
  pass
201
229
 
230
+ __wrapped_setattr_fixups__ = getattr(
231
+ self, "__wrapped_setattr_fixups__", None
232
+ )
233
+
234
+ if __wrapped_setattr_fixups__ is not None:
235
+ __wrapped_setattr_fixups__()
236
+
202
237
  elif name == "__qualname__":
203
238
  setattr(self.__wrapped__, name, value)
204
239
  object.__setattr__(self, name, value)
@@ -214,11 +249,26 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
214
249
  setattr(self.__wrapped__, name, value)
215
250
 
216
251
  def __getattr__(self, name):
217
- # If we are being to lookup '__wrapped__' then the
218
- # '__init__()' method cannot have been called.
252
+ # If we need to lookup `__wrapped__` then the `__init__()` method
253
+ # cannot have been called, or this is a lazy object proxy which is
254
+ # deferring creation of the wrapped object until it is first needed.
219
255
 
220
256
  if name == "__wrapped__":
221
- raise WrapperNotInitializedError("wrapper has not been initialised")
257
+ # Note that we use existance of `__wrapped_factory__` to gate whether
258
+ # we can attempt to initialize the wrapped object lazily, but it is
259
+ # `__wrapped_get__` that we actually call to do the initialization.
260
+ # This is so that we can handle multithreading correctly by having
261
+ # `__wrapped_get__` use a lock to protect against multiple threads
262
+ # trying to initialize the wrapped object at the same time.
263
+
264
+ try:
265
+ object.__getattribute__(self, "__wrapped_factory__")
266
+ except AttributeError:
267
+ pass
268
+ else:
269
+ return object.__getattribute__(self, "__wrapped_get__")()
270
+
271
+ raise WrapperNotInitializedError("wrapper has not been initialized")
222
272
 
223
273
  return getattr(self.__wrapped__, name)
224
274
 
@@ -227,7 +277,7 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
227
277
  object.__delattr__(self, name)
228
278
 
229
279
  elif name == "__wrapped__":
230
- raise TypeError("__wrapped__ must be an object")
280
+ raise TypeError("__wrapped__ attribute cannot be deleted")
231
281
 
232
282
  elif name == "__qualname__":
233
283
  object.__delattr__(self, name)
@@ -318,52 +368,90 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
318
368
  return other | self.__wrapped__
319
369
 
320
370
  def __iadd__(self, other):
321
- self.__wrapped__ += other
322
- return self
371
+ if hasattr(self.__wrapped__, "__iadd__"):
372
+ self.__wrapped__ += other
373
+ return self
374
+ else:
375
+ return self.__object_proxy__(self.__wrapped__ + other)
323
376
 
324
377
  def __isub__(self, other):
325
- self.__wrapped__ -= other
326
- return self
378
+ if hasattr(self.__wrapped__, "__isub__"):
379
+ self.__wrapped__ -= other
380
+ return self
381
+ else:
382
+ return self.__object_proxy__(self.__wrapped__ - other)
327
383
 
328
384
  def __imul__(self, other):
329
- self.__wrapped__ *= other
330
- return self
385
+ if hasattr(self.__wrapped__, "__imul__"):
386
+ self.__wrapped__ *= other
387
+ return self
388
+ else:
389
+ return self.__object_proxy__(self.__wrapped__ * other)
331
390
 
332
391
  def __itruediv__(self, other):
333
- self.__wrapped__ = operator.itruediv(self.__wrapped__, other)
334
- return self
392
+ if hasattr(self.__wrapped__, "__itruediv__"):
393
+ self.__wrapped__ /= other
394
+ return self
395
+ else:
396
+ return self.__object_proxy__(self.__wrapped__ / other)
335
397
 
336
398
  def __ifloordiv__(self, other):
337
- self.__wrapped__ //= other
338
- return self
399
+ if hasattr(self.__wrapped__, "__ifloordiv__"):
400
+ self.__wrapped__ //= other
401
+ return self
402
+ else:
403
+ return self.__object_proxy__(self.__wrapped__ // other)
339
404
 
340
405
  def __imod__(self, other):
341
- self.__wrapped__ %= other
406
+ if hasattr(self.__wrapped__, "__imod__"):
407
+ self.__wrapped__ %= other
408
+ return self
409
+ else:
410
+ return self.__object_proxy__(self.__wrapped__ % other)
411
+
342
412
  return self
343
413
 
344
414
  def __ipow__(self, other): # type: ignore[misc]
345
- self.__wrapped__ **= other
346
- return self
415
+ if hasattr(self.__wrapped__, "__ipow__"):
416
+ self.__wrapped__ **= other
417
+ return self
418
+ else:
419
+ return self.__object_proxy__(self.__wrapped__**other)
347
420
 
348
421
  def __ilshift__(self, other):
349
- self.__wrapped__ <<= other
350
- return self
422
+ if hasattr(self.__wrapped__, "__ilshift__"):
423
+ self.__wrapped__ <<= other
424
+ return self
425
+ else:
426
+ return self.__object_proxy__(self.__wrapped__ << other)
351
427
 
352
428
  def __irshift__(self, other):
353
- self.__wrapped__ >>= other
354
- return self
429
+ if hasattr(self.__wrapped__, "__irshift__"):
430
+ self.__wrapped__ >>= other
431
+ return self
432
+ else:
433
+ return self.__object_proxy__(self.__wrapped__ >> other)
355
434
 
356
435
  def __iand__(self, other):
357
- self.__wrapped__ &= other
358
- return self
436
+ if hasattr(self.__wrapped__, "__iand__"):
437
+ self.__wrapped__ &= other
438
+ return self
439
+ else:
440
+ return self.__object_proxy__(self.__wrapped__ & other)
359
441
 
360
442
  def __ixor__(self, other):
361
- self.__wrapped__ ^= other
362
- return self
443
+ if hasattr(self.__wrapped__, "__ixor__"):
444
+ self.__wrapped__ ^= other
445
+ return self
446
+ else:
447
+ return self.__object_proxy__(self.__wrapped__ ^ other)
363
448
 
364
449
  def __ior__(self, other):
365
- self.__wrapped__ |= other
366
- return self
450
+ if hasattr(self.__wrapped__, "__ior__"):
451
+ self.__wrapped__ |= other
452
+ return self
453
+ else:
454
+ return self.__object_proxy__(self.__wrapped__ | other)
367
455
 
368
456
  def __neg__(self):
369
457
  return -self.__wrapped__
@@ -395,6 +483,19 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
395
483
  def __index__(self):
396
484
  return operator.index(self.__wrapped__)
397
485
 
486
+ def __matmul__(self, other):
487
+ return self.__wrapped__ @ other
488
+
489
+ def __rmatmul__(self, other):
490
+ return other @ self.__wrapped__
491
+
492
+ def __imatmul__(self, other):
493
+ if hasattr(self.__wrapped__, "__imatmul__"):
494
+ self.__wrapped__ @= other
495
+ return self
496
+ else:
497
+ return self.__object_proxy__(self.__wrapped__ @ other)
498
+
398
499
  def __len__(self):
399
500
  return len(self.__wrapped__)
400
501
 
@@ -425,8 +526,11 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc]
425
526
  def __exit__(self, *args, **kwargs):
426
527
  return self.__wrapped__.__exit__(*args, **kwargs)
427
528
 
428
- def __iter__(self):
429
- return iter(self.__wrapped__)
529
+ def __aenter__(self):
530
+ return self.__wrapped__.__aenter__()
531
+
532
+ def __aexit__(self, *args, **kwargs):
533
+ return self.__wrapped__.__aexit__(*args, **kwargs)
430
534
 
431
535
  def __copy__(self):
432
536
  raise NotImplementedError("object proxy must define __copy__()")