proxytypes3 1.0.1__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- proxytypes3-1.0.2/LICENSE +21 -0
- proxytypes3-1.0.2/PKG-INFO +336 -0
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/README.md +1 -1
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/proxytypes3/__init__.py +1 -1
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/proxytypes3/proxies.py +17 -16
- proxytypes3-1.0.2/proxytypes3.egg-info/PKG-INFO +336 -0
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/proxytypes3.egg-info/SOURCES.txt +1 -0
- proxytypes3-1.0.2/requirements-test.txt +2 -0
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/setup.py +5 -5
- proxytypes3-1.0.1/PKG-INFO +0 -327
- proxytypes3-1.0.1/proxytypes3.egg-info/PKG-INFO +0 -327
- proxytypes3-1.0.1/requirements-test.txt +0 -2
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/MANIFEST.in +0 -0
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/proxytypes3.egg-info/dependency_links.txt +0 -0
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/proxytypes3.egg-info/not-zip-safe +0 -0
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/proxytypes3.egg-info/top_level.txt +0 -0
- {proxytypes3-1.0.1 → proxytypes3-1.0.2}/setup.cfg +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Chris Spencer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: proxytypes3
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: General purpose proxy and wrapper types.
|
|
5
|
+
Home-page: https://github.com/chrisspen/ProxyTypes3
|
|
6
|
+
Author: Chris Spencer
|
|
7
|
+
Author-email: chrisspen@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 6 - Mature
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
Simple Proxy Types
|
|
31
|
+
==================
|
|
32
|
+
|
|
33
|
+
[](https://pypi.python.org/pypi/proxytypes3) [](https://github.com/chrisspen/proxytypes3/actions/workflows/ci.yml)
|
|
34
|
+
|
|
35
|
+
The `proxytypes3` package provides some useful base classes for creating
|
|
36
|
+
proxies and wrappers for ordinary Python objects. Proxy objects automatically
|
|
37
|
+
delegate all attribute access and operations to the proxied object. Wrappers
|
|
38
|
+
are similar, but can be subclassed to allow additional attributes and
|
|
39
|
+
operations to be added to the wrapped object.
|
|
40
|
+
|
|
41
|
+
Note that these proxy types are not intended to be tamper-proof; the unproxied
|
|
42
|
+
form of an object can be readily accessed using a proxy's `__subject__`
|
|
43
|
+
attribute, and some proxy types even allow this attribute to be set. (This can
|
|
44
|
+
be handy for algorithms that lazily create circular structures and thus need to
|
|
45
|
+
be able to hand out "forward reference" proxies.)
|
|
46
|
+
|
|
47
|
+
This package is a fork of the [peak.util.proxies](https://pypi.org/project/ProxyTypes/) module,
|
|
48
|
+
extended to include support for Python 3.* as well as better testing and continuous integration.
|
|
49
|
+
|
|
50
|
+
Proxy Basics
|
|
51
|
+
------------
|
|
52
|
+
|
|
53
|
+
Here's a quick demo of the `ObjectProxy` type::
|
|
54
|
+
|
|
55
|
+
>>> from proxytypes3 import ObjectProxy
|
|
56
|
+
>>> p = ObjectProxy(42)
|
|
57
|
+
|
|
58
|
+
>>> p
|
|
59
|
+
42
|
|
60
|
+
|
|
61
|
+
>>> isinstance(p, int)
|
|
62
|
+
True
|
|
63
|
+
|
|
64
|
+
>>> p.__class__
|
|
65
|
+
<... 'int'>
|
|
66
|
+
|
|
67
|
+
>>> p*2
|
|
68
|
+
84
|
|
69
|
+
|
|
70
|
+
>>> 'X' * p
|
|
71
|
+
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
|
72
|
+
|
|
73
|
+
>>> hex(p)
|
|
74
|
+
'0x2a'
|
|
75
|
+
|
|
76
|
+
>>> chr(p)
|
|
77
|
+
'*'
|
|
78
|
+
|
|
79
|
+
>>> p ^ 1
|
|
80
|
+
43
|
|
81
|
+
|
|
82
|
+
>>> p ** 2
|
|
83
|
+
1764
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
As you can see, a proxy is virtually indistinguishable from the object it
|
|
87
|
+
proxies, except via its `__subject__` attribute, and its `type()`::
|
|
88
|
+
|
|
89
|
+
>>> p.__subject__
|
|
90
|
+
42
|
|
91
|
+
|
|
92
|
+
>>> type(p)
|
|
93
|
+
<class 'proxytypes3.proxies.ObjectProxy'>
|
|
94
|
+
|
|
95
|
+
You can change the `__subject__` of an `ObjectProxy`, and it will then
|
|
96
|
+
refer to something else::
|
|
97
|
+
|
|
98
|
+
>>> p.__subject__ = 99
|
|
99
|
+
>>> p
|
|
100
|
+
99
|
|
101
|
+
>>> p-33
|
|
102
|
+
66
|
|
103
|
+
|
|
104
|
+
>>> p.__subject__ = "foo"
|
|
105
|
+
>>> p
|
|
106
|
+
'foo'
|
|
107
|
+
|
|
108
|
+
All operations are delegated to the subject, including setattr and delattr::
|
|
109
|
+
|
|
110
|
+
>>> class Dummy: pass
|
|
111
|
+
>>> d = Dummy()
|
|
112
|
+
>>> p = ObjectProxy(d)
|
|
113
|
+
|
|
114
|
+
>>> p.foo = "bar"
|
|
115
|
+
>>> d.foo
|
|
116
|
+
'bar'
|
|
117
|
+
|
|
118
|
+
>>> del p.foo
|
|
119
|
+
>>> hasattr(d,'foo')
|
|
120
|
+
False
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
Callback Proxies
|
|
124
|
+
----------------
|
|
125
|
+
|
|
126
|
+
Sometimes, you may want a proxy's subject to be determined dynamically whenever
|
|
127
|
+
the proxy is used. For this purpose, you can use the `CallbackProxy` type,
|
|
128
|
+
which accepts a callback function and creates a proxy that will invoke the
|
|
129
|
+
callback in order to get the target. Here's a quick example of a counter
|
|
130
|
+
that gets incremented each time it's used, from zero to three::
|
|
131
|
+
|
|
132
|
+
>>> from proxytypes3 import CallbackProxy
|
|
133
|
+
|
|
134
|
+
>>> ct = -1
|
|
135
|
+
>>> def callback():
|
|
136
|
+
... global ct
|
|
137
|
+
... if ct == 3: raise StopIteration
|
|
138
|
+
... ct += 1
|
|
139
|
+
... return ct
|
|
140
|
+
|
|
141
|
+
>>> counter = CallbackProxy(callback)
|
|
142
|
+
|
|
143
|
+
>>> counter
|
|
144
|
+
0
|
|
145
|
+
>>> counter
|
|
146
|
+
1
|
|
147
|
+
>>> str(counter)
|
|
148
|
+
'2'
|
|
149
|
+
>>> hex(counter)
|
|
150
|
+
'0x3'
|
|
151
|
+
|
|
152
|
+
>>> counter
|
|
153
|
+
Traceback (most recent call last):
|
|
154
|
+
...
|
|
155
|
+
StopIteration
|
|
156
|
+
|
|
157
|
+
As you can see, the callback is automatically invoked on any attempt to use the
|
|
158
|
+
proxy. This is a somewhat silly example; a better one would be something like
|
|
159
|
+
a `thread_id` proxy that is always equal to the ID # of the thread it's
|
|
160
|
+
running in.
|
|
161
|
+
|
|
162
|
+
A callback proxy's callback can be obtained or changed via the `get_callback`
|
|
163
|
+
and `set_callback` functions::
|
|
164
|
+
|
|
165
|
+
>>> from proxytypes3 import get_callback, set_callback
|
|
166
|
+
>>> set_callback(counter, lambda: 42)
|
|
167
|
+
|
|
168
|
+
>>> counter
|
|
169
|
+
42
|
|
170
|
+
|
|
171
|
+
>>> get_callback(counter)
|
|
172
|
+
<function <lambda> at ...>
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
Lazy Proxies
|
|
176
|
+
------------
|
|
177
|
+
|
|
178
|
+
A `LazyProxy` is similar to a `CallbackProxy`, but its callback is called
|
|
179
|
+
at most once, and then cached::
|
|
180
|
+
|
|
181
|
+
>>> from proxytypes3 import LazyProxy
|
|
182
|
+
|
|
183
|
+
>>> def callback():
|
|
184
|
+
... print("called!")
|
|
185
|
+
... return 42
|
|
186
|
+
|
|
187
|
+
>>> lazy = LazyProxy(callback)
|
|
188
|
+
>>> lazy
|
|
189
|
+
called!
|
|
190
|
+
42
|
|
191
|
+
>>> lazy
|
|
192
|
+
42
|
|
193
|
+
|
|
194
|
+
You can use the `get_callback` and `set_callback` functions on lazy
|
|
195
|
+
proxies, but it has no effect if the callback was already called::
|
|
196
|
+
|
|
197
|
+
>>> set_callback(lazy, lambda: 99)
|
|
198
|
+
>>> lazy
|
|
199
|
+
42
|
|
200
|
+
|
|
201
|
+
But you can use the `get_cache` and `set_cache` functions to tamper with
|
|
202
|
+
the cached value::
|
|
203
|
+
|
|
204
|
+
>>> from proxytypes3 import get_cache, set_cache
|
|
205
|
+
>>> get_cache(lazy)
|
|
206
|
+
42
|
|
207
|
+
>>> set_cache(lazy, 99)
|
|
208
|
+
>>> lazy
|
|
209
|
+
99
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
Wrappers
|
|
213
|
+
--------
|
|
214
|
+
|
|
215
|
+
The `ObjectWrapper`, `CallbackWrapper` and `LazyWrapper` classes are
|
|
216
|
+
similar to their proxy counterparts, except that they are intended to be
|
|
217
|
+
subclassed in order to add custom extra attributes or methods. Any attribute
|
|
218
|
+
that exists in a subclass of these classes will be read or written from the
|
|
219
|
+
wrapper instance, instead of the wrapped object. For example::
|
|
220
|
+
|
|
221
|
+
>>> from proxytypes3 import ObjectWrapper
|
|
222
|
+
>>> class NameWrapper(ObjectWrapper):
|
|
223
|
+
... name = None
|
|
224
|
+
... def __init__(self, ob, name):
|
|
225
|
+
... ObjectWrapper.__init__(self, ob)
|
|
226
|
+
... self.name = name
|
|
227
|
+
... def __str__(self):
|
|
228
|
+
... return self.name
|
|
229
|
+
|
|
230
|
+
>>> w = NameWrapper(42, "The Ultimate Answer")
|
|
231
|
+
>>> w
|
|
232
|
+
42
|
|
233
|
+
|
|
234
|
+
>>> print(w)
|
|
235
|
+
The Ultimate Answer
|
|
236
|
+
|
|
237
|
+
>>> w * 2
|
|
238
|
+
84
|
|
239
|
+
|
|
240
|
+
>>> w.name
|
|
241
|
+
'The Ultimate Answer'
|
|
242
|
+
|
|
243
|
+
Notice that any attributes you add must be defined *in the class*. You can't
|
|
244
|
+
add arbitary attributes at runtime, because they'll be set on the wrapped
|
|
245
|
+
object instead of the wrapper::
|
|
246
|
+
|
|
247
|
+
>>> w.foo = 'bar'
|
|
248
|
+
Traceback (most recent call last):
|
|
249
|
+
...
|
|
250
|
+
AttributeError: 'int' object has no attribute 'foo'
|
|
251
|
+
|
|
252
|
+
Note that this means that all instance attributes must be implemented as either
|
|
253
|
+
slots, properties, or have a default value defined in the class body (like the
|
|
254
|
+
`name = None` shown in the example above).
|
|
255
|
+
|
|
256
|
+
The `CallbackWrapper` and `LazyWrapper` base classes are basically the same
|
|
257
|
+
as `ObjectWrapper`, except that they use a callback or cached lazy callback
|
|
258
|
+
instead of expecting an object as their subject.
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
Creating Custom Subclasses and Mixins
|
|
262
|
+
-------------------------------------
|
|
263
|
+
|
|
264
|
+
In addition to all the concrete classes described above, there are also two
|
|
265
|
+
abstract base classes: `AbstractProxy` and `AbstractWrapper`. If you want
|
|
266
|
+
to create a mixin type that can be used with any of the concrete types, you
|
|
267
|
+
should subclass the abstract version and set `__slots__` to an empty list::
|
|
268
|
+
|
|
269
|
+
>>> from proxytypes3 import AbstractWrapper
|
|
270
|
+
|
|
271
|
+
>>> class NamedMixin(AbstractWrapper):
|
|
272
|
+
... __slots__ = []
|
|
273
|
+
... name = None
|
|
274
|
+
... def __init__(self, ob, name):
|
|
275
|
+
... super(NamedMixin, self).__init__(ob)
|
|
276
|
+
... self.name = name
|
|
277
|
+
... def __str__(self):
|
|
278
|
+
... return self.name
|
|
279
|
+
|
|
280
|
+
Then, when you mix it in with the respective base class, you can add back in
|
|
281
|
+
any necessary slots, or leave off `__slots__` to give the subclass instances
|
|
282
|
+
a dictionary of their own::
|
|
283
|
+
|
|
284
|
+
>>> from proxytypes3 import CallbackWrapper, LazyWrapper
|
|
285
|
+
|
|
286
|
+
>>> class NamedObject(NamedMixin, ObjectWrapper): pass
|
|
287
|
+
>>> class NamedCallback(NamedMixin, CallbackWrapper): pass
|
|
288
|
+
>>> class NamedLazy(NamedMixin, LazyWrapper): pass
|
|
289
|
+
|
|
290
|
+
>>> print(NamedObject(42, "The Answer"))
|
|
291
|
+
The Answer
|
|
292
|
+
|
|
293
|
+
>>> n = NamedCallback(callback, "Test")
|
|
294
|
+
>>> n
|
|
295
|
+
called!
|
|
296
|
+
42
|
|
297
|
+
>>> n
|
|
298
|
+
called!
|
|
299
|
+
42
|
|
300
|
+
|
|
301
|
+
>>> n = NamedLazy(callback, "Once")
|
|
302
|
+
>>> n
|
|
303
|
+
called!
|
|
304
|
+
42
|
|
305
|
+
>>> n
|
|
306
|
+
42
|
|
307
|
+
|
|
308
|
+
Both the `AbstractProxy` and `AbstractWrapper` base classes work by
|
|
309
|
+
assuming that `self.__subject__` will be the wrapped or proxied object. If
|
|
310
|
+
you don't want to use any of the standard three ways of defining
|
|
311
|
+
`__subject__` (i.e., as an object, callback, or lazy callback), you will need
|
|
312
|
+
to subclass `AbstractProxy` or `AbstractWrapper` and provide your own
|
|
313
|
+
way of defining `__subject__`.
|
|
314
|
+
|
|
315
|
+
Tests
|
|
316
|
+
-----
|
|
317
|
+
|
|
318
|
+
To run unittests across multiple Python versions, first install the necessary Python versions. On Ubuntu, run:
|
|
319
|
+
|
|
320
|
+
sudo add-apt-repository ppa:deadsnakes/ppa
|
|
321
|
+
sudo apt-get update
|
|
322
|
+
sudo apt-get install python-dev python3.4-minimal python3.4-dev python3.5-minimal python3.5-dev python3.6 python3.6-dev
|
|
323
|
+
|
|
324
|
+
Then to run all [tests](http://tox.readthedocs.org/en/latest/):
|
|
325
|
+
|
|
326
|
+
tox
|
|
327
|
+
|
|
328
|
+
To run tests for a specific environment (e.g. Python 2.7):
|
|
329
|
+
|
|
330
|
+
tox -e py27
|
|
331
|
+
|
|
332
|
+
To run a specific test:
|
|
333
|
+
|
|
334
|
+
export TESTNAME=.additional_tests; tox -e py34
|
|
335
|
+
|
|
336
|
+
export TESTNAME=.TestObjectProxy.testNumbers; tox -e py36
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Simple Proxy Types
|
|
2
2
|
==================
|
|
3
3
|
|
|
4
|
-
[](https://pypi.python.org/pypi/proxytypes3) [](https://pypi.python.org/pypi/proxytypes3) [](https://github.com/chrisspen/proxytypes3/actions/workflows/ci.yml)
|
|
5
5
|
|
|
6
6
|
The `proxytypes3` package provides some useful base classes for creating
|
|
7
7
|
proxies and wrappers for ordinary Python objects. Proxy objects automatically
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class AbstractProxy
|
|
1
|
+
class AbstractProxy:
|
|
2
2
|
"""
|
|
3
3
|
Delegates all operations (except ``.__subject__``) to another object.
|
|
4
4
|
"""
|
|
@@ -52,25 +52,25 @@ class AbstractProxy(object):
|
|
|
52
52
|
return ob in self.__subject__
|
|
53
53
|
|
|
54
54
|
for name in 'repr str hash len abs complex int long float iter oct hex bool operator.index math.trunc'.split():
|
|
55
|
-
if name in ('len', 'complex') or hasattr(int, '__
|
|
55
|
+
if name in ('len', 'complex') or hasattr(int, f'__{name.split(".")[-1]}__'):
|
|
56
56
|
if '.' in name:
|
|
57
57
|
name = name.split('.')
|
|
58
|
-
exec("global
|
|
58
|
+
exec(f"global {name[1]}; from {name[0]} import {name[1]}")
|
|
59
59
|
name = name[1]
|
|
60
|
-
exec("def __
|
|
60
|
+
exec(f"def __{name}__(self): return {name}(self.__subject__)")
|
|
61
61
|
|
|
62
62
|
for name in 'cmp', 'coerce', 'divmod':
|
|
63
|
-
if hasattr(int, '__
|
|
64
|
-
exec("def __
|
|
63
|
+
if hasattr(int, f'__{name}__'):
|
|
64
|
+
exec(f"def __{name}__(self,ob): return {name}(self.__subject__,ob)")
|
|
65
65
|
|
|
66
66
|
for name, op in [
|
|
67
67
|
('lt', '<'), ('gt', '>'), ('le', '<='), ('ge', '>='),
|
|
68
68
|
('eq', '=='), ('ne', '!=')
|
|
69
69
|
]:
|
|
70
|
-
exec("def __
|
|
70
|
+
exec(f"def __{name}__(self,ob): return self.__subject__ {op} ob")
|
|
71
71
|
|
|
72
72
|
for name, op in [('neg', '-'), ('pos', '+'), ('invert', '~')]:
|
|
73
|
-
exec("def __
|
|
73
|
+
exec(f"def __{name}__(self): return {op} self.__subject__")
|
|
74
74
|
|
|
75
75
|
for name, op in [
|
|
76
76
|
('or', '|'), ('and', '&'), ('xor', '^'), ('lshift', '<<'), ('rshift', '>>'),
|
|
@@ -80,16 +80,16 @@ class AbstractProxy(object):
|
|
|
80
80
|
if name == 'div' and not hasattr(int, '__div__'):
|
|
81
81
|
continue
|
|
82
82
|
exec((
|
|
83
|
-
"def __
|
|
84
|
-
" return self.__subject__
|
|
83
|
+
f"def __{name}__(self, ob):\n"
|
|
84
|
+
f" return self.__subject__ {op} ob\n"
|
|
85
85
|
"\n"
|
|
86
|
-
"def __r
|
|
87
|
-
" return ob
|
|
86
|
+
f"def __r{name}__(self, ob):\n"
|
|
87
|
+
f" return ob {op} self.__subject__\n"
|
|
88
88
|
"\n"
|
|
89
|
-
"def __i
|
|
90
|
-
" self.__subject__
|
|
89
|
+
f"def __i{name}__(self, ob):\n"
|
|
90
|
+
f" self.__subject__ {op}=ob\n"
|
|
91
91
|
" return self\n"
|
|
92
|
-
)
|
|
92
|
+
))
|
|
93
93
|
|
|
94
94
|
del name, op
|
|
95
95
|
|
|
@@ -98,7 +98,8 @@ class AbstractProxy(object):
|
|
|
98
98
|
def __rdivmod__(self, ob):
|
|
99
99
|
return divmod(ob, self.__subject__)
|
|
100
100
|
|
|
101
|
-
def __pow__(self, *args):
|
|
101
|
+
def __pow__(self, *args): # pylint: disable=unexpected-special-method-signature
|
|
102
|
+
# Deliberately variadic: pow(subject), pow(subject, exp), pow(subject, exp, mod).
|
|
102
103
|
return pow(self.__subject__, *args)
|
|
103
104
|
|
|
104
105
|
def __ipow__(self, ob):
|