Skip to content

Instantly share code, notes, and snippets.

@blink1073
Last active January 10, 2016 02:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blink1073/7f9fccf85a1b2d430efe to your computer and use it in GitHub Desktop.
Save blink1073/7f9fccf85a1b2d430efe to your computer and use it in GitHub Desktop.
Spyder QProcess
# -*- 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_()
# -*- 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