diff options
Diffstat (limited to 'Tools')
-rw-r--r-- | Tools/README | 2 | ||||
-rw-r--r-- | Tools/demo/README | 16 | ||||
-rwxr-xr-x | Tools/demo/beer.py | 25 | ||||
-rwxr-xr-x | Tools/demo/eiffel.py | 146 | ||||
-rwxr-xr-x | Tools/demo/hanoi.py | 154 | ||||
-rwxr-xr-x | Tools/demo/life.py | 262 | ||||
-rwxr-xr-x | Tools/demo/markov.py | 125 | ||||
-rwxr-xr-x | Tools/demo/mcast.py | 82 | ||||
-rwxr-xr-x | Tools/demo/queens.py | 85 | ||||
-rwxr-xr-x | Tools/demo/redemo.py | 171 | ||||
-rwxr-xr-x | Tools/demo/rpython.py | 37 | ||||
-rwxr-xr-x | Tools/demo/rpythond.py | 58 | ||||
-rwxr-xr-x | Tools/demo/sortvisu.py | 635 | ||||
-rwxr-xr-x | Tools/demo/spreadsheet.py | 829 | ||||
-rwxr-xr-x | Tools/demo/vector.py | 94 |
15 files changed, 0 insertions, 2721 deletions
diff --git a/Tools/README b/Tools/README index f8bfbc0..04612b8 100644 --- a/Tools/README +++ b/Tools/README @@ -5,8 +5,6 @@ buildbot Batchfiles for running on Windows buildbot workers. ccbench A Python threads-based concurrency benchmark. (*) -demo Several Python programming demos. - freeze Create a stand-alone executable from a Python program. gdb Python code to be run inside gdb, to make it easier to diff --git a/Tools/demo/README b/Tools/demo/README deleted file mode 100644 index 9fccb97..0000000 --- a/Tools/demo/README +++ /dev/null @@ -1,16 +0,0 @@ -This directory contains a collection of demonstration scripts for -various aspects of Python programming. - -beer.py Well-known programming example: Bottles of beer. -eiffel.py Python advanced magic: A metaclass for Eiffel post/preconditions. -hanoi.py Well-known programming example: Towers of Hanoi. -life.py Curses programming: Simple game-of-life. -markov.py Algorithms: Markov chain simulation. -mcast.py Network programming: Send and receive UDP multicast packets. -queens.py Well-known programming example: N-Queens problem. -redemo.py Regular Expressions: GUI script to test regexes. -rpython.py Network programming: Small client for remote code execution. -rpythond.py Network programming: Small server for remote code execution. -sortvisu.py GUI programming: Visualization of different sort algorithms. -spreadsheet.py GUI/Application programming: A simple spreadsheet application. -vector.py Python basics: A vector class demonstrating special methods. diff --git a/Tools/demo/beer.py b/Tools/demo/beer.py deleted file mode 100755 index af58380..0000000 --- a/Tools/demo/beer.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 - -""" -A Python version of the classic "bottles of beer on the wall" programming -example. - -By Guido van Rossum, demystified after a version by Fredrik Lundh. -""" - -import sys - -n = 100 -if sys.argv[1:]: - n = int(sys.argv[1]) - -def bottle(n): - if n == 0: return "no more bottles of beer" - if n == 1: return "one bottle of beer" - return str(n) + " bottles of beer" - -for i in range(n, 0, -1): - print(bottle(i), "on the wall,") - print(bottle(i) + ".") - print("Take one down, pass it around,") - print(bottle(i-1), "on the wall.") diff --git a/Tools/demo/eiffel.py b/Tools/demo/eiffel.py deleted file mode 100755 index a76c232..0000000 --- a/Tools/demo/eiffel.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python3 - -""" -Support Eiffel-style preconditions and postconditions for functions. - -An example for Python metaclasses. -""" - -import unittest -from types import FunctionType as function - -class EiffelBaseMetaClass(type): - - def __new__(meta, name, bases, dict): - meta.convert_methods(dict) - return super(EiffelBaseMetaClass, meta).__new__( - meta, name, bases, dict) - - @classmethod - def convert_methods(cls, dict): - """Replace functions in dict with EiffelMethod wrappers. - - The dict is modified in place. - - If a method ends in _pre or _post, it is removed from the dict - regardless of whether there is a corresponding method. - """ - # find methods with pre or post conditions - methods = [] - for k, v in dict.items(): - if k.endswith('_pre') or k.endswith('_post'): - assert isinstance(v, function) - elif isinstance(v, function): - methods.append(k) - for m in methods: - pre = dict.get("%s_pre" % m) - post = dict.get("%s_post" % m) - if pre or post: - dict[m] = cls.make_eiffel_method(dict[m], pre, post) - - -class EiffelMetaClass1(EiffelBaseMetaClass): - # an implementation of the "eiffel" meta class that uses nested functions - - @staticmethod - def make_eiffel_method(func, pre, post): - def method(self, *args, **kwargs): - if pre: - pre(self, *args, **kwargs) - rv = func(self, *args, **kwargs) - if post: - post(self, rv, *args, **kwargs) - return rv - - if func.__doc__: - method.__doc__ = func.__doc__ - - return method - - -class EiffelMethodWrapper: - - def __init__(self, inst, descr): - self._inst = inst - self._descr = descr - - def __call__(self, *args, **kwargs): - return self._descr.callmethod(self._inst, args, kwargs) - - -class EiffelDescriptor: - - def __init__(self, func, pre, post): - self._func = func - self._pre = pre - self._post = post - - self.__name__ = func.__name__ - self.__doc__ = func.__doc__ - - def __get__(self, obj, cls=None): - return EiffelMethodWrapper(obj, self) - - def callmethod(self, inst, args, kwargs): - if self._pre: - self._pre(inst, *args, **kwargs) - x = self._func(inst, *args, **kwargs) - if self._post: - self._post(inst, x, *args, **kwargs) - return x - - -class EiffelMetaClass2(EiffelBaseMetaClass): - # an implementation of the "eiffel" meta class that uses descriptors - - make_eiffel_method = EiffelDescriptor - - -class Tests(unittest.TestCase): - - def testEiffelMetaClass1(self): - self._test(EiffelMetaClass1) - - def testEiffelMetaClass2(self): - self._test(EiffelMetaClass2) - - def _test(self, metaclass): - class Eiffel(metaclass=metaclass): - pass - - class Test(Eiffel): - def m(self, arg): - """Make it a little larger""" - return arg + 1 - - def m2(self, arg): - """Make it a little larger""" - return arg + 1 - - def m2_pre(self, arg): - assert arg > 0 - - def m2_post(self, result, arg): - assert result > arg - - class Sub(Test): - def m2(self, arg): - return arg**2 - - def m2_post(self, Result, arg): - super(Sub, self).m2_post(Result, arg) - assert Result < 100 - - t = Test() - self.assertEqual(t.m(1), 2) - self.assertEqual(t.m2(1), 2) - self.assertRaises(AssertionError, t.m2, 0) - - s = Sub() - self.assertRaises(AssertionError, s.m2, 1) - self.assertRaises(AssertionError, s.m2, 10) - self.assertEqual(s.m2(5), 25) - - -if __name__ == "__main__": - unittest.main() diff --git a/Tools/demo/hanoi.py b/Tools/demo/hanoi.py deleted file mode 100755 index 8db895c..0000000 --- a/Tools/demo/hanoi.py +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env python3 - -""" -Animated Towers of Hanoi using Tk with optional bitmap file in background. - -Usage: hanoi.py [n [bitmapfile]] - -n is the number of pieces to animate; default is 4, maximum 15. - -The bitmap file can be any X11 bitmap file (look in /usr/include/X11/bitmaps for -samples); it is displayed as the background of the animation. Default is no -bitmap. -""" - -from tkinter import Tk, Canvas - -# Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c -# as temporary. For each move, call report() -def hanoi(n, a, b, c, report): - if n <= 0: return - hanoi(n-1, a, c, b, report) - report(n, a, b) - hanoi(n-1, c, b, a, report) - - -# The graphical interface -class Tkhanoi: - - # Create our objects - def __init__(self, n, bitmap=None): - self.n = n - self.tk = tk = Tk() - self.canvas = c = Canvas(tk) - c.pack() - width, height = tk.getint(c['width']), tk.getint(c['height']) - - # Add background bitmap - if bitmap: - self.bitmap = c.create_bitmap(width//2, height//2, - bitmap=bitmap, - foreground='blue') - - # Generate pegs - pegwidth = 10 - pegheight = height//2 - pegdist = width//3 - x1, y1 = (pegdist-pegwidth)//2, height*1//3 - x2, y2 = x1+pegwidth, y1+pegheight - self.pegs = [] - p = c.create_rectangle(x1, y1, x2, y2, fill='black') - self.pegs.append(p) - x1, x2 = x1+pegdist, x2+pegdist - p = c.create_rectangle(x1, y1, x2, y2, fill='black') - self.pegs.append(p) - x1, x2 = x1+pegdist, x2+pegdist - p = c.create_rectangle(x1, y1, x2, y2, fill='black') - self.pegs.append(p) - self.tk.update() - - # Generate pieces - pieceheight = pegheight//16 - maxpiecewidth = pegdist*2//3 - minpiecewidth = 2*pegwidth - self.pegstate = [[], [], []] - self.pieces = {} - x1, y1 = (pegdist-maxpiecewidth)//2, y2-pieceheight-2 - x2, y2 = x1+maxpiecewidth, y1+pieceheight - dx = (maxpiecewidth-minpiecewidth) // (2*max(1, n-1)) - for i in range(n, 0, -1): - p = c.create_rectangle(x1, y1, x2, y2, fill='red') - self.pieces[i] = p - self.pegstate[0].append(i) - x1, x2 = x1 + dx, x2-dx - y1, y2 = y1 - pieceheight-2, y2-pieceheight-2 - self.tk.update() - self.tk.after(25) - - # Run -- never returns - def run(self): - while True: - hanoi(self.n, 0, 1, 2, self.report) - hanoi(self.n, 1, 2, 0, self.report) - hanoi(self.n, 2, 0, 1, self.report) - hanoi(self.n, 0, 2, 1, self.report) - hanoi(self.n, 2, 1, 0, self.report) - hanoi(self.n, 1, 0, 2, self.report) - - # Reporting callback for the actual hanoi function - def report(self, i, a, b): - if self.pegstate[a][-1] != i: raise RuntimeError # Assertion - del self.pegstate[a][-1] - p = self.pieces[i] - c = self.canvas - - # Lift the piece above peg a - ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a]) - while True: - x1, y1, x2, y2 = c.bbox(p) - if y2 < ay1: break - c.move(p, 0, -1) - self.tk.update() - - # Move it towards peg b - bx1, by1, bx2, by2 = c.bbox(self.pegs[b]) - newcenter = (bx1+bx2)//2 - while True: - x1, y1, x2, y2 = c.bbox(p) - center = (x1+x2)//2 - if center == newcenter: break - if center > newcenter: c.move(p, -1, 0) - else: c.move(p, 1, 0) - self.tk.update() - - # Move it down on top of the previous piece - pieceheight = y2-y1 - newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2 - while True: - x1, y1, x2, y2 = c.bbox(p) - if y2 >= newbottom: break - c.move(p, 0, 1) - self.tk.update() - - # Update peg state - self.pegstate[b].append(i) - - -def main(): - import sys - - # First argument is number of pegs, default 4 - if sys.argv[1:]: - n = int(sys.argv[1]) - else: - n = 4 - - # Second argument is bitmap file, default none - if sys.argv[2:]: - bitmap = sys.argv[2] - # Reverse meaning of leading '@' compared to Tk - if bitmap[0] == '@': bitmap = bitmap[1:] - else: bitmap = '@' + bitmap - else: - bitmap = None - - # Create the graphical objects... - h = Tkhanoi(n, bitmap) - - # ...and run! - h.run() - - -# Call main when run as script -if __name__ == '__main__': - main() diff --git a/Tools/demo/life.py b/Tools/demo/life.py deleted file mode 100755 index fc4cb49..0000000 --- a/Tools/demo/life.py +++ /dev/null @@ -1,262 +0,0 @@ -#!/usr/bin/env python3 - -""" -A curses-based version of Conway's Game of Life. - -An empty board will be displayed, and the following commands are available: - E : Erase the board - R : Fill the board randomly - S : Step for a single generation - C : Update continuously until a key is struck - Q : Quit - Cursor keys : Move the cursor around the board - Space or Enter : Toggle the contents of the cursor's position - -Contributed by Andrew Kuchling, Mouse support and color by Dafydd Crosby. -""" - -import curses -import random - - -class LifeBoard: - """Encapsulates a Life board - - Attributes: - X,Y : horizontal and vertical size of the board - state : dictionary mapping (x,y) to 0 or 1 - - Methods: - display(update_board) -- If update_board is true, compute the - next generation. Then display the state - of the board and refresh the screen. - erase() -- clear the entire board - make_random() -- fill the board randomly - set(y,x) -- set the given cell to Live; doesn't refresh the screen - toggle(y,x) -- change the given cell from live to dead, or vice - versa, and refresh the screen display - - """ - def __init__(self, scr, char=ord('*')): - """Create a new LifeBoard instance. - - scr -- curses screen object to use for display - char -- character used to render live cells (default: '*') - """ - self.state = {} - self.scr = scr - Y, X = self.scr.getmaxyx() - self.X, self.Y = X - 2, Y - 2 - 1 - self.char = char - self.scr.clear() - - # Draw a border around the board - border_line = '+' + (self.X * '-') + '+' - self.scr.addstr(0, 0, border_line) - self.scr.addstr(self.Y + 1, 0, border_line) - for y in range(0, self.Y): - self.scr.addstr(1 + y, 0, '|') - self.scr.addstr(1 + y, self.X + 1, '|') - self.scr.refresh() - - def set(self, y, x): - """Set a cell to the live state""" - if x < 0 or self.X <= x or y < 0 or self.Y <= y: - raise ValueError("Coordinates out of range %i,%i" % (y, x)) - self.state[x, y] = 1 - - def toggle(self, y, x): - """Toggle a cell's state between live and dead""" - if x < 0 or self.X <= x or y < 0 or self.Y <= y: - raise ValueError("Coordinates out of range %i,%i" % (y, x)) - if (x, y) in self.state: - del self.state[x, y] - self.scr.addch(y + 1, x + 1, ' ') - else: - self.state[x, y] = 1 - if curses.has_colors(): - # Let's pick a random color! - self.scr.attrset(curses.color_pair(random.randrange(1, 7))) - self.scr.addch(y + 1, x + 1, self.char) - self.scr.attrset(0) - self.scr.refresh() - - def erase(self): - """Clear the entire board and update the board display""" - self.state = {} - self.display(update_board=False) - - def display(self, update_board=True): - """Display the whole board, optionally computing one generation""" - M, N = self.X, self.Y - if not update_board: - for i in range(0, M): - for j in range(0, N): - if (i, j) in self.state: - self.scr.addch(j + 1, i + 1, self.char) - else: - self.scr.addch(j + 1, i + 1, ' ') - self.scr.refresh() - return - - d = {} - self.boring = 1 - for i in range(0, M): - L = range(max(0, i - 1), min(M, i + 2)) - for j in range(0, N): - s = 0 - live = (i, j) in self.state - for k in range(max(0, j - 1), min(N, j + 2)): - for l in L: - if (l, k) in self.state: - s += 1 - s -= live - if s == 3: - # Birth - d[i, j] = 1 - if curses.has_colors(): - # Let's pick a random color! - self.scr.attrset(curses.color_pair( - random.randrange(1, 7))) - self.scr.addch(j + 1, i + 1, self.char) - self.scr.attrset(0) - if not live: - self.boring = 0 - elif s == 2 and live: - # Survival - d[i, j] = 1 - elif live: - # Death - self.scr.addch(j + 1, i + 1, ' ') - self.boring = 0 - self.state = d - self.scr.refresh() - - def make_random(self): - "Fill the board with a random pattern" - self.state = {} - for i in range(0, self.X): - for j in range(0, self.Y): - if random.random() > 0.5: - self.set(j, i) - - -def erase_menu(stdscr, menu_y): - "Clear the space where the menu resides" - stdscr.move(menu_y, 0) - stdscr.clrtoeol() - stdscr.move(menu_y + 1, 0) - stdscr.clrtoeol() - - -def display_menu(stdscr, menu_y): - "Display the menu of possible keystroke commands" - erase_menu(stdscr, menu_y) - - # If color, then light the menu up :-) - if curses.has_colors(): - stdscr.attrset(curses.color_pair(1)) - stdscr.addstr(menu_y, 4, - 'Use the cursor keys to move, and space or Enter to toggle a cell.') - stdscr.addstr(menu_y + 1, 4, - 'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit') - stdscr.attrset(0) - - -def keyloop(stdscr): - # Clear the screen and display the menu of keys - stdscr.clear() - stdscr_y, stdscr_x = stdscr.getmaxyx() - menu_y = (stdscr_y - 3) - 1 - display_menu(stdscr, menu_y) - - # If color, then initialize the color pairs - if curses.has_colors(): - curses.init_pair(1, curses.COLOR_BLUE, 0) - curses.init_pair(2, curses.COLOR_CYAN, 0) - curses.init_pair(3, curses.COLOR_GREEN, 0) - curses.init_pair(4, curses.COLOR_MAGENTA, 0) - curses.init_pair(5, curses.COLOR_RED, 0) - curses.init_pair(6, curses.COLOR_YELLOW, 0) - curses.init_pair(7, curses.COLOR_WHITE, 0) - - # Set up the mask to listen for mouse events - curses.mousemask(curses.BUTTON1_CLICKED) - - # Allocate a subwindow for the Life board and create the board object - subwin = stdscr.subwin(stdscr_y - 3, stdscr_x, 0, 0) - board = LifeBoard(subwin, char=ord('*')) - board.display(update_board=False) - - # xpos, ypos are the cursor's position - xpos, ypos = board.X // 2, board.Y // 2 - - # Main loop: - while True: - stdscr.move(1 + ypos, 1 + xpos) # Move the cursor - c = stdscr.getch() # Get a keystroke - if 0 < c < 256: - c = chr(c) - if c in ' \n': - board.toggle(ypos, xpos) - elif c in 'Cc': - erase_menu(stdscr, menu_y) - stdscr.addstr(menu_y, 6, ' Hit any key to stop continuously ' - 'updating the screen.') - stdscr.refresh() - # Activate nodelay mode; getch() will return -1 - # if no keystroke is available, instead of waiting. - stdscr.nodelay(1) - while True: - c = stdscr.getch() - if c != -1: - break - stdscr.addstr(0, 0, '/') - stdscr.refresh() - board.display() - stdscr.addstr(0, 0, '+') - stdscr.refresh() - - stdscr.nodelay(0) # Disable nodelay mode - display_menu(stdscr, menu_y) - - elif c in 'Ee': - board.erase() - elif c in 'Qq': - break - elif c in 'Rr': - board.make_random() - board.display(update_board=False) - elif c in 'Ss': - board.display() - else: - # Ignore incorrect keys - pass - elif c == curses.KEY_UP and ypos > 0: - ypos -= 1 - elif c == curses.KEY_DOWN and ypos + 1 < board.Y: - ypos += 1 - elif c == curses.KEY_LEFT and xpos > 0: - xpos -= 1 - elif c == curses.KEY_RIGHT and xpos + 1 < board.X: - xpos += 1 - elif c == curses.KEY_MOUSE: - mouse_id, mouse_x, mouse_y, mouse_z, button_state = curses.getmouse() - if (mouse_x > 0 and mouse_x < board.X + 1 and - mouse_y > 0 and mouse_y < board.Y + 1): - xpos = mouse_x - 1 - ypos = mouse_y - 1 - board.toggle(ypos, xpos) - else: - # They've clicked outside the board - curses.flash() - else: - # Ignore incorrect keys - pass - - -def main(stdscr): - keyloop(stdscr) # Enter the main loop - -if __name__ == '__main__': - curses.wrapper(main) diff --git a/Tools/demo/markov.py b/Tools/demo/markov.py deleted file mode 100755 index 9729f38..0000000 --- a/Tools/demo/markov.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python3 - -""" -Markov chain simulation of words or characters. -""" - -class Markov: - def __init__(self, histsize, choice): - self.histsize = histsize - self.choice = choice - self.trans = {} - - def add(self, state, next): - self.trans.setdefault(state, []).append(next) - - def put(self, seq): - n = self.histsize - add = self.add - add(None, seq[:0]) - for i in range(len(seq)): - add(seq[max(0, i-n):i], seq[i:i+1]) - add(seq[len(seq)-n:], None) - - def get(self): - choice = self.choice - trans = self.trans - n = self.histsize - seq = choice(trans[None]) - while True: - subseq = seq[max(0, len(seq)-n):] - options = trans[subseq] - next = choice(options) - if not next: - break - seq += next - return seq - - -def test(): - import sys, random, getopt - args = sys.argv[1:] - try: - opts, args = getopt.getopt(args, '0123456789cdwq') - except getopt.error: - print('Usage: %s [-#] [-cddqw] [file] ...' % sys.argv[0]) - print('Options:') - print('-#: 1-digit history size (default 2)') - print('-c: characters (default)') - print('-w: words') - print('-d: more debugging output') - print('-q: no debugging output') - print('Input files (default stdin) are split in paragraphs') - print('separated blank lines and each paragraph is split') - print('in words by whitespace, then reconcatenated with') - print('exactly one space separating words.') - print('Output consists of paragraphs separated by blank') - print('lines, where lines are no longer than 72 characters.') - sys.exit(2) - histsize = 2 - do_words = False - debug = 1 - for o, a in opts: - if '-0' <= o <= '-9': histsize = int(o[1:]) - if o == '-c': do_words = False - if o == '-d': debug += 1 - if o == '-q': debug = 0 - if o == '-w': do_words = True - if not args: - args = ['-'] - - m = Markov(histsize, random.choice) - try: - for filename in args: - if filename == '-': - f = sys.stdin - if f.isatty(): - print('Sorry, need stdin from file') - continue - else: - f = open(filename, 'r') - with f: - if debug: print('processing', filename, '...') - text = f.read() - paralist = text.split('\n\n') - for para in paralist: - if debug > 1: print('feeding ...') - words = para.split() - if words: - if do_words: - data = tuple(words) - else: - data = ' '.join(words) - m.put(data) - except KeyboardInterrupt: - print('Interrupted -- continue with data read so far') - if not m.trans: - print('No valid input files') - return - if debug: print('done.') - - if debug > 1: - for key in m.trans.keys(): - if key is None or len(key) < histsize: - print(repr(key), m.trans[key]) - if histsize == 0: print(repr(''), m.trans['']) - print() - while True: - data = m.get() - if do_words: - words = data - else: - words = data.split() - n = 0 - limit = 72 - for w in words: - if n + len(w) > limit: - print() - n = 0 - print(w, end=' ') - n += len(w) + 1 - print() - print() - -if __name__ == "__main__": - test() diff --git a/Tools/demo/mcast.py b/Tools/demo/mcast.py deleted file mode 100755 index 924c7c3..0000000 --- a/Tools/demo/mcast.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 - -""" -Send/receive UDP multicast packets. -Requires that your OS kernel supports IP multicast. - -Usage: - mcast -s (sender, IPv4) - mcast -s -6 (sender, IPv6) - mcast (receivers, IPv4) - mcast -6 (receivers, IPv6) -""" - -MYPORT = 8123 -MYGROUP_4 = '225.0.0.250' -MYGROUP_6 = 'ff15:7079:7468:6f6e:6465:6d6f:6d63:6173' -MYTTL = 1 # Increase to reach other networks - -import time -import struct -import socket -import sys - -def main(): - group = MYGROUP_6 if "-6" in sys.argv[1:] else MYGROUP_4 - - if "-s" in sys.argv[1:]: - sender(group) - else: - receiver(group) - - -def sender(group): - addrinfo = socket.getaddrinfo(group, None)[0] - - s = socket.socket(addrinfo[0], socket.SOCK_DGRAM) - - # Set Time-to-live (optional) - ttl_bin = struct.pack('@i', MYTTL) - if addrinfo[0] == socket.AF_INET: # IPv4 - s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl_bin) - else: - s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin) - - while True: - data = repr(time.time()).encode('utf-8') + b'\0' - s.sendto(data, (addrinfo[4][0], MYPORT)) - time.sleep(1) - - -def receiver(group): - # Look up multicast group address in name server and find out IP version - addrinfo = socket.getaddrinfo(group, None)[0] - - # Create a socket - s = socket.socket(addrinfo[0], socket.SOCK_DGRAM) - - # Allow multiple copies of this program on one machine - # (not strictly needed) - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - # Bind it to the port - s.bind(('', MYPORT)) - - group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0]) - # Join group - if addrinfo[0] == socket.AF_INET: # IPv4 - mreq = group_bin + struct.pack('=I', socket.INADDR_ANY) - s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) - else: - mreq = group_bin + struct.pack('@I', 0) - s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) - - # Loop, printing any data we receive - while True: - data, sender = s.recvfrom(1500) - while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's - print(str(sender) + ' ' + repr(data)) - - -if __name__ == '__main__': - main() diff --git a/Tools/demo/queens.py b/Tools/demo/queens.py deleted file mode 100755 index dcc1bae..0000000 --- a/Tools/demo/queens.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 - -""" -N queens problem. - -The (well-known) problem is due to Niklaus Wirth. - -This solution is inspired by Dijkstra (Structured Programming). It is -a classic recursive backtracking approach. -""" - -N = 8 # Default; command line overrides - -class Queens: - - def __init__(self, n=N): - self.n = n - self.reset() - - def reset(self): - n = self.n - self.y = [None] * n # Where is the queen in column x - self.row = [0] * n # Is row[y] safe? - self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe? - self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe? - self.nfound = 0 # Instrumentation - - def solve(self, x=0): # Recursive solver - for y in range(self.n): - if self.safe(x, y): - self.place(x, y) - if x+1 == self.n: - self.display() - else: - self.solve(x+1) - self.remove(x, y) - - def safe(self, x, y): - return not self.row[y] and not self.up[x-y] and not self.down[x+y] - - def place(self, x, y): - self.y[x] = y - self.row[y] = 1 - self.up[x-y] = 1 - self.down[x+y] = 1 - - def remove(self, x, y): - self.y[x] = None - self.row[y] = 0 - self.up[x-y] = 0 - self.down[x+y] = 0 - - silent = 0 # If true, count solutions only - - def display(self): - self.nfound = self.nfound + 1 - if self.silent: - return - print('+-' + '--'*self.n + '+') - for y in range(self.n-1, -1, -1): - print('|', end=' ') - for x in range(self.n): - if self.y[x] == y: - print("Q", end=' ') - else: - print(".", end=' ') - print('|') - print('+-' + '--'*self.n + '+') - -def main(): - import sys - silent = 0 - n = N - if sys.argv[1:2] == ['-n']: - silent = 1 - del sys.argv[1] - if sys.argv[1:]: - n = int(sys.argv[1]) - q = Queens(n) - q.silent = silent - q.solve() - print("Found", q.nfound, "solutions.") - -if __name__ == "__main__": - main() diff --git a/Tools/demo/redemo.py b/Tools/demo/redemo.py deleted file mode 100755 index f801dfc..0000000 --- a/Tools/demo/redemo.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python3 - -"""Basic regular expression demonstration facility (Perl style syntax).""" - -from tkinter import * -import re - -class ReDemo: - - def __init__(self, master): - self.master = master - - self.promptdisplay = Label(self.master, anchor=W, - text="Enter a Perl-style regular expression:") - self.promptdisplay.pack(side=TOP, fill=X) - - self.regexdisplay = Entry(self.master) - self.regexdisplay.pack(fill=X) - self.regexdisplay.focus_set() - - self.addoptions() - - self.statusdisplay = Label(self.master, text="", anchor=W) - self.statusdisplay.pack(side=TOP, fill=X) - - self.labeldisplay = Label(self.master, anchor=W, - text="Enter a string to search:") - self.labeldisplay.pack(fill=X) - self.labeldisplay.pack(fill=X) - - self.showframe = Frame(master) - self.showframe.pack(fill=X, anchor=W) - - self.showvar = StringVar(master) - self.showvar.set("first") - - self.showfirstradio = Radiobutton(self.showframe, - text="Highlight first match", - variable=self.showvar, - value="first", - command=self.recompile) - self.showfirstradio.pack(side=LEFT) - - self.showallradio = Radiobutton(self.showframe, - text="Highlight all matches", - variable=self.showvar, - value="all", - command=self.recompile) - self.showallradio.pack(side=LEFT) - - self.stringdisplay = Text(self.master, width=60, height=4) - self.stringdisplay.pack(fill=BOTH, expand=1) - self.stringdisplay.tag_configure("hit", background="yellow") - - self.grouplabel = Label(self.master, text="Groups:", anchor=W) - self.grouplabel.pack(fill=X) - - self.grouplist = Listbox(self.master) - self.grouplist.pack(expand=1, fill=BOTH) - - self.regexdisplay.bind('<Key>', self.recompile) - self.stringdisplay.bind('<Key>', self.reevaluate) - - self.compiled = None - self.recompile() - - btags = self.regexdisplay.bindtags() - self.regexdisplay.bindtags(btags[1:] + btags[:1]) - - btags = self.stringdisplay.bindtags() - self.stringdisplay.bindtags(btags[1:] + btags[:1]) - - def addoptions(self): - self.frames = [] - self.boxes = [] - self.vars = [] - for name in ('IGNORECASE', - 'MULTILINE', - 'DOTALL', - 'VERBOSE'): - if len(self.boxes) % 3 == 0: - frame = Frame(self.master) - frame.pack(fill=X) - self.frames.append(frame) - val = getattr(re, name).value - var = IntVar() - box = Checkbutton(frame, - variable=var, text=name, - offvalue=0, onvalue=val, - command=self.recompile) - box.pack(side=LEFT) - self.boxes.append(box) - self.vars.append(var) - - def getflags(self): - flags = 0 - for var in self.vars: - flags = flags | var.get() - return flags - - def recompile(self, event=None): - try: - self.compiled = re.compile(self.regexdisplay.get(), - self.getflags()) - bg = self.promptdisplay['background'] - self.statusdisplay.config(text="", background=bg) - except re.error as msg: - self.compiled = None - self.statusdisplay.config( - text="re.error: %s" % str(msg), - background="red") - self.reevaluate() - - def reevaluate(self, event=None): - try: - self.stringdisplay.tag_remove("hit", "1.0", END) - except TclError: - pass - try: - self.stringdisplay.tag_remove("hit0", "1.0", END) - except TclError: - pass - self.grouplist.delete(0, END) - if not self.compiled: - return - self.stringdisplay.tag_configure("hit", background="yellow") - self.stringdisplay.tag_configure("hit0", background="orange") - text = self.stringdisplay.get("1.0", END) - last = 0 - nmatches = 0 - while last <= len(text): - m = self.compiled.search(text, last) - if m is None: - break - first, last = m.span() - if last == first: - last = first+1 - tag = "hit0" - else: - tag = "hit" - pfirst = "1.0 + %d chars" % first - plast = "1.0 + %d chars" % last - self.stringdisplay.tag_add(tag, pfirst, plast) - if nmatches == 0: - self.stringdisplay.yview_pickplace(pfirst) - groups = list(m.groups()) - groups.insert(0, m.group()) - for i in range(len(groups)): - g = "%2d: %r" % (i, groups[i]) - self.grouplist.insert(END, g) - nmatches = nmatches + 1 - if self.showvar.get() == "first": - break - - if nmatches == 0: - self.statusdisplay.config(text="(no match)", - background="yellow") - else: - self.statusdisplay.config(text="") - - -# Main function, run when invoked as a stand-alone Python program. - -def main(): - root = Tk() - demo = ReDemo(root) - root.protocol('WM_DELETE_WINDOW', root.quit) - root.mainloop() - -if __name__ == '__main__': - main() diff --git a/Tools/demo/rpython.py b/Tools/demo/rpython.py deleted file mode 100755 index 11f72cb..0000000 --- a/Tools/demo/rpython.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 - -""" -Remote python client. -Execute Python commands remotely and send output back. -""" - -import sys -from socket import socket, AF_INET, SOCK_STREAM, SHUT_WR - -PORT = 4127 -BUFSIZE = 1024 - -def main(): - if len(sys.argv) < 3: - print("usage: rpython host command") - sys.exit(2) - host = sys.argv[1] - port = PORT - i = host.find(':') - if i >= 0: - port = int(host[i+1:]) - host = host[:i] - command = ' '.join(sys.argv[2:]) - with socket(AF_INET, SOCK_STREAM) as s: - s.connect((host, port)) - s.send(command.encode()) - s.shutdown(SHUT_WR) - reply = b'' - while True: - data = s.recv(BUFSIZE) - if not data: - break - reply += data - print(reply.decode(), end=' ') - -main() diff --git a/Tools/demo/rpythond.py b/Tools/demo/rpythond.py deleted file mode 100755 index 4e47fb9..0000000 --- a/Tools/demo/rpythond.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 - -""" -Remote python server. -Execute Python commands remotely and send output back. - -WARNING: This version has a gaping security hole -- it accepts requests -from any host on the internet! -""" - -import sys -from socket import socket, AF_INET, SOCK_STREAM -import io -import traceback - -PORT = 4127 -BUFSIZE = 1024 - -def main(): - if len(sys.argv) > 1: - port = int(sys.argv[1]) - else: - port = PORT - s = socket(AF_INET, SOCK_STREAM) - s.bind(('', port)) - s.listen(1) - while True: - conn, (remotehost, remoteport) = s.accept() - with conn: - print('connection from', remotehost, remoteport) - request = b'' - while True: - data = conn.recv(BUFSIZE) - if not data: - break - request += data - reply = execute(request.decode()) - conn.send(reply.encode()) - -def execute(request): - stdout = sys.stdout - stderr = sys.stderr - sys.stdout = sys.stderr = fakefile = io.StringIO() - try: - try: - exec(request, {}, {}) - except: - print() - traceback.print_exc(100) - finally: - sys.stderr = stderr - sys.stdout = stdout - return fakefile.getvalue() - -try: - main() -except KeyboardInterrupt: - pass diff --git a/Tools/demo/sortvisu.py b/Tools/demo/sortvisu.py deleted file mode 100755 index 056a0e0..0000000 --- a/Tools/demo/sortvisu.py +++ /dev/null @@ -1,635 +0,0 @@ -#!/usr/bin/env python3 - -""" -Sorting algorithms visualizer using Tkinter. - -This module is comprised of three ``components'': - -- an array visualizer with methods that implement basic sorting -operations (compare, swap) as well as methods for ``annotating'' the -sorting algorithm (e.g. to show the pivot element); - -- a number of sorting algorithms (currently quicksort, insertion sort, -selection sort and bubble sort, as well as a randomization function), -all using the array visualizer for its basic operations and with calls -to its annotation methods; - -- and a ``driver'' class which can be used as a Grail applet or as a -stand-alone application. -""" - -from tkinter import * -import random - -XGRID = 10 -YGRID = 10 -WIDTH = 6 - - -class Array: - - class Cancelled(BaseException): - pass - - def __init__(self, master, data=None): - self.master = master - self.frame = Frame(self.master) - self.frame.pack(fill=X) - self.label = Label(self.frame) - self.label.pack() - self.canvas = Canvas(self.frame) - self.canvas.pack() - self.report = Label(self.frame) - self.report.pack() - self.left = self.canvas.create_line(0, 0, 0, 0) - self.right = self.canvas.create_line(0, 0, 0, 0) - self.pivot = self.canvas.create_line(0, 0, 0, 0) - self.items = [] - self.size = self.maxvalue = 0 - if data: - self.setdata(data) - - def setdata(self, data): - olditems = self.items - self.items = [] - for item in olditems: - item.delete() - self.size = len(data) - self.maxvalue = max(data) - self.canvas.config(width=(self.size+1)*XGRID, - height=(self.maxvalue+1)*YGRID) - for i in range(self.size): - self.items.append(ArrayItem(self, i, data[i])) - self.reset("Sort demo, size %d" % self.size) - - speed = "normal" - - def setspeed(self, speed): - self.speed = speed - - def destroy(self): - self.frame.destroy() - - in_mainloop = 0 - stop_mainloop = 0 - - def cancel(self): - self.stop_mainloop = 1 - if self.in_mainloop: - self.master.quit() - - def step(self): - if self.in_mainloop: - self.master.quit() - - def wait(self, msecs): - if self.speed == "fastest": - msecs = 0 - elif self.speed == "fast": - msecs = msecs//10 - elif self.speed == "single-step": - msecs = 1000000000 - if not self.stop_mainloop: - self.master.update() - id = self.master.after(msecs, self.master.quit) - self.in_mainloop = 1 - self.master.mainloop() - self.master.after_cancel(id) - self.in_mainloop = 0 - if self.stop_mainloop: - self.stop_mainloop = 0 - self.message("Cancelled") - raise Array.Cancelled - - def getsize(self): - return self.size - - def show_partition(self, first, last): - for i in range(self.size): - item = self.items[i] - if first <= i < last: - self.canvas.itemconfig(item, fill='red') - else: - self.canvas.itemconfig(item, fill='orange') - self.hide_left_right_pivot() - - def hide_partition(self): - for i in range(self.size): - item = self.items[i] - self.canvas.itemconfig(item, fill='red') - self.hide_left_right_pivot() - - def show_left(self, left): - if not 0 <= left < self.size: - self.hide_left() - return - x1, y1, x2, y2 = self.items[left].position() -## top, bot = HIRO - self.canvas.coords(self.left, (x1 - 2, 0, x1 - 2, 9999)) - self.master.update() - - def show_right(self, right): - if not 0 <= right < self.size: - self.hide_right() - return - x1, y1, x2, y2 = self.items[right].position() - self.canvas.coords(self.right, (x2 + 2, 0, x2 + 2, 9999)) - self.master.update() - - def hide_left_right_pivot(self): - self.hide_left() - self.hide_right() - self.hide_pivot() - - def hide_left(self): - self.canvas.coords(self.left, (0, 0, 0, 0)) - - def hide_right(self): - self.canvas.coords(self.right, (0, 0, 0, 0)) - - def show_pivot(self, pivot): - x1, y1, x2, y2 = self.items[pivot].position() - self.canvas.coords(self.pivot, (0, y1 - 2, 9999, y1 - 2)) - - def hide_pivot(self): - self.canvas.coords(self.pivot, (0, 0, 0, 0)) - - def swap(self, i, j): - if i == j: return - self.countswap() - item = self.items[i] - other = self.items[j] - self.items[i], self.items[j] = other, item - item.swapwith(other) - - def compare(self, i, j): - self.countcompare() - item = self.items[i] - other = self.items[j] - return item.compareto(other) - - def reset(self, msg): - self.ncompares = 0 - self.nswaps = 0 - self.message(msg) - self.updatereport() - self.hide_partition() - - def message(self, msg): - self.label.config(text=msg) - - def countswap(self): - self.nswaps = self.nswaps + 1 - self.updatereport() - - def countcompare(self): - self.ncompares = self.ncompares + 1 - self.updatereport() - - def updatereport(self): - text = "%d cmps, %d swaps" % (self.ncompares, self.nswaps) - self.report.config(text=text) - - -class ArrayItem: - - def __init__(self, array, index, value): - self.array = array - self.index = index - self.value = value - self.canvas = array.canvas - x1, y1, x2, y2 = self.position() - self.item_id = array.canvas.create_rectangle(x1, y1, x2, y2, - fill='red', outline='black', width=1) - self.canvas.tag_bind(self.item_id, '<Button-1>', self.mouse_down) - self.canvas.tag_bind(self.item_id, '<Button1-Motion>', self.mouse_move) - self.canvas.tag_bind(self.item_id, '<ButtonRelease-1>', self.mouse_up) - - def delete(self): - item_id = self.item_id - self.array = None - self.item_id = None - self.canvas.delete(item_id) - - def mouse_down(self, event): - self.lastx = event.x - self.lasty = event.y - self.origx = event.x - self.origy = event.y - self.canvas.tag_raise(self.item_id) - - def mouse_move(self, event): - self.canvas.move(self.item_id, - event.x - self.lastx, event.y - self.lasty) - self.lastx = event.x - self.lasty = event.y - - def mouse_up(self, event): - i = self.nearestindex(event.x) - if i >= self.array.getsize(): - i = self.array.getsize() - 1 - if i < 0: - i = 0 - other = self.array.items[i] - here = self.index - self.array.items[here], self.array.items[i] = other, self - self.index = i - x1, y1, x2, y2 = self.position() - self.canvas.coords(self.item_id, (x1, y1, x2, y2)) - other.setindex(here) - - def setindex(self, index): - nsteps = steps(self.index, index) - if not nsteps: return - if self.array.speed == "fastest": - nsteps = 0 - oldpts = self.position() - self.index = index - newpts = self.position() - trajectory = interpolate(oldpts, newpts, nsteps) - self.canvas.tag_raise(self.item_id) - for pts in trajectory: - self.canvas.coords(self.item_id, pts) - self.array.wait(50) - - def swapwith(self, other): - nsteps = steps(self.index, other.index) - if not nsteps: return - if self.array.speed == "fastest": - nsteps = 0 - myoldpts = self.position() - otheroldpts = other.position() - self.index, other.index = other.index, self.index - mynewpts = self.position() - othernewpts = other.position() - myfill = self.canvas.itemcget(self.item_id, 'fill') - otherfill = self.canvas.itemcget(other.item_id, 'fill') - self.canvas.itemconfig(self.item_id, fill='green') - self.canvas.itemconfig(other.item_id, fill='yellow') - self.array.master.update() - if self.array.speed == "single-step": - self.canvas.coords(self.item_id, mynewpts) - self.canvas.coords(other.item_id, othernewpts) - self.array.master.update() - self.canvas.itemconfig(self.item_id, fill=myfill) - self.canvas.itemconfig(other.item_id, fill=otherfill) - self.array.wait(0) - return - mytrajectory = interpolate(myoldpts, mynewpts, nsteps) - othertrajectory = interpolate(otheroldpts, othernewpts, nsteps) - if self.value > other.value: - self.canvas.tag_raise(self.item_id) - self.canvas.tag_raise(other.item_id) - else: - self.canvas.tag_raise(other.item_id) - self.canvas.tag_raise(self.item_id) - try: - for i in range(len(mytrajectory)): - mypts = mytrajectory[i] - otherpts = othertrajectory[i] - self.canvas.coords(self.item_id, mypts) - self.canvas.coords(other.item_id, otherpts) - self.array.wait(50) - finally: - mypts = mytrajectory[-1] - otherpts = othertrajectory[-1] - self.canvas.coords(self.item_id, mypts) - self.canvas.coords(other.item_id, otherpts) - self.canvas.itemconfig(self.item_id, fill=myfill) - self.canvas.itemconfig(other.item_id, fill=otherfill) - - def compareto(self, other): - myfill = self.canvas.itemcget(self.item_id, 'fill') - otherfill = self.canvas.itemcget(other.item_id, 'fill') - if self.value < other.value: - myflash = 'white' - otherflash = 'black' - outcome = -1 - elif self.value > other.value: - myflash = 'black' - otherflash = 'white' - outcome = 1 - else: - myflash = otherflash = 'grey' - outcome = 0 - try: - self.canvas.itemconfig(self.item_id, fill=myflash) - self.canvas.itemconfig(other.item_id, fill=otherflash) - self.array.wait(500) - finally: - self.canvas.itemconfig(self.item_id, fill=myfill) - self.canvas.itemconfig(other.item_id, fill=otherfill) - return outcome - - def position(self): - x1 = (self.index+1)*XGRID - WIDTH//2 - x2 = x1+WIDTH - y2 = (self.array.maxvalue+1)*YGRID - y1 = y2 - (self.value)*YGRID - return x1, y1, x2, y2 - - def nearestindex(self, x): - return int(round(float(x)/XGRID)) - 1 - - -# Subroutines that don't need an object - -def steps(here, there): - nsteps = abs(here - there) - if nsteps <= 3: - nsteps = nsteps * 3 - elif nsteps <= 5: - nsteps = nsteps * 2 - elif nsteps > 10: - nsteps = 10 - return nsteps - -def interpolate(oldpts, newpts, n): - if len(oldpts) != len(newpts): - raise ValueError("can't interpolate arrays of different length") - pts = [0]*len(oldpts) - res = [tuple(oldpts)] - for i in range(1, n): - for k in range(len(pts)): - pts[k] = oldpts[k] + (newpts[k] - oldpts[k])*i//n - res.append(tuple(pts)) - res.append(tuple(newpts)) - return res - - -# Various (un)sorting algorithms - -def uniform(array): - size = array.getsize() - array.setdata([(size+1)//2] * size) - array.reset("Uniform data, size %d" % size) - -def distinct(array): - size = array.getsize() - array.setdata(range(1, size+1)) - array.reset("Distinct data, size %d" % size) - -def randomize(array): - array.reset("Randomizing") - n = array.getsize() - for i in range(n): - j = random.randint(0, n-1) - array.swap(i, j) - array.message("Randomized") - -def insertionsort(array): - size = array.getsize() - array.reset("Insertion sort") - for i in range(1, size): - j = i-1 - while j >= 0: - if array.compare(j, j+1) <= 0: - break - array.swap(j, j+1) - j = j-1 - array.message("Sorted") - -def selectionsort(array): - size = array.getsize() - array.reset("Selection sort") - try: - for i in range(size): - array.show_partition(i, size) - for j in range(i+1, size): - if array.compare(i, j) > 0: - array.swap(i, j) - array.message("Sorted") - finally: - array.hide_partition() - -def bubblesort(array): - size = array.getsize() - array.reset("Bubble sort") - for i in range(size): - for j in range(1, size): - if array.compare(j-1, j) > 0: - array.swap(j-1, j) - array.message("Sorted") - -def quicksort(array): - size = array.getsize() - array.reset("Quicksort") - try: - stack = [(0, size)] - while stack: - first, last = stack[-1] - del stack[-1] - array.show_partition(first, last) - if last-first < 5: - array.message("Insertion sort") - for i in range(first+1, last): - j = i-1 - while j >= first: - if array.compare(j, j+1) <= 0: - break - array.swap(j, j+1) - j = j-1 - continue - array.message("Choosing pivot") - j, i, k = first, (first+last) // 2, last-1 - if array.compare(k, i) < 0: - array.swap(k, i) - if array.compare(k, j) < 0: - array.swap(k, j) - if array.compare(j, i) < 0: - array.swap(j, i) - pivot = j - array.show_pivot(pivot) - array.message("Pivot at left of partition") - array.wait(1000) - left = first - right = last - while True: - array.message("Sweep right pointer") - right = right-1 - array.show_right(right) - while right > first and array.compare(right, pivot) >= 0: - right = right-1 - array.show_right(right) - array.message("Sweep left pointer") - left = left+1 - array.show_left(left) - while left < last and array.compare(left, pivot) <= 0: - left = left+1 - array.show_left(left) - if left > right: - array.message("End of partition") - break - array.message("Swap items") - array.swap(left, right) - array.message("Swap pivot back") - array.swap(pivot, right) - n1 = right-first - n2 = last-left - if n1 > 1: stack.append((first, right)) - if n2 > 1: stack.append((left, last)) - array.message("Sorted") - finally: - array.hide_partition() - -def demosort(array): - while True: - for alg in [quicksort, insertionsort, selectionsort, bubblesort]: - randomize(array) - alg(array) - - -# Sort demo class -- usable as a Grail applet - -class SortDemo: - - def __init__(self, master, size=15): - self.master = master - self.size = size - self.busy = 0 - self.array = Array(self.master) - - self.botframe = Frame(master) - self.botframe.pack(side=BOTTOM) - self.botleftframe = Frame(self.botframe) - self.botleftframe.pack(side=LEFT, fill=Y) - self.botrightframe = Frame(self.botframe) - self.botrightframe.pack(side=RIGHT, fill=Y) - - self.b_qsort = Button(self.botleftframe, - text="Quicksort", command=self.c_qsort) - self.b_qsort.pack(fill=X) - self.b_isort = Button(self.botleftframe, - text="Insertion sort", command=self.c_isort) - self.b_isort.pack(fill=X) - self.b_ssort = Button(self.botleftframe, - text="Selection sort", command=self.c_ssort) - self.b_ssort.pack(fill=X) - self.b_bsort = Button(self.botleftframe, - text="Bubble sort", command=self.c_bsort) - self.b_bsort.pack(fill=X) - - # Terrible hack to overcome limitation of OptionMenu... - class MyIntVar(IntVar): - def __init__(self, master, demo): - self.demo = demo - IntVar.__init__(self, master) - def set(self, value): - IntVar.set(self, value) - if str(value) != '0': - self.demo.resize(value) - - self.v_size = MyIntVar(self.master, self) - self.v_size.set(size) - sizes = [1, 2, 3, 4] + list(range(5, 55, 5)) - if self.size not in sizes: - sizes.append(self.size) - sizes.sort() - self.m_size = OptionMenu(self.botleftframe, self.v_size, *sizes) - self.m_size.pack(fill=X) - - self.v_speed = StringVar(self.master) - self.v_speed.set("normal") - self.m_speed = OptionMenu(self.botleftframe, self.v_speed, - "single-step", "normal", "fast", "fastest") - self.m_speed.pack(fill=X) - - self.b_step = Button(self.botleftframe, - text="Step", command=self.c_step) - self.b_step.pack(fill=X) - - self.b_randomize = Button(self.botrightframe, - text="Randomize", command=self.c_randomize) - self.b_randomize.pack(fill=X) - self.b_uniform = Button(self.botrightframe, - text="Uniform", command=self.c_uniform) - self.b_uniform.pack(fill=X) - self.b_distinct = Button(self.botrightframe, - text="Distinct", command=self.c_distinct) - self.b_distinct.pack(fill=X) - self.b_demo = Button(self.botrightframe, - text="Demo", command=self.c_demo) - self.b_demo.pack(fill=X) - self.b_cancel = Button(self.botrightframe, - text="Cancel", command=self.c_cancel) - self.b_cancel.pack(fill=X) - self.b_cancel.config(state=DISABLED) - self.b_quit = Button(self.botrightframe, - text="Quit", command=self.c_quit) - self.b_quit.pack(fill=X) - - def resize(self, newsize): - if self.busy: - self.master.bell() - return - self.size = newsize - self.array.setdata(range(1, self.size+1)) - - def c_qsort(self): - self.run(quicksort) - - def c_isort(self): - self.run(insertionsort) - - def c_ssort(self): - self.run(selectionsort) - - def c_bsort(self): - self.run(bubblesort) - - def c_demo(self): - self.run(demosort) - - def c_randomize(self): - self.run(randomize) - - def c_uniform(self): - self.run(uniform) - - def c_distinct(self): - self.run(distinct) - - def run(self, func): - if self.busy: - self.master.bell() - return - self.busy = 1 - self.array.setspeed(self.v_speed.get()) - self.b_cancel.config(state=NORMAL) - try: - func(self.array) - except Array.Cancelled: - pass - self.b_cancel.config(state=DISABLED) - self.busy = 0 - - def c_cancel(self): - if not self.busy: - self.master.bell() - return - self.array.cancel() - - def c_step(self): - if not self.busy: - self.master.bell() - return - self.v_speed.set("single-step") - self.array.setspeed("single-step") - self.array.step() - - def c_quit(self): - if self.busy: - self.array.cancel() - self.master.after_idle(self.master.quit) - - -# Main program -- for stand-alone operation outside Grail - -def main(): - root = Tk() - demo = SortDemo(root) - root.protocol('WM_DELETE_WINDOW', demo.c_quit) - root.mainloop() - -if __name__ == '__main__': - main() diff --git a/Tools/demo/spreadsheet.py b/Tools/demo/spreadsheet.py deleted file mode 100755 index bf88820..0000000 --- a/Tools/demo/spreadsheet.py +++ /dev/null @@ -1,829 +0,0 @@ -#!/usr/bin/env python3 - -""" -SS1 -- a spreadsheet-like application. -""" - -import os -import re -import sys -from xml.parsers import expat -from xml.sax.saxutils import escape - -LEFT, CENTER, RIGHT = "LEFT", "CENTER", "RIGHT" - -def ljust(x, n): - return x.ljust(n) -def center(x, n): - return x.center(n) -def rjust(x, n): - return x.rjust(n) -align2action = {LEFT: ljust, CENTER: center, RIGHT: rjust} - -align2xml = {LEFT: "left", CENTER: "center", RIGHT: "right"} -xml2align = {"left": LEFT, "center": CENTER, "right": RIGHT} - -align2anchor = {LEFT: "w", CENTER: "center", RIGHT: "e"} - -def sum(seq): - total = 0 - for x in seq: - if x is not None: - total += x - return total - -class Sheet: - - def __init__(self): - self.cells = {} # {(x, y): cell, ...} - self.ns = dict( - cell = self.cellvalue, - cells = self.multicellvalue, - sum = sum, - ) - - def cellvalue(self, x, y): - cell = self.getcell(x, y) - if hasattr(cell, 'recalc'): - return cell.recalc(self.ns) - else: - return cell - - def multicellvalue(self, x1, y1, x2, y2): - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - seq = [] - for y in range(y1, y2+1): - for x in range(x1, x2+1): - seq.append(self.cellvalue(x, y)) - return seq - - def getcell(self, x, y): - return self.cells.get((x, y)) - - def setcell(self, x, y, cell): - assert x > 0 and y > 0 - assert isinstance(cell, BaseCell) - self.cells[x, y] = cell - - def clearcell(self, x, y): - try: - del self.cells[x, y] - except KeyError: - pass - - def clearcells(self, x1, y1, x2, y2): - for xy in self.selectcells(x1, y1, x2, y2): - del self.cells[xy] - - def clearrows(self, y1, y2): - self.clearcells(0, y1, sys.maxsize, y2) - - def clearcolumns(self, x1, x2): - self.clearcells(x1, 0, x2, sys.maxsize) - - def selectcells(self, x1, y1, x2, y2): - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - return [(x, y) for x, y in self.cells - if x1 <= x <= x2 and y1 <= y <= y2] - - def movecells(self, x1, y1, x2, y2, dx, dy): - if dx == 0 and dy == 0: - return - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - assert x1+dx > 0 and y1+dy > 0 - new = {} - for x, y in self.cells: - cell = self.cells[x, y] - if hasattr(cell, 'renumber'): - cell = cell.renumber(x1, y1, x2, y2, dx, dy) - if x1 <= x <= x2 and y1 <= y <= y2: - x += dx - y += dy - new[x, y] = cell - self.cells = new - - def insertrows(self, y, n): - assert n > 0 - self.movecells(0, y, sys.maxsize, sys.maxsize, 0, n) - - def deleterows(self, y1, y2): - if y1 > y2: - y1, y2 = y2, y1 - self.clearrows(y1, y2) - self.movecells(0, y2+1, sys.maxsize, sys.maxsize, 0, y1-y2-1) - - def insertcolumns(self, x, n): - assert n > 0 - self.movecells(x, 0, sys.maxsize, sys.maxsize, n, 0) - - def deletecolumns(self, x1, x2): - if x1 > x2: - x1, x2 = x2, x1 - self.clearcells(x1, x2) - self.movecells(x2+1, 0, sys.maxsize, sys.maxsize, x1-x2-1, 0) - - def getsize(self): - maxx = maxy = 0 - for x, y in self.cells: - maxx = max(maxx, x) - maxy = max(maxy, y) - return maxx, maxy - - def reset(self): - for cell in self.cells.values(): - if hasattr(cell, 'reset'): - cell.reset() - - def recalc(self): - self.reset() - for cell in self.cells.values(): - if hasattr(cell, 'recalc'): - cell.recalc(self.ns) - - def display(self): - maxx, maxy = self.getsize() - width, height = maxx+1, maxy+1 - colwidth = [1] * width - full = {} - # Add column heading labels in row 0 - for x in range(1, width): - full[x, 0] = text, alignment = colnum2name(x), RIGHT - colwidth[x] = max(colwidth[x], len(text)) - # Add row labels in column 0 - for y in range(1, height): - full[0, y] = text, alignment = str(y), RIGHT - colwidth[0] = max(colwidth[0], len(text)) - # Add sheet cells in columns with x>0 and y>0 - for (x, y), cell in self.cells.items(): - if x <= 0 or y <= 0: - continue - if hasattr(cell, 'recalc'): - cell.recalc(self.ns) - if hasattr(cell, 'format'): - text, alignment = cell.format() - assert isinstance(text, str) - assert alignment in (LEFT, CENTER, RIGHT) - else: - text = str(cell) - if isinstance(cell, str): - alignment = LEFT - else: - alignment = RIGHT - full[x, y] = (text, alignment) - colwidth[x] = max(colwidth[x], len(text)) - # Calculate the horizontal separator line (dashes and dots) - sep = "" - for x in range(width): - if sep: - sep += "+" - sep += "-"*colwidth[x] - # Now print The full grid - for y in range(height): - line = "" - for x in range(width): - text, alignment = full.get((x, y)) or ("", LEFT) - text = align2action[alignment](text, colwidth[x]) - if line: - line += '|' - line += text - print(line) - if y == 0: - print(sep) - - def xml(self): - out = ['<spreadsheet>'] - for (x, y), cell in self.cells.items(): - if hasattr(cell, 'xml'): - cellxml = cell.xml() - else: - cellxml = '<value>%s</value>' % escape(cell) - out.append('<cell row="%s" col="%s">\n %s\n</cell>' % - (y, x, cellxml)) - out.append('</spreadsheet>') - return '\n'.join(out) - - def save(self, filename): - text = self.xml() - with open(filename, "w", encoding='utf-8') as f: - f.write(text) - if text and not text.endswith('\n'): - f.write('\n') - - def load(self, filename): - with open(filename, 'rb') as f: - SheetParser(self).parsefile(f) - -class SheetParser: - - def __init__(self, sheet): - self.sheet = sheet - - def parsefile(self, f): - parser = expat.ParserCreate() - parser.StartElementHandler = self.startelement - parser.EndElementHandler = self.endelement - parser.CharacterDataHandler = self.data - parser.ParseFile(f) - - def startelement(self, tag, attrs): - method = getattr(self, 'start_'+tag, None) - if method: - method(attrs) - self.texts = [] - - def data(self, text): - self.texts.append(text) - - def endelement(self, tag): - method = getattr(self, 'end_'+tag, None) - if method: - method("".join(self.texts)) - - def start_cell(self, attrs): - self.y = int(attrs.get("row")) - self.x = int(attrs.get("col")) - - def start_value(self, attrs): - self.fmt = attrs.get('format') - self.alignment = xml2align.get(attrs.get('align')) - - start_formula = start_value - - def end_int(self, text): - try: - self.value = int(text) - except (TypeError, ValueError): - self.value = None - - end_long = end_int - - def end_double(self, text): - try: - self.value = float(text) - except (TypeError, ValueError): - self.value = None - - def end_complex(self, text): - try: - self.value = complex(text) - except (TypeError, ValueError): - self.value = None - - def end_string(self, text): - self.value = text - - def end_value(self, text): - if isinstance(self.value, BaseCell): - self.cell = self.value - elif isinstance(self.value, str): - self.cell = StringCell(self.value, - self.fmt or "%s", - self.alignment or LEFT) - else: - self.cell = NumericCell(self.value, - self.fmt or "%s", - self.alignment or RIGHT) - - def end_formula(self, text): - self.cell = FormulaCell(text, - self.fmt or "%s", - self.alignment or RIGHT) - - def end_cell(self, text): - self.sheet.setcell(self.x, self.y, self.cell) - -class BaseCell: - __init__ = None # Must provide - """Abstract base class for sheet cells. - - Subclasses may but needn't provide the following APIs: - - cell.reset() -- prepare for recalculation - cell.recalc(ns) -> value -- recalculate formula - cell.format() -> (value, alignment) -- return formatted value - cell.xml() -> string -- return XML - """ - -class NumericCell(BaseCell): - - def __init__(self, value, fmt="%s", alignment=RIGHT): - assert isinstance(value, (int, float, complex)) - assert alignment in (LEFT, CENTER, RIGHT) - self.value = value - self.fmt = fmt - self.alignment = alignment - - def recalc(self, ns): - return self.value - - def format(self): - try: - text = self.fmt % self.value - except: - text = str(self.value) - return text, self.alignment - - def xml(self): - method = getattr(self, '_xml_' + type(self.value).__name__) - return '<value align="%s" format="%s">%s</value>' % ( - align2xml[self.alignment], - self.fmt, - method()) - - def _xml_int(self): - if -2**31 <= self.value < 2**31: - return '<int>%s</int>' % self.value - else: - return '<long>%s</long>' % self.value - - def _xml_float(self): - return '<double>%r</double>' % self.value - - def _xml_complex(self): - return '<complex>%r</complex>' % self.value - -class StringCell(BaseCell): - - def __init__(self, text, fmt="%s", alignment=LEFT): - assert isinstance(text, str) - assert alignment in (LEFT, CENTER, RIGHT) - self.text = text - self.fmt = fmt - self.alignment = alignment - - def recalc(self, ns): - return self.text - - def format(self): - return self.text, self.alignment - - def xml(self): - s = '<value align="%s" format="%s"><string>%s</string></value>' - return s % ( - align2xml[self.alignment], - self.fmt, - escape(self.text)) - -class FormulaCell(BaseCell): - - def __init__(self, formula, fmt="%s", alignment=RIGHT): - assert alignment in (LEFT, CENTER, RIGHT) - self.formula = formula - self.translated = translate(self.formula) - self.fmt = fmt - self.alignment = alignment - self.reset() - - def reset(self): - self.value = None - - def recalc(self, ns): - if self.value is None: - try: - self.value = eval(self.translated, ns) - except: - exc = sys.exc_info()[0] - if hasattr(exc, "__name__"): - self.value = exc.__name__ - else: - self.value = str(exc) - return self.value - - def format(self): - try: - text = self.fmt % self.value - except: - text = str(self.value) - return text, self.alignment - - def xml(self): - return '<formula align="%s" format="%s">%s</formula>' % ( - align2xml[self.alignment], - self.fmt, - escape(self.formula)) - - def renumber(self, x1, y1, x2, y2, dx, dy): - out = [] - for part in re.split(r'(\w+)', self.formula): - m = re.match('^([A-Z]+)([1-9][0-9]*)$', part) - if m is not None: - sx, sy = m.groups() - x = colname2num(sx) - y = int(sy) - if x1 <= x <= x2 and y1 <= y <= y2: - part = cellname(x+dx, y+dy) - out.append(part) - return FormulaCell("".join(out), self.fmt, self.alignment) - -def translate(formula): - """Translate a formula containing fancy cell names to valid Python code. - - Examples: - B4 -> cell(2, 4) - B4:Z100 -> cells(2, 4, 26, 100) - """ - out = [] - for part in re.split(r"(\w+(?::\w+)?)", formula): - m = re.match(r"^([A-Z]+)([1-9][0-9]*)(?::([A-Z]+)([1-9][0-9]*))?$", part) - if m is None: - out.append(part) - else: - x1, y1, x2, y2 = m.groups() - x1 = colname2num(x1) - if x2 is None: - s = "cell(%s, %s)" % (x1, y1) - else: - x2 = colname2num(x2) - s = "cells(%s, %s, %s, %s)" % (x1, y1, x2, y2) - out.append(s) - return "".join(out) - -def cellname(x, y): - "Translate a cell coordinate to a fancy cell name (e.g. (1, 1)->'A1')." - assert x > 0 # Column 0 has an empty name, so can't use that - return colnum2name(x) + str(y) - -def colname2num(s): - "Translate a column name to number (e.g. 'A'->1, 'Z'->26, 'AA'->27)." - s = s.upper() - n = 0 - for c in s: - assert 'A' <= c <= 'Z' - n = n*26 + ord(c) - ord('A') + 1 - return n - -def colnum2name(n): - "Translate a column number to name (e.g. 1->'A', etc.)." - assert n > 0 - s = "" - while n: - n, m = divmod(n-1, 26) - s = chr(m+ord('A')) + s - return s - -import tkinter as Tk - -class SheetGUI: - - """Beginnings of a GUI for a spreadsheet. - - TO DO: - - clear multiple cells - - Insert, clear, remove rows or columns - - Show new contents while typing - - Scroll bars - - Grow grid when window is grown - - Proper menus - - Undo, redo - - Cut, copy and paste - - Formatting and alignment - """ - - def __init__(self, filename="sheet1.xml", rows=10, columns=5): - """Constructor. - - Load the sheet from the filename argument. - Set up the Tk widget tree. - """ - # Create and load the sheet - self.filename = filename - self.sheet = Sheet() - if os.path.isfile(filename): - self.sheet.load(filename) - # Calculate the needed grid size - maxx, maxy = self.sheet.getsize() - rows = max(rows, maxy) - columns = max(columns, maxx) - # Create the widgets - self.root = Tk.Tk() - self.root.wm_title("Spreadsheet: %s" % self.filename) - self.beacon = Tk.Label(self.root, text="A1", - font=('helvetica', 16, 'bold')) - self.entry = Tk.Entry(self.root) - self.savebutton = Tk.Button(self.root, text="Save", - command=self.save) - self.cellgrid = Tk.Frame(self.root) - # Configure the widget lay-out - self.cellgrid.pack(side="bottom", expand=1, fill="both") - self.beacon.pack(side="left") - self.savebutton.pack(side="right") - self.entry.pack(side="left", expand=1, fill="x") - # Bind some events - self.entry.bind("<Return>", self.return_event) - self.entry.bind("<Shift-Return>", self.shift_return_event) - self.entry.bind("<Tab>", self.tab_event) - self.entry.bind("<Shift-Tab>", self.shift_tab_event) - self.entry.bind("<Delete>", self.delete_event) - self.entry.bind("<Escape>", self.escape_event) - # Now create the cell grid - self.makegrid(rows, columns) - # Select the top-left cell - self.currentxy = None - self.cornerxy = None - self.setcurrent(1, 1) - # Copy the sheet cells to the GUI cells - self.sync() - - def delete_event(self, event): - if self.cornerxy != self.currentxy and self.cornerxy is not None: - self.sheet.clearcells(*(self.currentxy + self.cornerxy)) - else: - self.sheet.clearcell(*self.currentxy) - self.sync() - self.entry.delete(0, 'end') - return "break" - - def escape_event(self, event): - x, y = self.currentxy - self.load_entry(x, y) - - def load_entry(self, x, y): - cell = self.sheet.getcell(x, y) - if cell is None: - text = "" - elif isinstance(cell, FormulaCell): - text = '=' + cell.formula - else: - text, alignment = cell.format() - self.entry.delete(0, 'end') - self.entry.insert(0, text) - self.entry.selection_range(0, 'end') - - def makegrid(self, rows, columns): - """Helper to create the grid of GUI cells. - - The edge (x==0 or y==0) is filled with labels; the rest is real cells. - """ - self.rows = rows - self.columns = columns - self.gridcells = {} - # Create the top left corner cell (which selects all) - cell = Tk.Label(self.cellgrid, relief='raised') - cell.grid_configure(column=0, row=0, sticky='NSWE') - cell.bind("<ButtonPress-1>", self.selectall) - # Create the top row of labels, and configure the grid columns - for x in range(1, columns+1): - self.cellgrid.grid_columnconfigure(x, minsize=64) - cell = Tk.Label(self.cellgrid, text=colnum2name(x), relief='raised') - cell.grid_configure(column=x, row=0, sticky='WE') - self.gridcells[x, 0] = cell - cell.__x = x - cell.__y = 0 - cell.bind("<ButtonPress-1>", self.selectcolumn) - cell.bind("<B1-Motion>", self.extendcolumn) - cell.bind("<ButtonRelease-1>", self.extendcolumn) - cell.bind("<Shift-Button-1>", self.extendcolumn) - # Create the leftmost column of labels - for y in range(1, rows+1): - cell = Tk.Label(self.cellgrid, text=str(y), relief='raised') - cell.grid_configure(column=0, row=y, sticky='WE') - self.gridcells[0, y] = cell - cell.__x = 0 - cell.__y = y - cell.bind("<ButtonPress-1>", self.selectrow) - cell.bind("<B1-Motion>", self.extendrow) - cell.bind("<ButtonRelease-1>", self.extendrow) - cell.bind("<Shift-Button-1>", self.extendrow) - # Create the real cells - for x in range(1, columns+1): - for y in range(1, rows+1): - cell = Tk.Label(self.cellgrid, relief='sunken', - bg='white', fg='black') - cell.grid_configure(column=x, row=y, sticky='NSWE') - self.gridcells[x, y] = cell - cell.__x = x - cell.__y = y - # Bind mouse events - cell.bind("<ButtonPress-1>", self.press) - cell.bind("<B1-Motion>", self.motion) - cell.bind("<ButtonRelease-1>", self.release) - cell.bind("<Shift-Button-1>", self.release) - - def selectall(self, event): - self.setcurrent(1, 1) - self.setcorner(sys.maxsize, sys.maxsize) - - def selectcolumn(self, event): - x, y = self.whichxy(event) - self.setcurrent(x, 1) - self.setcorner(x, sys.maxsize) - - def extendcolumn(self, event): - x, y = self.whichxy(event) - if x > 0: - self.setcurrent(self.currentxy[0], 1) - self.setcorner(x, sys.maxsize) - - def selectrow(self, event): - x, y = self.whichxy(event) - self.setcurrent(1, y) - self.setcorner(sys.maxsize, y) - - def extendrow(self, event): - x, y = self.whichxy(event) - if y > 0: - self.setcurrent(1, self.currentxy[1]) - self.setcorner(sys.maxsize, y) - - def press(self, event): - x, y = self.whichxy(event) - if x > 0 and y > 0: - self.setcurrent(x, y) - - def motion(self, event): - x, y = self.whichxy(event) - if x > 0 and y > 0: - self.setcorner(x, y) - - release = motion - - def whichxy(self, event): - w = self.cellgrid.winfo_containing(event.x_root, event.y_root) - if w is not None and isinstance(w, Tk.Label): - try: - return w.__x, w.__y - except AttributeError: - pass - return 0, 0 - - def save(self): - self.sheet.save(self.filename) - - def setcurrent(self, x, y): - "Make (x, y) the current cell." - if self.currentxy is not None: - self.change_cell() - self.clearfocus() - self.beacon['text'] = cellname(x, y) - self.load_entry(x, y) - self.entry.focus_set() - self.currentxy = x, y - self.cornerxy = None - gridcell = self.gridcells.get(self.currentxy) - if gridcell is not None: - gridcell['bg'] = 'yellow' - - def setcorner(self, x, y): - if self.currentxy is None or self.currentxy == (x, y): - self.setcurrent(x, y) - return - self.clearfocus() - self.cornerxy = x, y - x1, y1 = self.currentxy - x2, y2 = self.cornerxy or self.currentxy - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - for (x, y), cell in self.gridcells.items(): - if x1 <= x <= x2 and y1 <= y <= y2: - cell['bg'] = 'lightBlue' - gridcell = self.gridcells.get(self.currentxy) - if gridcell is not None: - gridcell['bg'] = 'yellow' - self.setbeacon(x1, y1, x2, y2) - - def setbeacon(self, x1, y1, x2, y2): - if x1 == y1 == 1 and x2 == y2 == sys.maxsize: - name = ":" - elif (x1, x2) == (1, sys.maxsize): - if y1 == y2: - name = "%d" % y1 - else: - name = "%d:%d" % (y1, y2) - elif (y1, y2) == (1, sys.maxsize): - if x1 == x2: - name = "%s" % colnum2name(x1) - else: - name = "%s:%s" % (colnum2name(x1), colnum2name(x2)) - else: - name1 = cellname(*self.currentxy) - name2 = cellname(*self.cornerxy) - name = "%s:%s" % (name1, name2) - self.beacon['text'] = name - - - def clearfocus(self): - if self.currentxy is not None: - x1, y1 = self.currentxy - x2, y2 = self.cornerxy or self.currentxy - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 - for (x, y), cell in self.gridcells.items(): - if x1 <= x <= x2 and y1 <= y <= y2: - cell['bg'] = 'white' - - def return_event(self, event): - "Callback for the Return key." - self.change_cell() - x, y = self.currentxy - self.setcurrent(x, y+1) - return "break" - - def shift_return_event(self, event): - "Callback for the Return key with Shift modifier." - self.change_cell() - x, y = self.currentxy - self.setcurrent(x, max(1, y-1)) - return "break" - - def tab_event(self, event): - "Callback for the Tab key." - self.change_cell() - x, y = self.currentxy - self.setcurrent(x+1, y) - return "break" - - def shift_tab_event(self, event): - "Callback for the Tab key with Shift modifier." - self.change_cell() - x, y = self.currentxy - self.setcurrent(max(1, x-1), y) - return "break" - - def change_cell(self): - "Set the current cell from the entry widget." - x, y = self.currentxy - text = self.entry.get() - cell = None - if text.startswith('='): - cell = FormulaCell(text[1:]) - else: - for cls in int, float, complex: - try: - value = cls(text) - except (TypeError, ValueError): - continue - else: - cell = NumericCell(value) - break - if cell is None and text: - cell = StringCell(text) - if cell is None: - self.sheet.clearcell(x, y) - else: - self.sheet.setcell(x, y, cell) - self.sync() - - def sync(self): - "Fill the GUI cells from the sheet cells." - self.sheet.recalc() - for (x, y), gridcell in self.gridcells.items(): - if x == 0 or y == 0: - continue - cell = self.sheet.getcell(x, y) - if cell is None: - gridcell['text'] = "" - else: - if hasattr(cell, 'format'): - text, alignment = cell.format() - else: - text, alignment = str(cell), LEFT - gridcell['text'] = text - gridcell['anchor'] = align2anchor[alignment] - - -def test_basic(): - "Basic non-gui self-test." - a = Sheet() - for x in range(1, 11): - for y in range(1, 11): - if x == 1: - cell = NumericCell(y) - elif y == 1: - cell = NumericCell(x) - else: - c1 = cellname(x, 1) - c2 = cellname(1, y) - formula = "%s*%s" % (c1, c2) - cell = FormulaCell(formula) - a.setcell(x, y, cell) -## if os.path.isfile("sheet1.xml"): -## print "Loading from sheet1.xml" -## a.load("sheet1.xml") - a.display() - a.save("sheet1.xml") - -def test_gui(): - "GUI test." - if sys.argv[1:]: - filename = sys.argv[1] - else: - filename = "sheet1.xml" - g = SheetGUI(filename) - g.root.mainloop() - -if __name__ == '__main__': - #test_basic() - test_gui() diff --git a/Tools/demo/vector.py b/Tools/demo/vector.py deleted file mode 100755 index 6df1f50..0000000 --- a/Tools/demo/vector.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 - -""" -A demonstration of classes and their special methods in Python. -""" - -class Vec: - """A simple vector class. - - Instances of the Vec class can be constructed from numbers - - >>> a = Vec(1, 2, 3) - >>> b = Vec(3, 2, 1) - - added - >>> a + b - Vec(4, 4, 4) - - subtracted - >>> a - b - Vec(-2, 0, 2) - - and multiplied by a scalar on the left - >>> 3.0 * a - Vec(3.0, 6.0, 9.0) - - or on the right - >>> a * 3.0 - Vec(3.0, 6.0, 9.0) - - and dot product - >>> a.dot(b) - 10 - - and printed in vector notation - >>> print(a) - <1 2 3> - - """ - - def __init__(self, *v): - self.v = list(v) - - @classmethod - def fromlist(cls, v): - if not isinstance(v, list): - raise TypeError - inst = cls() - inst.v = v - return inst - - def __repr__(self): - args = ', '.join([repr(x) for x in self.v]) - return f'{type(self).__name__}({args})' - - def __str__(self): - components = ' '.join([str(x) for x in self.v]) - return f'<{components}>' - - def __len__(self): - return len(self.v) - - def __getitem__(self, i): - return self.v[i] - - def __add__(self, other): - "Element-wise addition" - v = [x + y for x, y in zip(self.v, other.v)] - return Vec.fromlist(v) - - def __sub__(self, other): - "Element-wise subtraction" - v = [x - y for x, y in zip(self.v, other.v)] - return Vec.fromlist(v) - - def __mul__(self, scalar): - "Multiply by scalar" - v = [x * scalar for x in self.v] - return Vec.fromlist(v) - - __rmul__ = __mul__ - - def dot(self, other): - "Vector dot product" - if not isinstance(other, Vec): - raise TypeError - return sum(x_i * y_i for (x_i, y_i) in zip(self, other)) - - -def test(): - import doctest - doctest.testmod() - -test() |