mirror of https://github.com/python/cpython
Initial revision
This commit is contained in:
parent
51777ce758
commit
d7b6ed268e
|
@ -0,0 +1,342 @@
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
|
||||||
|
VERBOSE = None
|
||||||
|
|
||||||
|
class SocketProtocol:
|
||||||
|
"""A simple protocol for sending strings across a socket"""
|
||||||
|
BUF_SIZE = 8192
|
||||||
|
|
||||||
|
def __init__(self, sock):
|
||||||
|
self.sock = sock
|
||||||
|
self._buffer = ''
|
||||||
|
self._closed = 0
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self._closed = 1
|
||||||
|
self.sock.close()
|
||||||
|
|
||||||
|
def send(self, buf):
|
||||||
|
"""Encode buf and write it on the socket"""
|
||||||
|
if VERBOSE:
|
||||||
|
VERBOSE.write('send %d:%s\n' % (len(buf), `buf`))
|
||||||
|
self.sock.send('%d:%s' % (len(buf), buf))
|
||||||
|
|
||||||
|
def receive(self, timeout=0):
|
||||||
|
"""Get next complete string from socket or return None
|
||||||
|
|
||||||
|
Raise EOFError on EOF
|
||||||
|
"""
|
||||||
|
buf = self._read_from_buffer()
|
||||||
|
if buf is not None:
|
||||||
|
return buf
|
||||||
|
recvbuf = self._read_from_socket(timeout)
|
||||||
|
if recvbuf is None:
|
||||||
|
return None
|
||||||
|
if recvbuf == '' and self._buffer == '':
|
||||||
|
raise EOFError
|
||||||
|
if VERBOSE:
|
||||||
|
VERBOSE.write('recv %s\n' % `recvbuf`)
|
||||||
|
self._buffer = self._buffer + recvbuf
|
||||||
|
r = self._read_from_buffer()
|
||||||
|
return r
|
||||||
|
|
||||||
|
def _read_from_socket(self, timeout):
|
||||||
|
"""Does not block"""
|
||||||
|
if self._closed:
|
||||||
|
return ''
|
||||||
|
if timeout is not None:
|
||||||
|
r, w, x = select.select([self.sock], [], [], timeout)
|
||||||
|
if timeout is None or r:
|
||||||
|
return self.sock.recv(self.BUF_SIZE)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _read_from_buffer(self):
|
||||||
|
buf = self._buffer
|
||||||
|
i = buf.find(':')
|
||||||
|
if i == -1:
|
||||||
|
return None
|
||||||
|
buflen = int(buf[:i])
|
||||||
|
enclen = i + 1 + buflen
|
||||||
|
if len(buf) >= enclen:
|
||||||
|
s = buf[i+1:enclen]
|
||||||
|
self._buffer = buf[enclen:]
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
self._buffer = buf
|
||||||
|
return None
|
||||||
|
|
||||||
|
# helpers for registerHandler method below
|
||||||
|
|
||||||
|
def get_methods(obj):
|
||||||
|
methods = []
|
||||||
|
for name in dir(obj):
|
||||||
|
attr = getattr(obj, name)
|
||||||
|
if callable(attr):
|
||||||
|
methods.append(name)
|
||||||
|
if type(obj) == types.InstanceType:
|
||||||
|
methods = methods + get_methods(obj.__class__)
|
||||||
|
if type(obj) == types.ClassType:
|
||||||
|
for super in obj.__bases__:
|
||||||
|
methods = methods + get_methods(super)
|
||||||
|
return methods
|
||||||
|
|
||||||
|
class CommandProtocol:
|
||||||
|
def __init__(self, sockp):
|
||||||
|
self.sockp = sockp
|
||||||
|
self.seqno = 0
|
||||||
|
self.handlers = {}
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.sockp.close()
|
||||||
|
self.handlers.clear()
|
||||||
|
|
||||||
|
def registerHandler(self, handler):
|
||||||
|
"""A Handler is an object with handle_XXX methods"""
|
||||||
|
for methname in get_methods(handler):
|
||||||
|
if methname[:7] == "handle_":
|
||||||
|
name = methname[7:]
|
||||||
|
self.handlers[name] = getattr(handler, methname)
|
||||||
|
|
||||||
|
def send(self, cmd, arg='', seqno=None):
|
||||||
|
if arg:
|
||||||
|
msg = "%s %s" % (cmd, arg)
|
||||||
|
else:
|
||||||
|
msg = cmd
|
||||||
|
if seqno is None:
|
||||||
|
seqno = self.get_seqno()
|
||||||
|
msgbuf = self.encode_seqno(seqno) + msg
|
||||||
|
self.sockp.send(msgbuf)
|
||||||
|
if cmd == "reply":
|
||||||
|
return
|
||||||
|
reply = self.sockp.receive(timeout=None)
|
||||||
|
r_cmd, r_arg, r_seqno = self._decode_msg(reply)
|
||||||
|
assert r_seqno == seqno and r_cmd == "reply", "bad reply"
|
||||||
|
return r_arg
|
||||||
|
|
||||||
|
def _decode_msg(self, msg):
|
||||||
|
seqno = self.decode_seqno(msg[:self.SEQNO_ENC_LEN])
|
||||||
|
msg = msg[self.SEQNO_ENC_LEN:]
|
||||||
|
parts = msg.split(" ", 2)
|
||||||
|
if len(parts) == 1:
|
||||||
|
cmd = msg
|
||||||
|
arg = ''
|
||||||
|
else:
|
||||||
|
cmd = parts[0]
|
||||||
|
arg = parts[1]
|
||||||
|
return cmd, arg, seqno
|
||||||
|
|
||||||
|
def dispatch(self):
|
||||||
|
msg = self.sockp.receive()
|
||||||
|
if msg is None:
|
||||||
|
return
|
||||||
|
cmd, arg, seqno = self._decode_msg(msg)
|
||||||
|
self._current_reply = seqno
|
||||||
|
h = self.handlers.get(cmd, self.default_handler)
|
||||||
|
try:
|
||||||
|
r = h(arg)
|
||||||
|
except TypeError, msg:
|
||||||
|
raise TypeError, "handle_%s: %s" % (cmd, msg)
|
||||||
|
if self._current_reply is None:
|
||||||
|
if r is not None:
|
||||||
|
sys.stderr.write("ignoring %s return value type %s\n" % \
|
||||||
|
(cmd, type(r).__name__))
|
||||||
|
return
|
||||||
|
if r is None:
|
||||||
|
r = ''
|
||||||
|
if type(r) != types.StringType:
|
||||||
|
raise ValueError, "invalid return type for %s" % cmd
|
||||||
|
self.send("reply", r, seqno=seqno)
|
||||||
|
|
||||||
|
def reply(self, arg=''):
|
||||||
|
"""Send a reply immediately
|
||||||
|
|
||||||
|
otherwise reply will be sent when handler returns
|
||||||
|
"""
|
||||||
|
self.send("reply", arg, self._current_reply)
|
||||||
|
self._current_reply = None
|
||||||
|
|
||||||
|
def default_handler(self, arg):
|
||||||
|
sys.stderr.write("WARNING: unhandled message %s\n" % arg)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
SEQNO_ENC_LEN = 4
|
||||||
|
|
||||||
|
def get_seqno(self):
|
||||||
|
seqno = self.seqno
|
||||||
|
self.seqno = seqno + 1
|
||||||
|
return seqno
|
||||||
|
|
||||||
|
def encode_seqno(self, seqno):
|
||||||
|
return struct.pack("I", seqno)
|
||||||
|
|
||||||
|
def decode_seqno(self, buf):
|
||||||
|
return struct.unpack("I", buf)[0]
|
||||||
|
|
||||||
|
|
||||||
|
class StdioRedirector:
|
||||||
|
"""Redirect sys.std{in,out,err} to a set of file-like objects"""
|
||||||
|
|
||||||
|
def __init__(self, stdin, stdout, stderr):
|
||||||
|
self.stdin = stdin
|
||||||
|
self.stdout = stdout
|
||||||
|
self.stderr = stderr
|
||||||
|
|
||||||
|
def redirect(self):
|
||||||
|
self.save()
|
||||||
|
sys.stdin = self.stdin
|
||||||
|
sys.stdout = self.stdout
|
||||||
|
sys.stderr = self.stderr
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
self._stdin = sys.stdin
|
||||||
|
self._stdout = sys.stdout
|
||||||
|
self._stderr = sys.stderr
|
||||||
|
|
||||||
|
def restore(self):
|
||||||
|
sys.stdin = self._stdin
|
||||||
|
sys.stdout = self._stdout
|
||||||
|
sys.stderr = self._stderr
|
||||||
|
|
||||||
|
class IOWrapper:
|
||||||
|
"""Send output from a file-like object across a SocketProtocol
|
||||||
|
|
||||||
|
XXX Should this be more tightly integrated with the CommandProtocol?
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, cmdp):
|
||||||
|
self.name = name
|
||||||
|
self.cmdp = cmdp
|
||||||
|
self.buffer = []
|
||||||
|
|
||||||
|
class InputWrapper(IOWrapper):
|
||||||
|
def write(self, buf):
|
||||||
|
# XXX what should this do on Windows?
|
||||||
|
raise IOError, (9, '[Errno 9] Bad file descriptor')
|
||||||
|
|
||||||
|
def read(self, arg=None):
|
||||||
|
if arg is not None:
|
||||||
|
if arg <= 0:
|
||||||
|
return ''
|
||||||
|
else:
|
||||||
|
arg = 0
|
||||||
|
return self.cmdp.send(self.name, "read,%s" % arg)
|
||||||
|
|
||||||
|
def readline(self):
|
||||||
|
return self.cmdp.send(self.name, "readline")
|
||||||
|
|
||||||
|
class OutputWrapper(IOWrapper):
|
||||||
|
def write(self, buf):
|
||||||
|
self.cmdp.send(self.name, buf)
|
||||||
|
|
||||||
|
def read(self, arg=None):
|
||||||
|
return ''
|
||||||
|
|
||||||
|
class RemoteInterp:
|
||||||
|
def __init__(self, sock):
|
||||||
|
self._sock = SocketProtocol(sock)
|
||||||
|
self._cmd = CommandProtocol(self._sock)
|
||||||
|
self._cmd.registerHandler(self)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
while 1:
|
||||||
|
self._cmd.dispatch()
|
||||||
|
except EOFError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handle_execfile(self, arg):
|
||||||
|
self._cmd.reply()
|
||||||
|
io = StdioRedirector(InputWrapper("stdin", self._cmd),
|
||||||
|
OutputWrapper("stdout", self._cmd),
|
||||||
|
OutputWrapper("stderr", self._cmd))
|
||||||
|
io.redirect()
|
||||||
|
execfile(arg, {'__name__':'__main__'})
|
||||||
|
io.restore()
|
||||||
|
self._cmd.send("terminated")
|
||||||
|
|
||||||
|
def handle_quit(self, arg):
|
||||||
|
self._cmd.reply()
|
||||||
|
self._cmd.close()
|
||||||
|
|
||||||
|
def startRemoteInterp(id):
|
||||||
|
import os
|
||||||
|
# UNIX domain sockets are simpler for starters
|
||||||
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
sock.bind("/var/tmp/ri.%s" % id)
|
||||||
|
try:
|
||||||
|
sock.listen(1)
|
||||||
|
cli, addr = sock.accept()
|
||||||
|
rinterp = RemoteInterp(cli)
|
||||||
|
rinterp.run()
|
||||||
|
finally:
|
||||||
|
os.unlink("/var/tmp/ri.%s" % id)
|
||||||
|
|
||||||
|
class RIClient:
|
||||||
|
"""Client of the remote interpreter"""
|
||||||
|
def __init__(self, sock):
|
||||||
|
self._sock = SocketProtocol(sock)
|
||||||
|
self._cmd = CommandProtocol(self._sock)
|
||||||
|
self._cmd.registerHandler(self)
|
||||||
|
|
||||||
|
def execfile(self, file):
|
||||||
|
self._cmd.send("execfile", file)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
while 1:
|
||||||
|
self._cmd.dispatch()
|
||||||
|
except EOFError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handle_stdout(self, buf):
|
||||||
|
sys.stdout.write(buf)
|
||||||
|
## sys.stdout.flush()
|
||||||
|
|
||||||
|
def handle_stderr(self, buf):
|
||||||
|
sys.stderr.write(buf)
|
||||||
|
|
||||||
|
def handle_stdin(self, arg):
|
||||||
|
if arg == "readline":
|
||||||
|
return sys.stdin.readline()
|
||||||
|
i = arg.find(",") + 1
|
||||||
|
bytes = int(arg[i:])
|
||||||
|
if bytes == 0:
|
||||||
|
return sys.stdin.read()
|
||||||
|
else:
|
||||||
|
return sys.stdin.read(bytes)
|
||||||
|
|
||||||
|
def handle_terminated(self, arg):
|
||||||
|
self._cmd.reply()
|
||||||
|
self._cmd.send("quit")
|
||||||
|
self._cmd.close()
|
||||||
|
|
||||||
|
def riExec(id, file):
|
||||||
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
sock.connect("/var/tmp/ri.%s" % id)
|
||||||
|
cli = RIClient(sock)
|
||||||
|
cli.execfile(file)
|
||||||
|
cli.run()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
import getopt
|
||||||
|
|
||||||
|
SERVER = 1
|
||||||
|
opts, args = getopt.getopt(sys.argv[1:], 'cv')
|
||||||
|
for o, v in opts:
|
||||||
|
if o == '-c':
|
||||||
|
SERVER = 0
|
||||||
|
elif o == '-v':
|
||||||
|
VERBOSE = sys.stderr
|
||||||
|
id = args[0]
|
||||||
|
|
||||||
|
if SERVER:
|
||||||
|
startRemoteInterp(id)
|
||||||
|
else:
|
||||||
|
file = args[1]
|
||||||
|
riExec(id, file)
|
|
@ -0,0 +1,12 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from idlelib import IdleConf
|
||||||
|
|
||||||
|
idle_dir = os.path.dirname(IdleConf.__file__)
|
||||||
|
IdleConf.load(idle_dir)
|
||||||
|
|
||||||
|
# defer importing Pyshell until IdleConf is loaded
|
||||||
|
from idlelib import PyShell
|
||||||
|
PyShell.main()
|
|
@ -0,0 +1,81 @@
|
||||||
|
import os,glob
|
||||||
|
from distutils.core import setup
|
||||||
|
from distutils.command.build_py import build_py
|
||||||
|
from distutils.command.install_lib import install_lib
|
||||||
|
import idlever
|
||||||
|
|
||||||
|
# name of idle package
|
||||||
|
idlelib = "idlelib"
|
||||||
|
|
||||||
|
# the normal build_py would not incorporate the .txt files
|
||||||
|
txt_files = ['config-unix.txt','config-win.txt','config.txt']
|
||||||
|
Icons = glob.glob1("Icons","*.gif")
|
||||||
|
class idle_build_py(build_py):
|
||||||
|
def get_plain_outfile(self, build_dir, package, file):
|
||||||
|
# like get_module_outfile, but does not append .py
|
||||||
|
outfile_path = [build_dir] + list(package) + [file]
|
||||||
|
return apply(os.path.join, outfile_path)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# Copies all .py files, then also copies the txt and gif files
|
||||||
|
build_py.run(self)
|
||||||
|
assert self.packages == [idlelib]
|
||||||
|
for name in txt_files:
|
||||||
|
outfile = self.get_plain_outfile(self.build_lib, [idlelib], name)
|
||||||
|
dir = os.path.dirname(outfile)
|
||||||
|
self.mkpath(dir)
|
||||||
|
self.copy_file(name, outfile, preserve_mode = 0)
|
||||||
|
for name in Icons:
|
||||||
|
outfile = self.get_plain_outfile(self.build_lib,
|
||||||
|
[idlelib,"Icons"], name)
|
||||||
|
dir = os.path.dirname(outfile)
|
||||||
|
self.mkpath(dir)
|
||||||
|
self.copy_file(os.path.join("Icons",name),
|
||||||
|
outfile, preserve_mode = 0)
|
||||||
|
|
||||||
|
def get_source_files(self):
|
||||||
|
# returns the .py files, the .txt files, and the icons
|
||||||
|
icons = [os.path.join("Icons",name) for name in Icons]
|
||||||
|
return build_py.get_source_files(self)+txt_files+icons
|
||||||
|
|
||||||
|
def get_outputs(self, include_bytecode=1):
|
||||||
|
# returns the built files
|
||||||
|
outputs = build_py.get_outputs(self, include_bytecode)
|
||||||
|
if not include_bytecode:
|
||||||
|
return outputs
|
||||||
|
for name in txt_files:
|
||||||
|
filename = self.get_plain_outfile(self.build_lib,
|
||||||
|
[idlelib], name)
|
||||||
|
outputs.append(filename)
|
||||||
|
for name in Icons:
|
||||||
|
filename = self.get_plain_outfile(self.build_lib,
|
||||||
|
[idlelib,"Icons"], name)
|
||||||
|
outputs.append(filename)
|
||||||
|
return outputs
|
||||||
|
|
||||||
|
# Arghhh. install_lib thinks that all files returned from build_py's
|
||||||
|
# get_outputs are bytecode files
|
||||||
|
class idle_install_lib(install_lib):
|
||||||
|
def _bytecode_filenames(self, files):
|
||||||
|
files = [n for n in files if n.endswith('.py')]
|
||||||
|
return install_lib._bytecode_filenames(self,files)
|
||||||
|
|
||||||
|
|
||||||
|
setup(name="IDLE",
|
||||||
|
version = idlever.IDLE_VERSION,
|
||||||
|
description = "IDLE, the Python IDE",
|
||||||
|
author = "Guido van Rossum",
|
||||||
|
author_email = "guido@python.org",
|
||||||
|
#url =
|
||||||
|
long_description =
|
||||||
|
"""IDLE is a Tkinter based IDE for Python. It is written in 100% pure
|
||||||
|
Python and works both on Windows and Unix. It features a multi-window
|
||||||
|
text editor with multiple undo, Python colorizing, and many other things,
|
||||||
|
as well as a Python shell window and a debugger.""",
|
||||||
|
|
||||||
|
cmdclass = {'build_py':idle_build_py,
|
||||||
|
'install_lib':idle_install_lib},
|
||||||
|
package_dir = {idlelib:'.'},
|
||||||
|
packages = [idlelib],
|
||||||
|
scripts = ['idle']
|
||||||
|
)
|
Loading…
Reference in New Issue