diff --git a/Tools/demo/README b/Tools/demo/README new file mode 100644 index 00000000000..e914358a26d --- /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/beer.py b/Tools/demo/beer.py index 56eec7b0cbb..af58380e0f5 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 old mode 100644 new mode 100755 similarity index 59% rename from Tools/demo/Eiffel.py rename to Tools/demo/eiffel.py index 15fa58a7003..3a282244d40 --- a/Tools/demo/Eiffel.py +++ b/Tools/demo/eiffel.py @@ -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 class EiffelBaseMetaClass(type): def __new__(meta, name, bases, dict): meta.convert_methods(dict) - return super(EiffelBaseMetaClass, meta).__new__(meta, name, bases, - dict) + return super(EiffelBaseMetaClass, meta).__new__( + meta, name, bases, dict) @classmethod def convert_methods(cls, dict): @@ -31,6 +38,7 @@ class EiffelBaseMetaClass(type): 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 @@ -39,16 +47,17 @@ class EiffelMetaClass1(EiffelBaseMetaClass): def method(self, *args, **kwargs): if pre: pre(self, *args, **kwargs) - x = func(self, *args, **kwargs) + rv = func(self, *args, **kwargs) if post: - post(self, x, *args, **kwargs) - return x + post(self, rv, *args, **kwargs) + return rv if func.__doc__: method.__doc__ = func.__doc__ return method + class EiffelMethodWrapper: def __init__(self, inst, descr): @@ -58,7 +67,8 @@ class EiffelMethodWrapper: def __call__(self, *args, **kwargs): return self._descr.callmethod(self._inst, args, kwargs) -class EiffelDescriptor(object): + +class EiffelDescriptor: def __init__(self, func, pre, post): self._func = func @@ -79,63 +89,58 @@ class EiffelDescriptor(object): 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): +class Tests(unittest.TestCase): - def m(self, arg): - """Make it a little larger""" - return arg + 1 + def testEiffelMetaClass1(self): + self._test(EiffelMetaClass1) - def m2(self, arg): - """Make it a little larger""" - return arg + 1 + def testEiffelMetaClass2(self): + self._test(EiffelMetaClass2) - def m2_pre(self, arg): - assert arg > 0 + def _test(self, metaclass): + class Eiffel(metaclass=metaclass): + pass - def m2_post(self, result, arg): - assert result > arg + class Test(Eiffel): + def m(self, arg): + """Make it a little larger""" + return arg + 1 - 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 + def m2(self, arg): + """Make it a little larger""" + return arg + 1 - t = Test() - t.m(1) - t.m2(1) - try: - t.m2(0) - except AssertionError: - pass - else: - assert False + 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) - 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) + unittest.main() diff --git a/Tools/demo/hanoi.py b/Tools/demo/hanoi.py old mode 100644 new mode 100755 index 34a0bbadd33..dad02342ae3 --- 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 3cbc053faeb..dfb9ab87c2b 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 7c08bdba678..7a0720fa7c3 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 6ce7c6d4068..924c7c3e80e 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 ffd4bea3a44..dcc1bae1ab3 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/scripts/redemo.py b/Tools/demo/redemo.py similarity index 100% rename from Tools/scripts/redemo.py rename to Tools/demo/redemo.py diff --git a/Tools/demo/rpython.py b/Tools/demo/rpython.py index e9657203df8..5e7bc0a27d1 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 fe24b3df94d..9ffe13ab4fe 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 417312181b0..8447bc757e6 --- 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 8b074895e49..2d1e49058c8 --- 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/Vec.py b/Tools/demo/vector.py old mode 100644 new mode 100755 similarity index 86% rename from Tools/demo/Vec.py rename to Tools/demo/vector.py index 787af6962c1..da5b3891d18 --- a/Tools/demo/Vec.py +++ b/Tools/demo/vector.py @@ -1,7 +1,13 @@ -class Vec: - """ A simple vector class +#!/usr/bin/env python3 - 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) >>> b = Vec(3, 2, 1) diff --git a/Tools/scripts/README b/Tools/scripts/README index 546ab21ec22..8c02529a9ff 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