Harmonize docstrings. Move redemo from Tools/scripts to Tools/demo. Add a README file to Tools/demo.

This commit is contained in:
Georg Brandl 2010-12-30 22:11:50 +00:00
parent a3fe8e0b9f
commit 856898b395
15 changed files with 188 additions and 143 deletions

16
Tools/demo/README Normal file
View File

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

View File

@ -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 import sys

109
Tools/demo/Eiffel.py → Tools/demo/eiffel.py Normal file → Executable file
View File

@ -1,13 +1,20 @@
"""Support Eiffel-style preconditions and postconditions.""" #!/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 from types import FunctionType as function
class EiffelBaseMetaClass(type): class EiffelBaseMetaClass(type):
def __new__(meta, name, bases, dict): def __new__(meta, name, bases, dict):
meta.convert_methods(dict) meta.convert_methods(dict)
return super(EiffelBaseMetaClass, meta).__new__(meta, name, bases, return super(EiffelBaseMetaClass, meta).__new__(
dict) meta, name, bases, dict)
@classmethod @classmethod
def convert_methods(cls, dict): def convert_methods(cls, dict):
@ -31,6 +38,7 @@ class EiffelBaseMetaClass(type):
if pre or post: if pre or post:
dict[k] = cls.make_eiffel_method(dict[m], pre, post) dict[k] = cls.make_eiffel_method(dict[m], pre, post)
class EiffelMetaClass1(EiffelBaseMetaClass): class EiffelMetaClass1(EiffelBaseMetaClass):
# an implementation of the "eiffel" meta class that uses nested functions # an implementation of the "eiffel" meta class that uses nested functions
@ -39,16 +47,17 @@ class EiffelMetaClass1(EiffelBaseMetaClass):
def method(self, *args, **kwargs): def method(self, *args, **kwargs):
if pre: if pre:
pre(self, *args, **kwargs) pre(self, *args, **kwargs)
x = func(self, *args, **kwargs) rv = func(self, *args, **kwargs)
if post: if post:
post(self, x, *args, **kwargs) post(self, rv, *args, **kwargs)
return x return rv
if func.__doc__: if func.__doc__:
method.__doc__ = func.__doc__ method.__doc__ = func.__doc__
return method return method
class EiffelMethodWrapper: class EiffelMethodWrapper:
def __init__(self, inst, descr): def __init__(self, inst, descr):
@ -58,7 +67,8 @@ class EiffelMethodWrapper:
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
return self._descr.callmethod(self._inst, args, kwargs) return self._descr.callmethod(self._inst, args, kwargs)
class EiffelDescriptor(object):
class EiffelDescriptor:
def __init__(self, func, pre, post): def __init__(self, func, pre, post):
self._func = func self._func = func
@ -79,63 +89,58 @@ class EiffelDescriptor(object):
self._post(inst, x, *args, **kwargs) self._post(inst, x, *args, **kwargs)
return x return x
class EiffelMetaClass2(EiffelBaseMetaClass): class EiffelMetaClass2(EiffelBaseMetaClass):
# an implementation of the "eiffel" meta class that uses descriptors # an implementation of the "eiffel" meta class that uses descriptors
make_eiffel_method = EiffelDescriptor make_eiffel_method = EiffelDescriptor
def _test(metaclass):
class Eiffel(metaclass=metaclass):
pass
class Test(Eiffel): class Tests(unittest.TestCase):
def m(self, arg): def testEiffelMetaClass1(self):
"""Make it a little larger""" self._test(EiffelMetaClass1)
return arg + 1
def m2(self, arg): def testEiffelMetaClass2(self):
"""Make it a little larger""" self._test(EiffelMetaClass2)
return arg + 1
def m2_pre(self, arg): def _test(self, metaclass):
assert arg > 0 class Eiffel(metaclass=metaclass):
pass
def m2_post(self, result, arg): class Test(Eiffel):
assert result > arg def m(self, arg):
"""Make it a little larger"""
return arg + 1
class Sub(Test): def m2(self, arg):
def m2(self, arg): """Make it a little larger"""
return arg**2 return arg + 1
def m2_post(self, Result, arg):
super(Sub, self).m2_post(Result, arg)
assert Result < 100
t = Test() def m2_pre(self, arg):
t.m(1) assert arg > 0
t.m2(1)
try: def m2_post(self, result, arg):
t.m2(0) assert result > arg
except AssertionError:
pass class Sub(Test):
else: def m2(self, arg):
assert False 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)
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__": if __name__ == "__main__":
_test(EiffelMetaClass1) unittest.main()
_test(EiffelMetaClass2)

