[Python-checkins] CVS: python/dist/src/Lib/test test_fileinput.py,NONE,1.1.2.1 test_socketserver.py,NONE,1.3.2.1 test_uu.py,NONE,1.1.2.1 test_cfgparser.py,1.7,1.7.6.1 test_gc.py,1.7,1.7.6.1 test_generators.py,1.17.2.3,1.17.2.4 test_pow.py,1.7,1.7.6.1 test_scope.py,1.14.4.1,1.14.4.2 test_sundry.py,1.4,1.4.4.1

Tim Peters tim_one@users.sourceforge.net
Sat, 14 Jul 2001 00:47:37 -0700


Update of /cvsroot/python/python/dist/src/Lib/test
In directory usw-pr-cvs1:/tmp/cvs-serv29618/descr/dist/src/Lib/test

Modified Files:
      Tag: descr-branch
	test_cfgparser.py test_gc.py test_generators.py test_pow.py 
	test_scope.py test_sundry.py 
Added Files:
      Tag: descr-branch
	test_fileinput.py test_socketserver.py test_uu.py 
Log Message:
Merge of trunk tag date2001-07-13 into descr-branch.  See PLAN.txt.


--- NEW FILE: test_fileinput.py ---
'''
Tests for fileinput module.
Nick Mathewson
'''

from test_support import verify, verbose, TESTFN
import sys, os, re
from StringIO import StringIO
from fileinput import FileInput

# The fileinput module has 2 interfaces: the FileInput class which does
# all the work, and a few functions (input, etc.) that use a global _state
# variable.  We only test the FileInput class, since the other functions
# only provide a thin facade over FileInput.

# Write lines (a list of lines) to temp file number i, and return the
# temp file's name.
def writeTmp(i, lines):
    name = TESTFN + str(i)
    f = open(name, 'w')
    f.writelines(lines)
    f.close()
    return name

pat = re.compile(r'LINE (\d+) OF FILE (\d+)')

def remove_tempfiles(*names):
    for name in names:
        try:
            os.unlink(name)
        except:
            pass

def runTests(t1, t2, t3, t4, bs=0, round=0):
    start = 1 + round*6
    if verbose:
        print '%s. Simple iteration (bs=%s)' % (start+0, bs)
    fi = FileInput(files=(t1, t2, t3, t4), bufsize=bs)
    lines = list(fi)
    fi.close()
    verify(len(lines) == 31)
    verify(lines[4] == 'Line 5 of file 1\n')
    verify(lines[30] == 'Line 1 of file 4\n')
    verify(fi.lineno() == 31)
    verify(fi.filename() == t4)

    if verbose:
        print '%s. Status variables (bs=%s)' % (start+1, bs)
    fi = FileInput(files=(t1, t2, t3, t4), bufsize=bs)
    s = "x"
    while s and s != 'Line 6 of file 2\n':
        s = fi.readline()
    verify(fi.filename() == t2)
    verify(fi.lineno() == 21)
    verify(fi.filelineno() == 6)
    verify(not fi.isfirstline())
    verify(not fi.isstdin())

    if verbose:
        print '%s. Nextfile (bs=%s)' % (start+2, bs)
    fi.nextfile()
    verify(fi.readline() == 'Line 1 of file 3\n')
    verify(fi.lineno() == 22)
    fi.close()

    if verbose:
        print '%s. Stdin (bs=%s)' % (start+3, bs)
    fi = FileInput(files=(t1, t2, t3, t4, '-'), bufsize=bs)
    savestdin = sys.stdin
    try:
        sys.stdin = StringIO("Line 1 of stdin\nLine 2 of stdin\n")
        lines = list(fi)
        verify(len(lines) == 33)
        verify(lines[32] == 'Line 2 of stdin\n')
        verify(fi.filename() == '<stdin>')
        fi.nextfile()
    finally:
        sys.stdin = savestdin

    if verbose:
        print '%s. Boundary conditions (bs=%s)' % (start+4, bs)
    fi = FileInput(files=(t1, t2, t3, t4), bufsize=bs)
    verify(fi.lineno() == 0)
    verify(fi.filename() == None)
    fi.nextfile()
    verify(fi.lineno() == 0)
    verify(fi.filename() == None)

    if verbose:
        print '%s. Inplace (bs=%s)' % (start+5, bs)
    savestdout = sys.stdout
    try:
        fi = FileInput(files=(t1, t2, t3, t4), inplace=1, bufsize=bs)
        for line in fi:
            line = line[:-1].upper()
            print line
        fi.close()
    finally:
        sys.stdout = savestdout

    fi = FileInput(files=(t1, t2, t3, t4), bufsize=bs)
    for line in fi:
        verify(line[-1] == '\n')
        m = pat.match(line[:-1])
        verify(m != None)
        verify(int(m.group(1)) == fi.filelineno())
    fi.close()


def writeFiles():
    global t1, t2, t3, t4
    t1 = writeTmp(1, ["Line %s of file 1\n" % (i+1) for i in range(15)])
    t2 = writeTmp(2, ["Line %s of file 2\n" % (i+1) for i in range(10)])
    t3 = writeTmp(3, ["Line %s of file 3\n" % (i+1) for i in range(5)])
    t4 = writeTmp(4, ["Line %s of file 4\n" % (i+1) for i in range(1)])

# First, run the tests with default and teeny buffer size.
for round, bs in (0, 0), (1, 30):
    try:
        writeFiles()
        runTests(t1, t2, t3, t4, bs, round)
    finally:
        remove_tempfiles(t1, t2, t3, t4)

# Next, check for proper behavior with 0-byte files.
if verbose:
    print "13. 0-byte files"
try:
    t1 = writeTmp(1, [""])
    t2 = writeTmp(2, [""])
    t3 = writeTmp(3, ["The only line there is.\n"])
    t4 = writeTmp(4, [""])
    fi = FileInput(files=(t1, t2, t3, t4))
    line = fi.readline()
    verify(line == 'The only line there is.\n')
    verify(fi.lineno() == 1)
    verify(fi.filelineno() == 1)
    verify(fi.filename() == t3)
    line = fi.readline()
    verify(not line)
    verify(fi.lineno() == 1)
    verify(fi.filelineno() == 0)
    verify(fi.filename() == t4)
    fi.close()
finally:
    remove_tempfiles(t1, t2, t3, t4)

if verbose:
    print "14. Files that don't end with newline"
try:
    t1 = writeTmp(1, ["A\nB\nC"])
    t2 = writeTmp(2, ["D\nE\nF"])
    fi = FileInput(files=(t1, t2))
    lines = list(fi)
    verify(lines == ["A\n", "B\n", "C", "D\n", "E\n", "F"])
    verify(fi.filelineno() == 3)
    verify(fi.lineno() == 6)
finally:
    remove_tempfiles(t1, t2)

--- NEW FILE: test_socketserver.py ---
# Test suite for SocketServer.py

# XXX This must be run manually -- somehow the I/O redirection of the
# regression test breaks the test.

from test_support import verbose, verify, TESTFN, TestSkipped
if not verbose:
    raise TestSkipped, "test_socketserver can only be run manually"

from SocketServer import *
import socket
import select
import time
import threading
import os

NREQ = 3
DELAY = 0.5

class MyMixinHandler:
    def handle(self):
        time.sleep(DELAY)
        line = self.rfile.readline()
        time.sleep(DELAY)
        self.wfile.write(line)

class MyStreamHandler(MyMixinHandler, StreamRequestHandler):
    pass

class MyDatagramHandler(MyMixinHandler, DatagramRequestHandler):
    pass

class MyMixinServer:
    def serve_a_few(self):
        for i in range(NREQ):
            self.handle_request()
    def handle_error(self, request, client_address):
        self.close_request(request)
        self.server_close()
        raise

teststring = "hello world\n"

def receive(sock, n, timeout=20):
    r, w, x = select.select([sock], [], [], timeout)
    if sock in r:
        return sock.recv(n)
    else:
        raise RuntimeError, "timed out on %s" % `sock`

def testdgram(proto, addr):
    s = socket.socket(proto, socket.SOCK_DGRAM)
    s.sendto(teststring, addr)
    buf = data = receive(s, 100)
    while data and '\n' not in buf:
        data = receive(s, 100)
        buf += data
    verify(buf == teststring)
    s.close()

def teststream(proto, addr):
    s = socket.socket(proto, socket.SOCK_STREAM)
    s.connect(addr)
    s.send(teststring)
    buf = data = receive(s, 100)
    while data and '\n' not in buf:
        data = receive(s, 100)
        buf += data
    verify(buf == teststring)
    s.close()

class ServerThread(threading.Thread):
    def __init__(self, addr, svrcls, hdlrcls):
        threading.Thread.__init__(self)
        self.__addr = addr
        self.__svrcls = svrcls
        self.__hdlrcls = hdlrcls
    def run(self):
        class svrcls(MyMixinServer, self.__svrcls):
            pass
        if verbose: print "thread: creating server"
        svr = svrcls(self.__addr, self.__hdlrcls)
        if verbose: print "thread: serving three times"
        svr.serve_a_few()
        if verbose: print "thread: done"

seed = 0
def pickport():
    global seed
    seed += 1
    return 10000 + (os.getpid() % 1000)*10 + seed

host = "localhost"
testfiles = []
def pickaddr(proto):
    if proto == socket.AF_INET:
        return (host, pickport())
    else:
        fn = TESTFN + str(pickport())
        testfiles.append(fn)
        return fn

def cleanup():
    for fn in testfiles:
        try:
            os.remove(fn)
        except os.error:
            pass
    testfiles[:] = []

def testloop(proto, servers, hdlrcls, testfunc):
    for svrcls in servers:
        addr = pickaddr(proto)
        if verbose:
            print "ADDR =", addr
            print "CLASS =", svrcls
        t = ServerThread(addr, svrcls, hdlrcls)
        if verbose: print "server created"
        t.start()
        if verbose: print "server running"
        for i in range(NREQ):
            time.sleep(DELAY)
            if verbose: print "test client", i
            testfunc(proto, addr)
        if verbose: print "waiting for server"
        t.join()
        if verbose: print "done"

tcpservers = [TCPServer, ThreadingTCPServer]
if hasattr(os, 'fork'):
    tcpservers.append(ForkingTCPServer)
udpservers = [UDPServer, ThreadingUDPServer]
if hasattr(os, 'fork'):
    udpservers.append(ForkingUDPServer)

if not hasattr(socket, 'AF_UNIX'):
    streamservers = []
    dgramservers = []
else:
    class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass
    streamservers = [UnixStreamServer, ThreadingUnixStreamServer,
                     ForkingUnixStreamServer]
    class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass
    dgramservers = [UnixDatagramServer, ThreadingUnixDatagramServer,
                    ForkingUnixDatagramServer]

def testall():
    testloop(socket.AF_INET, tcpservers, MyStreamHandler, teststream)
    testloop(socket.AF_INET, udpservers, MyDatagramHandler, testdgram)
    if hasattr(socket, 'AF_UNIX'):
        testloop(socket.AF_UNIX, streamservers, MyStreamHandler, teststream)
        # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
        # client address so this cannot work:
        ##testloop(socket.AF_UNIX, dgramservers, MyDatagramHandler, testdgram)

def main():
    try:
        testall()
    finally:
        cleanup()

main()

--- NEW FILE: test_uu.py ---
"""
Tests for uu module.
Nick Mathewson
"""

from test_support import verify, TestFailed, verbose, TESTFN
import sys, os
import uu
from StringIO import StringIO

teststr = "The smooth-scaled python crept over the sleeping dog\n"
expected = """\
M5&AE('-M;V]T:\"US8V%L960@<'ET:&]N(&-R97!T(&]V97(@=&AE('-L965P
(:6YG(&1O9PH """
encoded1 = "begin 666 t1\n"+expected+"\n \nend\n"
if verbose:
    print '1. encode file->file'
inp = StringIO(teststr)
out = StringIO()
uu.encode(inp, out, "t1")
verify(out.getvalue() == encoded1)
inp = StringIO(teststr)
out = StringIO()
uu.encode(inp, out, "t1", 0644)
verify(out.getvalue() == "begin 644 t1\n"+expected+"\n \nend\n")

if verbose:
    print '2. decode file->file'
inp = StringIO(encoded1)
out = StringIO()
uu.decode(inp, out)
verify(out.getvalue() == teststr)
inp = StringIO("""UUencoded files may contain many lines,
                  even some that have 'begin' in them.\n"""+encoded1)
out = StringIO()
uu.decode(inp, out)
verify(out.getvalue() == teststr)

stdinsave = sys.stdin
stdoutsave = sys.stdout
try:
    if verbose:
        print '3. encode stdin->stdout'
    sys.stdin = StringIO(teststr)
    sys.stdout = StringIO()
    uu.encode("-", "-", "t1", 0666)
    verify(sys.stdout.getvalue() == encoded1)
    if verbose:
        print >>stdoutsave, '4. decode stdin->stdout'
    sys.stdin = StringIO(encoded1)
    sys.stdout = StringIO()
    uu.decode("-", "-")
    verify(sys.stdout.getvalue() == teststr)
finally:
    sys.stdin = stdinsave
    sys.stdout = stdoutsave

if verbose:
    print '5. encode file->file'
tmpIn  = TESTFN + "i"
tmpOut = TESTFN + "o"
try:
    fin = open(tmpIn, 'w')
    fin.write(teststr)
    fin.close()

    fin = open(tmpIn, 'r')
    fout = open(tmpOut, 'w')
    uu.encode(fin, fout, tmpIn, mode=0644)
    fin.close()
    fout.close()

    fout = open(tmpOut, 'r')
    s = fout.read()
    fout.close()
    verify(s == 'begin 644 ' + tmpIn + '\n' + expected + '\n \nend\n')

    os.unlink(tmpIn)
    if verbose:
        print '6. decode file-> file'
    uu.decode(tmpOut)
    fin = open(tmpIn, 'r')
    s = fin.read()
    fin.close()
    verify(s == teststr)
    # XXX is there an xp way to verify the mode?

