Initial revision

This commit is contained in:
Steven M. Gava 2001-06-25 07:23:57 +00:00
parent 51777ce758
commit d7b6ed268e
3 changed files with 435 additions and 0 deletions

342
Lib/idlelib/RemoteInterp.py Normal file
View File

@ -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)

12
Lib/idlelib/idle Executable file
View 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()

81
Lib/idlelib/setup.py Normal file
View File

@ -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']
)