26
Tools/demo/hanoi.py Normal file → Executable file
View File

@ -1,17 +1,18 @@
# Animated Towers of Hanoi using Tk with optional bitmap file in #!/usr/bin/env python3
# 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.
# 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 # Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c
# as temporary. For each move, call report() # as temporary. For each move, call report()
@ -123,7 +124,6 @@ class Tkhanoi:
self.pegstate[b].append(i) self.pegstate[b].append(i)
# Main program
def main(): def main():
import sys import sys

View File

@ -1,23 +1,23 @@
#!/usr/bin/env python3 #!/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 curses
import random
class LifeBoard: class LifeBoard:
"""Encapsulates a Life board """Encapsulates a Life board
@ -31,7 +31,7 @@ class LifeBoard:
next generation. Then display the state next generation. Then display the state
of the board and refresh the screen. of the board and refresh the screen.
erase() -- clear the entire board 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 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 toggle(y,x) -- change the given cell from live to dead, or vice
versa, and refresh the screen display versa, and refresh the screen display
@ -53,7 +53,7 @@ class LifeBoard:
# Draw a border around the board # Draw a border around the board
border_line = '+'+(self.X*'-')+'+' border_line = '+'+(self.X*'-')+'+'
self.scr.addstr(0, 0, border_line) 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): for y in range(0, self.Y):
self.scr.addstr(1+y, 0, '|') self.scr.addstr(1+y, 0, '|')
self.scr.addstr(1+y, self.X+1, '|') self.scr.addstr(1+y, self.X+1, '|')
@ -62,21 +62,21 @@ class LifeBoard:
def set(self, y, x): def set(self, y, x):
"""Set a cell to the live state""" """Set a cell to the live state"""
if x<0 or self.X<=x or y<0 or self.Y<=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)) raise ValueError("Coordinates out of range %i,%i"% (y, x))
self.state[x,y] = 1 self.state[x,y] = 1
def toggle(self, y, x): def toggle(self, y, x):
"""Toggle a cell's state between live and dead""" """Toggle a cell's state between live and dead"""
if x<0 or self.X<=x or y<0 or self.Y<=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)) raise ValueError("Coordinates out of range %i,%i"% (y, x))
if (x,y) in self.state: if (x, y) in self.state:
del self.state[x,y] del self.state[x, y]
self.scr.addch(y+1, x+1, ' ') self.scr.addch(y+1, x+1, ' ')
else: else:
self.state[x,y] = 1 self.state[x, y] = 1
if curses.has_colors(): if curses.has_colors():
#Let's pick a random color! # Let's pick a random color!
self.scr.attrset(curses.color_pair(random.randrange(1,7))) self.scr.attrset(curses.color_pair(random.randrange(1, 7)))
self.scr.addch(y+1, x+1, self.char) self.scr.addch(y+1, x+1, self.char)
self.scr.attrset(0) self.scr.attrset(0)
self.scr.refresh() self.scr.refresh()
@ -115,8 +115,9 @@ class LifeBoard:
# Birth # Birth
d[i,j] = 1 d[i,j] = 1
if curses.has_colors(): if curses.has_colors():
#Let's pick a random color! # Let's pick a random color!
self.scr.attrset(curses.color_pair(random.randrange(1,7))) self.scr.attrset(curses.color_pair(
random.randrange(1, 7)))
self.scr.addch(j+1, i+1, self.char) self.scr.addch(j+1, i+1, self.char)
self.scr.attrset(0) self.scr.attrset(0)
if not live: self.boring = 0 if not live: self.boring = 0
@ -128,7 +129,7 @@ class LifeBoard:
self.state = d self.state = d
self.scr.refresh() self.scr.refresh()
def makeRandom(self): def make_random(self):
"Fill the board with a random pattern" "Fill the board with a random pattern"
self.state = {} self.state = {}
for i in range(0, self.X): for i in range(0, self.X):
@ -152,9 +153,9 @@ def display_menu(stdscr, menu_y):
if curses.has_colors(): if curses.has_colors():
stdscr.attrset(curses.color_pair(1)) stdscr.attrset(curses.color_pair(1))
stdscr.addstr(menu_y, 4, 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, 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) stdscr.attrset(0)
def keyloop(stdscr): def keyloop(stdscr):
@ -186,10 +187,10 @@ def keyloop(stdscr):
xpos, ypos = board.X//2, board.Y//2 xpos, ypos = board.X//2, board.Y//2
# Main loop: # Main loop:
while (1): while True:
stdscr.move(1+ypos, 1+xpos) # Move the cursor stdscr.move(1+ypos, 1+xpos) # Move the cursor
c = stdscr.getch() # Get a keystroke c = stdscr.getch() # Get a keystroke
if 0<c<256: if 0 < c < 256:
c = chr(c) c = chr(c)
if c in ' \n': if c in ' \n':
board.toggle(ypos, xpos) board.toggle(ypos, xpos)
@ -201,14 +202,14 @@ def keyloop(stdscr):
# Activate nodelay mode; getch() will return -1 # Activate nodelay mode; getch() will return -1
# if no keystroke is available, instead of waiting. # if no keystroke is available, instead of waiting.
stdscr.nodelay(1) stdscr.nodelay(1)
while (1): while True:
c = stdscr.getch() c = stdscr.getch()
if c != -1: if c != -1:
break break
stdscr.addstr(0,0, '/') stdscr.addstr(0, 0, '/')
stdscr.refresh() stdscr.refresh()
board.display() board.display()
stdscr.addstr(0,0, '+') stdscr.addstr(0, 0, '+')
stdscr.refresh() stdscr.refresh()
stdscr.nodelay(0) # Disable nodelay mode stdscr.nodelay(0) # Disable nodelay mode
@ -219,18 +220,19 @@ def keyloop(stdscr):
elif c in 'Qq': elif c in 'Qq':
break break
elif c in 'Rr': elif c in 'Rr':
board.makeRandom() board.make_random()
board.display(update_board=False) board.display(update_board=False)
elif c in 'Ss': elif c in 'Ss':
board.display() board.display()
else: pass # Ignore incorrect keys else: pass # Ignore incorrect keys
elif c == curses.KEY_UP and ypos>0: ypos -= 1 elif c == curses.KEY_UP and ypos > 0: ypos -= 1
elif c == curses.KEY_DOWN and ypos<board.Y-1: 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_LEFT and xpos > 0: xpos -= 1
elif c == curses.KEY_RIGHT and xpos<board.X-1: xpos += 1 elif c == curses.KEY_RIGHT and xpos < board.X-1: xpos += 1
elif c == curses.KEY_MOUSE: elif c == curses.KEY_MOUSE:
(mouse_id, mouse_x, mouse_y, mouse_z, button_state) = curses.getmouse() 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): if (mouse_x > 0 and mouse_x < board.X+1 and
mouse_y > 0 and mouse_y < board.Y+1):
xpos = mouse_x - 1 xpos = mouse_x - 1
ypos = mouse_y - 1 ypos = mouse_y - 1
board.toggle(ypos, xpos) board.toggle(ypos, xpos)
@ -245,6 +247,5 @@ def keyloop(stdscr):
def main(stdscr): def main(stdscr):
keyloop(stdscr) # Enter the main loop keyloop(stdscr) # Enter the main loop
if __name__ == '__main__': if __name__ == '__main__':
curses.wrapper(main) curses.wrapper(main)

