From 856898b3958626d2400e59b53dc134283addc988 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 30 Dec 2010 22:11:50 +0000 Subject: Harmonize docstrings. Move redemo from Tools/scripts to Tools/demo. Add a README file to Tools/demo. --- Tools/demo/Eiffel.py | 141 --------------------------------------- Tools/demo/README | 16 +++++ Tools/demo/Vec.py | 68 ------------------- Tools/demo/beer.py | 9 ++- Tools/demo/eiffel.py | 146 +++++++++++++++++++++++++++++++++++++++++ Tools/demo/hanoi.py | 26 ++++---- Tools/demo/life.py | 93 +++++++++++++------------- Tools/demo/markov.py | 6 +- Tools/demo/mcast.py | 20 +++--- Tools/demo/queens.py | 6 +- Tools/demo/redemo.py | 171 ++++++++++++++++++++++++++++++++++++++++++++++++ Tools/demo/rpython.py | 8 ++- Tools/demo/rpythond.py | 13 ++-- Tools/demo/sortvisu.py | 7 +- Tools/demo/ss1.py | 6 +- Tools/demo/vector.py | 74 +++++++++++++++++++++ Tools/scripts/README | 2 - Tools/scripts/redemo.py | 171 ------------------------------------------------ 18 files changed, 514 insertions(+), 469 deletions(-) delete mode 100644 Tools/demo/Eiffel.py create mode 100644 Tools/demo/README delete mode 100644 Tools/demo/Vec.py create mode 100755 Tools/demo/eiffel.py mode change 100644 => 100755 Tools/demo/hanoi.py create mode 100644 Tools/demo/redemo.py mode change 100644 => 100755 Tools/demo/sortvisu.py mode change 100644 => 100755 Tools/demo/ss1.py create mode 100755 Tools/demo/vector.py delete mode 100644 Tools/scripts/redemo.py diff --git a/Tools/demo/Eiffel.py b/Tools/demo/Eiffel.py deleted file mode 100644 index 15fa58a..0000000 --- a/Tools/demo/Eiffel.py +++ /dev/null @@ -1,141 +0,0 @@ -"""Support Eiffel-style preconditions and postconditions.""" - -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[k] = 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) - x = func(self, *args, **kwargs) - if post: - post(self, x, *args, **kwargs) - return x - - 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(object): - - 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): - 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 - -def _test(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() - t.m(1) - t.m2(1) - try: - t.m2(0) - except AssertionError: - pass - else: - assert False - - s = Sub() - try: - s.m2(1) - except AssertionError: - pass # result == arg - else: - assert False - try: - s.m2(10) - except AssertionError: - pass # result == 100 - else: - assert False - s.m2(5) - -if __name__ == "__main__": - _test(EiffelMetaClass1) - _test(EiffelMetaClass2) diff --git a/Tools/demo/README b/Tools/demo/README new file mode 100644 index 0000000..e914358 --- /dev/null +++ b/Tools/demo/README @@ -0,0 +1,16 @@ +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. +ss1.py GUI/Application programming: A simple spreadsheet application. +vector.py Python basics: A vector class with demonstrating special methods. \ No newline at end of file diff --git a/Tools/demo/Vec.py b/Tools/demo/Vec.py deleted file mode 100644 index 787af69..0000000 --- a/Tools/demo/Vec.py +++ /dev/null @@ -1,68 +0,0 @@ -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) - """ - 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 'Vec({})'.format(args) - - 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 test(): - import doctest - doctest.testmod() - -test() diff --git a/Tools/demo/beer.py b/Tools/demo/beer.py index 56eec7b..af58380 100755 --- a/Tools/demo/beer.py +++ b/Tools/demo/beer.py @@ -1,6 +1,11 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 -# By GvR, demystified after a version by Fredrik Lundh. +""" +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 diff --git a/Tools/demo/eiffel.py b/Tools/demo/eiffel.py new file mode 100755 index 0000000..3a28224 --- /dev/null +++ b/Tools/demo/eiffel.py @@ -0,0 +1,146 @@ +#!/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[k] = 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): + 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 old mode 100644 new mode 100755 index 34a0bba..dad0234 --- a/Tools/demo/hanoi.py +++ b/Tools/demo/hanoi.py @@ -1,17 +1,18 @@ -# Animated Towers of Hanoi using Tk with optional bitmap file in -# background. -# -# Usage: tkhanoi [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. +#!/usr/bin/env python3 -# This uses Steen Lumholt's Tk interface -from tkinter import * +""" +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() @@ -123,7 +124,6 @@ class Tkhanoi: self.pegstate[b].append(i) -# Main program def main(): import sys diff --git a/Tools/demo/life.py b/Tools/demo/life.py index 3cbc053..dfb9ab8 100755 --- a/Tools/demo/life.py +++ b/Tools/demo/life.py @@ -1,23 +1,23 @@ #!/usr/bin/env python3 -# life.py -- A curses-based version of Conway's Game of Life. -# Contributed by AMK -# Mouse support and color by Dafydd Crosby -# -# 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 -# -# TODO : -# Make board updates faster -# - -import random, string, traceback + +""" +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 @@ -31,7 +31,7 @@ class LifeBoard: next generation. Then display the state of the board and refresh the screen. erase() -- clear the entire board - makeRandom() -- fill the board randomly + 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 @@ -53,7 +53,7 @@ class LifeBoard: # 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) + 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, '|') @@ -62,21 +62,21 @@ class LifeBoard: 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)) + 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] + 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 + 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))) + # 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() @@ -115,8 +115,9 @@ class LifeBoard: # 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))) + # 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 @@ -128,7 +129,7 @@ class LifeBoard: self.state = d self.scr.refresh() - def makeRandom(self): + def make_random(self): "Fill the board with a random pattern" self.state = {} for i in range(0, self.X): @@ -152,9 +153,9 @@ def display_menu(stdscr, menu_y): 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.') + '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') + 'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit') stdscr.attrset(0) def keyloop(stdscr): @@ -186,10 +187,10 @@ def keyloop(stdscr): xpos, ypos = board.X//2, board.Y//2 # Main loop: - while (1): + while True: stdscr.move(1+ypos, 1+xpos) # Move the cursor c = stdscr.getch() # Get a keystroke - if 00: ypos -= 1 - elif c == curses.KEY_DOWN and ypos0: xpos -= 1 - elif c == curses.KEY_RIGHT and xpos 0: ypos -= 1 + elif c == curses.KEY_DOWN and ypos < board.Y-1: ypos += 1 + elif c == curses.KEY_LEFT and xpos > 0: xpos -= 1 + elif c == curses.KEY_RIGHT and xpos < board.X-1: 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_x0 and mouse_y 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) @@ -245,6 +247,5 @@ def keyloop(stdscr): 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 index 7c08bdb..7a0720f 100755 --- a/Tools/demo/markov.py +++ b/Tools/demo/markov.py @@ -1,4 +1,8 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 + +""" +Markov chain simulation of words or characters. +""" class Markov: def __init__(self, histsize, choice): diff --git a/Tools/demo/mcast.py b/Tools/demo/mcast.py index 6ce7c6d..924c7c3 100755 --- a/Tools/demo/mcast.py +++ b/Tools/demo/mcast.py @@ -1,13 +1,15 @@ #!/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) + +""" +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' diff --git a/Tools/demo/queens.py b/Tools/demo/queens.py index ffd4bea..dcc1bae 100755 --- a/Tools/demo/queens.py +++ b/Tools/demo/queens.py @@ -1,12 +1,12 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 -"""N queens problem. +""" +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 diff --git a/Tools/demo/redemo.py b/Tools/demo/redemo.py new file mode 100644 index 0000000..5286332 --- /dev/null +++ b/Tools/demo/redemo.py @@ -0,0 +1,171 @@ +"""Basic regular expression demostration 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('', self.recompile) + self.stringdisplay.bind('', 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', + 'LOCALE', + '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) + 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() + flags = flags + 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 index e965720..5e7bc0a 100755 --- a/Tools/demo/rpython.py +++ b/Tools/demo/rpython.py @@ -1,7 +1,9 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 -# Remote python client. -# Execute Python commands remotely and send output back. +""" +Remote python client. +Execute Python commands remotely and send output back. +""" import sys from socket import socket, AF_INET, SOCK_STREAM, SHUT_WR diff --git a/Tools/demo/rpythond.py b/Tools/demo/rpythond.py index fe24b3d..9ffe13a 100755 --- a/Tools/demo/rpythond.py +++ b/Tools/demo/rpythond.py @@ -1,9 +1,12 @@ -#! /usr/bin/env python3 +#!/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! +""" +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 diff --git a/Tools/demo/sortvisu.py b/Tools/demo/sortvisu.py old mode 100644 new mode 100755 index 4173121..8447bc7 --- a/Tools/demo/sortvisu.py +++ b/Tools/demo/sortvisu.py @@ -1,6 +1,7 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 -"""Sorting algorithms visualizer using Tkinter. +""" +Sorting algorithms visualizer using Tkinter. This module is comprised of three ``components'': @@ -15,13 +16,11 @@ 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 diff --git a/Tools/demo/ss1.py b/Tools/demo/ss1.py old mode 100644 new mode 100755 index 8b07489..2d1e490 --- a/Tools/demo/ss1.py +++ b/Tools/demo/ss1.py @@ -1,4 +1,8 @@ -"""SS1 -- a spreadsheet.""" +#!/usr/bin/env python3 + +""" +SS1 -- a spreadsheet-like application. +""" import os import re diff --git a/Tools/demo/vector.py b/Tools/demo/vector.py new file mode 100755 index 0000000..da5b389 --- /dev/null +++ b/Tools/demo/vector.py @@ -0,0 +1,74 @@ +#!/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) + """ + 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 'Vec({})'.format(args) + + 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 test(): + import doctest + doctest.testmod() + +test() diff --git a/Tools/scripts/README b/Tools/scripts/README index 546ab21e..8c02529 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -2,8 +2,6 @@ This directory contains a collection of executable Python scripts that are useful while building, extending or managing Python. Some (e.g., dutree or lll) are also generally useful UNIX tools. -See also the Demo/scripts directory! - 2to3 Main script for running the 2to3 conversion tool analyze_dxp.py Analyzes the result of sys.getdxp() byext.py Print lines/words/chars stats of files by extension diff --git a/Tools/scripts/redemo.py b/Tools/scripts/redemo.py deleted file mode 100644 index 5286332..0000000 --- a/Tools/scripts/redemo.py +++ /dev/null @@ -1,171 +0,0 @@ -"""Basic regular expression demostration 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('', self.recompile) - self.stringdisplay.bind('', 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', - 'LOCALE', - '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) - 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() - flags = flags - 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() -- cgit v0.12