retracesoftware-proxy 0.1.5__py3-none-any.whl → 0.2.4__py3-none-any.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.
- retracesoftware/__main__.py +285 -0
- retracesoftware/autoenable.py +53 -0
- retracesoftware/config.json +19 -233
- retracesoftware/config.yaml +0 -0
- retracesoftware/install/config.py +6 -0
- retracesoftware/install/edgecases.py +23 -1
- retracesoftware/install/patcher.py +98 -513
- retracesoftware/install/patchfindspec.py +117 -0
- retracesoftware/install/phases.py +338 -0
- retracesoftware/install/record.py +111 -40
- retracesoftware/install/replace.py +28 -0
- retracesoftware/install/replay.py +59 -11
- retracesoftware/install/tracer.py +171 -33
- retracesoftware/install/typeutils.py +20 -0
- retracesoftware/modules.toml +384 -0
- retracesoftware/preload.txt +216 -0
- retracesoftware/proxy/__init__.py +1 -1
- retracesoftware/proxy/globalref.py +31 -0
- retracesoftware/proxy/messagestream.py +204 -0
- retracesoftware/proxy/proxysystem.py +328 -71
- retracesoftware/proxy/proxytype.py +90 -38
- retracesoftware/proxy/record.py +109 -119
- retracesoftware/proxy/replay.py +94 -188
- retracesoftware/proxy/serializer.py +28 -0
- retracesoftware/proxy/startthread.py +40 -0
- retracesoftware/proxy/stubfactory.py +82 -27
- retracesoftware/proxy/thread.py +64 -4
- retracesoftware/replay.py +104 -0
- retracesoftware/run.py +378 -0
- retracesoftware/stackdifference.py +133 -0
- {retracesoftware_proxy-0.1.5.dist-info → retracesoftware_proxy-0.2.4.dist-info}/METADATA +2 -1
- retracesoftware_proxy-0.2.4.dist-info/RECORD +42 -0
- retracesoftware_proxy-0.1.5.dist-info/RECORD +0 -27
- {retracesoftware_proxy-0.1.5.dist-info → retracesoftware_proxy-0.2.4.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.5.dist-info → retracesoftware_proxy-0.2.4.dist-info}/top_level.txt +0 -0
retracesoftware/proxy/replay.py
CHANGED
|
@@ -1,86 +1,20 @@
|
|
|
1
1
|
import retracesoftware.functional as functional
|
|
2
2
|
import retracesoftware_utils as utils
|
|
3
|
-
import retracesoftware.stream as stream
|
|
4
3
|
|
|
5
4
|
from retracesoftware.install.tracer import Tracer
|
|
6
|
-
from retracesoftware.proxy.thread import per_thread_messages
|
|
5
|
+
from retracesoftware.proxy.thread import per_thread_messages, thread_id
|
|
6
|
+
from retracesoftware.proxy.messagestream import *
|
|
7
7
|
from retracesoftware.proxy.proxytype import *
|
|
8
8
|
# from retracesoftware.proxy.gateway import gateway_pair
|
|
9
|
-
from retracesoftware.proxy.record import StubRef
|
|
10
|
-
from retracesoftware.proxy.proxysystem import ProxySystem
|
|
11
|
-
from retracesoftware.proxy.stubfactory import StubFactory
|
|
9
|
+
from retracesoftware.proxy.record import StubRef
|
|
10
|
+
from retracesoftware.proxy.proxysystem import ProxySystem
|
|
11
|
+
from retracesoftware.proxy.stubfactory import StubFactory
|
|
12
|
+
from retracesoftware.proxy.globalref import GlobalRef
|
|
12
13
|
|
|
13
14
|
import os
|
|
14
|
-
import weakref
|
|
15
|
-
import traceback
|
|
16
|
-
# we can have a dummy method descriptor, its has a __name__ and when called, returns the next element
|
|
17
|
-
|
|
18
|
-
# for types, we can patch the __new__ method
|
|
19
|
-
# do it from C and immutable types can be patched too
|
|
20
|
-
# patch the tp_new pointer?
|
|
21
|
-
|
|
22
|
-
class ReplayError(RetraceError):
|
|
23
|
-
pass
|
|
24
15
|
|
|
25
16
|
class ReplayProxySystem(ProxySystem):
|
|
26
17
|
|
|
27
|
-
def stubtype(self, cls):
|
|
28
|
-
assert not issubclass(cls, Proxy)
|
|
29
|
-
|
|
30
|
-
return dynamic_proxytype(handler = self.ext_handler, cls = cls)
|
|
31
|
-
|
|
32
|
-
def create_stub(self): return True
|
|
33
|
-
|
|
34
|
-
# def stubtype_from_spec(self, spec):
|
|
35
|
-
# print (f'FOOO!!! {spec}')
|
|
36
|
-
# return stubtype_from_spec(
|
|
37
|
-
# handler = self.ext_handler,
|
|
38
|
-
# module = spec.module,
|
|
39
|
-
# name = spec.name,
|
|
40
|
-
# methods = spec.methods,
|
|
41
|
-
# members = spec.members)
|
|
42
|
-
|
|
43
|
-
@utils.striptraceback
|
|
44
|
-
def next_result(self):
|
|
45
|
-
while True:
|
|
46
|
-
next = self.messages()
|
|
47
|
-
|
|
48
|
-
if next == 'CALL':
|
|
49
|
-
func = self.messages()
|
|
50
|
-
args = self.messages()
|
|
51
|
-
kwargs = self.messages()
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
func(*args, **kwargs)
|
|
55
|
-
except:
|
|
56
|
-
pass
|
|
57
|
-
|
|
58
|
-
elif next == 'RESULT':
|
|
59
|
-
return self.messages()
|
|
60
|
-
elif next == 'ERROR':
|
|
61
|
-
err_type = self.messages()
|
|
62
|
-
err_value = self.messages()
|
|
63
|
-
utils.raise_exception(err_type, err_value)
|
|
64
|
-
else:
|
|
65
|
-
assert type(next) is not str
|
|
66
|
-
return next
|
|
67
|
-
|
|
68
|
-
def bind(self, obj):
|
|
69
|
-
read = self.messages()
|
|
70
|
-
|
|
71
|
-
assert isinstance(read, Placeholder)
|
|
72
|
-
|
|
73
|
-
self.bindings[read] = obj
|
|
74
|
-
|
|
75
|
-
# def dynamic_path(self):
|
|
76
|
-
# if self.getpid() != self.pid:
|
|
77
|
-
# self.pid = self.getpid()
|
|
78
|
-
# # ok we are in child, calculate new path
|
|
79
|
-
# self.path = self.path / f'fork-{self.fork_counter}'
|
|
80
|
-
# self.fork_counter = 0
|
|
81
|
-
|
|
82
|
-
# return self.path
|
|
83
|
-
|
|
84
18
|
def after_fork_in_child(self):
|
|
85
19
|
self.reader.path = self.new_child_path(self.reader.path)
|
|
86
20
|
super().after_fork_in_child()
|
|
@@ -88,145 +22,117 @@ class ReplayProxySystem(ProxySystem):
|
|
|
88
22
|
# def dynamic_ext_proxytype(self, cls):
|
|
89
23
|
# raise Exception('dynamic_ext_proxytype should not be called in replay')
|
|
90
24
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return super().proxy_function(func)
|
|
25
|
+
@property
|
|
26
|
+
def ext_apply(self):
|
|
27
|
+
return functional.repeatedly(self.next_result)
|
|
96
28
|
|
|
97
|
-
def
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
path,
|
|
102
|
-
fork_path = []):
|
|
103
|
-
|
|
104
|
-
# self.writer = writer
|
|
105
|
-
# super().__init__(thread_state = thread_state)
|
|
106
|
-
reader = stream.reader(path)
|
|
107
|
-
|
|
108
|
-
self.bindings = utils.id_dict()
|
|
109
|
-
self.set_thread_id = utils.set_thread_id
|
|
110
|
-
self.fork_path = fork_path
|
|
111
|
-
deserialize = functional.walker(self.bindings.get_else_key)
|
|
112
|
-
|
|
113
|
-
self.messages = functional.sequence(per_thread_messages(reader), deserialize)
|
|
29
|
+
def proxy__new__(self, __new__, *args, **kwargs):
|
|
30
|
+
func = functional.repeatedly(self.next_result)
|
|
31
|
+
func.__name__ = '__new__'
|
|
32
|
+
return super().proxy__new__(func, *args, **kwargs)
|
|
114
33
|
|
|
115
|
-
|
|
34
|
+
def basetype(self, cls):
|
|
35
|
+
return self.stub_factory.create_stubtype(StubRef(cls))
|
|
116
36
|
|
|
117
|
-
|
|
37
|
+
def trace_writer(self, name, *args):
|
|
38
|
+
with self.thread_state.select('disabled'):
|
|
39
|
+
# read = self.messages_read
|
|
118
40
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return self.messages()
|
|
123
|
-
except Exception as error:
|
|
124
|
-
# print(f'Error reading stream: {error}')
|
|
125
|
-
traceback.print_exc()
|
|
41
|
+
self.read_required('TRACE')
|
|
42
|
+
# self.read_required(read)
|
|
43
|
+
self.read_required(name)
|
|
126
44
|
|
|
45
|
+
if name == 'stacktrace':
|
|
46
|
+
print('FOOO!!!')
|
|
47
|
+
os._exit(1)
|
|
48
|
+
record = self.readnext()
|
|
49
|
+
if args[0] == record:
|
|
50
|
+
self.last_matching_stack = args[0]
|
|
51
|
+
else:
|
|
52
|
+
on_stack_mismatch(
|
|
53
|
+
last_matching = self.last_matching_stack,
|
|
54
|
+
record = record,
|
|
55
|
+
replay = args[0])
|
|
127
56
|
os._exit(1)
|
|
57
|
+
else:
|
|
58
|
+
# print(f'Trace: {self.reader.messages_read} {name} {args}')
|
|
59
|
+
for arg in args:
|
|
60
|
+
self.read_required(arg)
|
|
128
61
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
62
|
+
def on_thread_exit(self, thread_id):
|
|
63
|
+
# print(f'on_thread_exit!!!!')
|
|
64
|
+
self.reader.wake_pending()
|
|
132
65
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
print(f'Replay: {required} Record: {obj}')
|
|
143
|
-
for i in range(5):
|
|
144
|
-
print(readnext())
|
|
145
|
-
|
|
146
|
-
utils.sigtrap(None)
|
|
147
|
-
os._exit(1)
|
|
148
|
-
raise Exception(f'Expected: {required} but got: {obj}')
|
|
66
|
+
def __init__(self,
|
|
67
|
+
reader,
|
|
68
|
+
thread_state,
|
|
69
|
+
immutable_types,
|
|
70
|
+
tracing_config,
|
|
71
|
+
traceargs,
|
|
72
|
+
verbose = False,
|
|
73
|
+
fork_path = [],
|
|
74
|
+
skip_weakref_callbacks = False):
|
|
149
75
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
print(f'Trace: {name} {args}')
|
|
153
|
-
|
|
154
|
-
read_required('TRACE')
|
|
155
|
-
read_required(name)
|
|
76
|
+
self.reader = reader
|
|
77
|
+
# self.skip_weakref_callbacks = skip_weakref_callbacks
|
|
156
78
|
|
|
157
|
-
|
|
158
|
-
read_required(arg)
|
|
79
|
+
self.fork_path = fork_path
|
|
159
80
|
|
|
160
|
-
|
|
161
|
-
|
|
81
|
+
self.messages = MessageStream(
|
|
82
|
+
thread_state = thread_state,
|
|
83
|
+
source = reader,
|
|
84
|
+
skip_weakref_callbacks = skip_weakref_callbacks,
|
|
85
|
+
verbose = verbose)
|
|
162
86
|
|
|
163
|
-
self.
|
|
87
|
+
self.checkpoint = self.messages.checkpoint
|
|
88
|
+
self.bind = self.messages.bind
|
|
89
|
+
self.next_result = self.messages.result
|
|
90
|
+
self.exclude_from_stacktrace = self.messages.excludes.add
|
|
164
91
|
|
|
165
|
-
|
|
166
|
-
# print(cls)
|
|
167
|
-
# assert isinstance(cls, type)
|
|
168
|
-
# immutable_types.add(cls)
|
|
92
|
+
self.stub_factory = StubFactory(thread_state = thread_state, next_result = self.next_result)
|
|
169
93
|
|
|
170
|
-
|
|
171
|
-
# add_stubtype = functional.side_effect(immutable_types.add)
|
|
94
|
+
self.last_matching_stack = None
|
|
172
95
|
|
|
173
|
-
|
|
96
|
+
def run_ref(ref):
|
|
97
|
+
print(f'run_ref!!!! {ref}')
|
|
98
|
+
return ref()
|
|
174
99
|
|
|
175
|
-
reader.type_deserializer[StubRef] = self.stub_factory
|
|
176
|
-
# reader.type_deserializer[
|
|
100
|
+
self.reader.type_deserializer[StubRef] = self.stub_factory
|
|
101
|
+
# self.reader.type_deserializer[GlobalRef] = lambda ref: ref()
|
|
102
|
+
self.reader.type_deserializer[GlobalRef] = run_ref
|
|
177
103
|
|
|
178
|
-
|
|
179
|
-
|
|
104
|
+
excludes = [ReplayProxySystem.trace_writer]
|
|
105
|
+
|
|
106
|
+
for exclude in excludes:
|
|
107
|
+
self.messages.excludes.add(exclude)
|
|
180
108
|
|
|
181
|
-
|
|
182
|
-
# return lambda cls: dynamic_int_proxytype(handler = gateway, cls = cls, bind = self.bind)
|
|
109
|
+
sync = functional.lazy(self.messages.read_required, 'SYNC')
|
|
183
110
|
|
|
184
|
-
|
|
185
|
-
# create_stubs = functional.walker(functional.when(is_stub_type, lambda cls: cls()))
|
|
111
|
+
read_sync = thread_state.dispatch(utils.noop, internal = sync)
|
|
186
112
|
|
|
187
|
-
|
|
188
|
-
# self.ext_apply = functional.repeatedly(self.next_result)
|
|
189
|
-
|
|
190
|
-
def read_sync(): read_required('SYNC')
|
|
113
|
+
self.on_ext_call = sync
|
|
191
114
|
|
|
192
|
-
self.sync = lambda function: utils.observer(on_call =
|
|
193
|
-
|
|
194
|
-
super().__init__(thread_state = thread_state,
|
|
195
|
-
tracer = Tracer(tracing_config, writer = trace_writer),
|
|
196
|
-
immutable_types = immutable_types)
|
|
197
|
-
|
|
198
|
-
# super().__init__(
|
|
199
|
-
# thread_state=thread_state,
|
|
200
|
-
# immutable_types= immutable_types,
|
|
201
|
-
# tracer=self.tracer,
|
|
202
|
-
# ext_apply = ext_apply)
|
|
115
|
+
self.sync = lambda function: utils.observer(on_call = read_sync, function = function)
|
|
203
116
|
|
|
204
|
-
|
|
205
|
-
# thread_state,
|
|
206
|
-
# self.tracer,
|
|
207
|
-
# immutable_types = immutable_types,
|
|
208
|
-
# ext_apply = ext_apply,
|
|
209
|
-
# int_proxytype = int_proxytype,
|
|
210
|
-
# ext_proxytype = functional.identity)
|
|
211
|
-
|
|
212
|
-
# def extend_type(self, base):
|
|
213
|
-
|
|
214
|
-
# # ok, how to provide __getattr__ style access,
|
|
117
|
+
self.create_from_external = utils.noop
|
|
215
118
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
119
|
+
if skip_weakref_callbacks:
|
|
120
|
+
self.wrap_weakref_callback = \
|
|
121
|
+
lambda callback: \
|
|
122
|
+
thread_state.dispatch(
|
|
123
|
+
callback, internal = self.disable_for(callback))
|
|
124
|
+
else:
|
|
125
|
+
self.on_weakref_callback_start = functional.lazy(self.messages.read_required, 'ON_WEAKREF_CALLBACK_START')
|
|
126
|
+
self.on_weakref_callback_end = functional.lazy(self.messages.read_required, 'ON_WEAKREF_CALLBACK_END')
|
|
223
127
|
|
|
224
|
-
|
|
225
|
-
|
|
128
|
+
super().__init__(thread_state = thread_state,
|
|
129
|
+
tracer = Tracer(tracing_config, writer = self.trace_writer),
|
|
130
|
+
immutable_types = immutable_types,
|
|
131
|
+
traceargs = traceargs)
|
|
226
132
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
# # on_new = self.reader.supply)
|
|
133
|
+
def write_trace(self, obj):
|
|
134
|
+
if 'TRACER' != self.messages():
|
|
135
|
+
utils.sigtrap(obj)
|
|
231
136
|
|
|
232
|
-
|
|
137
|
+
# self.read_required ('TRACER')
|
|
138
|
+
self.read_required(obj)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
def serializer(obj):
|
|
2
|
+
cls = type(obj)
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
if issubclass(cls, Enum):
|
|
6
|
+
return str(obj)
|
|
7
|
+
|
|
8
|
+
if issubclass(cls, (tuple, list)):
|
|
9
|
+
return list(map(serializer, obj))
|
|
10
|
+
elif issubclass(cls, dict):
|
|
11
|
+
return {str(serializer(k)):serializer(v) for k,v in obj.items()}
|
|
12
|
+
elif issubclass(cls, int):
|
|
13
|
+
if obj > 1000000 or obj < -1000000:
|
|
14
|
+
return "XXXX"
|
|
15
|
+
else:
|
|
16
|
+
return int(obj)
|
|
17
|
+
elif issubclass(cls, (bool, str, types.NoneType)):
|
|
18
|
+
return obj
|
|
19
|
+
elif issubclass(cls, types.FunctionType):
|
|
20
|
+
return obj.__qualname__
|
|
21
|
+
elif issubclass(cls, types.CellType):
|
|
22
|
+
return getattr(obj, '__qualname__', 'CellType')
|
|
23
|
+
elif issubclass(cls, types.GeneratorType):
|
|
24
|
+
return obj.__qualname__
|
|
25
|
+
else:
|
|
26
|
+
return cleanse(str(obj))
|
|
27
|
+
except:
|
|
28
|
+
return f'Unserializable object of type: {cls}'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from retracesoftware import functional
|
|
2
|
+
from retracesoftware import utils
|
|
3
|
+
|
|
4
|
+
import _thread
|
|
5
|
+
|
|
6
|
+
# _thread.start_new_thread(function, args[, kwargs])
|
|
7
|
+
|
|
8
|
+
# push a per thread executor function, as a context manager
|
|
9
|
+
|
|
10
|
+
counters = _thread._local()
|
|
11
|
+
counters.id = ()
|
|
12
|
+
counters.counter = 0
|
|
13
|
+
|
|
14
|
+
def with_thread_id(thread_id, function, *args, **kwargs):
|
|
15
|
+
counters.id = thread_id
|
|
16
|
+
counters.counter = 0
|
|
17
|
+
return function(*args, **kwargs)
|
|
18
|
+
|
|
19
|
+
thread_id = functional.lazy(getattr, counters, 'id')
|
|
20
|
+
|
|
21
|
+
def start_new_thread(original, wrapper, function, *args):
|
|
22
|
+
return original(wrapper(function), *args)
|
|
23
|
+
|
|
24
|
+
def wrap_thread_function(thread_state, function):
|
|
25
|
+
if thread_state.value == 'internal':
|
|
26
|
+
next_id = counters.id + (counters.counter,)
|
|
27
|
+
counters.counter += 1
|
|
28
|
+
return functional.partial(with_thread_id, next_id, thread_state.wrap('internal', function))
|
|
29
|
+
else:
|
|
30
|
+
return function
|
|
31
|
+
|
|
32
|
+
def patch_thread_start(thread_state):
|
|
33
|
+
|
|
34
|
+
wrapper = functional.partial(wrap_thread_function, thread_state)
|
|
35
|
+
|
|
36
|
+
_thread.start_new = functional.partial(start_new_thread, _thread.start_new, wrapper)
|
|
37
|
+
_thread.start_new_thread = functional.partial(start_new_thread, _thread.start_new_thread, wrapper)
|
|
38
|
+
|
|
39
|
+
import threading
|
|
40
|
+
threading._start_new_thread = _thread.start_new_thread
|
|
@@ -13,14 +13,33 @@ class ExtendedRef:
|
|
|
13
13
|
self.module = module
|
|
14
14
|
|
|
15
15
|
class StubRef:
|
|
16
|
-
def __init__(self,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
self.methods =
|
|
20
|
-
self.
|
|
16
|
+
def __init__(self, cls):
|
|
17
|
+
blacklist = ['__class__', '__dict__', '__module__', '__doc__', '__new__']
|
|
18
|
+
|
|
19
|
+
self.methods = []
|
|
20
|
+
self.static_methods = []
|
|
21
|
+
self.class_methods = []
|
|
22
|
+
|
|
23
|
+
for key,value in cls.__dict__.items():
|
|
24
|
+
if key not in blacklist:
|
|
25
|
+
if isinstance(value, classmethod):
|
|
26
|
+
self.class_methods.append(key)
|
|
27
|
+
elif isinstance(value, staticmethod):
|
|
28
|
+
self.class_methods.append(key)
|
|
29
|
+
elif utils.is_method_descriptor(value):
|
|
30
|
+
self.methods.append(key)
|
|
31
|
+
|
|
32
|
+
self.name = cls.__name__
|
|
33
|
+
self.module = cls.__module__
|
|
34
|
+
|
|
35
|
+
# def __init__(self, module, name, methods, members):
|
|
36
|
+
# self.name = name
|
|
37
|
+
# self.module = module
|
|
38
|
+
# self.methods = methods
|
|
39
|
+
# self.members = members
|
|
21
40
|
|
|
22
41
|
def __str__(self):
|
|
23
|
-
return f'StubRef(module = {self.module}, name = {self.name}, methods = {self.methods}
|
|
42
|
+
return f'StubRef(module = {self.module}, name = {self.name}, methods = {self.methods})'
|
|
24
43
|
|
|
25
44
|
def resolve(module, name):
|
|
26
45
|
try:
|
|
@@ -33,6 +52,11 @@ class StubMethodDescriptor(functional.repeatedly):
|
|
|
33
52
|
super().__init__(next_result)
|
|
34
53
|
self.__name__ = name
|
|
35
54
|
|
|
55
|
+
# @utils.striptraceback
|
|
56
|
+
# def __call__(self, *args, **kwargs):
|
|
57
|
+
# super().__call__(*args, **kwargs)
|
|
58
|
+
|
|
59
|
+
#@utils.striptraceback
|
|
36
60
|
def __str__(self):
|
|
37
61
|
return f"stub - {__name__}"
|
|
38
62
|
|
|
@@ -41,29 +65,25 @@ class StubMemberDescriptor:
|
|
|
41
65
|
self.next_result = next_result
|
|
42
66
|
self.__name__ = name
|
|
43
67
|
|
|
68
|
+
#@utils.striptraceback
|
|
44
69
|
def __get__(self, instance, owner):
|
|
45
70
|
if instance is None:
|
|
46
71
|
return self
|
|
47
72
|
|
|
48
73
|
return self.next_result()
|
|
49
74
|
|
|
75
|
+
#@utils.striptraceback
|
|
50
76
|
def __set__(self, instance, value):
|
|
51
77
|
return self.next_result()
|
|
52
78
|
|
|
79
|
+
#@utils.striptraceback
|
|
53
80
|
def __delete__(self, instance):
|
|
54
81
|
return self.next_result()
|
|
55
|
-
|
|
82
|
+
|
|
83
|
+
#@utils.striptraceback
|
|
56
84
|
def __str__(self):
|
|
57
85
|
return f"stub member - {__name__}"
|
|
58
86
|
|
|
59
|
-
class StubFunction(functional.repeatedly):
|
|
60
|
-
def __init__(self, name, next_result):
|
|
61
|
-
super().__init__(next_result)
|
|
62
|
-
self.__name__ = name
|
|
63
|
-
|
|
64
|
-
def __str__(self):
|
|
65
|
-
return f"stub function - {__name__}"
|
|
66
|
-
|
|
67
87
|
class StubFactory:
|
|
68
88
|
|
|
69
89
|
__slots__ = ['next_result', 'thread_state', 'cache']
|
|
@@ -85,16 +105,21 @@ class StubFactory:
|
|
|
85
105
|
next_result = self.thread_state.dispatch(disabled, external = self.next_result)
|
|
86
106
|
|
|
87
107
|
return StubMemberDescriptor(name = name, next_result = next_result)
|
|
88
|
-
|
|
108
|
+
|
|
89
109
|
def create_method(self, name):
|
|
90
110
|
|
|
91
111
|
def disabled(*args, **kwargs):
|
|
92
112
|
if self.thread_state.value == 'disabled' and name == '__repr__':
|
|
93
113
|
return f"stub - {name}"
|
|
94
114
|
else:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
115
|
+
return None
|
|
116
|
+
# print(f'Error trying to call descriptor: {name} {args} {kwargs}, retrace mode: {self.thread_state.value}')
|
|
117
|
+
|
|
118
|
+
# import traceback
|
|
119
|
+
# traceback.print_stack()
|
|
120
|
+
|
|
121
|
+
# utils.sigtrap(None)
|
|
122
|
+
# os._exit(1)
|
|
98
123
|
|
|
99
124
|
next_result = self.thread_state.dispatch(disabled, external = self.next_result)
|
|
100
125
|
|
|
@@ -105,36 +130,66 @@ class StubFactory:
|
|
|
105
130
|
|
|
106
131
|
def create_stubtype(self, spec):
|
|
107
132
|
|
|
133
|
+
assert self.thread_state.value == 'disabled'
|
|
134
|
+
|
|
108
135
|
slots = {
|
|
109
136
|
'__module__': spec.module,
|
|
110
137
|
'__qualname__': spec.name,
|
|
138
|
+
'__name__': spec.name,
|
|
111
139
|
}
|
|
112
140
|
|
|
113
141
|
for method in spec.methods:
|
|
114
142
|
slots[method] = self.create_method(method)
|
|
115
143
|
assert utils.is_method_descriptor(slots[method])
|
|
116
144
|
|
|
117
|
-
|
|
118
|
-
|
|
145
|
+
def on_disabled(name):
|
|
146
|
+
print(f'Error trying to get/set attribute: {name}, when retrace mode: {self.thread_state.value} was not external')
|
|
147
|
+
utils.sigtrap(None)
|
|
148
|
+
os._exit(1)
|
|
149
|
+
|
|
150
|
+
#@utils.striptraceback
|
|
151
|
+
def getattr(instance, name):
|
|
152
|
+
print('In stub getattr!!!')
|
|
153
|
+
if self.thread_state.value == 'external':
|
|
154
|
+
return self.next_result()
|
|
155
|
+
else:
|
|
156
|
+
print(f'Error trying to get attribute: {name}, when retrace mode: {self.thread_state.value} was not external')
|
|
157
|
+
utils.sigtrap(None)
|
|
158
|
+
os._exit(1)
|
|
159
|
+
|
|
160
|
+
#@utils.striptraceback
|
|
161
|
+
def setattr(instance, name, value):
|
|
162
|
+
if self.thread_state.value == 'external':
|
|
163
|
+
return self.next_result()
|
|
164
|
+
else:
|
|
165
|
+
print(f'Error trying to set attribute: {name}, to: {value} when retrace mode: {self.thread_state.value} was not external')
|
|
166
|
+
utils.sigtrap(None)
|
|
167
|
+
os._exit(1)
|
|
168
|
+
|
|
169
|
+
slots['__getattr__'] = self.thread_state.method_dispatch(on_disabled, external = self.next_result)
|
|
170
|
+
# slots['__getattr__'] = getattr
|
|
171
|
+
slots['__setattr__'] = self.thread_state.method_dispatch(on_disabled, external = self.next_result)
|
|
119
172
|
|
|
120
173
|
resolved = resolve(spec.module, spec.name)
|
|
121
174
|
|
|
122
|
-
if isinstance(resolved, type):
|
|
123
|
-
|
|
175
|
+
# if isinstance(resolved, type):
|
|
176
|
+
# slots['__class__'] = property(functional.repeatedly(resolved))
|
|
177
|
+
|
|
178
|
+
# else:
|
|
179
|
+
# utils.sigtrap(f'{spec.module}.{spec.name}')
|
|
124
180
|
|
|
125
181
|
stubtype = type(spec.name, (Stub, ), slots)
|
|
126
182
|
|
|
127
183
|
for method in spec.methods:
|
|
128
184
|
slots[method].__objclass__ = stubtype
|
|
129
185
|
|
|
186
|
+
stubtype.__retrace_target_type__ = resolved
|
|
187
|
+
|
|
130
188
|
return stubtype
|
|
131
189
|
|
|
132
190
|
def __call__(self, spec):
|
|
133
|
-
print(f'In stubFactory.__call__ {spec}')
|
|
134
191
|
if spec not in self.cache:
|
|
135
192
|
self.cache[spec] = self.create_stubtype(spec)
|
|
136
193
|
|
|
137
194
|
stubtype = self.cache[spec]
|
|
138
|
-
|
|
139
|
-
print(f'In stubFactory created new')
|
|
140
|
-
return stub
|
|
195
|
+
return stubtype.__new__(stubtype)
|