• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / zope.proxy / 16098813542

18 Feb 2025 08:01AM UTC coverage: 99.941% (+0.002%) from 99.939%
16098813542

push

github

web-flow
Update Python version support. (#74)

* Drop support for Python 3.8.
* Add preliminary support for Python 3.14.

---------

Co-authored-by: Jens Vagelpohl <jens@plyp.com>

213 of 213 branches covered (100.0%)

Branch coverage included in aggregate %.

1481 of 1482 relevant lines covered (99.93%)

6.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.73
/src/zope/proxy/__init__.py
1
##############################################################################
2
#
3
# Copyright (c) 2003 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
"""More convenience functions for dealing with proxies.
7✔
15
"""
16
import operator
7✔
17
import os
7✔
18
import pickle
7✔
19

20
from zope.interface import moduleProvides
7✔
21

22
from zope.proxy.interfaces import IProxyIntrospection
7✔
23

24

25
moduleProvides(IProxyIntrospection)
7✔
26
__all__ = tuple(IProxyIntrospection)
7✔
27

28

29
def ProxyIterator(p):
7✔
30
    yield p
7✔
31
    while isProxy(p):
7✔
32
        p = getProxiedObject(p)
7✔
33
        yield p
7✔
34

35

36
_MARKER = object()
7✔
37

38

39
def _WrapperType_Lookup(type_, name):
7✔
40
    """
41
    Looks up information in class dictionaries in MRO
42
    order, ignoring the proxy type itself.
43

44
    Returns the first found object, or _MARKER
45
    """
46

47
    for base in type_.mro():
7✔
48
        if base is AbstractPyProxyBase:
7✔
49
            continue
7✔
50
        res = base.__dict__.get(name, _MARKER)
7✔
51
        if res is not _MARKER:
7✔
52
            return res
7✔
53
    return _MARKER
7✔
54

55

56
def _get_wrapped(self):
7✔
57
    """
58
    Helper method to access the wrapped object.
59
    """
60
    return super(AbstractPyProxyBase, self).__getattribute__('_wrapped')
7✔
61

62

63
class _EmptyInterfaceDescriptor:
7✔
64
    """A descriptor for the attributes used on the class by the
65
    Python implementation of `zope.interface`.
66

67
    When wrapping builtin types, these descriptors prevent the objects
68
    we find in the AbstractPyProxyBase from being used.
69
    """
70

71
    def __get__(self, inst, klass):
7✔
72
        raise AttributeError()
7✔
73

74
    def __set__(self, inst, value):
7✔
75
        raise TypeError()
7✔
76

77
    def __delete__(self, inst):
7✔
78
        pass
7✔
79

80
    def __iter__(self):
7✔
81
        return self
7✔
82

83
    def __next__(self):
7✔
84
        raise StopIteration()
7✔
85
    next = __next__
7✔
86

87

88
class _ProxyMetaclass(type):
7✔
89
    # The metaclass is applied after the class definition
90
    # for Py2/Py3 compatibility.
91
    __implemented__ = _EmptyInterfaceDescriptor()
7✔
92

93

94
class AbstractPyProxyBase:
7✔
95
    """
96
    A reference implementation that cannot be instantiated. Most users
97
    will want to use :class:`PyProxyBase`.
98

99
    This type is intended to be used in multiple-inheritance
100
    scenarios, where another super class already has defined
101
    ``__slots__``. In order to subclass both that class and this
102
    class, you must include the ``_wrapped`` value in your own
103
    ``__slots__`` definition (or else you will get the infamous
104
    TypeError: "multiple bases have instance lay-out conflicts")
105
    """
106
    __slots__ = ()
7✔
107

108
    def __new__(cls, value=None):
7✔
109
        # Some subclasses (zope.security.proxy) fail to pass the object
110
        inst = super(AbstractPyProxyBase, cls).__new__(cls)
7✔
111
        inst._wrapped = value
7✔
112
        return inst
7✔
113

114
    def __init__(self, obj):
7✔
115
        self._wrapped = obj
7✔
116

117
    def __call__(self, *args, **kw):
7✔
118
        return self._wrapped(*args, **kw)
7✔
119

120
    def __repr__(self):
7✔
121
        return repr(self._wrapped)
7✔
122

123
    def __str__(self):
7✔
124
        return str(self._wrapped)
7✔
125

126
    def __reduce__(self):  # pragma: no cover  (__reduce_ex__ prevents normal)
127
        raise pickle.PicklingError
128

129
    def __reduce_ex__(self, proto):
7✔
130
        raise pickle.PicklingError
7✔
131

132
    # Rich comparison protocol
133
    def __lt__(self, other):
7✔
134
        return self._wrapped < other
7✔
135

136
    def __le__(self, other):
7✔
137
        return self._wrapped <= other
7✔
138

139
    def __eq__(self, other):
7✔
140
        return self._wrapped == other
7✔
141

142
    def __ne__(self, other):
7✔
143
        return self._wrapped != other
7✔
144

145
    def __gt__(self, other):
7✔
146
        return self._wrapped > other
7✔
147

148
    def __ge__(self, other):
7✔
149
        return self._wrapped >= other
7✔
150

151
    def __bool__(self):
7✔
152
        return bool(self._wrapped)
7✔
153

154
    def __hash__(self):
7✔
155
        return hash(self._wrapped)
7✔
156

157
    # Attribute protocol
158
    def __getattribute__(self, name):
7✔
159
        # Try to avoid accessing the _wrapped value until we need to.
160
        # We don't know how subclasses may be storing it
161
        # (e.g., persistent subclasses)
162
        if name == '_wrapped':
7✔
163
            return _get_wrapped(self)
7✔
164

165
        if name in ('__class__', '__module__'):
7✔
166
            # __class__ and __module__ are special cased in the C
167
            # implementation, because we will always find them on the
168
            # type of this object if we are being subclassed
169
            return getattr(_get_wrapped(self), name)
7✔
170

171
        if name in ('__reduce__', '__reduce_ex__'):
7✔
172
            # These things we specifically override and no one
173
            # can stop us, not even a subclass
174
            return object.__getattribute__(self, name)
7✔
175

176
        # First, look for descriptors in this object's type
177
        type_self = type(self)
7✔
178
        descriptor = _WrapperType_Lookup(type_self, name)
7✔
179
        if descriptor is _MARKER:
7✔
180
            # Nothing in the class, go straight to the wrapped object
181
            return getattr(_get_wrapped(self), name)
7✔
182

183
        if hasattr(descriptor, '__get__'):
7✔
184
            if not hasattr(descriptor, '__set__'):
7✔
185
                # Non-data-descriptor: call through to the wrapped object
186
                # to see if it's there
187
                try:
7✔
188
                    return getattr(_get_wrapped(self), name)
7✔
189
                except AttributeError:
7✔
190
                    pass
7✔
191
            # Data-descriptor on this type. Call it
192
            return descriptor.__get__(self, type_self)
7✔
193
        return descriptor
7✔
194

195
    def __getattr__(self, name):
7✔
196
        return getattr(self._wrapped, name)
7✔
197

198
    def __setattr__(self, name, value):
7✔
199
        if name == '_wrapped':
7✔
200
            return super(AbstractPyProxyBase, self).__setattr__(name, value)
7✔
201

202
        # First, look for descriptors in this object's type
203
        type_self = type(self)
7✔
204
        descriptor = _WrapperType_Lookup(type_self, name)
7✔
205
        if descriptor is _MARKER or not hasattr(descriptor, '__set__'):
7✔
206
            # Nothing in the class that's a descriptor,
207
            # go straight to the wrapped object
208
            return setattr(self._wrapped, name, value)
7✔
209

210
        return object.__setattr__(self, name, value)
7✔
211

212
    def __delattr__(self, name):
7✔
213
        if name == '_wrapped':
7✔
214
            raise AttributeError()
7✔
215
        delattr(self._wrapped, name)
7✔
216

217
    # Container protocols
218

219
    def __len__(self):
7✔
220
        return len(self._wrapped)
7✔
221

222
    def __getitem__(self, key):
7✔
223
        return self._wrapped[key]
7✔
224

225
    def __setitem__(self, key, value):
7✔
226
        self._wrapped[key] = value
7✔
227

228
    def __delitem__(self, key):
7✔
229
        del self._wrapped[key]
7✔
230

231
    def __iter__(self):
7✔
232
        # This handles a custom __iter__ and generator support at the same
233
        # time.
234
        return iter(self._wrapped)
7✔
235

236
    def next(self):
7✔
237
        # Called when we wrap an iterator itself.
238
        return next(self._wrapped)
×
239

240
    def __next__(self):
7✔
241
        return self._wrapped.__next__()
7✔
242

243
    # Python 2.7 won't let the C wrapper support __reversed__
244
    # Uncomment this when the supported Python versions do
245
    # def __reversed__(self):
246
    #    return reversed(self._wrapped)
247

248
    def __contains__(self, item):
7✔
249
        return item in self._wrapped
7✔
250

251
    # Numeric protocol:  unary operators
252
    def __neg__(self):
7✔
253
        return -self._wrapped
7✔
254

255
    def __pos__(self):
7✔
256
        return +self._wrapped
7✔
257

258
    def __abs__(self):
7✔
259
        return abs(self._wrapped)
7✔
260

261
    def __invert__(self):
7✔
262
        return ~self._wrapped
7✔
263

264
    # Numeric protocol:  unary conversions
265
    def __complex__(self):
7✔
266
        return complex(self._wrapped)
7✔
267

268
    def __int__(self):
7✔
269
        return int(self._wrapped)
7✔
270

271
    def __float__(self):
7✔
272
        return float(self._wrapped)
7✔
273

274
    def __index__(self):
7✔
275
        return operator.index(self._wrapped)
7✔
276

277
    # Numeric protocol:  binary arithmetic operators
278
    def __add__(self, other):
7✔
279
        return self._wrapped + other
7✔
280

281
    def __sub__(self, other):
7✔
282
        return self._wrapped - other
7✔
283

284
    def __mul__(self, other):
7✔
285
        return self._wrapped * other
7✔
286

287
    def __floordiv__(self, other):
7✔
288
        return self._wrapped // other
7✔
289

290
    def __truediv__(self, other):
7✔
291
        return self._wrapped / other
7✔
292

293
    def __mod__(self, other):
7✔
294
        return self._wrapped % other
7✔
295

296
    def __divmod__(self, other):
7✔
297
        return divmod(self._wrapped, other)
7✔
298

299
    def __pow__(self, other, modulus=None):
7✔
300
        if modulus is None:
7✔
301
            return pow(self._wrapped, other)
7✔
302
        return pow(self._wrapped, other, modulus)
7✔
303

304
    def __radd__(self, other):
7✔
305
        return other + self._wrapped
7✔
306

307
    def __rsub__(self, other):
7✔
308
        return other - self._wrapped
7✔
309

310
    def __rmul__(self, other):
7✔
311
        return other * self._wrapped
7✔
312

313
    def __rfloordiv__(self, other):
7✔
314
        return other // self._wrapped
7✔
315

316
    def __rtruediv__(self, other):
7✔
317
        return other / self._wrapped
7✔
318

319
    def __rmod__(self, other):
7✔
320
        return other % self._wrapped
7✔
321

322
    def __rdivmod__(self, other):
7✔
323
        return divmod(other, self._wrapped)
7✔
324

325
    def __rpow__(self, other, modulus=None):
7✔
326
        if modulus is None:
7✔
327
            return pow(other, self._wrapped)
7✔
328
        # We can't actually get here, because we can't lie about our type()
329
        return pow(other, self._wrapped, modulus)  # pragma: no cover
330

331
    # Numeric protocol:  binary bitwise operators
332
    def __lshift__(self, other):
7✔
333
        return self._wrapped << other
7✔
334

335
    def __rshift__(self, other):
7✔
336
        return self._wrapped >> other
7✔
337

338
    def __and__(self, other):
7✔
339
        return self._wrapped & other
7✔
340

341
    def __xor__(self, other):
7✔
342
        return self._wrapped ^ other
7✔
343

344
    def __or__(self, other):
7✔
345
        return self._wrapped | other
7✔
346

347
    def __rlshift__(self, other):
7✔
348
        return other << self._wrapped
7✔
349

350
    def __rrshift__(self, other):
7✔
351
        return other >> self._wrapped
7✔
352

353
    def __rand__(self, other):
7✔
354
        return other & self._wrapped
7✔
355

356
    def __rxor__(self, other):
7✔
357
        return other ^ self._wrapped
7✔
358

359
    def __ror__(self, other):
7✔
360
        return other | self._wrapped
7✔
361

362
    # Numeric protocol:  binary in-place operators
363
    def __iadd__(self, other):
7✔
364
        self._wrapped += other
7✔
365
        return self
7✔
366

367
    def __isub__(self, other):
7✔
368
        self._wrapped -= other
7✔
369
        return self
7✔
370

371
    def __imul__(self, other):
7✔
372
        self._wrapped *= other
7✔
373
        return self
7✔
374

375
    def __itruediv__(self, other):
7✔
376
        self._wrapped /= other
7✔
377
        return self
7✔
378

379
    def __ifloordiv__(self, other):
7✔
380
        self._wrapped //= other
7✔
381
        return self
7✔
382

383
    def __imod__(self, other):
7✔
384
        self._wrapped %= other
7✔
385
        return self
7✔
386

387
    def __ilshift__(self, other):
7✔
388
        self._wrapped <<= other
7✔
389
        return self
7✔
390

391
    def __irshift__(self, other):
7✔
392
        self._wrapped >>= other
7✔
393
        return self
7✔
394

395
    def __iand__(self, other):
7✔
396
        self._wrapped &= other
7✔
397
        return self
7✔
398

399
    def __ixor__(self, other):
7✔
400
        self._wrapped ^= other
7✔
401
        return self
7✔
402

403
    def __ior__(self, other):
7✔
404
        self._wrapped |= other
7✔
405
        return self
7✔
406

407
    def __ipow__(self, other, modulus=None):
7✔
408
        if modulus is None:
7✔
409
            self._wrapped **= other
7✔
410
        else:  # pragma: no cover
411
            # There is no syntax which triggers in-place pow w/ modulus
412
            self._wrapped = pow(self._wrapped, other, modulus)
413
        return self
7✔
414

415

416
AbstractPyProxyBase = _ProxyMetaclass('AbstractPyProxyBase', (),
7✔
417
                                      dict(AbstractPyProxyBase.__dict__))
418

419

420
class PyProxyBase(AbstractPyProxyBase):
7✔
421
    """Reference implementation.
422
    """
423
    __slots__ = ('_wrapped', )
7✔
424

425

426
def py_getProxiedObject(obj):
7✔
427
    if isinstance(obj, PyProxyBase):
7✔
428
        return obj._wrapped
7✔
429
    return obj
7✔
430

431

432
def py_setProxiedObject(obj, new_value):
7✔
433
    if not isinstance(obj, PyProxyBase):
7✔
434
        raise TypeError('Not a proxy')
7✔
435
    old, obj._wrapped = obj._wrapped, new_value
7✔
436
    return old
7✔
437

438

439
def py_isProxy(obj, klass=None):
7✔
440
    if klass is None:
7✔
441
        klass = PyProxyBase
7✔
442
    return isinstance(obj, klass)
7✔
443

444

445
def py_sameProxiedObjects(lhs, rhs):
7✔
446
    while isinstance(lhs, PyProxyBase):
7✔
447
        lhs = super(PyProxyBase, lhs).__getattribute__('_wrapped')
7✔
448
    while isinstance(rhs, PyProxyBase):
7✔
449
        rhs = super(PyProxyBase, rhs).__getattribute__('_wrapped')
7✔
450
    return lhs is rhs
7✔
451

452

453
def py_queryProxy(obj, klass=None, default=None):
7✔
454
    if klass is None:
7✔
455
        klass = PyProxyBase
7✔
456
    while obj is not None and not isinstance(obj, klass):
7✔
457
        obj = getattr(obj, '_wrapped', None)
7✔
458
    if obj is not None:
7✔
459
        return obj
7✔
460
    return default
7✔
461

462

463
def py_queryInnerProxy(obj, klass=None, default=None):
7✔
464
    if klass is None:
7✔
465
        klass = PyProxyBase
7✔
466
    found = []
7✔
467
    while obj is not None:
7✔
468
        if isinstance(obj, klass):
7✔
469
            found.append(obj)  # stack
7✔
470
        obj = getattr(obj, '_wrapped', None)
7✔
471
    if found:
7✔
472
        return found[-1]
7✔
473
    return default
7✔
474

475

476
def py_removeAllProxies(obj):
7✔
477
    while isinstance(obj, PyProxyBase):
7✔
478
        obj = super(PyProxyBase, obj).__getattribute__('_wrapped')
7✔
479
    return obj
7✔
480

481

482
_c_available = False
7✔
483
if not int(os.environ.get('PURE_PYTHON', '0')):
7✔
484
    try:  # pragma: no cover
485
        from zope.proxy._zope_proxy_proxy import ProxyBase as _c_available
486
    except ImportError:
487
        pass
488

489

490
class PyNonOverridable:
7✔
491
    "Deprecated, only for BWC."
492

493
    def __init__(self, method_desc):  # pragma: no cover PyPy
494
        self.desc = method_desc
495

496

497
if _c_available:  # pragma: no cover
498
    # Python API:  not used in this module
499
    # API for proxy-using C extensions.
500
    from zope.proxy._zope_proxy_proxy import _CAPI  # noqa: F401 unused
501
    from zope.proxy._zope_proxy_proxy import ProxyBase
502
    from zope.proxy._zope_proxy_proxy import getProxiedObject
503
    from zope.proxy._zope_proxy_proxy import isProxy
504
    from zope.proxy._zope_proxy_proxy import queryInnerProxy
505
    from zope.proxy._zope_proxy_proxy import queryProxy
506
    from zope.proxy._zope_proxy_proxy import removeAllProxies
507
    from zope.proxy._zope_proxy_proxy import sameProxiedObjects
508
    from zope.proxy._zope_proxy_proxy import setProxiedObject
509

510
else:
511
    # no C extension available, fall back
512
    ProxyBase = PyProxyBase
7✔
513
    getProxiedObject = py_getProxiedObject
7✔
514
    setProxiedObject = py_setProxiedObject
7✔
515
    isProxy = py_isProxy
7✔
516
    sameProxiedObjects = py_sameProxiedObjects
7✔
517
    queryProxy = py_queryProxy
7✔
518
    queryInnerProxy = py_queryInnerProxy
7✔
519
    removeAllProxies = py_removeAllProxies
7✔
520

521

522
def non_overridable(func):
7✔
523
    return property(lambda self: func.__get__(self))
7✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc