Skip to content

Commit e933221

Browse files
authored
Merge pull request #190 from bluetech/execmodel-split
gateway_base: refactor execmodel to avoid dynamic features
2 parents 0189fcf + cdfcc2d commit e933221

File tree

1 file changed

+220
-83
lines changed

1 file changed

+220
-83
lines changed

execnet/gateway_base.py

+220-83
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"""
1414
from __future__ import annotations
1515

16+
import abc
1617
import os
1718
import struct
1819
import sys
@@ -23,106 +24,242 @@
2324
from typing import Callable
2425

2526

26-
SUBPROCESS32 = False
27-
# f = open("/tmp/execnet-%s" % os.getpid(), "w")
28-
# def log_extra(*msg):
29-
# f.write(" ".join([str(x) for x in msg]) + "\n")
27+
class ExecModel(metaclass=abc.ABCMeta):
28+
@property
29+
@abc.abstractmethod
30+
def backend(self):
31+
raise NotImplementedError()
3032

33+
def __repr__(self):
34+
return "<ExecModel %r>" % self.backend
3135

32-
def get_execmodel(backend):
33-
if hasattr(backend, "backend"):
34-
return backend
35-
if backend == "thread":
36-
importdef = {
37-
"get_ident": "_thread::get_ident",
38-
"_start_new_thread": "_thread::start_new_thread",
39-
"queue": "queue",
40-
"sleep": "time::sleep",
41-
"subprocess": "subprocess",
42-
"socket": "socket",
43-
"_fdopen": "os::fdopen",
44-
"_lock": "threading",
45-
"_event": "threading",
46-
}
36+
@property
37+
@abc.abstractmethod
38+
def queue(self):
39+
raise NotImplementedError()
4740

48-
def exec_start(self, func, args=()):
49-
self._start_new_thread(func, args)
41+
@property
42+
@abc.abstractmethod
43+
def subprocess(self):
44+
raise NotImplementedError()
5045

51-
elif backend == "eventlet":
52-
importdef = {
53-
"get_ident": "eventlet.green.thread::get_ident",
54-
"_spawn_n": "eventlet::spawn_n",
55-
"queue": "eventlet.queue",
56-
"sleep": "eventlet::sleep",
57-
"subprocess": "eventlet.green.subprocess",
58-
"socket": "eventlet.green.socket",
59-
"_fdopen": "eventlet.green.os::fdopen",
60-
"_lock": "eventlet.green.threading",
61-
"_event": "eventlet.green.threading",
62-
}
46+
@property
47+
@abc.abstractmethod
48+
def socket(self):
49+
raise NotImplementedError()
6350

64-
def exec_start(self, func, args=()):
65-
self._spawn_n(func, *args)
51+
@abc.abstractmethod
52+
def start(self, func, args=()):
53+
raise NotImplementedError()
6654

67-
elif backend == "gevent":
68-
importdef = {
69-
"get_ident": "gevent.thread::get_ident",
70-
"_spawn_n": "gevent::spawn",
71-
"queue": "gevent.queue",
72-
"sleep": "gevent::sleep",
73-
"subprocess": "gevent.subprocess",
74-
"socket": "gevent.socket",
75-
# XXX
76-
"_fdopen": "gevent.fileobject::FileObjectThread",
77-
"_lock": "gevent.lock",
78-
"_event": "gevent.event",
79-
}
55+
@abc.abstractmethod
56+
def get_ident(self):
57+
raise NotImplementedError()
8058

81-
def exec_start(self, func, args=()):
82-
self._spawn_n(func, *args)
59+
@abc.abstractmethod
60+
def sleep(self, delay):
61+
raise NotImplementedError()
8362

84-
else:
85-
raise ValueError(f"unknown execmodel {backend!r}")
63+
@abc.abstractmethod
64+
def fdopen(self, fd, mode, bufsize=1):
65+
raise NotImplementedError()
8666

87-
class ExecModel:
88-
def __init__(self, name):
89-
self._importdef = importdef
90-
self.backend = name
67+
@abc.abstractmethod
68+
def Lock(self):
69+
raise NotImplementedError()
9170

92-
def __repr__(self):
93-
return "<ExecModel %r>" % self.backend
71+
@abc.abstractmethod
72+
def RLock(self):
73+
raise NotImplementedError()
9474

95-
def __getattr__(self, name):
96-
loc = self._importdef.get(name)
97-
if loc is None:
98-
raise AttributeError(name)
99-
parts = loc.split("::")
100-
try:
101-
mod = __import__(parts[0], None, None, "__doc__")
102-
except ImportError:
103-
pass
104-
else:
105-
if len(parts) > 1:
106-
mod = getattr(mod, parts[1])
107-
setattr(self, name, mod)
108-
return mod
109-
raise AttributeError(name)
75+
@abc.abstractmethod
76+
def Event(self):
77+
raise NotImplementedError()
78+
79+
80+
class ThreadExecModel(ExecModel):
81+
backend = "thread"
82+
83+
@property
84+
def queue(self):
85+
import queue
86+
87+
return queue
88+
89+
@property
90+
def subprocess(self):
91+
import subprocess
92+
93+
return subprocess
94+
95+
@property
96+
def socket(self):
97+
import socket
98+
99+
return socket
100+
101+
def get_ident(self):
102+
import _thread
103+
104+
return _thread.get_ident()
105+
106+
def sleep(self, delay):
107+
import time
108+
109+
time.sleep(delay)
110+
111+
def start(self, func, args=()):
112+
import _thread
113+
114+
return _thread.start_new_thread(func, args)
115+
116+
def fdopen(self, fd, mode, bufsize=1):
117+
import os
118+
119+
return os.fdopen(fd, mode, bufsize)
120+
121+
def Lock(self):
122+
import threading
123+
124+
return threading.RLock()
125+
126+
def RLock(self):
127+
import threading
128+
129+
return threading.RLock()
130+
131+
def Event(self):
132+
import threading
133+
134+
return threading.Event()
135+
136+
137+
class EventletExecModel(ExecModel):
138+
backend = "eventlet"
139+
140+
@property
141+
def queue(self):
142+
import eventlet
143+
144+
return eventlet.queue
145+
146+
@property
147+
def subprocess(self):
148+
import eventlet.green.subprocess
149+
150+
return eventlet.green.subprocess
110151

111-
start = exec_start
152+
@property
153+
def socket(self):
154+
import eventlet.green.socket
112155

113-
def fdopen(self, fd, mode, bufsize=1):
114-
return self._fdopen(fd, mode, bufsize)
156+
return eventlet.green.socket
115157

116-
def Lock(self):
117-
return self._lock.RLock()
158+
def get_ident(self):
159+
import eventlet.green.thread
118160

119-
def RLock(self):
120-
return self._lock.RLock()
161+
return eventlet.green.thread.get_ident()
121162

122-
def Event(self):
123-
return self._event.Event()
163+
def sleep(self, delay):
164+
import eventlet
124165

125-
return ExecModel(backend)
166+
eventlet.sleep(delay)
167+
168+
def start(self, func, args=()):
169+
import eventlet
170+
171+
return eventlet.spawn_n(func, *args)
172+
173+
def fdopen(self, fd, mode, bufsize=1):
174+
import eventlet.green.os
175+
176+
return eventlet.green.os.fdopen(fd, mode, bufsize)
177+
178+
def Lock(self):
179+
import eventlet.green.threading
180+
181+
return eventlet.green.threading.RLock()
182+
183+
def RLock(self):
184+
import eventlet.green.threading
185+
186+
return eventlet.green.threading.RLock()
187+
188+
def Event(self):
189+
import eventlet.green.threading
190+
191+
return eventlet.green.threading.Event()
192+
193+
194+
class GeventExecModel(ExecModel):
195+
backend = "gevent"
196+
197+
@property
198+
def queue(self):
199+
import gevent.queue
200+
201+
return gevent.queue
202+
203+
@property
204+
def subprocess(self):
205+
import gevent.subprocess
206+
207+
return gevent.subprocess
208+
209+
@property
210+
def socket(self):
211+
import gevent
212+
213+
return gevent.socket
214+
215+
def get_ident(self):
216+
import gevent.thread
217+
218+
return gevent.thread.get_ident()
219+
220+
def sleep(self, delay):
221+
import gevent
222+
223+
gevent.sleep(delay)
224+
225+
def start(self, func, args=()):
226+
import gevent
227+
228+
return gevent.spawn(func, *args)
229+
230+
def fdopen(self, fd, mode, bufsize=1):
231+
# XXX
232+
import gevent.fileobject
233+
234+
return gevent.fileobject.FileObjectThread(fd, mode, bufsize)
235+
236+
def Lock(self):
237+
import gevent.lock
238+
239+
return gevent.lock.RLock()
240+
241+
def RLock(self):
242+
import gevent.lock
243+
244+
return gevent.lock.RLock()
245+
246+
def Event(self):
247+
import gevent.event
248+
249+
return gevent.event.Event()
250+
251+
252+
def get_execmodel(backend):
253+
if hasattr(backend, "backend"):
254+
return backend
255+
if backend == "thread":
256+
return ThreadExecModel()
257+
elif backend == "eventlet":
258+
return EventletExecModel()
259+
elif backend == "gevent":
260+
return GeventExecModel()
261+
else:
262+
raise ValueError(f"unknown execmodel {backend!r}")
126263

127264

128265
class Reply:

0 commit comments

Comments
 (0)