View File

@ -1,4 +1,8 @@
#! /usr/bin/env python3 #!/usr/bin/env python3
"""
Markov chain simulation of words or characters.
"""
class Markov: class Markov:
def __init__(self, histsize, choice): def __init__(self, histsize, choice):

View File

@ -1,13 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
#
# Send/receive UDP multicast packets. """
# Requires that your OS kernel supports IP multicast. Send/receive UDP multicast packets.
# Requires that your OS kernel supports IP multicast.
# Usage:
# mcast -s (sender, IPv4) Usage:
# mcast -s -6 (sender, IPv6) mcast -s (sender, IPv4)
# mcast (receivers, IPv4) mcast -s -6 (sender, IPv6)
# mcast -6 (receivers, IPv6) mcast (receivers, IPv4)
mcast -6 (receivers, IPv6)
"""
MYPORT = 8123 MYPORT = 8123
MYGROUP_4 = '225.0.0.250' MYGROUP_4 = '225.0.0.250'

View File

@ -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. The (well-known) problem is due to Niklaus Wirth.
This solution is inspired by Dijkstra (Structured Programming). It is This solution is inspired by Dijkstra (Structured Programming). It is
a classic recursive backtracking approach. a classic recursive backtracking approach.
""" """
N = 8 # Default; command line overrides N = 8 # Default; command line overrides

View File

@ -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 import sys
from socket import socket, AF_INET, SOCK_STREAM, SHUT_WR from socket import socket, AF_INET, SOCK_STREAM, SHUT_WR

View File

@ -1,9 +1,12 @@
#! /usr/bin/env python3 #!/usr/bin/env python3
# Remote python server. """
# Execute Python commands remotely and send output back. Remote python server.
# WARNING: This version has a gaping security hole -- it accepts requests Execute Python commands remotely and send output back.
# from any host on the Internet!
WARNING: This version has a gaping security hole -- it accepts requests
from any host on the Internet!
"""
import sys import sys
from socket import socket, AF_INET, SOCK_STREAM from socket import socket, AF_INET, SOCK_STREAM

7
Tools/demo/sortvisu.py Normal file → Executable file
View File

@ -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'': 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 - and a ``driver'' class which can be used as a Grail applet or as a
stand-alone application. stand-alone application.
""" """
from tkinter import * from tkinter import *
import random import random
XGRID = 10 XGRID = 10
YGRID = 10 YGRID = 10
WIDTH = 6 WIDTH = 6

6
Tools/demo/ss1.py Normal file → Executable file
View File

@ -1,4 +1,8 @@
"""SS1 -- a spreadsheet.""" #!/usr/bin/env python3
"""
SS1 -- a spreadsheet-like application.
"""
import os import os
import re import re

12
Tools/demo/Vec.py → Tools/demo/vector.py Normal file → Executable file
View File

@ -1,7 +1,13 @@
class Vec: #!/usr/bin/env python3
""" A simple vector class
Instances of the Vec class can be constructed from numbers """
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) >>> a = Vec(1, 2, 3)
>>> b = Vec(3, 2, 1) >>> b = Vec(3, 2, 1)

View File

@ -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) useful while building, extending or managing Python. Some (e.g., dutree or lll)
are also generally useful UNIX tools. are also generally useful UNIX tools.
See also the Demo/scripts directory!
2to3 Main script for running the 2to3 conversion tool 2to3 Main script for running the 2to3 conversion tool
analyze_dxp.py Analyzes the result of sys.getdxp() analyze_dxp.py Analyzes the result of sys.getdxp()
byext.py Print lines/words/chars stats of files by extension byext.py Print lines/words/chars stats of files by extension