summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2009-10-27 20:19:02 (GMT)
committerGeorg Brandl <georg@python.org>2009-10-27 20:19:02 (GMT)
commit22fff4363324c408b13761e5ccc5e318797fdc30 (patch)
treeca1ad7048b9cdffc0d23bb8b50224ef6180f96f4
parent7dc008d001ef3037d0634ba4c5bcb5631d4ec0ce (diff)
downloadcpython-22fff4363324c408b13761e5ccc5e318797fdc30.zip
cpython-22fff4363324c408b13761e5ccc5e318797fdc30.tar.gz
cpython-22fff4363324c408b13761e5ccc5e318797fdc30.tar.bz2
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. ........ ................
-rw-r--r--Demo/scripts/README9
-rw-r--r--Demo/scripts/beer.py16
-rwxr-xr-xDemo/scripts/fact.py36
-rw-r--r--Demo/scripts/find-uname.py12
-rwxr-xr-xDemo/scripts/ftpstats.py142
-rwxr-xr-xDemo/scripts/lpwatch.py84
-rwxr-xr-xDemo/scripts/markov.py64
-rwxr-xr-xDemo/scripts/mkrcs.py61
-rwxr-xr-xDemo/scripts/morse.py128
-rwxr-xr-xDemo/scripts/newslist.py140
-rwxr-xr-xDemo/scripts/pi.py3
-rwxr-xr-xDemo/scripts/pp.py68
-rwxr-xr-xDemo/scripts/queens.py6
-rwxr-xr-xDemo/scripts/script.py29
-rwxr-xr-xDemo/scripts/unbirthday.py48
-rw-r--r--Demo/xml/elem_count.py26
-rw-r--r--Demo/xml/roundtrip.py11
-rw-r--r--Demo/xml/rss2html.py52
-rw-r--r--Doc/library/configparser.rst15
-rw-r--r--Doc/library/copy.rst22
-rw-r--r--Doc/library/marshal.rst14
-rw-r--r--Doc/library/urllib.parse.rst3
-rw-r--r--Doc/reference/datamodel.rst2
-rwxr-xr-xLib/pdb.py4
-rwxr-xr-xLib/pydoc.py12
-rw-r--r--Lib/test/test_funcattrs.py125
-rw-r--r--Lib/test/test_pdb.py88
27 files changed, 624 insertions, 596 deletions
diff --git a/Demo/scripts/README b/Demo/scripts/README
index d8434e8..097b9b7 100644
--- a/Demo/scripts/README
+++ b/Demo/scripts/README
@@ -5,15 +5,14 @@ See also the Tools/scripts directory!
beer.py Print the classic 'bottles of beer' list.
eqfix.py Fix .py files to use the correct equality test operator
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
-ftpstats.py Summarize ftp daemon log file
lpwatch.py Watch BSD line printer queues
makedir.py Like mkdir -p
markov.py Markov chain simulation of words or characters
-mboxconvvert.py Convert MH or MMDF mailboxes to unix mailbox format
-mkrcs.py Fix symlinks named RCS into parallel tree
-morse.py Produce morse code (audible or on AIFF file)
+mboxconvert.py Convert MH or MMDF mailboxes to unix mailbox format
+morse.py Produce morse code (as an 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
pp.py Emulate some Perl command line options
primes.py Print prime numbers
diff --git a/Demo/scripts/beer.py b/Demo/scripts/beer.py
index f050572..8135509 100644
--- a/Demo/scripts/beer.py
+++ b/Demo/scripts/beer.py
@@ -1,14 +1,20 @@
#! /usr/bin/env python
+
# By GvR, demystified after a version by Fredrik Lundh.
+
import sys
+
n = 100
-if sys.argv[1:]: n = int(sys.argv[1])
+if sys.argv[1:]:
+ n = int(sys.argv[1])
+
def bottle(n):
if n == 0: return "no more bottles of beer"
if n == 1: return "one bottle of beer"
return str(n) + " bottles of beer"
-for i in range(n):
- print(bottle(n-i), "on the wall,")
- print(bottle(n-i) + ".")
+
+for i in range(n, 0, -1):
+ print(bottle(i), "on the wall,")
+ print(bottle(i) + ".")
print("Take one down, pass it around,")
- print(bottle(n-i-1), "on the wall.")
+ print(bottle(i-1), "on the wall.")
diff --git a/Demo/scripts/fact.py b/Demo/scripts/fact.py
index c76474c..71fcda2 100755
--- a/Demo/scripts/fact.py
+++ b/Demo/scripts/fact.py
@@ -9,39 +9,41 @@ import sys
from math import sqrt
def fact(n):
- if n < 1: raise ValueError # fact() argument should be >= 1
- if n == 1: return [] # special case
+ if n < 1:
+ raise ValueError('fact() argument should be >= 1')
+ if n == 1:
+ return [] # special case
res = []
- # Treat even factors special, so we can use i = i+2 later
- while n%2 == 0:
+ # Treat even factors special, so we can use i += 2 later
+ while n % 2 == 0:
res.append(2)
- n = n//2
+ n //= 2
# Try odd numbers up to sqrt(n)
- limit = sqrt(float(n+1))
+ limit = sqrt(n+1)
i = 3
while i <= limit:
- if n%i == 0:
+ if n % i == 0:
res.append(i)
- n = n//i
+ n //= i
limit = sqrt(n+1)
else:
- i = i+2
+ i += 2
if n != 1:
res.append(n)
return res
def main():
if len(sys.argv) > 1:
- for arg in sys.argv[1:]:
- n = eval(arg)
- print(n, fact(n))
+ source = sys.argv[1:]
else:
+ source = iter(input, '')
+ for arg in source:
try:
- while 1:
- n = eval(input())
- print(n, fact(n))
- except EOFError:
- pass
+ n = int(arg)
+ except ValueError:
+ print(arg, 'is not an integer')
+ else:
+ print(n, fact(n))
if __name__ == "__main__":
main()
diff --git a/Demo/scripts/find-uname.py b/Demo/scripts/find-uname.py
index fbf4033..1902423 100644
--- a/Demo/scripts/find-uname.py
+++ b/Demo/scripts/find-uname.py
@@ -21,20 +21,20 @@ import sys
import re
def main(args):
- unicode_names= []
+ unicode_names = []
for ix in range(sys.maxunicode+1):
try:
- unicode_names.append( (ix, unicodedata.name(chr(ix))) )
+ unicode_names.append((ix, unicodedata.name(chr(ix))))
except ValueError: # no name for the character
pass
for arg in args:
pat = re.compile(arg, re.I)
- matches = [(x,y) for (x,y) in unicode_names
- if pat.search(y) is not None]
+ matches = [(y,x) for (x,y) in unicode_names
+ if pat.search(y) is not None]
if matches:
print("***", arg, "matches", "***")
- for (x,y) in matches:
- print("%s (%d)" % (y,x))
+ for match in matches:
+ print("%s (%d)" % match)
if __name__ == "__main__":
main(sys.argv[1:])
diff --git a/Demo/scripts/ftpstats.py b/Demo/scripts/ftpstats.py
deleted file mode 100755
index cb0c242..0000000
--- a/Demo/scripts/ftpstats.py
+++ /dev/null
@@ -1,142 +0,0 @@
-#! /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()
diff --git a/Demo/scripts/lpwatch.py b/Demo/scripts/lpwatch.py
index 262e562..90b3ecf 100755
--- a/Demo/scripts/lpwatch.py
+++ b/Demo/scripts/lpwatch.py
@@ -3,10 +3,9 @@
# Watch line printer queue(s).
# Intended for BSD 4.3 lpq.
-import posix
+import os
import sys
import time
-import string
DEF_PRINTER = 'psc'
DEF_DELAY = 10
@@ -14,94 +13,87 @@ DEF_DELAY = 10
def main():
delay = DEF_DELAY # XXX Use getopt() later
try:
- thisuser = posix.environ['LOGNAME']
+ thisuser = os.environ['LOGNAME']
except:
- thisuser = posix.environ['USER']
+ thisuser = os.environ['USER']
printers = sys.argv[1:]
if printers:
# Strip '-P' from printer names just in case
# the user specified it...
- for i in range(len(printers)):
- if printers[i][:2] == '-P':
- printers[i] = printers[i][2:]
+ for i, name in enumerate(printers):
+ if name[:2] == '-P':
+ printers[i] = name[2:]
else:
- if 'PRINTER' in posix.environ:
- printers = [posix.environ['PRINTER']]
+ if 'PRINTER' in os.environ:
+ printers = [os.environ['PRINTER']]
else:
printers = [DEF_PRINTER]
- #
- clearhome = posix.popen('clear', 'r').read()
- #
- while 1:
+
+ clearhome = os.popen('clear', 'r').read()
+
+ while True:
text = clearhome
for name in printers:
- text = text + makestatus(name, thisuser) + '\n'
+ text += makestatus(name, thisuser) + '\n'
print(text)
time.sleep(delay)
def makestatus(name, thisuser):
- pipe = posix.popen('lpq -P' + name + ' 2>&1', 'r')
+ pipe = os.popen('lpq -P' + name + ' 2>&1', 'r')
lines = []
users = {}
aheadbytes = 0
aheadjobs = 0
- userseen = 0
+ userseen = False
totalbytes = 0
totaljobs = 0
- while 1:
- line = pipe.readline()
- if not line: break
- fields = string.split(line)
+ for line in pipe:
+ fields = line.split()
n = len(fields)
if len(fields) >= 6 and fields[n-1] == 'bytes':
- rank = fields[0]
- user = fields[1]
- job = fields[2]
+ rank, user, job = fields[0:3]
files = fields[3:-2]
- bytes = eval(fields[n-2])
+ bytes = int(fields[n-2])
if user == thisuser:
- userseen = 1
+ userseen = True
elif not userseen:
- aheadbytes = aheadbytes + bytes
- aheadjobs = aheadjobs + 1
- totalbytes = totalbytes + bytes
- totaljobs = totaljobs + 1
- if user in users:
- ujobs, ubytes = users[user]
- else:
- ujobs, ubytes = 0, 0
- ujobs = ujobs + 1
- ubytes = ubytes + bytes
+ aheadbytes += bytes
+ aheadjobs += 1
+ totalbytes += bytes
+ totaljobs += 1
+ ujobs, ubytes = users.get(user, (0, 0))
+ ujobs += 1
+ ubytes += bytes
users[user] = ujobs, ubytes
else:
if fields and fields[0] != 'Rank':
- line = string.strip(line)
+ line = line.strip()
if line == 'no entries':
line = name + ': idle'
elif line[-22:] == ' is ready and printing':
line = name
lines.append(line)
- #
+
if totaljobs:
- line = '%d K' % ((totalbytes+1023)//1024)
+ line = '%d K' % ((totalbytes+1023) // 1024)
if totaljobs != len(users):
- line = line + ' (%d jobs)' % totaljobs
+ line += ' (%d jobs)' % totaljobs
if len(users) == 1:
- line = line + ' for %s' % (list(users.keys())[0],)
+ line += ' for %s' % next(iter(users))
else:
- line = line + ' for %d users' % len(users)
+ line += ' for %d users' % len(users)
if userseen:
if aheadjobs == 0:
- line = line + ' (%s first)' % thisuser
+ line += ' (%s first)' % thisuser
else:
- line = line + ' (%d K before %s)' % (
- (aheadbytes+1023)//1024, thisuser)
+ line += ' (%d K before %s)' % (
+ (aheadbytes+1023) // 1024, thisuser)
lines.append(line)
- #
+
sts = pipe.close()
if sts:
lines.append('lpq exit status %r' % (sts,))
- return string.joinfields(lines, ': ')
+ return ': '.join(lines)
if __name__ == "__main__":
try:
diff --git a/Demo/scripts/markov.py b/Demo/scripts/markov.py
index 6f3482b..990c972 100755
--- a/Demo/scripts/markov.py
+++ b/Demo/scripts/markov.py
@@ -5,11 +5,10 @@ class Markov:
self.histsize = histsize
self.choice = choice
self.trans = {}
+
def add(self, state, next):
- if state not in self.trans:
- self.trans[state] = [next]
- else:
- self.trans[state].append(next)
+ self.trans.setdefault(state, []).append(next)
+
def put(self, seq):
n = self.histsize
add = self.add
@@ -17,26 +16,29 @@ class Markov:
for i in range(len(seq)):
add(seq[max(0, i-n):i], seq[i:i+1])
add(seq[len(seq)-n:], None)
+
def get(self):
choice = self.choice
trans = self.trans
n = self.histsize
seq = choice(trans[None])
- while 1:
+ while True:
subseq = seq[max(0, len(seq)-n):]
options = trans[subseq]
next = choice(options)
- if not next: break
- seq = seq + next
+ if not next:
+ break
+ seq += next
return seq
+
def test():
- import sys, string, random, getopt
+ import sys, random, getopt
args = sys.argv[1:]
try:
- opts, args = getopt.getopt(args, '0123456789cdw')
+ opts, args = getopt.getopt(args, '0123456789cdwq')
except getopt.error:
- print('Usage: markov [-#] [-cddqw] [file] ...')
+ print('Usage: %s [-#] [-cddqw] [file] ...' % sys.argv[0])
print('Options:')
print('-#: 1-digit history size (default 2)')
print('-c: characters (default)')
@@ -49,16 +51,19 @@ def test():
print('exactly one space separating words.')
print('Output consists of paragraphs separated by blank')
print('lines, where lines are no longer than 72 characters.')
+ sys.exit(2)
histsize = 2
- do_words = 0
+ do_words = False
debug = 1
for o, a in opts:
- if '-0' <= o <= '-9': histsize = eval(o[1:])
- if o == '-c': do_words = 0
- if o == '-d': debug = debug + 1
+ if '-0' <= o <= '-9': histsize = int(o[1:])
+ if o == '-c': do_words = False
+ if o == '-d': debug += 1
if o == '-q': debug = 0
- if o == '-w': do_words = 1
- if not args: args = ['-']
+ if o == '-w': do_words = True
+ if not args:
+ args = ['-']
+
m = Markov(histsize, random.choice)
try:
for filename in args:
@@ -72,13 +77,15 @@ def test():
if debug: print('processing', filename, '...')
text = f.read()
f.close()
- paralist = string.splitfields(text, '\n\n')
+ paralist = text.split('\n\n')
for para in paralist:
if debug > 1: print('feeding ...')
- words = string.split(para)
+ words = para.split()
if words:
- if do_words: data = tuple(words)
- else: data = string.joinfields(words, ' ')
+ if do_words:
+ data = tuple(words)
+ else:
+ data = ' '.join(words)
m.put(data)
except KeyboardInterrupt:
print('Interrupted -- continue with data read so far')
@@ -86,16 +93,19 @@ def test():
print('No valid input files')
return
if debug: print('done.')
+
if debug > 1:
for key in m.trans.keys():
if key is None or len(key) < histsize:
print(repr(key), m.trans[key])
if histsize == 0: print(repr(''), m.trans[''])
print()
- while 1:
+ while True:
data = m.get()
- if do_words: words = data
- else: words = string.split(data)
+ if do_words:
+ words = data
+ else:
+ words = data.split()
n = 0
limit = 72
for w in words:
@@ -103,15 +113,9 @@ def test():
print()
n = 0
print(w, end=' ')
- n = n + len(w) + 1
+ n += len(w) + 1
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__":
test()
diff --git a/Demo/scripts/mkrcs.py b/Demo/scripts/mkrcs.py
deleted file mode 100755
index 317647a..0000000
--- a/Demo/scripts/mkrcs.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#! /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()
diff --git a/Demo/scripts/morse.py b/Demo/scripts/morse.py
new file mode 100755
index 0000000..5aacaa1
--- /dev/null
+++ b/Demo/scripts/morse.py
@@ -0,0 +1,128 @@
+#! /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()
diff --git a/Demo/scripts/newslist.py b/Demo/scripts/newslist.py
index 02b4b7c..9cea1b4 100755
--- a/Demo/scripts/newslist.py
+++ b/Demo/scripts/newslist.py
@@ -32,22 +32,22 @@
# fraser@europarc.xerox.com qs101@cl.cam.ac.uk
# #
#######################################################################
-import sys,nntplib, string, marshal, time, os, posix, string
+import sys, nntplib, marshal, time, os
#######################################################################
# Check these variables before running! #
# Top directory.
# Filenames which don't start with / are taken as being relative to this.
-topdir='/anfs/qsbigdisc/web/html/newspage'
+topdir = os.path.expanduser('~/newspage')
# The name of your NNTP host
# eg.
# newshost = 'nntp-serv.cl.cam.ac.uk'
# or use following to get the name from the NNTPSERVER environment
# variable:
-# newshost = posix.environ['NNTPSERVER']
-newshost = 'nntp-serv.cl.cam.ac.uk'
+# newshost = os.environ['NNTPSERVER']
+newshost = 'news.example.com'
# The filename for a local cache of the newsgroup list
treefile = 'grouptree'
@@ -81,7 +81,7 @@ skipempty = 1
# pagelinkicon can contain html to put an icon after links to
# further pages. This helps to make important links stand out.
# Set to '' if not wanted, or '...' is quite a good one.
-pagelinkicon='... <img src="http://pelican.cl.cam.ac.uk/icons/page.xbm"> '
+pagelinkicon = '... <img src="http://pelican.cl.cam.ac.uk/icons/page.xbm"> '
# ---------------------------------------------------------------------
# Less important personal preferences:
@@ -106,7 +106,7 @@ from nntplib import NNTP
from stat import *
rcsrev = '$Revision$'
-rcsrev = string.join([s for s in string.split(rcsrev) if '$' not in s])
+rcsrev = ' '.join([s for s in rcsrev.split() if '$' not in s])
desc = {}
# Make (possibly) relative filenames into absolute ones
@@ -120,7 +120,7 @@ page = os.path.join(topdir,pagedir)
def addtotree(tree, groups):
print('Updating tree...')
for i in groups:
- parts = string.splitfields(i,'.')
+ parts = i.split('.')
makeleaf(tree, parts)
# Makeleaf makes a leaf and the branch leading to it if necessary
@@ -141,34 +141,38 @@ def makeleaf(tree,path):
# to those groups beginning with <root>.
def createpage(root, tree, p):
- filename = os.path.join(pagedir,root+'.html')
+ filename = os.path.join(pagedir, root+'.html')
if root == rootpage:
detail = ''
else:
detail = ' under ' + root
- f = open(filename,'w')
- # f.write('Content-Type: text/html\n')
- f.write('<TITLE>Newsgroups available' + detail + '</TITLE>\n')
- f.write('<H1>Newsgroups available' + detail +'</H1>\n')
- f.write('<A HREF="'+httppref+rootpage+'.html">Back to top level</A><P>\n')
- printtree(f,tree,0,p)
- f.write('<I>This page automatically created by \'newslist\' v. '+rcsrev+'.')
- f.write(time.ctime(time.time()) + '</I><P>')
- f.close()
+ with open(filename, 'w') as f:
+ # f.write('Content-Type: text/html\n')
+ f.write('<html>\n<head>\n')
+ f.write('<title>Newsgroups available%s</title>\n' % detail)
+ f.write('</head>\n<body>\n')
+ f.write('<h1>Newsgroups available%s</h1>\n' % detail)
+ f.write('<a href="%s%s.html">Back to top level</a><p>\n' %
+ (httppref, rootpage))
+ printtree(f, tree, 0, p)
+ f.write('\n<p>')
+ f.write("<i>This page automatically created by 'newslist' v. %s." %
+ rcsrev)
+ f.write(time.ctime(time.time()) + '</i>\n')
+ f.write('</body>\n</html>\n')
# Printtree prints the groups as a bulleted list. Groups with
# more than <sublistsize> subgroups will be put on a separate page.
# Other sets of subgroups are just indented.
def printtree(f, tree, indent, p):
- global desc
l = len(tree)
- if l > sublistsize and indent>0:
+ if l > sublistsize and indent > 0:
# Create a new page and a link to it
- f.write('<LI><B><A HREF="'+httppref+p[1:]+'.html">')
- f.write(p[1:]+'.*')
- f.write('</A></B>'+pagelinkicon+'\n')
+ f.write('<li><b><a href="%s%s.html">' % (httppref, p[1:]))
+ f.write(p[1:] + '.*')
+ f.write('</a></b>%s\n' % pagelinkicon)
createpage(p[1:], tree, p)
return
@@ -177,67 +181,64 @@ def printtree(f, tree, indent, p):
if l > 1:
if indent > 0:
# Create a sub-list
- f.write('<LI>'+p[1:]+'\n<UL>')
+ f.write('<li>%s\n<ul>' % p[1:])
else:
# Create a main list
- f.write('<UL>')
+ f.write('<ul>')
indent = indent + 1
for i in kl:
if i == '.':
# Output a newsgroup
- f.write('<LI><A HREF="news:' + p[1:] + '">'+ p[1:] + '</A> ')
+ f.write('<li><a href="news:%s">%s</a> ' % (p[1:], p[1:]))
if p[1:] in desc:
- f.write(' <I>'+desc[p[1:]]+'</I>\n')
+ f.write(' <i>%s</i>\n' % desc[p[1:]])
else:
f.write('\n')
else:
# Output a hierarchy
- printtree(f,tree[i], indent, p+'.'+i)
+ printtree(f, tree[i], indent, p+'.'+i)
if l > 1:
- f.write('\n</UL>')
+ f.write('\n</ul>')
# Reading descriptions file ---------------------------------------
-# This returns an array mapping group name to its description
+# This returns a dict mapping group name to its description
def readdesc(descfile):
global desc
-
desc = {}
if descfile == '':
return
try:
- d = open(descfile, 'r')
- print('Reading descriptions...')
- except (IOError):
+ with open(descfile, 'r') as d:
+ print('Reading descriptions...')
+ for l in d:
+ bits = l.split()
+ try:
+ grp = bits[0]
+ dsc = ' '.join(bits[1:])
+ if len(dsc) > 1:
+ desc[grp] = dsc
+ except IndexError:
+ pass
+ except IOError:
print('Failed to open description file ' + descfile)
return
- l = d.readline()
- while l != '':
- bits = string.split(l)
- try:
- grp = bits[0]
- dsc = string.join(bits[1:])
- if len(dsc)>1:
- desc[grp] = dsc
- except (IndexError):
- pass
- l = d.readline()
# Check that ouput directory exists, ------------------------------
# and offer to create it if not
def checkopdir(pagedir):
if not os.path.isdir(pagedir):
- print('Directory '+pagedir+' does not exist.')
+ print('Directory %s does not exist.' % pagedir)
print('Shall I create it for you? (y/n)')
if sys.stdin.readline()[0] == 'y':
try:
- os.mkdir(pagedir,0o777)
+ os.mkdir(pagedir, 0o777)
except:
print('Sorry - failed!')
sys.exit(1)
@@ -257,23 +258,21 @@ def readlocallist(treefile):
print('If this is the first time you have run newslist, then')
print('use the -a option to create it.')
sys.exit(1)
- treedate = '%02d%02d%02d' % (treetime[0] % 100 ,treetime[1], treetime[2])
+ treedate = '%02d%02d%02d' % (treetime[0] % 100, treetime[1], treetime[2])
try:
- dump = open(treefile,'r')
- tree = marshal.load(dump)
- dump.close()
- except (IOError):
+ with open(treefile, 'rb') as dump:
+ tree = marshal.load(dump)
+ except IOError:
print('Cannot open local group list ' + treefile)
return (tree, treedate)
def writelocallist(treefile, tree):
try:
- dump = open(treefile,'w')
- groups = marshal.dump(tree,dump)
- dump.close()
- print('Saved list to '+treefile+'\n')
+ with open(treefile, 'wb') as dump:
+ groups = marshal.dump(tree, dump)
+ print('Saved list to %s\n' % treefile)
except:
- print('Sorry - failed to write to local group cache '+treefile)
+ print('Sorry - failed to write to local group cache', treefile)
print('Does it (or its directory) have the correct permissions?')
sys.exit(1)
@@ -281,18 +280,18 @@ def writelocallist(treefile, tree):
def getallgroups(server):
print('Getting list of all groups...')
- treedate='010101'
+ treedate = '010101'
info = server.list()[1]
groups = []
print('Processing...')
if skipempty:
print('\nIgnoring following empty groups:')
for i in info:
- grpname = string.split(i[0])[0]
- if skipempty and string.atoi(i[1]) < string.atoi(i[2]):
- print(grpname+' ', end=' ')
+ grpname = i[0].split()[0]
+ if skipempty and int(i[1]) < int(i[2]):
+ print(grpname.decode() + ' ', end=' ')
else:
- groups.append(grpname)
+ groups.append(grpname.decode())
print('\n')
if skipempty:
print('(End of empty groups)')
@@ -301,42 +300,39 @@ def getallgroups(server):
# Return list of new groups on server -----------------------------
def getnewgroups(server, treedate):
- print('Getting list of new groups since start of '+treedate+'...', end=' ')
- info = server.newgroups(treedate,'000001')[1]
+ print('Getting list of new groups since start of %s...' % treedate, end=' ')
+ info = server.newgroups(treedate, '000001')[1]
print('got %d.' % len(info))
print('Processing...', end=' ')
groups = []
for i in info:
- grpname = string.split(i)[0]
- groups.append(grpname)
+ grpname = i.split()[0]
+ groups.append(grpname.decode())
print('Done')
return groups
# Now the main program --------------------------------------------
def main():
- global desc
-
- tree={}
+ tree = {}
# Check that the output directory exists
checkopdir(pagedir)
try:
- print('Connecting to '+newshost+'...')
+ print('Connecting to %s...' % newshost)
if sys.version[0] == '0':
s = NNTP.init(newshost)
else:
s = NNTP(newshost)
- connected = 1
+ connected = True
except (nntplib.error_temp, nntplib.error_perm) as x:
print('Error connecting to host:', x)
print('I\'ll try to use just the local list.')
- connected = 0
+ connected = False
# If -a is specified, read the full list of groups from server
if connected and len(sys.argv) > 1 and sys.argv[1] == '-a':
-
groups = getallgroups(s)
# Otherwise just read the local file and then add
diff --git a/Demo/scripts/pi.py b/Demo/scripts/pi.py
index 19733cb..0740cd0 100755
--- a/Demo/scripts/pi.py
+++ b/Demo/scripts/pi.py
@@ -12,7 +12,7 @@ import sys
def main():
k, a, b, a1, b1 = 2, 4, 1, 12, 4
- while 1:
+ while True:
# Next approximation
p, q, k = k*k, 2*k+1, k+1
a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
@@ -25,7 +25,6 @@ def main():
def output(d):
# Use write() to avoid spaces between the digits
- # Use str() to avoid the 'L'
sys.stdout.write(str(d))
# Flush so the output is seen immediately
sys.stdout.flush()
diff --git a/Demo/scripts/pp.py b/Demo/scripts/pp.py
index 9010b7a..2c948f7 100755
--- a/Demo/scripts/pp.py
+++ b/Demo/scripts/pp.py
@@ -22,7 +22,6 @@
# - except for -n/-p, run directly from the file if at all possible
import sys
-import string
import getopt
FS = ''
@@ -36,7 +35,7 @@ PFLAG = 0
try:
optlist, ARGS = getopt.getopt(sys.argv[1:], 'acde:F:np')
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)
for option, optarg in optlist:
@@ -47,7 +46,7 @@ for option, optarg in optlist:
elif option == '-d':
DFLAG = 1
elif option == '-e':
- for line in string.splitfields(optarg, '\n'):
+ for line in optarg.split('\n'):
SCRIPT.append(line)
elif option == '-F':
FS = optarg
@@ -81,31 +80,31 @@ if CFLAG:
elif NFLAG:
# Note that it is on purpose that AFLAG and PFLAG are
# tested dynamically each time through the loop
- prologue = [ \
- 'LINECOUNT = 0', \
- 'for FILE in ARGS:', \
- ' \tif FILE == \'-\':', \
- ' \t \tFP = sys.stdin', \
- ' \telse:', \
- ' \t \tFP = open(FILE, \'r\')', \
- ' \tLINENO = 0', \
- ' \twhile 1:', \
- ' \t \tLINE = FP.readline()', \
- ' \t \tif not LINE: break', \
- ' \t \tLINENO = LINENO + 1', \
- ' \t \tLINECOUNT = LINECOUNT + 1', \
- ' \t \tL = LINE[:-1]', \
- ' \t \taflag = AFLAG', \
- ' \t \tif aflag:', \
- ' \t \t \tif FS: F = string.splitfields(L, FS)', \
- ' \t \t \telse: F = string.split(L)' \
+ prologue = [
+ 'LINECOUNT = 0',
+ 'for FILE in ARGS:',
+ ' \tif FILE == \'-\':',
+ ' \t \tFP = sys.stdin',
+ ' \telse:',
+ ' \t \tFP = open(FILE, \'r\')',
+ ' \tLINENO = 0',
+ ' \twhile 1:',
+ ' \t \tLINE = FP.readline()',
+ ' \t \tif not LINE: break',
+ ' \t \tLINENO = LINENO + 1',
+ ' \t \tLINECOUNT = LINECOUNT + 1',
+ ' \t \tL = LINE[:-1]',
+ ' \t \taflag = AFLAG',
+ ' \t \tif aflag:',
+ ' \t \t \tif FS: F = L.split(FS)',
+ ' \t \t \telse: F = L.split()'
]
- epilogue = [ \
- ' \t \tif not PFLAG: continue', \
- ' \t \tif aflag:', \
- ' \t \t \tif FS: print string.joinfields(F, FS)', \
- ' \t \t \telse: print string.join(F)', \
- ' \t \telse: print L', \
+ epilogue = [
+ ' \t \tif not PFLAG: continue',
+ ' \t \tif aflag:',
+ ' \t \t \tif FS: print(FS.join(F))',
+ ' \t \t \telse: print(\' \'.join(F))',
+ ' \t \telse: print(L)',
]
else:
prologue = ['if 1:']
@@ -114,18 +113,13 @@ else:
# Note that we indent using tabs only, so that any indentation style
# 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:
- program = program + (' \t \t' + line + '\n')
-program = program + (string.joinfields(epilogue, '\n') + '\n')
+ program += ' \t \t' + line + '\n'
+program += '\n'.join(epilogue) + '\n'
-import tempfile
-fp = tempfile.NamedTemporaryFile()
-fp.write(program)
-fp.flush()
-script = open(tfn).read()
if DFLAG:
import pdb
- pdb.run(script)
+ pdb.run(program)
else:
- exec(script)
+ exec(program)
diff --git a/Demo/scripts/queens.py b/Demo/scripts/queens.py
index 820c9ad..726433c 100755
--- a/Demo/scripts/queens.py
+++ b/Demo/scripts/queens.py
@@ -19,8 +19,8 @@ class Queens:
def reset(self):
n = self.n
- self.y = [None]*n # Where is the queen in column x
- self.row = [0]*n # Is row[y] safe?
+ self.y = [None] * n # Where is the queen in column x
+ self.row = [0] * n # Is row[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.nfound = 0 # Instrumentation
@@ -50,7 +50,7 @@ class Queens:
self.up[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):
self.nfound = self.nfound + 1
diff --git a/Demo/scripts/script.py b/Demo/scripts/script.py
index 174c13e..b490b17 100755
--- a/Demo/scripts/script.py
+++ b/Demo/scripts/script.py
@@ -1,4 +1,5 @@
#! /usr/bin/env python
+
# script.py -- Make typescript of terminal session.
# Usage:
# -a Append to typescript.
@@ -6,28 +7,36 @@
# Author: Steen Lumholt.
-import os, time, sys
+import os, time, sys, getopt
import pty
def read(fd):
data = os.read(fd, 1024)
- file.write(data)
+ script.write(data)
return data
shell = 'sh'
filename = 'typescript'
-mode = 'w'
+mode = 'wb'
if 'SHELL' in os.environ:
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)
-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)
-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)
diff --git a/Demo/scripts/unbirthday.py b/Demo/scripts/unbirthday.py
index 991537d..af58f8f 100755
--- a/Demo/scripts/unbirthday.py
+++ b/Demo/scripts/unbirthday.py
@@ -9,35 +9,27 @@ import sys
import time
import calendar
-def raw_input(prompt):
- sys.stdout.write(prompt)
- sys.stdout.flush()
- return sys.stdin.readline()
-
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:]:
year = int(sys.argv[1])
else:
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=' ')
year = year + 1900
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)
return
- #
+
if sys.argv[2:]:
month = int(sys.argv[2])
else:
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)
return
- #
+
if sys.argv[3:]:
day = int(sys.argv[3])
else:
@@ -46,36 +38,36 @@ def main():
maxday = 29
else:
maxday = calendar.mdays[month]
- if not (1<=day<=maxday):
+ if not (1 <= day <= maxday):
print('There are no', day, 'days in that month!')
return
- #
+
bdaytuple = (year, month, day)
bdaydate = mkdate(bdaytuple)
print('You were born on', format(bdaytuple))
- #
+
todaytuple = time.localtime()[:3]
todaydate = mkdate(todaytuple)
print('Today is', format(todaytuple))
- #
+
if bdaytuple > todaytuple:
print('You are a time traveler. Go back to the future!')
return
- #
+
if bdaytuple == todaytuple:
print('You were born today. Have a nice life!')
return
- #
+
days = todaydate - bdaydate
print('You have lived', days, 'days')
- #
+
age = 0
for y in range(year, todaytuple[0] + 1):
if bdaytuple < (y, month, day) <= todaytuple:
age = age + 1
- #
+
print('You are', age, 'years old')
- #
+
if todaytuple[1:] == bdaytuple[1:]:
print('Congratulations! Today is your', nth(age), 'birthday')
print('Yesterday was your', end=' ')
@@ -83,8 +75,8 @@ def main():
print('Today is your', end=' ')
print(nth(days - age), 'unbirthday')
-def format(xxx_todo_changeme):
- (year, month, day) = xxx_todo_changeme
+def format(date):
+ (year, month, day) = date
return '%d %s %d' % (day, calendar.month_name[month], year)
def nth(n):
@@ -93,12 +85,12 @@ def nth(n):
if n == 3: return '3rd'
return '%dth' % n
-def mkdate(xxx_todo_changeme1):
- # Januari 1st, in 0 A.D. is arbitrarily defined to be day 1,
+def mkdate(date):
+ # January 1st, in 0 A.D. is arbitrarily defined to be day 1,
# even though that day never actually existed and the calendar
# was different then...
- (year, month, day) = xxx_todo_changeme1
- days = year*365 # years, roughly
+ (year, month, day) = date
+ days = year*365 # 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+399)//400 # plus leap years every 4 centirues
diff --git a/Demo/xml/elem_count.py b/Demo/xml/elem_count.py
index e083e64..99d6ca9 100644
--- a/Demo/xml/elem_count.py
+++ b/Demo/xml/elem_count.py
@@ -1,4 +1,10 @@
+"""
+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
+from collections import defaultdict
from xml.sax import make_parser, handler
@@ -7,16 +13,16 @@ class FancyCounter(handler.ContentHandler):
def __init__(self):
self._elems = 0
self._attrs = 0
- self._elem_types = {}
- self._attr_types = {}
+ self._elem_types = defaultdict(int)
+ self._attr_types = defaultdict(int)
def startElement(self, name, attrs):
- self._elems = self._elems + 1
- self._attrs = self._attrs + len(attrs)
- self._elem_types[name] = self._elem_types.get(name, 0) + 1
+ self._elems += 1
+ self._attrs += len(attrs)
+ self._elem_types[name] += 1
for name in attrs.keys():
- self._attr_types[name] = self._attr_types.get(name, 0) + 1
+ self._attr_types[name] += 1
def endDocument(self):
print("There were", self._elems, "elements.")
@@ -30,7 +36,7 @@ class FancyCounter(handler.ContentHandler):
for pair in self._attr_types.items():
print("%20s %d" % pair)
-
-parser = make_parser()
-parser.setContentHandler(FancyCounter())
-parser.parse(sys.argv[1])
+if __name__ == '__main__':
+ parser = make_parser()
+ parser.setContentHandler(FancyCounter())
+ parser.parse(sys.argv[1])
diff --git a/Demo/xml/roundtrip.py b/Demo/xml/roundtrip.py
index 8d7d437..801c009 100644
--- a/Demo/xml/roundtrip.py
+++ b/Demo/xml/roundtrip.py
@@ -3,7 +3,7 @@ A simple demo that reads in an XML document and spits out an equivalent,
but not necessarily identical, document.
"""
-import sys, string
+import sys
from xml.sax import saxutils, handler, make_parser
@@ -11,7 +11,7 @@ from xml.sax import saxutils, handler, make_parser
class ContentGenerator(handler.ContentHandler):
- def __init__(self, out = sys.stdout):
+ def __init__(self, out=sys.stdout):
handler.ContentHandler.__init__(self)
self._out = out
@@ -40,6 +40,7 @@ class ContentGenerator(handler.ContentHandler):
# --- The main program
-parser = make_parser()
-parser.setContentHandler(ContentGenerator())
-parser.parse(sys.argv[1])
+if __name__ == '__main__':
+ parser = make_parser()
+ parser.setContentHandler(ContentGenerator())
+ parser.parse(sys.argv[1])
diff --git a/Demo/xml/rss2html.py b/Demo/xml/rss2html.py
index 15c9891..49cd154 100644
--- a/Demo/xml/rss2html.py
+++ b/Demo/xml/rss2html.py
@@ -1,45 +1,50 @@
+"""
+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 codecs
from xml.sax import make_parser, handler
# --- Templates
-top = \
-"""
+top = """\
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<HTML>
-<HEAD>
- <TITLE>%s</TITLE>
-</HEAD>
-
-<BODY>
-<H1>%s</H1>
+<html>
+<head>
+ <title>%s</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+
+<body>
+<h1>%s</h1>
"""
-bottom = \
-"""
+bottom = """
</ul>
-<HR>
-<ADDRESS>
-Converted to HTML by sax_rss2html.py.
-</ADDRESS>
+<hr>
+<address>
+Converted to HTML by rss2html.py.
+</address>
-</BODY>
-</HTML>
+</body>
+</html>
"""
# --- The ContentHandler
class RSSHandler(handler.ContentHandler):
- def __init__(self, out = sys.stdout):
+ def __init__(self, out=sys.stdout):
handler.ContentHandler.__init__(self)
self._out = out
self._text = ""
self._parent = None
- self._list_started = 0
+ self._list_started = False
self._title = None
self._link = None
self._descr = ""
@@ -69,7 +74,7 @@ class RSSHandler(handler.ContentHandler):
elif name == "item":
if not self._list_started:
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._link, self._title, self._descr))
@@ -86,6 +91,7 @@ class RSSHandler(handler.ContentHandler):
# --- Main program
-parser = make_parser()
-parser.setContentHandler(RSSHandler())
-parser.parse(sys.argv[1])
+if __name__ == '__main__':
+ parser = make_parser()
+ parser.setContentHandler(RSSHandler())
+ parser.parse(sys.argv[1])
diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst
index a54bc19..a5d3a77 100644
--- a/Doc/library/configparser.rst
+++ b/Doc/library/configparser.rst
@@ -231,9 +231,11 @@ RawConfigParser Objects
.. method:: RawConfigParser.readfp(fp, filename=None)
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*
- has a :attr:`name` attribute, that is used for *filename*; the default is
- ``<???>``.
+ (only the :meth:`readline` method is used). The file-like object must
+ 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)
@@ -279,8 +281,9 @@ RawConfigParser Objects
.. method:: RawConfigParser.write(fileobject)
- Write a representation of the configuration to the specified file object. This
- representation can be parsed by a future :meth:`read` call.
+ Write a representation of the configuration to the specified file object,
+ 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)
@@ -370,7 +373,7 @@ An example of writing to a configuration file::
config.set('Section1', 'foo', '%(bar)s is %(baz)s!')
# Writing our configuration file to 'example.cfg'
- with open('example.cfg', 'wb') as configfile:
+ with open('example.cfg', 'w') as configfile:
config.write(configfile)
An example of reading the configuration file again::
diff --git a/Doc/library/copy.rst b/Doc/library/copy.rst
index e6ad857..5ae79aa9 100644
--- a/Doc/library/copy.rst
+++ b/Doc/library/copy.rst
@@ -4,21 +4,25 @@
.. module:: copy
: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
- x = copy.deepcopy(y) # make a deep copy of y
+ Raised for module specific errors.
-For module specific errors, :exc:`copy.error` is raised.
The difference between shallow and deep copying is only relevant for compound
objects (objects that contain other objects, like lists or class instances):
diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst
index 7e1daf3..3b9e3d2 100644
--- a/Doc/library/marshal.rst
+++ b/Doc/library/marshal.rst
@@ -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
is independent from a particular invocation of Python can be written and read by
-this module. The following types are supported: ``None``, integers,
-floating point numbers, strings, bytes, bytearrays, tuples, lists, sets,
-dictionaries, and code objects, where it should be understood that tuples, lists
-and dictionaries are only supported as long as the values contained therein are
-themselves supported; and recursive lists and dictionaries should not be written
-(they will cause infinite loops).
+this module. The following types are supported: booleans, integers, floating
+point numbers, complex numbers, strings, bytes, bytearrays, tuples, lists, sets,
+frozensets, dictionaries, and code objects, where it should be understood that
+tuples, lists, sets, frozensets and dictionaries are only supported as long as
+the values contained therein are themselves supported; and recursive lists, sets
+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
strings.
diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst
index fc23417..f251852 100644
--- a/Doc/library/urllib.parse.rst
+++ b/Doc/library/urllib.parse.rst
@@ -227,7 +227,8 @@ The :mod:`urllib.parse` module defines the following functions:
.. function:: quote(string, safe='/', encoding=None, errors=None)
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
--- its default value is ``'/'``.
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index ef2f382..e3abeb7 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -666,7 +666,7 @@ Modules
of the shared library file.
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.
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
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 627cd29..22dcff7 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -208,7 +208,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
"""Custom displayhook for the exec in default(), which prevents
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):
if line[:1] == '!': line = line[1:]
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index fe439c2..68771c9 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -1557,7 +1557,7 @@ class Helper:
'global': ('global', 'NAMESPACES'),
'if': ('if', 'TRUTHVALUE'),
'import': ('import', 'MODULES'),
- 'in': ('in', 'SEQUENCEMETHODS2'),
+ 'in': ('in', 'SEQUENCEMETHODS'),
'is': 'COMPARISON',
'lambda': ('lambda', 'FUNCTIONS'),
'not': 'BOOLEAN',
@@ -1643,12 +1643,12 @@ class Helper:
'PRECEDENCE': 'EXPRESSIONS',
'OBJECTS': ('objects', 'TYPES'),
'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
- 'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
- 'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
+ 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
+ 'NUMBERMETHODS CLASSES'),
'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
- 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
+ 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
'SPECIALMETHODS'),
'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
@@ -1672,8 +1672,8 @@ class Helper:
'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
- 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
- 'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
+ 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
+ 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
'CALLS': ('calls', 'EXPRESSIONS'),
'POWER': ('power', 'EXPRESSIONS'),
'UNARY': ('unary', 'EXPRESSIONS'),
diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py
index 5765b4e..d1d03a3 100644
--- a/Lib/test/test_funcattrs.py
+++ b/Lib/test/test_funcattrs.py
@@ -56,8 +56,29 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.assertEqual(test(), 3) # self.b always returns 3, arbitrarily
def test___globals__(self):
- self.assertEqual(self.b.__globals__, globals())
- self.cannot_set_attr(self.b, '__globals__', 2, (AttributeError, TypeError))
+ self.assertIs(self.b.__globals__, globals())
+ 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):
self.assertEqual(self.b.__name__, 'b')
@@ -90,16 +111,20 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.assertEqual(c.__code__, d.__code__)
self.assertEqual(c(), 7)
# self.assertEqual(d(), 7)
- try: b.__code__ = c.__code__
- except ValueError: pass
- else: self.fail(
- "__code__ with different numbers of free vars should not be "
- "possible")
- try: e.__code__ = d.__code__
- except ValueError: pass
- else: self.fail(
- "__code__ with different numbers of free vars should not be "
- "possible")
+ try:
+ b.__code__ = c.__code__
+ except ValueError:
+ pass
+ else:
+ self.fail("__code__ with different numbers of free vars should "
+ "not be possible")
+ try:
+ e.__code__ = d.__code__
+ except ValueError:
+ pass
+ else:
+ self.fail("__code__ with different numbers of free vars should "
+ "not be possible")
def test_blank_func_defaults(self):
self.assertEqual(self.b.__defaults__, None)
@@ -120,13 +145,16 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.assertEqual(first_func(3, 5), 8)
del second_func.__defaults__
self.assertEqual(second_func.__defaults__, None)
- try: second_func()
- except TypeError: pass
- else: self.fail(
- "func_defaults does not update; deleting it does not remove "
- "requirement")
+ try:
+ second_func()
+ except TypeError:
+ pass
+ else:
+ self.fail("__defaults__ does not update; deleting it does not "
+ "remove requirement")
-class ImplicitReferencesTest(FuncAttrsTest):
+
+class InstancemethodAttrTest(FuncAttrsTest):
def test___class__(self):
self.assertEqual(self.fi.a.__self__.__class__, self.F)
@@ -146,31 +174,45 @@ class ImplicitReferencesTest(FuncAttrsTest):
self.fi.id = types.MethodType(id, self.fi)
self.assertEqual(self.fi.id(), id(self.fi))
# Test usage
- try: self.fi.id.unknown_attr
- except AttributeError: pass
- else: self.fail("using unknown attributes should raise AttributeError")
+ try:
+ self.fi.id.unknown_attr
+ except AttributeError:
+ pass
+ else:
+ self.fail("using unknown attributes should raise AttributeError")
# Test assignment and deletion
self.cannot_set_attr(self.fi.id, 'unknown_attr', 2, AttributeError)
+
class ArbitraryFunctionAttrTest(FuncAttrsTest):
def test_set_attr(self):
self.b.known_attr = 7
self.assertEqual(self.b.known_attr, 7)
- try: self.fi.a.known_attr = 7
- except AttributeError: pass
- else: self.fail("setting attributes on methods should raise error")
+ try:
+ self.fi.a.known_attr = 7
+ except AttributeError:
+ pass
+ else:
+ self.fail("setting attributes on methods should raise error")
def test_delete_unknown_attr(self):
- try: del self.b.unknown_attr
- except AttributeError: pass
- else: self.fail("deleting unknown attribute should raise TypeError")
+ try:
+ del self.b.unknown_attr
+ except AttributeError:
+ pass
+ else:
+ self.fail("deleting unknown attribute should raise TypeError")
def test_unset_attr(self):
for func in [self.b, self.fi.a]:
- try: func.non_existent_attr
- except AttributeError: pass
- else: self.fail("using unknown attributes should raise "
- "AttributeError")
+ try:
+ func.non_existent_attr
+ except AttributeError:
+ pass
+ else:
+ self.fail("using unknown attributes should raise "
+ "AttributeError")
+
class FunctionDictsTest(FuncAttrsTest):
def test_setting_dict_to_invalid(self):
@@ -183,11 +225,11 @@ class FunctionDictsTest(FuncAttrsTest):
d = {'known_attr': 7}
self.b.__dict__ = d
# 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
self.F.a.__dict__ = d
- self.assertEqual(d, self.fi.a.__func__.__dict__)
- self.assertEqual(d, self.fi.a.__dict__)
+ self.assertIs(d, self.fi.a.__func__.__dict__)
+ self.assertIs(d, self.fi.a.__dict__)
# Test value
self.assertEqual(self.b.known_attr, 7)
self.assertEqual(self.b.__dict__['known_attr'], 7)
@@ -196,9 +238,12 @@ class FunctionDictsTest(FuncAttrsTest):
self.assertEqual(self.fi.a.known_attr, 7)
def test_delete___dict__(self):
- try: del self.b.__dict__
- except TypeError: pass
- else: self.fail("deleting function dictionary should raise TypeError")
+ try:
+ del self.b.__dict__
+ except TypeError:
+ pass
+ else:
+ self.fail("deleting function dictionary should raise TypeError")
def test_unassigned_dict(self):
self.assertEqual(self.b.__dict__, {})
@@ -209,6 +254,7 @@ class FunctionDictsTest(FuncAttrsTest):
d[self.b] = value
self.assertEqual(d[self.b], value)
+
class FunctionDocstringTest(FuncAttrsTest):
def test_set_docstring_attr(self):
self.assertEqual(self.b.__doc__, None)
@@ -224,6 +270,7 @@ class FunctionDocstringTest(FuncAttrsTest):
del self.b.__doc__
self.assertEqual(self.b.__doc__, None)
+
def cell(value):
"""Create a cell containing the given value."""
def f():
@@ -242,6 +289,7 @@ def empty_cell(empty=True):
a = 1729
return f.__closure__[0]
+
class CellTest(unittest.TestCase):
def test_comparison(self):
# These tests are here simply to exercise the comparison code;
@@ -254,6 +302,7 @@ class CellTest(unittest.TestCase):
self.assertTrue(cell(-36) == cell(-36.0))
self.assertTrue(cell(True) > empty_cell())
+
class StaticMethodAttrsTest(unittest.TestCase):
def test_func_attribute(self):
def f():
@@ -267,7 +316,7 @@ class StaticMethodAttrsTest(unittest.TestCase):
def test_main():
- support.run_unittest(FunctionPropertiesTest, ImplicitReferencesTest,
+ support.run_unittest(FunctionPropertiesTest, InstancemethodAttrTest,
ArbitraryFunctionAttrTest, FunctionDictsTest,
FunctionDocstringTest, CellTest,
StaticMethodAttrsTest)
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index bcd4853..5d52707 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -12,6 +12,49 @@ from test import support
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():
"""This illustrates the simple case of module skipping.
@@ -19,16 +62,12 @@ def test_pdb_skip_modules():
... import string
... import pdb; pdb.Pdb(skip=['stri*']).set_trace()
... string.capwords('FOO')
- >>> real_stdin = sys.stdin
- >>> sys.stdin = _FakeInput([
- ... 'step',
- ... 'continue',
- ... ])
- >>> try:
+ >>> with PdbTestInput([
+ ... 'step',
+ ... 'continue',
+ ... ]):
... skip_module()
- ... finally:
- ... sys.stdin = real_stdin
> <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()
-> string.capwords('FOO')
(Pdb) step
@@ -36,7 +75,7 @@ def test_pdb_skip_modules():
> <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()->None
-> string.capwords('FOO')
(Pdb) continue
-"""
+ """
# Module for testing skipping of module that makes a callback
@@ -50,22 +89,19 @@ def test_pdb_skip_modules_with_callback():
>>> def skip_module():
... def callback():
... 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)
- >>> real_stdin = sys.stdin
- >>> sys.stdin = _FakeInput([
- ... 'step',
- ... 'step',
- ... 'step',
- ... 'step',
- ... 'step',
- ... 'continue',
- ... ])
-
- >>> try:
+
+ >>> with PdbTestInput([
+ ... 'step',
+ ... 'step',
+ ... 'step',
+ ... 'step',
+ ... 'step',
+ ... 'continue',
+ ... ]):
... skip_module()
- ... finally:
- ... sys.stdin = real_stdin
+ ... pass # provides something to "step" to
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()
-> mod.foo_pony(callback)
(Pdb) step
@@ -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
-> mod.foo_pony(callback)
(Pdb) step
- > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[3]>(4)<module>()
- -> sys.stdin = real_stdin
+ > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[1]>(10)<module>()
+ -> pass # provides something to "step" to
(Pdb) continue
-"""
+ """
def test_main():