Kaydet (Commit) 22fff436 authored tarafından Georg Brandl's avatar Georg Brandl

Merged revisions…

Merged revisions 74609,74627,74634,74645,74651,74738,74840,75016,75316-75317,75323-75324,75326,75328,75330,75338,75340-75341,75343,75352-75353,75355,75357,75359 via svnmerge from
svn+ssh://svn.python.org/python/branches/py3k

................
  r74609 | senthil.kumaran | 2009-08-31 18:43:45 +0200 (Mo, 31 Aug 2009) | 3 lines

  Doc fix for issue2637.
................
  r74627 | georg.brandl | 2009-09-02 22:31:26 +0200 (Mi, 02 Sep 2009) | 1 line

  #6819: fix typo.
................
  r74634 | georg.brandl | 2009-09-03 14:34:10 +0200 (Do, 03 Sep 2009) | 9 lines

  Merged revisions 74633 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r74633 | georg.brandl | 2009-09-03 14:31:39 +0200 (Do, 03 Sep 2009) | 1 line

    #6757: complete the list of types that marshal can serialize.
  ........
................
  r74645 | georg.brandl | 2009-09-04 10:07:32 +0200 (Fr, 04 Sep 2009) | 1 line

  #5221: fix related topics: SEQUENCEMETHODS[12] doesnt exist any more.
................
  r74651 | georg.brandl | 2009-09-04 13:20:54 +0200 (Fr, 04 Sep 2009) | 9 lines

  Recorded merge of revisions 74650 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r74650 | georg.brandl | 2009-09-04 13:19:34 +0200 (Fr, 04 Sep 2009) | 1 line

    #5101: add back tests to test_funcattrs that were lost during unittest conversion, and make some PEP8 cleanups.
  ........
................
  r74738 | georg.brandl | 2009-09-09 18:51:05 +0200 (Mi, 09 Sep 2009) | 9 lines

  Merged revisions 74737 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r74737 | georg.brandl | 2009-09-09 18:49:13 +0200 (Mi, 09 Sep 2009) | 1 line

    Properly document copy and deepcopy as functions.
  ........
................
  r74840 | georg.brandl | 2009-09-16 18:40:45 +0200 (Mi, 16 Sep 2009) | 13 lines

  Merged revisions 74838-74839 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r74838 | georg.brandl | 2009-09-16 18:22:12 +0200 (Mi, 16 Sep 2009) | 1 line

    Remove some more boilerplate from the actual tests in test_pdb.
  ........
    r74839 | georg.brandl | 2009-09-16 18:36:39 +0200 (Mi, 16 Sep 2009) | 1 line

    Make the pdb displayhook compatible with the standard displayhook: do not print Nones. Add a test for that.
  ........
................
  r75016 | georg.brandl | 2009-09-22 15:53:14 +0200 (Di, 22 Sep 2009) | 1 line

  #6969: make it explicit that configparser writes/reads text files, and fix the example.
................
  r75316 | georg.brandl | 2009-10-10 23:12:35 +0200 (Sa, 10 Okt 2009) | 9 lines

  Merged revisions 75313 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75313 | georg.brandl | 2009-10-10 23:07:35 +0200 (Sa, 10 Okt 2009) | 1 line

    Bring old demo up-to-date.
  ........
................
  r75317 | georg.brandl | 2009-10-10 23:13:21 +0200 (Sa, 10 Okt 2009) | 9 lines

  Merged revisions 75315 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75315 | georg.brandl | 2009-10-10 23:10:05 +0200 (Sa, 10 Okt 2009) | 1 line

    Remove unneeded "L" suffixes.
  ........
................
  r75323 | georg.brandl | 2009-10-10 23:48:05 +0200 (Sa, 10 Okt 2009) | 9 lines

  Recorded merge of revisions 75321 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75321 | georg.brandl | 2009-10-10 23:43:21 +0200 (Sa, 10 Okt 2009) | 1 line

    Remove outdated comment and fix a few style issues.
  ........
................
  r75324 | georg.brandl | 2009-10-10 23:49:24 +0200 (Sa, 10 Okt 2009) | 9 lines

  Merged revisions 75322 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75322 | georg.brandl | 2009-10-10 23:47:31 +0200 (Sa, 10 Okt 2009) | 1 line

    Show use of range() step argument nicely.
  ........
................
  r75326 | georg.brandl | 2009-10-10 23:57:03 +0200 (Sa, 10 Okt 2009) | 9 lines

  Merged revisions 75325 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75325 | georg.brandl | 2009-10-10 23:55:11 +0200 (Sa, 10 Okt 2009) | 1 line

    Modernize factorisation demo (mostly augassign.)
  ........
................
  r75328 | georg.brandl | 2009-10-11 00:05:26 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75327 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75327 | georg.brandl | 2009-10-11 00:03:43 +0200 (So, 11 Okt 2009) | 1 line

    Style fixes.
  ........
................
  r75330 | georg.brandl | 2009-10-11 00:32:28 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75329 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75329 | georg.brandl | 2009-10-11 00:26:45 +0200 (So, 11 Okt 2009) | 1 line

    Modernize all around (dont ask me how useful that script is nowadays...)
  ........
................
  r75338 | georg.brandl | 2009-10-11 10:31:41 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75337 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75337 | georg.brandl | 2009-10-11 10:18:44 +0200 (So, 11 Okt 2009) | 1 line

    Update morse script, avoid globals, use iterators.
  ........
................
  r75340 | georg.brandl | 2009-10-11 10:42:09 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75339 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75339 | georg.brandl | 2009-10-11 10:39:16 +0200 (So, 11 Okt 2009) | 1 line

    Update markov demo.
  ........
................
  r75341 | georg.brandl | 2009-10-11 10:43:08 +0200 (So, 11 Okt 2009) | 1 line

  Fix README description.
................
  r75343 | georg.brandl | 2009-10-11 10:46:56 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75342 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75342 | georg.brandl | 2009-10-11 10:45:03 +0200 (So, 11 Okt 2009) | 1 line

    Remove useless script "mkrcs" and update README.
  ........
................
  r75352 | georg.brandl | 2009-10-11 14:04:10 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75350 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75350 | georg.brandl | 2009-10-11 14:00:18 +0200 (So, 11 Okt 2009) | 1 line

    Use getopt in script.py demo.
  ........
................
  r75353 | georg.brandl | 2009-10-11 14:04:40 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75351 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75351 | georg.brandl | 2009-10-11 14:03:01 +0200 (So, 11 Okt 2009) | 1 line

    Fix variable.
  ........
................
  r75355 | georg.brandl | 2009-10-11 16:27:51 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75354 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75354 | georg.brandl | 2009-10-11 16:23:49 +0200 (So, 11 Okt 2009) | 1 line

    Update lpwatch script.
  ........
................
  r75357 | georg.brandl | 2009-10-11 16:50:57 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75356 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75356 | georg.brandl | 2009-10-11 16:49:37 +0200 (So, 11 Okt 2009) | 1 line

    Remove ftpstats script, the daemon whose log files it reads is long gone.
  ........
................
  r75359 | georg.brandl | 2009-10-11 17:56:06 +0200 (So, 11 Okt 2009) | 9 lines

  Merged revisions 75358 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r75358 | georg.brandl | 2009-10-11 17:06:44 +0200 (So, 11 Okt 2009) | 1 line

    Overhaul of Demo/xml.
  ........