finally:
    try:
        fin.close()
    except:
        pass
    try:
        fout.close()
    except:
        pass
    try:
        os.unlink(tmpIn)
    except:
        pass
    try:
        os.unlink(tmpOut)
    except:
        pass

if verbose:
    print '7. error: truncated input'
inp = StringIO("begin 644 t1\n"+expected)
out = StringIO()
try:
    uu.decode(inp, out)
    raise TestFailed("No exception thrown")
except uu.Error, e:
    verify(str(e) == 'Truncated input file')

if verbose:
    print '8. error: missing begin'
inp = StringIO("")
out = StringIO()
try:
    uu.decode(inp, out)
    raise TestFailed("No exception thrown")
except uu.Error, e:
    verify(str(e) == 'No valid begin line found in input file')

Index: test_cfgparser.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_cfgparser.py,v
retrieving revision 1.7
retrieving revision 1.7.6.1
diff -C2 -r1.7 -r1.7.6.1
*** test_cfgparser.py	2001/02/26 21:55:34	1.7
--- test_cfgparser.py	2001/07/14 07:47:34	1.7.6.1
***************
*** 71,74 ****
--- 71,81 ----
      verify(cf.options("a") == [])
  
+     # SF bug #432369:
+     cf = ConfigParser.ConfigParser()
+     sio = StringIO.StringIO("[MySection]\nOption: first line\n\tsecond line\n")
+     cf.readfp(sio)
+     verify(cf.options("MySection") == ["option"])
+     verify(cf.get("MySection", "Option") == "first line\nsecond line")
+ 
  
  def interpolation(src):

Index: test_gc.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_gc.py,v
retrieving revision 1.7
retrieving revision 1.7.6.1
diff -C2 -r1.7 -r1.7.6.1
*** test_gc.py	2001/01/17 19:11:13	1.7
--- test_gc.py	2001/07/14 07:47:34	1.7.6.1
***************
*** 1,3 ****
--- 1,4 ----
  from test_support import verify, verbose, TestFailed
+ import sys
  import gc
  
***************
*** 108,111 ****
--- 109,121 ----
          raise TestFailed
  
+ def test_frame():
+     def f():
+         frame = sys._getframe()
+     gc.collect()
+     f()
+     if gc.collect() != 1:
+         raise TestFailed
+ 
+ 
  def test_saveall():
      # Verify that cyclic garbage like lists show up in gc.garbage if the
***************
*** 153,156 ****
--- 163,167 ----
      run_test("methods", test_method)
      run_test("functions", test_function)
+     run_test("frames", test_frame)
      run_test("finalizers", test_finalizer)
      run_test("__del__", test_del)

Index: test_generators.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_generators.py,v
retrieving revision 1.17.2.3
retrieving revision 1.17.2.4
diff -C2 -r1.17.2.3 -r1.17.2.4
*** test_generators.py	2001/07/13 21:49:33	1.17.2.3
--- test_generators.py	2001/07/14 07:47:34	1.17.2.4
***************
*** 1,4 ****
- from __future__ import nested_scopes
- 
  tutorial_tests = """
  Let's try a simple generator:
--- 1,2 ----
***************
*** 50,54 ****
      >>> def f():
      ...     yield 1
!     ...     return
      ...     yield 2 # never reached
      ...
--- 48,52 ----
      >>> def f():
      ...     yield 1
!     ...     raise StopIteration
      ...     yield 2 # never reached
      ...
***************
*** 444,450 ****
  ...     def __str__(self):
  ...         return self.name
- ...
- ...     def clear(self):
- ...         self.__dict__.clear()
  
  >>> names = "ABCDEFGHIJKLM"
--- 442,445 ----
***************
*** 491,496 ****
  merged A into G
  A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G
- >>> for s in sets:  # XXX memory leak without this
- ...    s.clear()
  """
  
--- 486,489 ----
***************
*** 605,611 ****
  ...             sofar.append(fetch())
  ...         return sofar[i]
- ...
- ...     def clear(self):
- ...         self.__dict__.clear()
  
  >>> def m235():
--- 598,601 ----
***************
*** 621,625 ****
  
  Print as many of these as you like -- *this* implementation is memory-
! efficient.  XXX Except that it leaks unless you clear the dict!
  
  >>> m235 = LazyList(m235())
--- 611,615 ----
  
  Print as many of these as you like -- *this* implementation is memory-
! efficient.
  
  >>> m235 = LazyList(m235())
