Last active
January 10, 2016 02:06
-
-
Save blink1073/7f9fccf85a1b2d430efe to your computer and use it in GitHub Desktop.
Spyder QProcess
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# | |
# Copyright © 2016 The Spyder development team | |
# Licensed under the terms of the MIT License | |
# (see spyderlib/__init__.py for details) | |
import socket | |
import errno | |
import os | |
import sys | |
# Local imports | |
from spyderlib.utils.misc import select_port | |
from spyderlib.utils.bsdsocket import read_packet, write_packet | |
from spyderlib.qt.QtCore import QThread, QProcess, Signal, QObject | |
class PluginManager(QObject): | |
initialized = Signal() | |
finished = Signal() | |
request_handled = Signal(object) | |
def __init__(self, plugin_name): | |
super(PluginManager, self).__init__() | |
self.plugin_name = plugin_name | |
self.start() | |
def start(self): | |
self._initialized = False | |
plugin_name = self.plugin_name | |
server_port = select_port() | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
sock.bind(("127.0.0.1", server_port)) | |
self.client_port = select_port() | |
self.process = QProcess(self) | |
self.process.setProcessChannelMode(QProcess.MergedChannels) | |
self.process.setWorkingDirectory(os.path.dirname(__file__)) | |
p_args = ['plugin_server.py', str(self.client_port), | |
str(server_port), plugin_name] | |
self.listener = PluginListener(sock) | |
self.listener.request_handled.connect(self.request_handled.emit) | |
self.listener.initialized.connect(self._on_initialized) | |
self.listener.start() | |
self.process.start(sys.executable, p_args) | |
self.process.finished.connect(self._on_finished) | |
running = self.process.waitForStarted() | |
if not running: | |
raise IOError('Could not start plugin %s' % plugin_name) | |
def send(self, request): | |
# send a request to the port | |
try: | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
sock.connect(("127.0.0.1", self.client_port)) | |
write_packet(sock, request) | |
sock.close() | |
except socket.error: | |
pass | |
def _on_initialized(self): | |
self._initialized = True | |
self.initialized.emit() | |
def _on_finished(self): | |
if self._initialized: | |
self.start() | |
else: | |
self.finished.emit() | |
class PluginListener(QThread): | |
initialized = Signal() | |
request_handled = Signal(object) | |
def __init__(self, sock): | |
super(PluginListener, self).__init__() | |
self.sock = sock | |
self._initialized = False | |
def run(self): | |
while True: | |
self.sock.listen(2) | |
try: | |
conn, _addr = self.sock.accept() | |
except socket.error as e: | |
# See Issue 1275 for details on why errno EINTR is | |
# silently ignored here. | |
eintr = errno.WSAEINTR if os.name == 'nt' else errno.EINTR | |
if e.args[0] == eintr: | |
continue | |
raise | |
if not self._initialized: | |
if read_packet(conn) == 'initialized': | |
self._initialized = True | |
self.initialized.emit() | |
else: | |
self.request_handled.emit(read_packet(conn)) | |
class IntrospectionManager(object): | |
managers = {} # by plugin name | |
requests = [] | |
def __init__(self): | |
# create the plugin managers and plugin listeners | |
# hook up to their signals | |
# when we get a request, send it to the plugin managers | |
# when we get a response, handle it | |
pass | |
if __name__ == '__main__': | |
from spyderlib.qt.QtGui import QApplication | |
app = QApplication(sys.argv) | |
plugin = PluginManager('jedi') | |
def handle_return(value): | |
print(value) | |
if value == 'barbar': | |
app.quit() | |
else: | |
plugin.send('bar') | |
def handle_close(): | |
print('closed') | |
sys.exit(1) | |
def start(): | |
plugin.send('foo') | |
plugin.finished.connect(handle_close) | |
plugin.request_handled.connect(handle_return) | |
plugin.initialized.connect(start) | |
app.exec_() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# | |
# Copyright © 2016 The Spyder development team | |
# Licensed under the terms of the MIT License | |
# (see spyderlib/__init__.py for details) | |
import threading | |
import socket | |
import errno | |
import os | |
import sys | |
# Local imports | |
from spyderlib.py3compat import Queue | |
from spyderlib.utils.bsdsocket import read_packet, write_packet | |
class PluginServer(object): | |
def __init__(self, server_port, client_port, plugin_name): | |
mod_name = plugin_name + '_plugin' | |
mod = __import__('spyderlib.utils.introspection.' + mod_name, | |
fromlist=[mod_name]) | |
cls = getattr(mod, '%sPlugin' % plugin_name.capitalize()) | |
plugin = cls() | |
plugin.load_plugin() | |
self._client_port = int(client_port) | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
sock.bind(("127.0.0.1", int(server_port))) | |
self._server_sock = sock | |
self.queue = Queue.Queue() | |
self._listener = threading.Thread(target=self.listen) | |
self._listener.setDaemon(True) | |
self._listener.start() | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
sock.connect(("127.0.0.1", self._client_port)) | |
write_packet(sock, 'initialized') | |
sock.close() | |
def listen(self): | |
while True: | |
self._server_sock.listen(2) | |
try: | |
conn, _addr = self._server_sock.accept() | |
except socket.error as e: | |
# See Issue 1275 for details on why errno EINTR is | |
# silently ignored here. | |
eintr = errno.WSAEINTR if os.name == 'nt' else errno.EINTR | |
if e.args[0] == eintr: | |
continue | |
raise | |
self.queue.put(read_packet(conn)) | |
def run(self): | |
while 1: | |
# Get most recent request | |
request = None | |
while 1: | |
try: | |
request = self.queue.get(True, 0.005) | |
except Queue.Empty: | |
break | |
if request is None: | |
continue | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
sock.connect(("127.0.0.1", self._client_port)) | |
write_packet(sock, request + request) | |
sock.close() | |
if __name__ == '__main__': | |
args = sys.argv[1:] | |
plugin = PluginServer(*args) | |
print('Started') | |
plugin.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment