File: testsupport.py

package info (click to toggle)
pyro4 4.82-2
  • links: PTS
  • area: main
  • in suites: bookworm
  • size: 2,528 kB
  • sloc: python: 17,736; makefile: 169; sh: 113; javascript: 62
file content (295 lines) | stat: -rw-r--r-- 6,553 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
"""
Support code for the test suite.
There's some Python 2.x <-> 3.x compatibility code here.

Pyro - Python Remote Objects.  Copyright by Irmen de Jong (irmen@razorvine.net).
"""

import sys
import pickle
import threading
from Pyro4 import errors, core, expose, behavior, current_context
from Pyro4.configuration import config


__all__ = ["tobytes", "tostring", "unicode", "unichr", "basestring", "StringIO",
           "NonserializableError", "MyThingPartlyExposed", "MyThingFullExposed",
           "MyThingExposedSub", "MyThingPartlyExposedSub", "ConnectionMock",
           "AtomicCounter", "ResourceService", "Resource"]


config.reset(False)   # reset the config to default

if sys.version_info < (3, 0):
    # noinspection PyUnresolvedReferences
    from StringIO import StringIO

    def tobytes(string, encoding=None):
        return string

    def tostring(bytes):
        return bytes

    unicode = unicode
    unichr = unichr
    basestring = basestring
else:
    from io import StringIO

    def tobytes(string, encoding="iso-8859-1"):
        return bytes(string, encoding)

    def tostring(bytes, encoding="utf-8"):
        return str(bytes, encoding)

    unicode = str
    unichr = chr
    basestring = str


class NonserializableError(Exception):
    def __reduce__(self):
        raise pickle.PicklingError("to make this error non-serializable")


class MyThingPartlyExposed(object):
    c_attr = "hi"
    propvalue = 42
    _private_attr1 = "hi"
    __private_attr2 = "hi"
    name = ""

    def __init__(self, name="dummy"):
        self.name = name

    def __eq__(self, other):
        if type(other) is MyThingPartlyExposed:
            return self.name == other.name
        return False

    def method(self, arg, default=99, **kwargs):
        pass

    @staticmethod
    def staticmethod(arg):
        pass

    @classmethod
    def classmethod(cls, arg):
        pass

    def __dunder__(self):
        pass

    def __private(self):
        pass

    def _private(self):
        pass

    @core.expose
    @property
    def prop1(self):
        return self.propvalue

    @core.expose
    @prop1.setter
    def prop1(self, value):
        self.propvalue = value

    @core.expose
    @property
    def readonly_prop1(self):
        return self.propvalue

    @property
    def prop2(self):
        return self.propvalue

    @prop2.setter
    def prop2(self, value):
        self.propvalue = value

    @core.oneway
    @core.expose
    def oneway(self, arg):
        pass

    @core.expose
    def exposed(self):
        pass

    __hash__ = object.__hash__


@core.expose
class MyThingFullExposed(object):
    """this is the same as MyThingPartlyExposed but the whole class should be exposed"""
    c_attr = "hi"
    propvalue = 42
    _private_attr1 = "hi"
    __private_attr2 = "hi"
    name = ""

    def __init__(self, name="dummy"):
        self.name = name    # note: not affected by @expose, only real properties are

    def __eq__(self, other):
        if type(other) is MyThingFullExposed:
            return self.name == other.name
        return False

    def method(self, arg, default=99, **kwargs):
        pass

    @staticmethod
    def staticmethod(arg):
        pass

    @classmethod
    def classmethod(cls, arg):
        pass

    def __dunder__(self):
        pass

    def __private(self):
        pass

    def _private(self):
        pass

    @property
    def prop1(self):
        return self.propvalue

    @prop1.setter
    def prop1(self, value):
        self.propvalue = value

    @property
    def readonly_prop1(self):
        return self.propvalue

    @property
    def prop2(self):
        return self.propvalue

    @prop2.setter
    def prop2(self, value):
        self.propvalue = value

    @core.oneway
    def oneway(self, arg):
        pass

    def exposed(self):
        pass

    __hash__ = object.__hash__


@core.expose
class MyThingExposedSub(MyThingFullExposed):
    def sub_exposed(self):
        pass

    def sub_unexposed(self):
        pass

    @core.oneway
    def oneway2(self):
        pass


class MyThingPartlyExposedSub(MyThingPartlyExposed):
    @core.expose
    def sub_exposed(self):
        pass

    def sub_unexposed(self):
        pass

    @core.oneway
    def oneway2(self):
        pass


class ConnectionMock(object):
    def __init__(self, initial_msg=None):
        self.keep_open = False
        if not initial_msg:
            self.received = b""
        elif isinstance(initial_msg, (str, bytes)):
            self.received = initial_msg
        else:
            self.received = initial_msg.to_bytes()   # it's probably a Message object

    def send(self, data):
        self.received += data

    def recv(self, datasize):
        chunk = self.received[:datasize]
        self.received = self.received[datasize:]
        if len(chunk) < datasize:
            raise errors.ConnectionClosedError("receiving: not enough data")
        return chunk


class AtomicCounter(object):
    def __init__(self, value=0):
        self.__initial = value
        self.__value = value
        self.__lock = threading.Lock()

    def reset(self):
        self.__value = self.__initial

    def incr(self, amount=1):
        with self.__lock:
            self.__value += amount
            return self.__value

    def decr(self, amount=1):
        with self.__lock:
            self.__value -= amount
            return self.__value

    @property
    def value(self):
        return self.__value


class Resource(object):
    # a fictional resource that gets allocated and must be freed again later.
    def __init__(self, name, collection):
        self.name = name
        self.collection = collection
        self.close_called = False

    def close(self):
        # Pyro will call this on a tracked resource once the client's connection gets closed!
        self.collection.discard(self)
        self.close_called = True


@expose
@behavior(instance_mode="single")
class ResourceService(object):
    def __init__(self):
        self.resources = set()      # the allocated resources

    def allocate(self, name):
        resource = Resource(name, self.resources)
        self.resources.add(resource)
        current_context.track_resource(resource)

    def free(self, name):
        resources = {r for r in self.resources if r.name == name}
        self.resources -= resources
        for r in resources:
            r.close()
            current_context.untrack_resource(r)

    def list(self):
        return [r.name for r in self.resources]