***************
*** 632,638 ****
  [400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
  
- >>> m235.clear()  # XXX memory leak without this
  
- 
  Ye olde Fibonacci generator, LazyList style.
  
--- 622,626 ----
***************
*** 657,662 ****
  >>> firstn(iter(fib), 17)
  [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]
- 
- >>> fib.clear()  # XXX memory leak without this
  """
  
--- 645,648 ----
***************
*** 924,928 ****
  # NOTE WELL:  This allows large problems to be solved with only trivial
  # demands on stack space.  Without explicitly resumable generators, this is
! # much harder to achieve.
  
  def flat_conjoin(gs):  # rename to conjoin to run tests with this instead
--- 910,915 ----
  # NOTE WELL:  This allows large problems to be solved with only trivial
  # demands on stack space.  Without explicitly resumable generators, this is
! # much harder to achieve.  OTOH, this is much slower (up to a factor of 2)
! # than the fancy unrolled recursive conjoin.
  
  def flat_conjoin(gs):  # rename to conjoin to run tests with this instead
***************
*** 930,954 ****
      values = [None] * n
      iters  = [None] * n
      i = 0
!     while i >= 0:
!         # Need a fresh iterator.
!         if i >= n:
!             yield values
!             # Backtrack.
!             i -= 1
          else:
!             iters[i] = gs[i]().next
  
!         # Need next value from current iterator.
          while i >= 0:
              try:
                  values[i] = iters[i]()
!             except StopIteration:
!                 # Backtrack.
!                 i -= 1
!             else:
!                 # Start fresh at next level.
                  i += 1
                  break
  
  # A conjoin-based N-Queens solver.
--- 917,949 ----
      values = [None] * n
      iters  = [None] * n
+     _StopIteration = StopIteration  # make local because caught a *lot*
      i = 0
!     while 1:
!         # Descend.
!         try:
!             while i < n:
!                 it = iters[i] = gs[i]().next
!                 values[i] = it()
!                 i += 1
!         except _StopIteration:
!             pass
          else:
!             assert i == n
!             yield values
  
!         # Backtrack until an older iterator can be resumed.
!         i -= 1
          while i >= 0:
              try:
                  values[i] = iters[i]()
!                 # Success!  Start fresh at next level.
                  i += 1
                  break
+             except _StopIteration:
+                 # Continue backtracking.
+                 i -= 1
+         else:
+             assert i < 0
+             break
  
  # A conjoin-based N-Queens solver.
***************
*** 1007,1035 ****
  # (e.g., when used with flat_conjoin above, and passing hard=1 to the
  # constructor, a 200x200 Knight's Tour was found quickly -- note that we're
! # creating 10s of thousands of generators then!), so goes on at some length
  
  class Knights:
!     def __init__(self, n, hard=0):
!         self.n = n
! 
!         def coords2index(i, j):
!             return i*n + j
  
!         offsets = [( 1,  2), ( 2,  1), ( 2, -1), ( 1, -2),
!                    (-1, -2), (-2, -1), (-2,  1), (-1,  2)]
!         succs = []
!         for i in range(n):
!             for j in range(n):
!                 s = [coords2index(i+io, j+jo) for io, jo in offsets
!                                               if 0 <= i+io < n and
!                                                  0 <= j+jo < n]
!                 succs.append(s)
!                 del s
!         del offsets
  
!         free   = [0] * n**2     # 0 if occupied, 1 if visited
!         nexits = free[:]        # number of free successors
! 
!         def decrexits(i0):
              # If we remove all exits from a free square, we're dead:
              # even if we move to it next, we can't leave it again.
--- 1002,1020 ----
  # (e.g., when used with flat_conjoin above, and passing hard=1 to the
  # constructor, a 200x200 Knight's Tour was found quickly -- note that we're
! # creating 10s of thousands of generators then!), and is lengthy.
  
  class Knights:
!     def __init__(self, m, n, hard=0):
!         self.m, self.n = m, n
  
!         # solve() will set up succs[i] to be a list of square #i's
!         # successors.
!         succs = self.succs = []
! 
!         # Remove i0 from each of its successor's successor lists, i.e.
!         # successors can't go back to i0 again.  Return 0 if we can
!         # detect this makes a solution impossible, else return 1.
  
!         def remove_from_successors(i0, len=len):
              # If we remove all exits from a free square, we're dead:
              # even if we move to it next, we can't leave it again.
***************
*** 1042,1120 ****
              ne0 = ne1 = 0
              for i in succs[i0]:
!                 if free[i]:
!                     e = nexits[i] - 1
!                     nexits[i] = e
!                     if e == 0:
!                         ne0 += 1
!                     elif e == 1:
!                         ne1 += 1
              return ne0 == 0 and ne1 < 2
  
!         def increxits(i0):
              for i in succs[i0]:
!                 if free[i]:
!                     nexits[i] += 1
  
          # Generate the first move.
          def first():
!             if n < 1:
                  return
  
-             # Initialize board structures.
-             for i in xrange(n**2):
-                 free[i] = 1
-                 nexits[i] = len(succs[i])
- 
              # Since we're looking for a cycle, it doesn't matter where we
              # start.  Starting in a corner makes the 2nd move easy.
!             corner = coords2index(0, 0)
!             free[corner] = 0
!             decrexits(corner)
              self.lastij = corner
              yield corner
!             increxits(corner)
!             free[corner] = 1
  
          # Generate the second moves.
          def second():
!             corner = coords2index(0, 0)
              assert self.lastij == corner  # i.e., we started in the corner
!             if n < 3:
                  return
!             assert nexits[corner] == len(succs[corner]) == 2
!             assert coords2index(1, 2) in succs[corner]
!             assert coords2index(2, 1) in succs[corner]
              # Only two choices.  Whichever we pick, the other must be the
!             # square picked on move n**2, as it's the only way to get back
              # to (0, 0).  Save its index in self.final so that moves before
              # the last know it must be kept free.
              for i, j in (1, 2), (2, 1):
!                 this, final = coords2index(i, j), coords2index(3-i, 3-j)
!                 assert free[this] and free[final]
                  self.final = final
-                 nexits[final] += 1  # it has an exit back to 0,0
  
!                 free[this] = 0
!                 decrexits(this)
                  self.lastij = this
                  yield this
!                 increxits(this)
!                 free[this] = 1
! 
!                 nexits[final] -= 1
  
!         # Generate moves 3 thru n**2-1.
!         def advance():
              # If some successor has only one exit, must take it.
              # Else favor successors with fewer exits.
              candidates = []
              for i in succs[self.lastij]:
!                 if free[i]:
!                     e = nexits[i]
!                     assert e > 0, "else decrexits() pruning flawed"
!                     if e == 1:
!                         candidates = [(e, i)]
!                         break
!                     candidates.append((e, i))
              else:
                  candidates.sort()
--- 1027,1095 ----
              ne0 = ne1 = 0
              for i in succs[i0]:
!                 s = succs[i]
!                 s.remove(i0)
!                 e = len(s)
!                 if e == 0:
!                     ne0 += 1
!                 elif e == 1:
!                     ne1 += 1
              return ne0 == 0 and ne1 < 2
+ 
+         # Put i0 back in each of its successor's successor lists.
  
!         def add_to_successors(i0):
              for i in succs[i0]:
!                 succs[i].append(i0)
  
          # Generate the first move.
          def first():
!             if m < 1 or n < 1:
                  return
  
              # Since we're looking for a cycle, it doesn't matter where we
              # start.  Starting in a corner makes the 2nd move easy.
!             corner = self.coords2index(0, 0)
!             remove_from_successors(corner)
              self.lastij = corner
              yield corner
!             add_to_successors(corner)
  
          # Generate the second moves.
          def second():
!             corner = self.coords2index(0, 0)
              assert self.lastij == corner  # i.e., we started in the corner
!             if m < 3 or n < 3:
                  return
!             assert len(succs[corner]) == 2
!             assert self.coords2index(1, 2) in succs[corner]
!             assert self.coords2index(2, 1) in succs[corner]
              # Only two choices.  Whichever we pick, the other must be the
!             # square picked on move m*n, as it's the only way to get back
              # to (0, 0).  Save its index in self.final so that moves before
              # the last know it must be kept free.
              for i, j in (1, 2), (2, 1):
!                 this  = self.coords2index(i, j)
!                 final = self.coords2index(3-i, 3-j)
                  self.final = final
  
!                 remove_from_successors(this)
!                 succs[final].append(corner)
                  self.lastij = this
                  yield this
!                 succs[final].remove(corner)
!                 add_to_successors(this)
  
!         # Generate moves 3 thru m*n-1.
!         def advance(len=len):
              # If some successor has only one exit, must take it.
              # Else favor successors with fewer exits.
              candidates = []
              for i in succs[self.lastij]:
!                 e = len(succs[i])
!                 assert e > 0, "else remove_from_successors() pruning flawed"
!                 if e == 1:
!                     candidates = [(e, i)]
!                     break
!                 candidates.append((e, i))
              else:
                  candidates.sort()
***************
*** 1122,1138 ****
              for e, i in candidates:
                  if i != self.final:
!                     if decrexits(i):
!                         free[i] = 0
                          self.lastij = i
                          yield i
!                         free[i] = 1
!                     increxits(i)
  
!         # Generate moves 3 thru n**2-1.  Alternative version using a
          # stronger (but more expensive) heuristic to order successors.
!         # Since the # of backtracking levels is n**2, a poor move early on
!         # can take eons to undo.  Smallest n for which this matters a lot is
!         # n==52.
!         def advance_hard(midpoint=(n-1)/2.0):
              # If some successor has only one exit, must take it.
              # Else favor successors with fewer exits.
--- 1097,1111 ----
              for e, i in candidates:
                  if i != self.final:
!                     if remove_from_successors(i):
                          self.lastij = i
                          yield i
!                     add_to_successors(i)
  
!         # Generate moves 3 thru m*n-1.  Alternative version using a
          # stronger (but more expensive) heuristic to order successors.
!         # Since the # of backtracking levels is m*n, a poor move early on
!         # can take eons to undo.  Smallest square board for which this
!         # matters a lot is 52x52.
!         def advance_hard(vmid=(m-1)/2.0, hmid=(n-1)/2.0, len=len):
              # If some successor has only one exit, must take it.
              # Else favor successors with fewer exits.
***************
*** 1141,1153 ****
              candidates = []
              for i in succs[self.lastij]:
!                 if free[i]:
!                     e = nexits[i]
!                     assert e > 0, "else decrexits() pruning flawed"
!                     if e == 1:
!                         candidates = [(e, 0, i)]
!                         break
!                     i1, j1 = divmod(i, n)
!                     d = (i1 - midpoint)**2 + (j1 - midpoint)**2
!                     candidates.append((e, -d, i))
              else:
                  candidates.sort()
--- 1114,1125 ----
              candidates = []
              for i in succs[self.lastij]:
!                 e = len(succs[i])
!                 assert e > 0, "else remove_from_successors() pruning flawed"
!                 if e == 1:
!                     candidates = [(e, 0, i)]
!                     break
!                 i1, j1 = self.index2coords(i)
!                 d = (i1 - vmid)**2 + (j1 - hmid)**2
!                 candidates.append((e, -d, i))
              else:
                  candidates.sort()
***************
*** 1155,1164 ****
              for e, d, i in candidates:
                  if i != self.final:
!                     if decrexits(i):
!                         free[i] = 0
                          self.lastij = i
                          yield i
!                         free[i] = 1
!                     increxits(i)
  
          # Generate the last move.
--- 1127,1134 ----
              for e, d, i in candidates:
                  if i != self.final:
!                     if remove_from_successors(i):
                          self.lastij = i
                          yield i
!                     add_to_successors(i)
  
          # Generate the last move.
***************
*** 1167,1192 ****
              yield self.final
  
!         if n <= 1:
!             self.rowgenerators = [first]
          else:
!             self.rowgenerators = [first, second] + \
!                 [hard and advance_hard or advance] * (n**2 - 3) + \
                  [last]
  
      # Generate solutions.
      def solve(self):
!         for x in conjoin(self.rowgenerators):
              yield x
  
      def printsolution(self, x):
!         n = self.n
!         assert len(x) == n**2
!         w = len(str(n**2 + 1))
          format = "%" + str(w) + "d"
  
!         squares = [[None] * n for i in range(n)]
          k = 1
          for i in x:
!             i1, j1 = divmod(i, n)
              squares[i1][j1] = format % k
              k += 1
--- 1137,1188 ----
              yield self.final
  
!         if m*n < 4:
!             self.squaregenerators = [first]
          else:
!             self.squaregenerators = [first, second] + \
!                 [hard and advance_hard or advance] * (m*n - 3) + \
                  [last]
  
+     def coords2index(self, i, j):
+         assert 0 <= i < self.m
+         assert 0 <= j < self.n
+         return i * self.n + j
+ 
+     def index2coords(self, index):
+         assert 0 <= index < self.m * self.n
+         return divmod(index, self.n)
+ 
+     def _init_board(self):
+         succs = self.succs
+         del succs[:]
+         m, n = self.m, self.n
+         c2i = self.coords2index
+ 
+         offsets = [( 1,  2), ( 2,  1), ( 2, -1), ( 1, -2),
+                    (-1, -2), (-2, -1), (-2,  1), (-1,  2)]
+         rangen = range(n)
+         for i in range(m):
+             for j in rangen:
+                 s = [c2i(i+io, j+jo) for io, jo in offsets
+                                      if 0 <= i+io < m and
+                                         0 <= j+jo < n]
+                 succs.append(s)
+ 
      # Generate solutions.
      def solve(self):
!         self._init_board()
!         for x in conjoin(self.squaregenerators):
              yield x
  
      def printsolution(self, x):
!         m, n = self.m, self.n
!         assert len(x) == m*n
!         w = len(str(m*n))
          format = "%" + str(w) + "d"
  
!         squares = [[None] * n for i in range(m)]
          k = 1
          for i in x:
!             i1, j1 = self.index2coords(i)
              squares[i1][j1] = format % k
              k += 1
***************
*** 1194,1198 ****
          sep = "+" + ("-" * w + "+") * n
          print sep
!         for i in range(n):
              row = squares[i]
              print "|" + "|".join(row) + "|"
--- 1190,1194 ----
          sep = "+" + ("-" * w + "+") * n
          print sep
!         for i in range(m):
              row = squares[i]
              print "|" + "|".join(row) + "|"
***************
*** 1290,1294 ****
  20,000 solutions even on a 6x6 board, so don't dare run this to exhaustion.
  
! >>> k = Knights(10)
  >>> LIMIT = 2
  >>> count = 0
--- 1286,1290 ----
  20,000 solutions even on a 6x6 board, so don't dare run this to exhaustion.
  
! >>> k = Knights(10, 10)
  >>> LIMIT = 2
  >>> count = 0
***************
*** 1359,1370 ****
  def test_main():
      import doctest, test_generators
!     if 0:
!         # Temporary block to help track down leaks.  So far, the blame
!         # fell mostly on doctest.  Later:  the only leaks remaining are
!         # in fun_tests, and only if you comment out the two LazyList.clear()
!         # calls.
!         for i in range(10000):
              doctest.master = None
              doctest.testmod(test_generators)
      else:
          doctest.testmod(test_generators)
--- 1355,1363 ----
  def test_main():
      import doctest, test_generators
!     if 0:   # change to 1 to run forever (to check for leaks)
!         while 1:
              doctest.master = None
              doctest.testmod(test_generators)
+             print ".",
      else:
          doctest.testmod(test_generators)

Index: test_pow.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_pow.py,v
retrieving revision 1.7
retrieving revision 1.7.6.1
diff -C2 -r1.7 -r1.7.6.1
*** test_pow.py	2000/12/12 23:11:42	1.7
--- test_pow.py	2001/07/14 07:47:34	1.7.6.1
***************
*** 33,39 ****
                          pow(ii, jj)
                      except ValueError:
!                         pass # taking an int to a neg int power should fail
!                     else:
!                         raise ValueError, "pow(%s, %s) did not fail" % (ii, jj)
  
      for othertype in int, long, float:
--- 33,37 ----
                          pow(ii, jj)
                      except ValueError:
!                         raise ValueError, "pow(%s, %s) failed" % (ii, jj)
  
      for othertype in int, long, float:

Index: test_scope.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_scope.py,v
retrieving revision 1.14.4.1
retrieving revision 1.14.4.2
diff -C2 -r1.14.4.1 -r1.14.4.2
*** test_scope.py	2001/07/07 22:55:29	1.14.4.1
--- test_scope.py	2001/07/14 07:47:34	1.14.4.2
***************
*** 1,4 ****
- from __future__ import nested_scopes
- 
  from test.test_support import verify, TestFailed, check_syntax
  
--- 1,2 ----
***************
*** 180,184 ****
  print "11. unoptimized namespaces"
  
! check_syntax("""from __future__ import nested_scopes
  def unoptimized_clash1(strip):
      def f(s):
--- 178,182 ----
  print "11. unoptimized namespaces"
  
! check_syntax("""\
  def unoptimized_clash1(strip):
      def f(s):
***************
*** 188,192 ****
  """)
  
! check_syntax("""from __future__ import nested_scopes
  def unoptimized_clash2():
      from string import *
--- 186,190 ----
  """)
  
! check_syntax("""\
  def unoptimized_clash2():
      from string import *
***************
*** 196,200 ****
  """)
  
! check_syntax("""from __future__ import nested_scopes
  def unoptimized_clash2():
      from string import *
--- 194,198 ----
  """)
  
! check_syntax("""\
  def unoptimized_clash2():
      from string import *
***************
*** 206,210 ****
  
  # XXX could allow this for exec with const argument, but what's the point
! check_syntax("""from __future__ import nested_scopes
  def error(y):
      exec "a = 1"
--- 204,208 ----
  
  # XXX could allow this for exec with const argument, but what's the point
! check_syntax("""\
  def error(y):
      exec "a = 1"
***************
*** 214,218 ****
  """)
  
! check_syntax("""from __future__ import nested_scopes
  def f(x):
      def g():
--- 212,216 ----
  """)
  
! check_syntax("""\
  def f(x):
      def g():
***************
*** 221,225 ****
  """)
  
! check_syntax("""from __future__ import nested_scopes
  def f():
      def g():
--- 219,223 ----
  """)
  
! check_syntax("""\
  def f():
      def g():

Index: test_sundry.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_sundry.py,v
retrieving revision 1.4
retrieving revision 1.4.4.1
diff -C2 -r1.4 -r1.4.4.1
*** test_sundry.py	2001/04/06 18:59:17	1.4
--- test_sundry.py	2001/07/14 07:47:34	1.4.4.1
***************
*** 31,35 ****
  import encodings
  import filecmp
- import fileinput
  import fnmatch
  import formatter
--- 31,34 ----
***************
*** 97,101 ****
  # can screw up all sorts of things (esp. if it prints!).
  #import user
- import uu
  import webbrowser
  import whichdb
--- 96,99 ----