................
üst 7dc008d0
...@@ -5,15 +5,14 @@ See also the Tools/scripts directory! ...@@ -5,15 +5,14 @@ See also the Tools/scripts directory!
beer.py Print the classic 'bottles of beer' list. beer.py Print the classic 'bottles of beer' list.
eqfix.py Fix .py files to use the correct equality test operator eqfix.py Fix .py files to use the correct equality test operator
fact.py Factorize numbers fact.py Factorize numbers
find-uname.py Search for Unicode characters using regexps. find-uname.py Search for Unicode characters using regexps
from.py Summarize mailbox from.py Summarize mailbox
ftpstats.py Summarize ftp daemon log file
lpwatch.py Watch BSD line printer queues lpwatch.py Watch BSD line printer queues
makedir.py Like mkdir -p makedir.py Like mkdir -p
markov.py Markov chain simulation of words or characters markov.py Markov chain simulation of words or characters
mboxconvvert.py Convert MH or MMDF mailboxes to unix mailbox format mboxconvert.py Convert MH or MMDF mailboxes to unix mailbox format
mkrcs.py Fix symlinks named RCS into parallel tree morse.py Produce morse code (as an AIFF file)
morse.py Produce morse code (audible or on AIFF file) newslist.py List all newsgroups on a NNTP server as HTML pages
pi.py Print all digits of pi -- given enough time and memory pi.py Print all digits of pi -- given enough time and memory
pp.py Emulate some Perl command line options pp.py Emulate some Perl command line options
primes.py Print prime numbers primes.py Print prime numbers
......
#! /usr/bin/env python #! /usr/bin/env python
# By GvR, demystified after a version by Fredrik Lundh. # By GvR, demystified after a version by Fredrik Lundh.
import sys import sys
n = 100 n = 100
if sys.argv[1:]: n = int(sys.argv[1]) if sys.argv[1:]:
n = int(sys.argv[1])
def bottle(n): def bottle(n):
if n == 0: return "no more bottles of beer" if n == 0: return "no more bottles of beer"
if n == 1: return "one bottle of beer" if n == 1: return "one bottle of beer"
return str(n) + " bottles of beer" return str(n) + " bottles of beer"
for i in range(n):
print(bottle(n-i), "on the wall,") for i in range(n, 0, -1):
print(bottle(n-i) + ".") print(bottle(i), "on the wall,")
print(bottle(i) + ".")
print("Take one down, pass it around,") print("Take one down, pass it around,")
print(bottle(n-i-1), "on the wall.") print(bottle(i-1), "on the wall.")
...@@ -9,39 +9,41 @@ import sys ...@@ -9,39 +9,41 @@ import sys
from math import sqrt from math import sqrt
def fact(n): def fact(n):
if n < 1: raise ValueError # fact() argument should be >= 1 if n < 1:
if n == 1: return [] # special case raise ValueError('fact() argument should be >= 1')
if n == 1:
return [] # special case
res = [] res = []
# Treat even factors special, so we can use i = i+2 later # Treat even factors special, so we can use i += 2 later
while n%2 == 0: while n % 2 == 0:
res.append(2) res.append(2)
n = n//2 n //= 2
# Try odd numbers up to sqrt(n) # Try odd numbers up to sqrt(n)
limit = sqrt(float(n+1)) limit = sqrt(n+1)
i = 3 i = 3
while i <= limit: while i <= limit:
if n%i == 0: if n % i == 0:
res.append(i) res.append(i)
n = n//i n //= i
limit = sqrt(n+1) limit = sqrt(n+1)
else: else:
i = i+2 i += 2
if n != 1: if n != 1:
res.append(n) res.append(n)
return res return res
def main(): def main():
if len(sys.argv) > 1: if len(sys.argv) > 1:
for arg in sys.argv[1:]: source = sys.argv[1:]
n = eval(arg)
print(n, fact(n))
else: else:
source = iter(input, '')
for arg in source:
try: try:
while 1: n = int(arg)
n = eval(input()) except ValueError:
print(n, fact(n)) print(arg, 'is not an integer')
except EOFError: else:
pass print(n, fact(n))
if __name__ == "__main__": if __name__ == "__main__":
main() main()
...@@ -21,20 +21,20 @@ import sys ...@@ -21,20 +21,20 @@ import sys
import re import re
def main(args): def main(args):
unicode_names= [] unicode_names = []
for ix in range(sys.maxunicode+1): for ix in range(sys.maxunicode+1):
try: try:
unicode_names.append( (ix, unicodedata.name(chr(ix))) ) unicode_names.append((ix, unicodedata.name(chr(ix))))
except ValueError: # no name for the character except ValueError: # no name for the character
pass pass
for arg in args: for arg in args:
pat = re.compile(arg, re.I) pat = re.compile(arg, re.I)
matches = [(x,y) for (x,y) in unicode_names matches = [(y,x) for (x,y) in unicode_names
if pat.search(y) is not None] if pat.search(y) is not None]
if matches: if matches:
print("***", arg, "matches", "***") print("***", arg, "matches", "***")
for (x,y) in matches: for match in matches:
print("%s (%d)" % (y,x)) print("%s (%d)" % match)
if __name__ == "__main__": if __name__ == "__main__":
main(sys.argv[1:]) main(sys.argv[1:])
#! /usr/bin/env python
# Extract statistics from ftp daemon log.
# Usage:
# ftpstats [-m maxitems] [-s search] [file]
# -m maxitems: restrict number of items in "top-N" lists, default 25.
# -s string: restrict statistics to lines containing this string.
# Default file is /usr/adm/ftpd; a "-" means read standard input.
# The script must be run on the host where the ftp daemon runs.
# (At CWI this is currently buizerd.)
import os
import sys
import re
import string
import getopt
pat = '^([a-zA-Z0-9 :]*)!(.*)!(.*)!([<>].*)!([0-9]+)!([0-9]+)$'
prog = re.compile(pat)
def main():
maxitems = 25
search = None
try:
opts, args = getopt.getopt(sys.argv[1:], 'm:s:')
except getopt.error as msg:
print(msg)
print('usage: ftpstats [-m maxitems] [file]')
sys.exit(2)
for o, a in opts:
if o == '-m':
maxitems = string.atoi(a)
if o == '-s':
search = a
file = '/usr/adm/ftpd'
if args: file = args[0]
if file == '-':
f = sys.stdin
else:
try:
f = open(file, 'r')
except IOError as msg:
print(file, ':', msg)
sys.exit(1)
bydate = {}
bytime = {}
byfile = {}
bydir = {}
byhost = {}
byuser = {}
bytype = {}
lineno = 0
try:
while 1:
line = f.readline()
if not line: break
lineno = lineno + 1
if search and string.find(line, search) < 0:
continue
if prog.match(line) < 0:
print('Bad line', lineno, ':', repr(line))
continue
items = prog.group(1, 2, 3, 4, 5, 6)
(logtime, loguser, loghost, logfile, logbytes,
logxxx2) = items
## print logtime
## print '-->', loguser
## print '--> -->', loghost
## print '--> --> -->', logfile
## print '--> --> --> -->', logbytes
## print '--> --> --> --> -->', logxxx2
## for i in logtime, loghost, logbytes, logxxx2:
## if '!' in i: print '???', i
add(bydate, logtime[-4:] + ' ' + logtime[:6], items)
add(bytime, logtime[7:9] + ':00-59', items)
direction, logfile = logfile[0], logfile[1:]
# The real path probably starts at the last //...
while 1:
i = string.find(logfile, '//')
if i < 0: break
logfile = logfile[i+1:]
add(byfile, logfile + ' ' + direction, items)
logdir = os.path.dirname(logfile)
## logdir = os.path.normpath(logdir) + '/.'
while 1:
add(bydir, logdir + ' ' + direction, items)
dirhead = os.path.dirname(logdir)
if dirhead == logdir: break
logdir = dirhead
add(byhost, loghost, items)
add(byuser, loguser, items)
add(bytype, direction, items)
except KeyboardInterrupt:
print('Interrupted at line', lineno)
show(bytype, 'by transfer direction', maxitems)
show(bydir, 'by directory', maxitems)
show(byfile, 'by file', maxitems)
show(byhost, 'by host', maxitems)
show(byuser, 'by user', maxitems)
showbar(bydate, 'by date')
showbar(bytime, 'by time of day')
def showbar(dict, title):
n = len(title)
print('='*((70-n)//2), title, '='*((71-n)//2))
list = []
for key in sorted(dict.keys()):
n = len(str(key))
list.append((len(dict[key]), key))
maxkeylength = 0
maxcount = 0
for count, key in list:
maxkeylength = max(maxkeylength, len(key))
maxcount = max(maxcount, count)
maxbarlength = 72 - maxkeylength - 7
for count, key in list:
barlength = int(round(maxbarlength*float(count)/maxcount))
bar = '*'*barlength
print('%5d %-*s %s' % (count, maxkeylength, key, bar))
def show(dict, title, maxitems):
if len(dict) > maxitems:
title = title + ' (first %d)'%maxitems
n = len(title)
print('='*((70-n)//2), title, '='*((71-n)//2))
list = []
for key in dict.keys():
list.append((-len(dict[key]), key))
list.sort()
for count, key in list[:maxitems]:
print('%5d %s' % (-count, key))
def add(dict, key, item):
if key in dict:
dict[key].append(item)
else:
dict[key] = [item]
if __name__ == "__main__":
main()
...@@ -3,10 +3,9 @@ ...@@ -3,10 +3,9 @@
# Watch line printer queue(s). # Watch line printer queue(s).
# Intended for BSD 4.3 lpq. # Intended for BSD 4.3 lpq.
import posix import os
import sys import sys
import time import time
import string
DEF_PRINTER = 'psc' DEF_PRINTER = 'psc'
DEF_DELAY = 10 DEF_DELAY = 10
...@@ -14,94 +13,87 @@ DEF_DELAY = 10 ...@@ -14,94 +13,87 @@ DEF_DELAY = 10
def main(): def main():
delay = DEF_DELAY # XXX Use getopt() later delay = DEF_DELAY # XXX Use getopt() later
try: try:
thisuser = posix.environ['LOGNAME'] thisuser = os.environ['LOGNAME']
except: except:
thisuser = posix.environ['USER'] thisuser = os.environ['USER']
printers = sys.argv[1:] printers = sys.argv[1:]
if printers: if printers:
# Strip '-P' from printer names just in case # Strip '-P' from printer names just in case
# the user specified it... # the user specified it...
for i in range(len(printers)): for i, name in enumerate(printers):
if printers[i][:2] == '-P': if name[:2] == '-P':
printers[i] = printers[i][2:] printers[i] = name[2:]
else: else:
if 'PRINTER' in posix.environ: if 'PRINTER' in os.environ:
printers = [posix.environ['PRINTER']] printers = [os.environ['PRINTER']]
else: else:
printers = [DEF_PRINTER] printers = [DEF_PRINTER]
#
clearhome = posix.popen('clear', 'r').read() clearhome = os.popen('clear', 'r').read()
#
while 1: while True:
text = clearhome text = clearhome
for name in printers: for name in printers:
text = text + makestatus(name, thisuser) + '\n' text += makestatus(name, thisuser) + '\n'
print(text) print(text)
time.sleep(delay) time.sleep(delay)
def makestatus(name, thisuser): def makestatus(name, thisuser):
pipe = posix.popen('lpq -P' + name + ' 2>&1', 'r') pipe = os.popen('lpq -P' + name + ' 2>&1', 'r')
lines = [] lines = []
users = {} users = {}
aheadbytes = 0 aheadbytes = 0
aheadjobs = 0 aheadjobs = 0
userseen = 0 userseen = False
totalbytes = 0 totalbytes = 0
totaljobs = 0 totaljobs = 0
while 1: for line in pipe:
line = pipe.readline() fields = line.split()
if not line: break
fields = string.split(line)
n = len(fields) n = len(fields)
if len(fields) >= 6 and fields[n-1] == 'bytes': if len(fields) >= 6 and fields[n-1] == 'bytes':
rank = fields[0] rank, user, job = fields[0:3]
user = fields[1]
job = fields[2]
files = fields[3:-2] files = fields[3:-2]
bytes = eval(fields[n-2]) bytes = int(fields[n-2])
if user == thisuser: if user == thisuser:
userseen = 1 userseen = True
elif not userseen: elif not userseen:
aheadbytes = aheadbytes + bytes aheadbytes += bytes
aheadjobs = aheadjobs + 1 aheadjobs += 1
totalbytes = totalbytes + bytes totalbytes += bytes
totaljobs = totaljobs + 1 totaljobs += 1
if user in users: ujobs, ubytes = users.get(user, (0, 0))
ujobs, ubytes = users[user] ujobs += 1
else: ubytes += bytes
ujobs, ubytes = 0, 0
ujobs = ujobs + 1
ubytes = ubytes + bytes
users[user] = ujobs, ubytes users[user] = ujobs, ubytes
else: else:
if fields and fields[0] != 'Rank': if fields and fields[0] != 'Rank':
line = string.strip(line) line = line.strip()
if line == 'no entries': if line == 'no entries':
line = name + ': idle' line = name + ': idle'
elif line[-22:] == ' is ready and printing': elif line[-22:] == ' is ready and printing':
line = name line = name
lines.append(line) lines.append(line)
#
if totaljobs: if totaljobs:
line = '%d K' % ((totalbytes+1023)//1024) line = '%d K' % ((totalbytes+1023) // 1024)
if totaljobs != len(users): if totaljobs != len(users):
line = line + ' (%d jobs)' % totaljobs line += ' (%d jobs)' % totaljobs
if len(users) == 1: if len(users) == 1:
line = line + ' for %s' % (list(users.keys())[0],) line += ' for %s' % next(iter(users))
else: else:
line = line + ' for %d users' % len(users) line += ' for %d users' % len(users)
if userseen: if userseen:
if aheadjobs == 0: if aheadjobs == 0:
line = line + ' (%s first)' % thisuser line += ' (%s first)' % thisuser
else: else:
line = line + ' (%d K before %s)' % ( line += ' (%d K before %s)' % (
(aheadbytes+1023)//1024, thisuser) (aheadbytes+1023) // 1024, thisuser)
lines.append(line) lines.append(line)
#
sts = pipe.close() sts = pipe.close()
if sts: if sts:
lines.append('lpq exit status %r' % (sts,)) lines.append('lpq exit status %r' % (sts,))
return string.joinfields(lines, ': ') return ': '.join(lines)
if __name__ == "__main__": if __name__ == "__main__":
try: try:
......
...@@ -5,11 +5,10 @@ class Markov: ...@@ -5,11 +5,10 @@ class Markov:
self.histsize = histsize self.histsize = histsize
self.choice = choice self.choice = choice
self.trans = {} self.trans = {}
def add(self, state, next): def add(self, state, next):
if state not in self.trans: self.trans.setdefault(state, []).append(next)
self.trans[state] = [next]
else:
self.trans[state].append(next)
def put(self, seq): def put(self, seq):
n = self.histsize n = self.histsize
add = self.add add = self.add
...@@ -17,26 +16,29 @@ class Markov: ...@@ -17,26 +16,29 @@ class Markov:
for i in range(len(seq)): for i in range(len(seq)):
add(seq[max(0, i-n):i], seq[i:i+1]) add(seq[max(0, i-n):i], seq[i:i+1])
add(seq[len(seq)-n:], None) add(seq[len(seq)-n:], None)
def get(self): def get(self):
choice = self.choice choice = self.choice
trans = self.trans trans = self.trans
n = self.histsize n = self.histsize
seq = choice(trans[None]) seq = choice(trans[None])
while 1: while True:
subseq = seq[max(0, len(seq)-n):] subseq = seq[max(0, len(seq)-n):]
options = trans[subseq] options = trans[subseq]
next = choice(options) next = choice(options)
if not next: break if not next:
seq = seq + next break
seq += next
return seq return seq
def test(): def test():
import sys, string, random, getopt import sys, random, getopt
args = sys.argv[1:] args = sys.argv[1:]
try: try:
opts, args = getopt.getopt(args, '0123456789cdw') opts, args = getopt.getopt(args, '0123456789cdwq')
except getopt.error: except getopt.error:
print('Usage: markov [-#] [-cddqw] [file] ...') print('Usage: %s [-#] [-cddqw] [file] ...' % sys.argv[0])
print('Options:') print('Options:')
print('-#: 1-digit history size (default 2)') print('-#: 1-digit history size (default 2)')
print('-c: characters (default)') print('-c: characters (default)')
...@@ -49,16 +51,19 @@ def test(): ...@@ -49,16 +51,19 @@ def test():
print('exactly one space separating words.') print('exactly one space separating words.')
print('Output consists of paragraphs separated by blank') print('Output consists of paragraphs separated by blank')
print('lines, where lines are no longer than 72 characters.') print('lines, where lines are no longer than 72 characters.')
sys.exit(2)
histsize = 2 histsize = 2
do_words = 0 do_words = False
debug = 1 debug = 1
for o, a in opts: for o, a in opts:
if '-0' <= o <= '-9': histsize = eval(o[1:]) if '-0' <= o <= '-9': histsize = int(o[1:])
if o == '-c': do_words = 0 if o == '-c': do_words = False
if o == '-d': debug = debug + 1 if o == '-d': debug += 1
if o == '-q': debug = 0 if o == '-q': debug = 0
if o == '-w': do_words = 1 if o == '-w': do_words = True
if not args: args = ['-'] if not args:
args = ['-']
m = Markov(histsize, random.choice) m = Markov(histsize, random.choice)
try: try:
for filename in args: for filename in args:
...@@ -72,13 +77,15 @@ def test(): ...@@ -72,13 +77,15 @@ def test():
if debug: print('processing', filename, '...') if debug: print('processing', filename, '...')
text = f.read() text = f.read()
f.close() f.close()
paralist = string.splitfields(text, '\n\n') paralist = text.split('\n\n')
for para in paralist: for para in paralist:
if debug > 1: print('feeding ...') if debug > 1: print('feeding ...')
words = string.split(para) words = para.split()
if words: if words:
if do_words: data = tuple(words) if do_words:
else: data = string.joinfields(words, ' ') data = tuple(words)
else:
data = ' '.join(words)
m.put(data) m.put(data)
except KeyboardInterrupt: except KeyboardInterrupt:
print('Interrupted -- continue with data read so far') print('Interrupted -- continue with data read so far')
...@@ -86,16 +93,19 @@ def test(): ...@@ -86,16 +93,19 @@ def test():
print('No valid input files') print('No valid input files')
return return
if debug: print('done.') if debug: print('done.')
if debug > 1: if debug > 1:
for key in m.trans.keys(): for key in m.trans.keys():
if key is None or len(key) < histsize: if key is None or len(key) < histsize:
print(repr(key), m.trans[key]) print(repr(key), m.trans[key])
if histsize == 0: print(repr(''), m.trans['']) if histsize == 0: print(repr(''), m.trans[''])
print() print()
while 1: while True:
data = m.get() data = m.get()
if do_words: words = data if do_words:
else: words = string.split(data) words = data
else:
words = data.split()
n = 0 n = 0
limit = 72 limit = 72
for w in words: for w in words:
...@@ -103,15 +113,9 @@ def test(): ...@@ -103,15 +113,9 @@ def test():
print() print()
n = 0 n = 0
print(w, end=' ') print(w, end=' ')
n = n + len(w) + 1 n += len(w) + 1
print() print()
print() print()
def tuple(list):
if len(list) == 0: return ()
if len(list) == 1: return (list[0],)
i = len(list)//2
return tuple(list[:i]) + tuple(list[i:])
if __name__ == "__main__": if __name__ == "__main__":
test() test()
#! /usr/bin/env python
# A rather specialized script to make sure that a symbolic link named
# RCS exists pointing to a real RCS directory in a parallel tree
# referenced as RCStree in an ancestor directory.
# (I use this because I like my RCS files to reside on a physically
# different machine).
import os
def main():
rcstree = 'RCStree'
rcs = 'RCS'
if os.path.islink(rcs):
print('%r is a symlink to %r' % (rcs, os.readlink(rcs)))
return
if os.path.isdir(rcs):
print('%r is an ordinary directory' % (rcs,))
return
if os.path.exists(rcs):
print('%r is a file?!?!' % (rcs,))
return
#
p = os.getcwd()
up = ''
down = ''
# Invariants:
# (1) join(p, down) is the current directory
# (2) up is the same directory as p
# Ergo:
# (3) join(up, down) is the current directory
#print 'p =', repr(p)
while not os.path.isdir(os.path.join(p, rcstree)):
head, tail = os.path.split(p)
#print 'head = %r; tail = %r' % (head, tail)
if not tail:
print('Sorry, no ancestor dir contains %r' % (rcstree,))
return
p = head
up = os.path.join(os.pardir, up)
down = os.path.join(tail, down)
#print 'p = %r; up = %r; down = %r' % (p, up, down)
there = os.path.join(up, rcstree)
there = os.path.join(there, down)
there = os.path.join(there, rcs)
if os.path.isdir(there):
print('%r already exists' % (there, ))
else:
print('making %r' % (there,))
makedirs(there)
print('making symlink %r -> %r' % (rcs, there))
os.symlink(there, rcs)
def makedirs(p):
if not os.path.isdir(p):
head, tail = os.path.split(p)
makedirs(head)
os.mkdir(p, 0o777)
if __name__ == "__main__":
main()
#! /usr/bin/env python
# DAH should be three DOTs.
# Space between DOTs and DAHs should be one DOT.
# Space between two letters should be one DAH.
# Space between two words should be DOT DAH DAH.
import sys, math, aifc
from contextlib import closing
DOT = 30
DAH = 3 * DOT
OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ...
morsetab = {
'A': '.-', 'a': '.-',
'B': '-...', 'b': '-...',
'C': '-.-.', 'c': '-.-.',
'D': '-..', 'd': '-..',
'E': '.', 'e': '.',
'F': '..-.', 'f': '..-.',
'G': '--.', 'g': '--.',
'H': '....', 'h': '....',
'I': '..', 'i': '..',
'J': '.---', 'j': '.---',
'K': '-.-', 'k': '-.-',
'L': '.-..', 'l': '.-..',
'M': '--', 'm': '--',
'N': '-.', 'n': '-.',
'O': '---', 'o': '---',
'P': '.--.', 'p': '.--.',
'Q': '--.-', 'q': '--.-',
'R': '.-.', 'r': '.-.',
'S': '...', 's': '...',
'T': '-', 't': '-',
'U': '..-', 'u': '..-',
'V': '...-', 'v': '...-',
'W': '.--', 'w': '.--',
'X': '-..-', 'x': '-..-',
'Y': '-.--', 'y': '-.--',
'Z': '--..', 'z': '--..',
'0': '-----', ',': '--..--',
'1': '.----', '.': '.-.-.-',
'2': '..---', '?': '..--..',
'3': '...--', ';': '-.-.-.',
'4': '....-', ':': '---...',
'5': '.....', "'": '.----.',
'6': '-....', '-': '-....-',
'7': '--...', '/': '-..-.',
'8': '---..', '(': '-.--.-',
'9': '----.', ')': '-.--.-',
' ': ' ', '_': '..--.-',
}
nowave = b'\0' * 200
# If we play at 44.1 kHz (which we do), then if we produce one sine
# wave in 100 samples, we get a tone of 441 Hz. If we produce two
# sine waves in these 100 samples, we get a tone of 882 Hz. 882 Hz
# appears to be a nice one for playing morse code.
def mkwave(octave):
sinewave = bytearray()
for i in range(100):
val = int(math.sin(math.pi * i * octave / 50.0) * 30000)
sinewave.extend([(val >> 8) & 255, val & 255])
return bytes(sinewave)
defaultwave = mkwave(OCTAVE)
def main():
import getopt
try:
opts, args = getopt.getopt(sys.argv[1:], 'o:p:')
except getopt.error:
sys.stderr.write('Usage ' + sys.argv[0] +
' [ -o outfile ] [ -p octave ] [ words ] ...\n')
sys.exit(1)
wave = defaultwave
outfile = 'morse.aifc'
for o, a in opts:
if o == '-o':
outfile = a
if o == '-p':
wave = mkwave(int(a))
with closing(aifc.open(outfile, 'w')) as fp:
fp.setframerate(44100)
fp.setsampwidth(2)
fp.setnchannels(1)
if args:
source = [' '.join(args)]
else:
source = iter(sys.stdin.readline, '')
for line in source:
mline = morse(line)
play(mline, fp, wave)
# Convert a string to morse code with \001 between the characters in
# the string.
def morse(line):
res = ''
for c in line:
try:
res += morsetab[c] + '\001'
except KeyError:
pass
return res
# Play a line of morse code.
def play(line, fp, wave):
for c in line:
if c == '.':
sine(fp, DOT, wave)
elif c == '-':
sine(fp, DAH, wave)
else: # space
pause(fp, DAH + DOT)
pause(fp, DOT)
def sine(fp, length, wave):
for i in range(length):
fp.writeframesraw(wave)
def pause(fp, length):
for i in range(length):
fp.writeframesraw(nowave)
if __name__ == '__main__':
main()
This diff is collapsed.
...@@ -12,7 +12,7 @@ import sys ...@@ -12,7 +12,7 @@ import sys
def main(): def main():
k, a, b, a1, b1 = 2, 4, 1, 12, 4 k, a, b, a1, b1 = 2, 4, 1, 12, 4
while 1: while True:
# Next approximation # Next approximation
p, q, k = k*k, 2*k+1, k+1 p, q, k = k*k, 2*k+1, k+1
a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1 a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
...@@ -25,7 +25,6 @@ def main(): ...@@ -25,7 +25,6 @@ def main():
def output(d): def output(d):
# Use write() to avoid spaces between the digits # Use write() to avoid spaces between the digits
# Use str() to avoid the 'L'
sys.stdout.write(str(d)) sys.stdout.write(str(d))
# Flush so the output is seen immediately # Flush so the output is seen immediately
sys.stdout.flush() sys.stdout.flush()
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
# - except for -n/-p, run directly from the file if at all possible # - except for -n/-p, run directly from the file if at all possible
import sys import sys
import string
import getopt import getopt
FS = '' FS = ''
...@@ -36,7 +35,7 @@ PFLAG = 0 ...@@ -36,7 +35,7 @@ PFLAG = 0
try: try:
optlist, ARGS = getopt.getopt(sys.argv[1:], 'acde:F:np') optlist, ARGS = getopt.getopt(sys.argv[1:], 'acde:F:np')
except getopt.error as msg: except getopt.error as msg:
sys.stderr.write(sys.argv[0] + ': ' + msg + '\n') sys.stderr.write('%s: %s\n' % (sys.argv[0], msg))
sys.exit(2) sys.exit(2)
for option, optarg in optlist: for option, optarg in optlist:
...@@ -47,7 +46,7 @@ for option, optarg in optlist: ...@@ -47,7 +46,7 @@ for option, optarg in optlist:
elif option == '-d': elif option == '-d':
DFLAG = 1 DFLAG = 1
elif option == '-e': elif option == '-e':
for line in string.splitfields(optarg, '\n'): for line in optarg.split('\n'):
SCRIPT.append(line) SCRIPT.append(line)
elif option == '-F': elif option == '-F':
FS = optarg FS = optarg
...@@ -81,31 +80,31 @@ if CFLAG: ...@@ -81,31 +80,31 @@ if CFLAG:
elif NFLAG: elif NFLAG:
# Note that it is on purpose that AFLAG and PFLAG are # Note that it is on purpose that AFLAG and PFLAG are
# tested dynamically each time through the loop # tested dynamically each time through the loop
prologue = [ \ prologue = [
'LINECOUNT = 0', \ 'LINECOUNT = 0',
'for FILE in ARGS:', \ 'for FILE in ARGS:',
' \tif FILE == \'-\':', \ ' \tif FILE == \'-\':',
' \t \tFP = sys.stdin', \ ' \t \tFP = sys.stdin',
' \telse:', \ ' \telse:',
' \t \tFP = open(FILE, \'r\')', \ ' \t \tFP = open(FILE, \'r\')',
' \tLINENO = 0', \ ' \tLINENO = 0',
' \twhile 1:', \ ' \twhile 1:',
' \t \tLINE = FP.readline()', \ ' \t \tLINE = FP.readline()',
' \t \tif not LINE: break', \ ' \t \tif not LINE: break',
' \t \tLINENO = LINENO + 1', \ ' \t \tLINENO = LINENO + 1',
' \t \tLINECOUNT = LINECOUNT + 1', \ ' \t \tLINECOUNT = LINECOUNT + 1',
' \t \tL = LINE[:-1]', \ ' \t \tL = LINE[:-1]',
' \t \taflag = AFLAG', \ ' \t \taflag = AFLAG',
' \t \tif aflag:', \ ' \t \tif aflag:',
' \t \t \tif FS: F = string.splitfields(L, FS)', \ ' \t \t \tif FS: F = L.split(FS)',
' \t \t \telse: F = string.split(L)' \ ' \t \t \telse: F = L.split()'
] ]
epilogue = [ \ epilogue = [
' \t \tif not PFLAG: continue', \ ' \t \tif not PFLAG: continue',
' \t \tif aflag:', \ ' \t \tif aflag:',
' \t \t \tif FS: print string.joinfields(F, FS)', \ ' \t \t \tif FS: print(FS.join(F))',
' \t \t \telse: print string.join(F)', \ ' \t \t \telse: print(\' \'.join(F))',
' \t \telse: print L', \ ' \t \telse: print(L)',
] ]
else: else:
prologue = ['if 1:'] prologue = ['if 1:']
...@@ -114,18 +113,13 @@ else: ...@@ -114,18 +113,13 @@ else:
# Note that we indent using tabs only, so that any indentation style # Note that we indent using tabs only, so that any indentation style
# used in 'command' will come out right after re-indentation. # used in 'command' will come out right after re-indentation.
program = string.joinfields(prologue, '\n') + '\n' program = '\n'.join(prologue) + '\n'
for line in SCRIPT: for line in SCRIPT:
program = program + (' \t \t' + line + '\n') program += ' \t \t' + line + '\n'
program = program + (string.joinfields(epilogue, '\n') + '\n') program += '\n'.join(epilogue) + '\n'
import tempfile
fp = tempfile.NamedTemporaryFile()
fp.write(program)
fp.flush()
script = open(tfn).read()
if DFLAG: if DFLAG:
import pdb import pdb
pdb.run(script) pdb.run(program)
else: else:
exec(script) exec(program)
...@@ -19,8 +19,8 @@ class Queens: ...@@ -19,8 +19,8 @@ class Queens:
def reset(self): def reset(self):
n = self.n n = self.n
self.y = [None]*n # Where is the queen in column x self.y = [None] * n # Where is the queen in column x
self.row = [0]*n # Is row[y] safe? self.row = [0] * n # Is row[y] safe?
self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe? self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe?
self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe? self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe?
self.nfound = 0 # Instrumentation self.nfound = 0 # Instrumentation
...@@ -50,7 +50,7 @@ class Queens: ...@@ -50,7 +50,7 @@ class Queens:
self.up[x-y] = 0 self.up[x-y] = 0
self.down[x+y] = 0 self.down[x+y] = 0
silent = 0 # If set, count solutions only silent = 0 # If true, count solutions only
def display(self): def display(self):
self.nfound = self.nfound + 1 self.nfound = self.nfound + 1
......
#! /usr/bin/env python #! /usr/bin/env python
# script.py -- Make typescript of terminal session. # script.py -- Make typescript of terminal session.
# Usage: # Usage:
# -a Append to typescript. # -a Append to typescript.
...@@ -6,28 +7,36 @@ ...@@ -6,28 +7,36 @@
# Author: Steen Lumholt. # Author: Steen Lumholt.
import os, time, sys import os, time, sys, getopt
import pty import pty
def read(fd): def read(fd):
data = os.read(fd, 1024) data = os.read(fd, 1024)
file.write(data) script.write(data)
return data return data
shell = 'sh' shell = 'sh'
filename = 'typescript' filename = 'typescript'
mode = 'w' mode = 'wb'
if 'SHELL' in os.environ: if 'SHELL' in os.environ:
shell = os.environ['SHELL'] shell = os.environ['SHELL']
if '-a' in sys.argv:
mode = 'a'
if '-p' in sys.argv:
shell = 'python'
file = open(filename, mode) try:
opts, args = getopt.getopt(sys.argv[1:], 'ap')
except getopt.error as msg:
print('%s: %s' % (sys.argv[0], msg))
sys.exit(2)
for o, a in opts:
if o == '-a':
mode = 'ab'
elif o == '-p':
shell = 'python'
script = open(filename, mode)
sys.stdout.write('Script started, file is %s\n' % filename) sys.stdout.write('Script started, file is %s\n' % filename)
file.write('Script started on %s\n' % time.ctime(time.time())) script.write(('Script started on %s\n' % time.ctime(time.time())).encode())
pty.spawn(shell, read) pty.spawn(shell, read)
file.write('Script done on %s\n' % time.ctime(time.time())) script.write(('Script done on %s\n' % time.ctime(time.time())).encode())
sys.stdout.write('Script done, file is %s\n' % filename) sys.stdout.write('Script done, file is %s\n' % filename)
...@@ -9,35 +9,27 @@ import sys ...@@ -9,35 +9,27 @@ import sys
import time import time
import calendar import calendar
def raw_input(prompt):
sys.stdout.write(prompt)
sys.stdout.flush()
return sys.stdin.readline()
def main(): def main():
# Note that the range checks below also check for bad types,
# e.g. 3.14 or (). However syntactically invalid replies
# will raise an exception.
if sys.argv[1:]: if sys.argv[1:]:
year = int(sys.argv[1]) year = int(sys.argv[1])
else: else:
year = int(input('In which year were you born? ')) year = int(input('In which year were you born? '))
if 0<=year<100: if 0 <= year < 100:
print("I'll assume that by", year, end=' ') print("I'll assume that by", year, end=' ')
year = year + 1900 year = year + 1900
print('you mean', year, 'and not the early Christian era') print('you mean', year, 'and not the early Christian era')
elif not (1850<=year<=2002): elif not (1850 <= year <= time.localtime()[0]):
print("It's hard to believe you were born in", year) print("It's hard to believe you were born in", year)
return return
#
if sys.argv[2:]: if sys.argv[2:]:
month = int(sys.argv[2]) month = int(sys.argv[2])
else: else:
month = int(input('And in which month? (1-12) ')) month = int(input('And in which month? (1-12) '))
if not (1<=month<=12): if not (1 <= month <= 12):
print('There is no month numbered', month) print('There is no month numbered', month)
return return
#
if sys.argv[3:]: if sys.argv[3:]:
day = int(sys.argv[3]) day = int(sys.argv[3])
else: else:
...@@ -46,36 +38,36 @@ def main(): ...@@ -46,36 +38,36 @@ def main():
maxday = 29 maxday = 29
else: else:
maxday = calendar.mdays[month] maxday = calendar.mdays[month]
if not (1<=day<=maxday): if not (1 <= day <= maxday):
print('There are no', day, 'days in that month!') print('There are no', day, 'days in that month!')
return return
#
bdaytuple = (year, month, day) bdaytuple = (year, month, day)
bdaydate = mkdate(bdaytuple) bdaydate = mkdate(bdaytuple)
print('You were born on', format(bdaytuple)) print('You were born on', format(bdaytuple))
#
todaytuple = time.localtime()[:3] todaytuple = time.localtime()[:3]
todaydate = mkdate(todaytuple) todaydate = mkdate(todaytuple)
print('Today is', format(todaytuple)) print('Today is', format(todaytuple))
#
if bdaytuple > todaytuple: if bdaytuple > todaytuple:
print('You are a time traveler. Go back to the future!') print('You are a time traveler. Go back to the future!')
return return
#
if bdaytuple == todaytuple: if bdaytuple == todaytuple:
print('You were born today. Have a nice life!') print('You were born today. Have a nice life!')
return return
#
days = todaydate - bdaydate days = todaydate - bdaydate
print('You have lived', days, 'days') print('You have lived', days, 'days')
#
age = 0 age = 0
for y in range(year, todaytuple[0] + 1): for y in range(year, todaytuple[0] + 1):
if bdaytuple < (y, month, day) <= todaytuple: if bdaytuple < (y, month, day) <= todaytuple:
age = age + 1 age = age + 1
#
print('You are', age, 'years old') print('You are', age, 'years old')
#
if todaytuple[1:] == bdaytuple[1:]: if todaytuple[1:] == bdaytuple[1:]:
print('Congratulations! Today is your', nth(age), 'birthday') print('Congratulations! Today is your', nth(age), 'birthday')
print('Yesterday was your', end=' ') print('Yesterday was your', end=' ')
...@@ -83,8 +75,8 @@ def main(): ...@@ -83,8 +75,8 @@ def main():
print('Today is your', end=' ') print('Today is your', end=' ')
print(nth(days - age), 'unbirthday') print(nth(days - age), 'unbirthday')
def format(xxx_todo_changeme): def format(date):
(year, month, day) = xxx_todo_changeme (year, month, day) = date
return '%d %s %d' % (day, calendar.month_name[month], year) return '%d %s %d' % (day, calendar.month_name[month], year)
def nth(n): def nth(n):
...@@ -93,12 +85,12 @@ def nth(n): ...@@ -93,12 +85,12 @@ def nth(n):
if n == 3: return '3rd' if n == 3: return '3rd'
return '%dth' % n return '%dth' % n
def mkdate(xxx_todo_changeme1): def mkdate(date):
# Januari 1st, in 0 A.D. is arbitrarily defined to be day 1, # January 1st, in 0 A.D. is arbitrarily defined to be day 1,
# even though that day never actually existed and the calendar # even though that day never actually existed and the calendar
# was different then... # was different then...
(year, month, day) = xxx_todo_changeme1 (year, month, day) = date
days = year*365 # years, roughly days = year*365 # years, roughly
days = days + (year+3)//4 # plus leap years, roughly days = days + (year+3)//4 # plus leap years, roughly
days = days - (year+99)//100 # minus non-leap years every century days = days - (year+99)//100 # minus non-leap years every century
days = days + (year+399)//400 # plus leap years every 4 centirues days = days + (year+399)//400 # plus leap years every 4 centirues
......
"""
A simple demo that reads in an XML document and displays the number of
elements and attributes as well as a tally of elements and attributes by name.
"""
import sys import sys
from collections import defaultdict
from xml.sax import make_parser, handler from xml.sax import make_parser, handler
...@@ -7,16 +13,16 @@ class FancyCounter(handler.ContentHandler): ...@@ -7,16 +13,16 @@ class FancyCounter(handler.ContentHandler):
def __init__(self): def __init__(self):
self._elems = 0 self._elems = 0
self._attrs = 0 self._attrs = 0
self._elem_types = {} self._elem_types = defaultdict(int)
self._attr_types = {} self._attr_types = defaultdict(int)
def startElement(self, name, attrs): def startElement(self, name, attrs):
self._elems = self._elems + 1 self._elems += 1
self._attrs = self._attrs + len(attrs) self._attrs += len(attrs)
self._elem_types[name] = self._elem_types.get(name, 0) + 1 self._elem_types[name] += 1
for name in attrs.keys(): for name in attrs.keys():
self._attr_types[name] = self._attr_types.get(name, 0) + 1 self._attr_types[name] += 1
def endDocument(self): def endDocument(self):
print("There were", self._elems, "elements.") print("There were", self._elems, "elements.")
...@@ -30,7 +36,7 @@ class FancyCounter(handler.ContentHandler): ...@@ -30,7 +36,7 @@ class FancyCounter(handler.ContentHandler):
for pair in self._attr_types.items(): for pair in self._attr_types.items():
print("%20s %d" % pair) print("%20s %d" % pair)
if __name__ == '__main__':
parser = make_parser() parser = make_parser()
parser.setContentHandler(FancyCounter()) parser.setContentHandler(FancyCounter())
parser.parse(sys.argv[1]) parser.parse(sys.argv[1])
...@@ -3,7 +3,7 @@ A simple demo that reads in an XML document and spits out an equivalent, ...@@ -3,7 +3,7 @@ A simple demo that reads in an XML document and spits out an equivalent,
but not necessarily identical, document. but not necessarily identical, document.
""" """
import sys, string import sys
from xml.sax import saxutils, handler, make_parser from xml.sax import saxutils, handler, make_parser
...@@ -11,7 +11,7 @@ from xml.sax import saxutils, handler, make_parser ...@@ -11,7 +11,7 @@ from xml.sax import saxutils, handler, make_parser
class ContentGenerator(handler.ContentHandler): class ContentGenerator(handler.ContentHandler):
def __init__(self, out = sys.stdout): def __init__(self, out=sys.stdout):
handler.ContentHandler.__init__(self) handler.ContentHandler.__init__(self)
self._out = out self._out = out
...@@ -40,6 +40,7 @@ class ContentGenerator(handler.ContentHandler): ...@@ -40,6 +40,7 @@ class ContentGenerator(handler.ContentHandler):
# --- The main program # --- The main program
parser = make_parser() if __name__ == '__main__':
parser.setContentHandler(ContentGenerator()) parser = make_parser()
parser.parse(sys.argv[1]) parser.setContentHandler(ContentGenerator())
parser.parse(sys.argv[1])
"""
A demo that reads in an RSS XML document and emits an HTML file containing
a list of the individual items in the feed.
"""
import sys import sys
import codecs
from xml.sax import make_parser, handler from xml.sax import make_parser, handler
# --- Templates # --- Templates
top = \ top = """\
"""
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML> <html>
<HEAD> <head>
<TITLE>%s</TITLE> <title>%s</title>
</HEAD> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<BODY>
<H1>%s</H1> <body>
<h1>%s</h1>
""" """
bottom = \ bottom = """
"""
</ul> </ul>
<HR> <hr>
<ADDRESS> <address>
Converted to HTML by sax_rss2html.py. Converted to HTML by rss2html.py.
</ADDRESS> </address>
</BODY> </body>
</HTML> </html>
""" """
# --- The ContentHandler # --- The ContentHandler
class RSSHandler(handler.ContentHandler): class RSSHandler(handler.ContentHandler):
def __init__(self, out = sys.stdout): def __init__(self, out=sys.stdout):
handler.ContentHandler.__init__(self) handler.ContentHandler.__init__(self)
self._out = out self._out = out
self._text = "" self._text = ""
self._parent = None self._parent = None
self._list_started = 0 self._list_started = False
self._title = None self._title = None
self._link = None self._link = None
self._descr = "" self._descr = ""
...@@ -69,7 +74,7 @@ class RSSHandler(handler.ContentHandler): ...@@ -69,7 +74,7 @@ class RSSHandler(handler.ContentHandler):
elif name == "item": elif name == "item":
if not self._list_started: if not self._list_started:
self._out.write("<ul>\n") self._out.write("<ul>\n")
self._list_started = 1 self._list_started = True
self._out.write(' <li><a href="%s">%s</a> %s\n' % self._out.write(' <li><a href="%s">%s</a> %s\n' %
(self._link, self._title, self._descr)) (self._link, self._title, self._descr))
...@@ -86,6 +91,7 @@ class RSSHandler(handler.ContentHandler): ...@@ -86,6 +91,7 @@ class RSSHandler(handler.ContentHandler):
# --- Main program # --- Main program
parser = make_parser() if __name__ == '__main__':
parser.setContentHandler(RSSHandler()) parser = make_parser()
parser.parse(sys.argv[1]) parser.setContentHandler(RSSHandler())
parser.parse(sys.argv[1])
...@@ -231,9 +231,11 @@ RawConfigParser Objects ...@@ -231,9 +231,11 @@ RawConfigParser Objects
.. method:: RawConfigParser.readfp(fp, filename=None) .. method:: RawConfigParser.readfp(fp, filename=None)
Read and parse configuration data from the file or file-like object in *fp* Read and parse configuration data from the file or file-like object in *fp*
(only the :meth:`readline` method is used). If *filename* is omitted and *fp* (only the :meth:`readline` method is used). The file-like object must
has a :attr:`name` attribute, that is used for *filename*; the default is operate in text mode, i.e. return strings from :meth:`readline`.
``<???>``.
If *filename* is omitted and *fp* has a :attr:`name` attribute, that is used
for *filename*; the default is ``<???>``.
.. method:: RawConfigParser.get(section, option) .. method:: RawConfigParser.get(section, option)
...@@ -279,8 +281,9 @@ RawConfigParser Objects ...@@ -279,8 +281,9 @@ RawConfigParser Objects
.. method:: RawConfigParser.write(fileobject) .. method:: RawConfigParser.write(fileobject)
Write a representation of the configuration to the specified file object. This Write a representation of the configuration to the specified file object,
representation can be parsed by a future :meth:`read` call. which must be opened in text mode (accepting strings). This representation
can be parsed by a future :meth:`read` call.
.. method:: RawConfigParser.remove_option(section, option) .. method:: RawConfigParser.remove_option(section, option)
...@@ -370,7 +373,7 @@ An example of writing to a configuration file:: ...@@ -370,7 +373,7 @@ An example of writing to a configuration file::
config.set('Section1', 'foo', '%(bar)s is %(baz)s!') config.set('Section1', 'foo', '%(bar)s is %(baz)s!')
# Writing our configuration file to 'example.cfg' # Writing our configuration file to 'example.cfg'
with open('example.cfg', 'wb') as configfile: with open('example.cfg', 'w') as configfile:
config.write(configfile) config.write(configfile)
An example of reading the configuration file again:: An example of reading the configuration file again::
......
...@@ -4,21 +4,25 @@ ...@@ -4,21 +4,25 @@
.. module:: copy .. module:: copy
:synopsis: Shallow and deep copy operations. :synopsis: Shallow and deep copy operations.
This module provides generic (shallow and deep) copying operations.
.. index::
single: copy() (in copy)
single: deepcopy() (in copy)
This module provides generic (shallow and deep) copying operations. Interface summary:
.. function:: copy(x)
Return a shallow copy of *x*.
.. function:: deepcopy(x)
Return a deep copy of *x*.
Interface summary::
import copy .. exception:: error
x = copy.copy(y) # make a shallow copy of y Raised for module specific errors.
x = copy.deepcopy(y) # make a deep copy of y
For module specific errors, :exc:`copy.error` is raised.
The difference between shallow and deep copying is only relevant for compound The difference between shallow and deep copying is only relevant for compound
objects (objects that contain other objects, like lists or class instances): objects (objects that contain other objects, like lists or class instances):
......
...@@ -36,12 +36,14 @@ supports a substantially wider range of objects than marshal. ...@@ -36,12 +36,14 @@ supports a substantially wider range of objects than marshal.
Not all Python object types are supported; in general, only objects whose value Not all Python object types are supported; in general, only objects whose value
is independent from a particular invocation of Python can be written and read by is independent from a particular invocation of Python can be written and read by
this module. The following types are supported: ``None``, integers, this module. The following types are supported: booleans, integers, floating
floating point numbers, strings, bytes, bytearrays, tuples, lists, sets, point numbers, complex numbers, strings, bytes, bytearrays, tuples, lists, sets,
dictionaries, and code objects, where it should be understood that tuples, lists frozensets, dictionaries, and code objects, where it should be understood that
and dictionaries are only supported as long as the values contained therein are tuples, lists, sets, frozensets and dictionaries are only supported as long as
themselves supported; and recursive lists and dictionaries should not be written the values contained therein are themselves supported; and recursive lists, sets
(they will cause infinite loops). and dictionaries should not be written (they will cause infinite loops). The
singletons :const:`None`, :const:`Ellipsis` and :exc:`StopIteration` can also be
marshalled and unmarshalled.
There are functions that read/write files as well as functions operating on There are functions that read/write files as well as functions operating on
strings. strings.
......
...@@ -227,7 +227,8 @@ The :mod:`urllib.parse` module defines the following functions: ...@@ -227,7 +227,8 @@ The :mod:`urllib.parse` module defines the following functions:
.. function:: quote(string, safe='/', encoding=None, errors=None) .. function:: quote(string, safe='/', encoding=None, errors=None)
Replace special characters in *string* using the ``%xx`` escape. Letters, Replace special characters in *string* using the ``%xx`` escape. Letters,
digits, and the characters ``'_.-'`` are never quoted. The optional *safe* digits, and the characters ``'_.-'`` are never quoted. By default, this
function is intended for quoting the path section of URL. The optional *safe*
parameter specifies additional ASCII characters that should not be quoted parameter specifies additional ASCII characters that should not be quoted
--- its default value is ``'/'``. --- its default value is ``'/'``.
......
...@@ -666,7 +666,7 @@ Modules ...@@ -666,7 +666,7 @@ Modules
of the shared library file. of the shared library file.
Custom classes Custom classes
Custon class types are typically created by class definitions (see section Custom class types are typically created by class definitions (see section
:ref:`class`). A class has a namespace implemented by a dictionary object. :ref:`class`). A class has a namespace implemented by a dictionary object.
Class attribute references are translated to lookups in this dictionary, e.g., Class attribute references are translated to lookups in this dictionary, e.g.,
``C.x`` is translated to ``C.__dict__["x"]`` (although there are a number of ``C.x`` is translated to ``C.__dict__["x"]`` (although there are a number of
......
...@@ -208,7 +208,9 @@ class Pdb(bdb.Bdb, cmd.Cmd): ...@@ -208,7 +208,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
"""Custom displayhook for the exec in default(), which prevents """Custom displayhook for the exec in default(), which prevents
assignment of the _ variable in the builtins. assignment of the _ variable in the builtins.
""" """
print(repr(obj)) # reproduce the behavior of the standard displayhook, not printing None
if obj is not None:
print(repr(obj))
def default(self, line): def default(self, line):
if line[:1] == '!': line = line[1:] if line[:1] == '!': line = line[1:]
......
...@@ -1557,7 +1557,7 @@ class Helper: ...@@ -1557,7 +1557,7 @@ class Helper:
'global': ('global', 'NAMESPACES'), 'global': ('global', 'NAMESPACES'),
'if': ('if', 'TRUTHVALUE'), 'if': ('if', 'TRUTHVALUE'),
'import': ('import', 'MODULES'), 'import': ('import', 'MODULES'),
'in': ('in', 'SEQUENCEMETHODS2'), 'in': ('in', 'SEQUENCEMETHODS'),
'is': 'COMPARISON', 'is': 'COMPARISON',
'lambda': ('lambda', 'FUNCTIONS'), 'lambda': ('lambda', 'FUNCTIONS'),
'not': 'BOOLEAN', 'not': 'BOOLEAN',
...@@ -1643,12 +1643,12 @@ class Helper: ...@@ -1643,12 +1643,12 @@ class Helper:
'PRECEDENCE': 'EXPRESSIONS', 'PRECEDENCE': 'EXPRESSIONS',
'OBJECTS': ('objects', 'TYPES'), 'OBJECTS': ('objects', 'TYPES'),
'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS ' 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS ' 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'), 'NUMBERMETHODS CLASSES'),
'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'), 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'), 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'), 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 ' 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
'SPECIALMETHODS'), 'SPECIALMETHODS'),
'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'), 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT ' 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
...@@ -1672,8 +1672,8 @@ class Helper: ...@@ -1672,8 +1672,8 @@ class Helper:
'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'), 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'), 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'), 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'), 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'), 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
'CALLS': ('calls', 'EXPRESSIONS'), 'CALLS': ('calls', 'EXPRESSIONS'),
'POWER': ('power', 'EXPRESSIONS'), 'POWER': ('power', 'EXPRESSIONS'),
'UNARY': ('unary', 'EXPRESSIONS'), 'UNARY': ('unary', 'EXPRESSIONS'),
......
...@@ -56,8 +56,29 @@ class FunctionPropertiesTest(FuncAttrsTest): ...@@ -56,8 +56,29 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.assertEqual(test(), 3) # self.b always returns 3, arbitrarily self.assertEqual(test(), 3) # self.b always returns 3, arbitrarily
def test___globals__(self): def test___globals__(self):
self.assertEqual(self.b.__globals__, globals()) self.assertIs(self.b.__globals__, globals())
self.cannot_set_attr(self.b, '__globals__', 2, (AttributeError, TypeError)) self.cannot_set_attr(self.b, '__globals__', 2,
(AttributeError, TypeError))
def test___closure__(self):
a = 12
def f(): print(a)
c = f.__closure__
self.assertTrue(isinstance(c, tuple))
self.assertEqual(len(c), 1)
# don't have a type object handy
self.assertEqual(c[0].__class__.__name__, "cell")
self.cannot_set_attr(f, "__closure__", c, AttributeError)
def test_empty_cell(self):
def f(): print(a)
try:
f.__closure__[0].cell_contents
except ValueError:
pass
else:
self.fail("shouldn't be able to read an empty cell")
a = 12
def test___name__(self): def test___name__(self):
self.assertEqual(self.b.__name__, 'b') self.assertEqual(self.b.__name__, 'b')
...@@ -90,16 +111,20 @@ class FunctionPropertiesTest(FuncAttrsTest): ...@@ -90,16 +111,20 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.assertEqual(c.__code__, d.__code__) self.assertEqual(c.__code__, d.__code__)
self.assertEqual(c(), 7) self.assertEqual(c(), 7)
# self.assertEqual(d(), 7) # self.assertEqual(d(), 7)
try: b.__code__ = c.__code__ try:
except ValueError: pass b.__code__ = c.__code__
else: self.fail( except ValueError:
"__code__ with different numbers of free vars should not be " pass
"possible") else:
try: e.__code__ = d.__code__ self.fail("__code__ with different numbers of free vars should "
except ValueError: pass "not be possible")
else: self.fail( try:
"__code__ with different numbers of free vars should not be " e.__code__ = d.__code__
"possible") except ValueError:
pass
else:
self.fail("__code__ with different numbers of free vars should "
"not be possible")
def test_blank_func_defaults(self): def test_blank_func_defaults(self):
self.assertEqual(self.b.__defaults__, None) self.assertEqual(self.b.__defaults__, None)
...@@ -120,13 +145,16 @@ class FunctionPropertiesTest(FuncAttrsTest): ...@@ -120,13 +145,16 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.assertEqual(first_func(3, 5), 8) self.assertEqual(first_func(3, 5), 8)
del second_func.__defaults__ del second_func.__defaults__
self.assertEqual(second_func.__defaults__, None) self.assertEqual(second_func.__defaults__, None)
try: second_func() try:
except TypeError: pass second_func()
else: self.fail( except TypeError:
"func_defaults does not update; deleting it does not remove " pass
"requirement") else:
self.fail("__defaults__ does not update; deleting it does not "
"remove requirement")
class ImplicitReferencesTest(FuncAttrsTest):
class InstancemethodAttrTest(FuncAttrsTest):
def test___class__(self): def test___class__(self):
self.assertEqual(self.fi.a.__self__.__class__, self.F) self.assertEqual(self.fi.a.__self__.__class__, self.F)
...@@ -146,31 +174,45 @@ class ImplicitReferencesTest(FuncAttrsTest): ...@@ -146,31 +174,45 @@ class ImplicitReferencesTest(FuncAttrsTest):
self.fi.id = types.MethodType(id, self.fi) self.fi.id = types.MethodType(id, self.fi)
self.assertEqual(self.fi.id(), id(self.fi)) self.assertEqual(self.fi.id(), id(self.fi))
# Test usage # Test usage
try: self.fi.id.unknown_attr try:
except AttributeError: pass self.fi.id.unknown_attr
else: self.fail("using unknown attributes should raise AttributeError") except AttributeError:
pass
else:
self.fail("using unknown attributes should raise AttributeError")
# Test assignment and deletion # Test assignment and deletion
self.cannot_set_attr(self.fi.id, 'unknown_attr', 2, AttributeError) self.cannot_set_attr(self.fi.id, 'unknown_attr', 2, AttributeError)
class ArbitraryFunctionAttrTest(FuncAttrsTest): class ArbitraryFunctionAttrTest(FuncAttrsTest):
def test_set_attr(self): def test_set_attr(self):
self.b.known_attr = 7 self.b.known_attr = 7
self.assertEqual(self.b.known_attr, 7) self.assertEqual(self.b.known_attr, 7)
try: self.fi.a.known_attr = 7 try:
except AttributeError: pass self.fi.a.known_attr = 7
else: self.fail("setting attributes on methods should raise error") except AttributeError:
pass
else:
self.fail("setting attributes on methods should raise error")
def test_delete_unknown_attr(self): def test_delete_unknown_attr(self):
try: del self.b.unknown_attr try:
except AttributeError: pass del self.b.unknown_attr
else: self.fail("deleting unknown attribute should raise TypeError") except AttributeError:
pass
else:
self.fail("deleting unknown attribute should raise TypeError")
def test_unset_attr(self): def test_unset_attr(self):
for func in [self.b, self.fi.a]: for func in [self.b, self.fi.a]:
try: func.non_existent_attr try:
except AttributeError: pass func.non_existent_attr
else: self.fail("using unknown attributes should raise " except AttributeError:
"AttributeError") pass
else:
self.fail("using unknown attributes should raise "
"AttributeError")
class FunctionDictsTest(FuncAttrsTest): class FunctionDictsTest(FuncAttrsTest):
def test_setting_dict_to_invalid(self): def test_setting_dict_to_invalid(self):
...@@ -183,11 +225,11 @@ class FunctionDictsTest(FuncAttrsTest): ...@@ -183,11 +225,11 @@ class FunctionDictsTest(FuncAttrsTest):
d = {'known_attr': 7} d = {'known_attr': 7}
self.b.__dict__ = d self.b.__dict__ = d
# Test assignment # Test assignment
self.assertEqual(d, self.b.__dict__) self.assertIs(d, self.b.__dict__)
# ... and on all the different ways of referencing the method's func # ... and on all the different ways of referencing the method's func
self.F.a.__dict__ = d self.F.a.__dict__ = d
self.assertEqual(d, self.fi.a.__func__.__dict__) self.assertIs(d, self.fi.a.__func__.__dict__)
self.assertEqual(d, self.fi.a.__dict__) self.assertIs(d, self.fi.a.__dict__)
# Test value # Test value
self.assertEqual(self.b.known_attr, 7) self.assertEqual(self.b.known_attr, 7)
self.assertEqual(self.b.__dict__['known_attr'], 7) self.assertEqual(self.b.__dict__['known_attr'], 7)
...@@ -196,9 +238,12 @@ class FunctionDictsTest(FuncAttrsTest): ...@@ -196,9 +238,12 @@ class FunctionDictsTest(FuncAttrsTest):
self.assertEqual(self.fi.a.known_attr, 7) self.assertEqual(self.fi.a.known_attr, 7)
def test_delete___dict__(self): def test_delete___dict__(self):
try: del self.b.__dict__ try:
except TypeError: pass del self.b.__dict__
else: self.fail("deleting function dictionary should raise TypeError") except TypeError:
pass
else:
self.fail("deleting function dictionary should raise TypeError")
def test_unassigned_dict(self): def test_unassigned_dict(self):
self.assertEqual(self.b.__dict__, {}) self.assertEqual(self.b.__dict__, {})
...@@ -209,6 +254,7 @@ class FunctionDictsTest(FuncAttrsTest): ...@@ -209,6 +254,7 @@ class FunctionDictsTest(FuncAttrsTest):
d[self.b] = value d[self.b] = value
self.assertEqual(d[self.b], value) self.assertEqual(d[self.b], value)
class FunctionDocstringTest(FuncAttrsTest): class FunctionDocstringTest(FuncAttrsTest):
def test_set_docstring_attr(self): def test_set_docstring_attr(self):
self.assertEqual(self.b.__doc__, None) self.assertEqual(self.b.__doc__, None)
...@@ -224,6 +270,7 @@ class FunctionDocstringTest(FuncAttrsTest): ...@@ -224,6 +270,7 @@ class FunctionDocstringTest(FuncAttrsTest):
del self.b.__doc__ del self.b.__doc__
self.assertEqual(self.b.__doc__, None) self.assertEqual(self.b.__doc__, None)
def cell(value): def cell(value):
"""Create a cell containing the given value.""" """Create a cell containing the given value."""
def f(): def f():
...@@ -242,6 +289,7 @@ def empty_cell(empty=True): ...@@ -242,6 +289,7 @@ def empty_cell(empty=True):
a = 1729 a = 1729
return f.__closure__[0] return f.__closure__[0]
class CellTest(unittest.TestCase): class CellTest(unittest.TestCase):
def test_comparison(self): def test_comparison(self):
# These tests are here simply to exercise the comparison code; # These tests are here simply to exercise the comparison code;
...@@ -254,6 +302,7 @@ class CellTest(unittest.TestCase): ...@@ -254,6 +302,7 @@ class CellTest(unittest.TestCase):
self.assertTrue(cell(-36) == cell(-36.0)) self.assertTrue(cell(-36) == cell(-36.0))
self.assertTrue(cell(True) > empty_cell()) self.assertTrue(cell(True) > empty_cell())
class StaticMethodAttrsTest(unittest.TestCase): class StaticMethodAttrsTest(unittest.TestCase):
def test_func_attribute(self): def test_func_attribute(self):
def f(): def f():
...@@ -267,7 +316,7 @@ class StaticMethodAttrsTest(unittest.TestCase): ...@@ -267,7 +316,7 @@ class StaticMethodAttrsTest(unittest.TestCase):
def test_main(): def test_main():
support.run_unittest(FunctionPropertiesTest, ImplicitReferencesTest, support.run_unittest(FunctionPropertiesTest, InstancemethodAttrTest,
ArbitraryFunctionAttrTest, FunctionDictsTest, ArbitraryFunctionAttrTest, FunctionDictsTest,
FunctionDocstringTest, CellTest, FunctionDocstringTest, CellTest,
StaticMethodAttrsTest) StaticMethodAttrsTest)
......
...@@ -12,6 +12,49 @@ from test import support ...@@ -12,6 +12,49 @@ from test import support
from test.test_doctest import _FakeInput from test.test_doctest import _FakeInput
class PdbTestInput(object):
"""Context manager that makes testing Pdb in doctests easier."""
def __init__(self, input):
self.input = input
def __enter__(self):
self.real_stdin = sys.stdin
sys.stdin = _FakeInput(self.input)
def __exit__(self, *exc):
sys.stdin = self.real_stdin
def test_pdb_displayhook():
"""This tests the custom displayhook for pdb.
>>> def test_function(foo, bar):
... import pdb; pdb.Pdb().set_trace()
... pass
>>> with PdbTestInput([
... 'foo',
... 'bar',
... 'for i in range(5): print(i)',
... 'continue',
... ]):
... test_function(1, None)
> <doctest test.test_pdb.test_pdb_displayhook[0]>(3)test_function()
-> pass
(Pdb) foo
1
(Pdb) bar
(Pdb) for i in range(5): print(i)
0
1
2
3
4
(Pdb) continue
"""
def test_pdb_skip_modules(): def test_pdb_skip_modules():
"""This illustrates the simple case of module skipping. """This illustrates the simple case of module skipping.
...@@ -19,16 +62,12 @@ def test_pdb_skip_modules(): ...@@ -19,16 +62,12 @@ def test_pdb_skip_modules():
... import string ... import string
... import pdb; pdb.Pdb(skip=['stri*']).set_trace() ... import pdb; pdb.Pdb(skip=['stri*']).set_trace()
... string.capwords('FOO') ... string.capwords('FOO')
>>> real_stdin = sys.stdin
>>> sys.stdin = _FakeInput([
... 'step',
... 'continue',
... ])
>>> try: >>> with PdbTestInput([
... 'step',
... 'continue',
... ]):
... skip_module() ... skip_module()
... finally:
... sys.stdin = real_stdin
> <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module() > <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()
-> string.capwords('FOO') -> string.capwords('FOO')
(Pdb) step (Pdb) step
...@@ -36,7 +75,7 @@ def test_pdb_skip_modules(): ...@@ -36,7 +75,7 @@ def test_pdb_skip_modules():
> <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()->None > <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()->None
-> string.capwords('FOO') -> string.capwords('FOO')
(Pdb) continue (Pdb) continue
""" """
# Module for testing skipping of module that makes a callback # Module for testing skipping of module that makes a callback
...@@ -50,22 +89,19 @@ def test_pdb_skip_modules_with_callback(): ...@@ -50,22 +89,19 @@ def test_pdb_skip_modules_with_callback():
>>> def skip_module(): >>> def skip_module():
... def callback(): ... def callback():
... return None ... return None
... import pdb;pdb.Pdb(skip=['module_to_skip*']).set_trace() ... import pdb; pdb.Pdb(skip=['module_to_skip*']).set_trace()
... mod.foo_pony(callback) ... mod.foo_pony(callback)
>>> real_stdin = sys.stdin
>>> sys.stdin = _FakeInput([ >>> with PdbTestInput([
... 'step', ... 'step',
... 'step', ... 'step',
... 'step', ... 'step',
... 'step', ... 'step',
... 'step', ... 'step',
... 'continue', ... 'continue',
... ]) ... ]):
>>> try:
... skip_module() ... skip_module()
... finally: ... pass # provides something to "step" to
... sys.stdin = real_stdin
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module() > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()
-> mod.foo_pony(callback) -> mod.foo_pony(callback)
(Pdb) step (Pdb) step
...@@ -84,10 +120,10 @@ def test_pdb_skip_modules_with_callback(): ...@@ -84,10 +120,10 @@ def test_pdb_skip_modules_with_callback():
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()->None > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()->None
-> mod.foo_pony(callback) -> mod.foo_pony(callback)
(Pdb) step (Pdb) step
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[3]>(4)<module>() > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[1]>(10)<module>()
-> sys.stdin = real_stdin -> pass # provides something to "step" to
(Pdb) continue (Pdb) continue
""" """
def test_main(): def test_main():
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment