The third and final doc-string sweep by Ka-Ping Yee.

The attached patches update the standard library so that all modules
have docstrings beginning with one-line summaries.

A new docstring was added to formatter.  The docstring for os.py
was updated to mention nt, os2, ce in addition to posix, dos, mac.
This commit is contained in:
Guido van Rossum 2000-02-04 15:28:42 +00:00
parent 54f22ed30b
commit e7b146fb3b
29 changed files with 891 additions and 778 deletions

View File

@ -1,6 +1,7 @@
#! /usr/bin/env python #! /usr/bin/env python
# Conversions to/from quoted-printable transport encoding as per RFC-1521 """Conversions to/from quoted-printable transport encoding as per RFC-1521."""
# (Dec 1991 version). # (Dec 1991 version).
ESCAPE = '=' ESCAPE = '='
@ -8,11 +9,15 @@ MAXLINESIZE = 76
HEX = '0123456789ABCDEF' HEX = '0123456789ABCDEF'
def needsquoting(c, quotetabs): def needsquoting(c, quotetabs):
"""Decide whether a particular character needs to be quoted.
The 'quotetabs' flag indicates whether tabs should be quoted."""
if c == '\t': if c == '\t':
return not quotetabs return not quotetabs
return c == ESCAPE or not(' ' <= c <= '~') return c == ESCAPE or not(' ' <= c <= '~')
def quote(c): def quote(c):
"""Quote a single character."""
if c == ESCAPE: if c == ESCAPE:
return ESCAPE * 2 return ESCAPE * 2
else: else:
@ -20,6 +25,10 @@ def quote(c):
return ESCAPE + HEX[i/16] + HEX[i%16] return ESCAPE + HEX[i/16] + HEX[i%16]
def encode(input, output, quotetabs): def encode(input, output, quotetabs):
"""Read 'input', apply quoted-printable encoding, and write to 'output'.
'input' and 'output' are files with readline() and write() methods.
The 'quotetabs' flag indicates whether tabs should be quoted."""
while 1: while 1:
line = input.readline() line = input.readline()
if not line: break if not line: break
@ -42,6 +51,9 @@ def encode(input, output, quotetabs):
output.write(new + '\n') output.write(new + '\n')
def decode(input, output): def decode(input, output):
"""Read 'input', apply quoted-printable decoding, and write to 'output'.
'input' and 'output' are files with readline() and write() methods."""
new = '' new = ''
while 1: while 1:
line = input.readline() line = input.readline()
@ -73,9 +85,11 @@ def decode(input, output):
output.write(new) output.write(new)
def ishex(c): def ishex(c):
"""Return true if the character 'c' is a hexadecimal digit."""
return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F' return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F'
def unhex(s): def unhex(s):
"""Get the integer value of a hexadecimal number."""
bits = 0 bits = 0
for c in s: for c in s:
if '0' <= c <= '9': if '0' <= c <= '9':

View File

@ -1,23 +1,24 @@
# R A N D O M V A R I A B L E G E N E R A T O R S """Random variable generators.
#
# distributions on the real line:
# ------------------------------
# normal (Gaussian)
# lognormal
# negative exponential
# gamma
# beta
#
# distributions on the circle (angles 0 to 2pi)
# ---------------------------------------------
# circular uniform
# von Mises
# Translated from anonymously contributed C/C++ source. distributions on the real line:
------------------------------
normal (Gaussian)
lognormal
negative exponential
gamma
beta
# Multi-threading note: the random number generator used here is not distributions on the circle (angles 0 to 2pi)
# thread-safe; it is possible that two calls return the same random ---------------------------------------------
# value. See whrandom.py for more info. circular uniform
von Mises
Translated from anonymously contributed C/C++ source.
Multi-threading note: the random number generator used here is not
thread-safe; it is possible that two calls return the same random
value. See whrandom.py for more info.
"""
import whrandom import whrandom
from whrandom import random, uniform, randint, choice, randrange # For export! from whrandom import random, uniform, randint, choice, randrange # For export!

View File

@ -1,5 +1,11 @@
# These bits are passed to regex.set_syntax() to choose among """Constants for selecting regexp syntaxes for the obsolete regex module.
# alternative regexp syntaxes.
This module is only for backward compatibility. "regex" has now
been replaced by the new regular expression module, "re".
These bits are passed to regex.set_syntax() to choose among
alternative regexp syntaxes.
"""
# 1 means plain parentheses serve as grouping, and backslash # 1 means plain parentheses serve as grouping, and backslash
# parentheses are needed for literal searching. # parentheses are needed for literal searching.

View File

@ -1,10 +1,14 @@
# Regular expression subroutines: """Regexp-based split and replace using the obsolete regex module.
# sub(pat, repl, str): replace first occurrence of pattern in string
# gsub(pat, repl, str): replace all occurrences of pattern in string
# split(str, pat, maxsplit): split string using pattern as delimiter
# splitx(str, pat, maxsplit): split string using pattern as delimiter plus
# return delimiters
This module is only for backward compatibility. These operations
are now provided by the new regular expression module, "re".
sub(pat, repl, str): replace first occurrence of pattern in string
gsub(pat, repl, str): replace all occurrences of pattern in string
split(str, pat, maxsplit): split string using pattern as delimiter
splitx(str, pat, maxsplit): split string using pattern as delimiter plus
return delimiters
"""
import regex import regex

View File

@ -1,4 +1,4 @@
# Redo the `...` (representation) but with limits on most sizes. """Redo the `...` (representation) but with limits on most sizes."""
import string import string

View File

@ -1,4 +1,4 @@
# A parser for SGML, using the derived class as static DTD. """A parser for SGML, using the derived class as a static DTD."""
# XXX This only supports those SGML features used by HTML. # XXX This only supports those SGML features used by HTML.

View File

@ -1,3 +1,5 @@
"""A lexical analyzer class for simple shell-like syntaxes."""
# Module and documentation by Eric S. Raymond, 21 Dec 1998 # Module and documentation by Eric S. Raymond, 21 Dec 1998
import sys import sys

View File

@ -1,4 +1,4 @@
"""Utility functions for copying files. """Utility functions for copying files and directory trees.
XXX The functions here don't copy the resource fork or other metadata on Mac. XXX The functions here don't copy the resource fork or other metadata on Mac.

View File

@ -1,10 +1,8 @@
# Module 'stat' """Constants/functions for interpreting results of os.stat() and os.lstat().
#
# Defines constants and functions for interpreting stat/lstat struct Suggested usage: from stat import *
# as returned by os.stat() and os.lstat() (if it exists). """
#
# Suggested usage: from stat import *
#
# XXX Strictly spoken, this module may have to be adapted for each POSIX # XXX Strictly spoken, this module may have to be adapted for each POSIX
# implementation; in practice, however, the numeric constants used by # implementation; in practice, however, the numeric constants used by
# stat() are almost universal (even for stat() emulations on non-UNIX # stat() are almost universal (even for stat() emulations on non-UNIX

View File

@ -1,7 +1,6 @@
# Module 'statcache' """Maintain a cache of file stats.
# There are functions to reset the cache or to selectively remove items.
# Maintain a cache of file stats. """
# There are functions to reset the cache or to selectively remove items.
import os import os
from stat import * from stat import *
@ -12,42 +11,37 @@ from stat import *
cache = {} cache = {}
# Stat a file, possibly out of the cache.
#
def stat(path): def stat(path):
"""Stat a file, possibly out of the cache."""
if cache.has_key(path): if cache.has_key(path):
return cache[path] return cache[path]
cache[path] = ret = os.stat(path) cache[path] = ret = os.stat(path)
return ret return ret
# Reset the cache completely.
#
def reset(): def reset():
"""Reset the cache completely."""
global cache global cache
cache = {} cache = {}
# Remove a given item from the cache, if it exists.
#
def forget(path): def forget(path):
"""Remove a given item from the cache, if it exists."""
if cache.has_key(path): if cache.has_key(path):
del cache[path] del cache[path]
# Remove all pathnames with a given prefix.
#
def forget_prefix(prefix): def forget_prefix(prefix):
"""Remove all pathnames with a given prefix."""
n = len(prefix) n = len(prefix)
for path in cache.keys(): for path in cache.keys():
if path[:n] == prefix: if path[:n] == prefix:
del cache[path] del cache[path]
# Forget about a directory and all entries in it, but not about
# entries in subdirectories.
#
def forget_dir(prefix): def forget_dir(prefix):
"""Forget about a directory and all entries in it, but not about
entries in subdirectories."""
if prefix[-1:] == '/' and prefix <> '/': if prefix[-1:] == '/' and prefix <> '/':
prefix = prefix[:-1] prefix = prefix[:-1]
forget(prefix) forget(prefix)
@ -62,19 +56,17 @@ def forget_dir(prefix):
del cache[path] del cache[path]
# Remove all pathnames except with a given prefix.
# Normally used with prefix = '/' after a chdir().
#
def forget_except_prefix(prefix): def forget_except_prefix(prefix):
"""Remove all pathnames except with a given prefix.
Normally used with prefix = '/' after a chdir()."""
n = len(prefix) n = len(prefix)
for path in cache.keys(): for path in cache.keys():
if path[:n] <> prefix: if path[:n] <> prefix:
del cache[path] del cache[path]
# Check for directory.
#
def isdir(path): def isdir(path):
"""Check for directory."""
try: try:
st = stat(path) st = stat(path)
except os.error: except os.error:

View File

@ -1,8 +1,4 @@
# Module 'statvfs' """Constants for interpreting the results of os.statvfs() and os.fstatvfs()."""
#
# Defines constants for interpreting statvfs struct as returned
# by os.statvfs() and os.fstatvfs() (if they exist).
#
# Indices for statvfs struct members in the tuple returned by # Indices for statvfs struct members in the tuple returned by
# os.statvfs() and os.fstatvfs(). # os.statvfs() and os.fstatvfs().

View File

@ -1,11 +1,9 @@
# module 'string' -- A collection of string operations """A collection of string operations (most are no longer used in Python 1.6).
# Warning: most of the code you see here isn't normally used nowadays. With Warning: most of the code you see here isn't normally used nowadays. With
# Python 1.6, many of these functions are implemented as methods on the Python 1.6, many of these functions are implemented as methods on the
# standard string object. They used to be implemented by a built-in module standard string object. They used to be implemented by a built-in module
# called strop, but strop is now obsolete itself. called strop, but strop is now obsolete itself.
"""Common string manipulations.
Public module variables: Public module variables:

View File

@ -1,106 +1,107 @@
# Stuff to parse Sun and NeXT audio files. """Stuff to parse Sun and NeXT audio files.
#
# An audio consists of a header followed by the data. The structure An audio consists of a header followed by the data. The structure
# of the header is as follows. of the header is as follows.
#
# +---------------+ +---------------+
# | magic word | | magic word |
# +---------------+ +---------------+
# | header size | | header size |
# +---------------+ +---------------+
# | data size | | data size |
# +---------------+ +---------------+
# | encoding | | encoding |
# +---------------+ +---------------+
# | sample rate | | sample rate |
# +---------------+ +---------------+
# | # of channels | | # of channels |
# +---------------+ +---------------+
# | info | | info |
# | | | |
# +---------------+ +---------------+
#
# The magic word consists of the 4 characters '.snd'. Apart from the The magic word consists of the 4 characters '.snd'. Apart from the
# info field, all header fields are 4 bytes in size. They are all info field, all header fields are 4 bytes in size. They are all
# 32-bit unsigned integers encoded in big-endian byte order. 32-bit unsigned integers encoded in big-endian byte order.
#
# The header size really gives the start of the data. The header size really gives the start of the data.
# The data size is the physical size of the data. From the other The data size is the physical size of the data. From the other
# parameter the number of frames can be calculated. parameter the number of frames can be calculated.
# The encoding gives the way in which audio samples are encoded. The encoding gives the way in which audio samples are encoded.
# Possible values are listed below. Possible values are listed below.
# The info field currently consists of an ASCII string giving a The info field currently consists of an ASCII string giving a
# human-readable description of the audio file. The info field is human-readable description of the audio file. The info field is
# padded with NUL bytes to the header size. padded with NUL bytes to the header size.
#
# Usage. Usage.
#
# Reading audio files: Reading audio files:
# f = sunau.open(file, 'r') f = sunau.open(file, 'r')
# where file is either the name of a file or an open file pointer. where file is either the name of a file or an open file pointer.
# The open file pointer must have methods read(), seek(), and close(). The open file pointer must have methods read(), seek(), and close().
# When the setpos() and rewind() methods are not used, the seek() When the setpos() and rewind() methods are not used, the seek()
# method is not necessary. method is not necessary.
#
# This returns an instance of a class with the following public methods: This returns an instance of a class with the following public methods:
# getnchannels() -- returns number of audio channels (1 for getnchannels() -- returns number of audio channels (1 for
# mono, 2 for stereo) mono, 2 for stereo)
# getsampwidth() -- returns sample width in bytes getsampwidth() -- returns sample width in bytes
# getframerate() -- returns sampling frequency getframerate() -- returns sampling frequency
# getnframes() -- returns number of audio frames getnframes() -- returns number of audio frames
# getcomptype() -- returns compression type ('NONE' or 'ULAW') getcomptype() -- returns compression type ('NONE' or 'ULAW')
# getcompname() -- returns human-readable version of getcompname() -- returns human-readable version of
# compression type ('not compressed' matches 'NONE') compression type ('not compressed' matches 'NONE')
# getparams() -- returns a tuple consisting of all of the getparams() -- returns a tuple consisting of all of the
# above in the above order above in the above order
# getmarkers() -- returns None (for compatibility with the getmarkers() -- returns None (for compatibility with the
# aifc module) aifc module)
# getmark(id) -- raises an error since the mark does not getmark(id) -- raises an error since the mark does not
# exist (for compatibility with the aifc module) exist (for compatibility with the aifc module)
# readframes(n) -- returns at most n frames of audio readframes(n) -- returns at most n frames of audio
# rewind() -- rewind to the beginning of the audio stream rewind() -- rewind to the beginning of the audio stream
# setpos(pos) -- seek to the specified position setpos(pos) -- seek to the specified position
# tell() -- return the current position tell() -- return the current position
# close() -- close the instance (make it unusable) close() -- close the instance (make it unusable)
# The position returned by tell() and the position given to setpos() The position returned by tell() and the position given to setpos()
# are compatible and have nothing to do with the actual postion in the are compatible and have nothing to do with the actual postion in the
# file. file.
# The close() method is called automatically when the class instance The close() method is called automatically when the class instance
# is destroyed. is destroyed.
#
# Writing audio files: Writing audio files:
# f = sunau.open(file, 'w') f = sunau.open(file, 'w')
# where file is either the name of a file or an open file pointer. where file is either the name of a file or an open file pointer.
# The open file pointer must have methods write(), tell(), seek(), and The open file pointer must have methods write(), tell(), seek(), and
# close(). close().
#
# This returns an instance of a class with the following public methods: This returns an instance of a class with the following public methods:
# setnchannels(n) -- set the number of channels setnchannels(n) -- set the number of channels
# setsampwidth(n) -- set the sample width setsampwidth(n) -- set the sample width
# setframerate(n) -- set the frame rate setframerate(n) -- set the frame rate
# setnframes(n) -- set the number of frames setnframes(n) -- set the number of frames
# setcomptype(type, name) setcomptype(type, name)
# -- set the compression type and the -- set the compression type and the
# human-readable compression type human-readable compression type
# setparams(tuple)-- set all parameters at once setparams(tuple)-- set all parameters at once
# tell() -- return current position in output file tell() -- return current position in output file
# writeframesraw(data) writeframesraw(data)
# -- write audio frames without pathing up the -- write audio frames without pathing up the
# file header file header
# writeframes(data) writeframes(data)
# -- write audio frames and patch up the file header -- write audio frames and patch up the file header
# close() -- patch up the file header and close the close() -- patch up the file header and close the
# output file output file
# You should set the parameters before the first writeframesraw or You should set the parameters before the first writeframesraw or
# writeframes. The total number of frames does not need to be set, writeframes. The total number of frames does not need to be set,
# but when it is set to the correct value, the header does not have to but when it is set to the correct value, the header does not have to
# be patched up. be patched up.
# It is best to first set all parameters, perhaps possibly the It is best to first set all parameters, perhaps possibly the
# compression type, and then write audio frames using writeframesraw. compression type, and then write audio frames using writeframesraw.
# When all frames have been written, either call writeframes('') or When all frames have been written, either call writeframes('') or
# close() to patch up the sizes in the header. close() to patch up the sizes in the header.
# The close() method is called automatically when the class instance The close() method is called automatically when the class instance
# is destroyed. is destroyed.
"""
# from <multimedia/audio_filehdr.h> # from <multimedia/audio_filehdr.h>
AUDIO_FILE_MAGIC = 0x2e736e64 AUDIO_FILE_MAGIC = 0x2e736e64

View File

@ -1,19 +1,17 @@
# Module 'sunaudio' -- interpret sun audio headers """Interpret sun audio headers."""
MAGIC = '.snd' MAGIC = '.snd'
error = 'sunaudio sound header conversion error' error = 'sunaudio sound header conversion error'
# convert a 4-char value to integer
def get_long_be(s): def get_long_be(s):
"""Convert a 4-char value to integer."""
return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3]) return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
# read a sound header from an open file
def gethdr(fp): def gethdr(fp):
"""Read a sound header from an open file."""
if fp.read(4) <> MAGIC: if fp.read(4) <> MAGIC:
raise error, 'gethdr: bad magic word' raise error, 'gethdr: bad magic word'
hdr_size = get_long_be(fp.read(4)) hdr_size = get_long_be(fp.read(4))
@ -31,9 +29,8 @@ def gethdr(fp):
return (data_size, encoding, sample_rate, channels, info) return (data_size, encoding, sample_rate, channels, info)
# read and print the sound header of a named file
def printhdr(file): def printhdr(file):
"""Read and print the sound header of a named file."""
hdr = gethdr(open(file, 'r')) hdr = gethdr(open(file, 'r'))
data_size, encoding, sample_rate, channels, info = hdr data_size, encoding, sample_rate, channels, info = hdr
while info[-1:] == '\0': while info[-1:] == '\0':

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python #! /usr/bin/env python
#
# Non-terminal symbols of Python grammar (from "graminit.h") """Non-terminal symbols of Python grammar (from "graminit.h")."""
#
# This file is automatically generated; please don't muck it up! # This file is automatically generated; please don't muck it up!
# #
# To update the symbols in this file, 'cd' to the top directory of # To update the symbols in this file, 'cd' to the top directory of

View File

@ -1,5 +1,5 @@
# Temporary file name allocation """Temporary files and filenames."""
#
# XXX This tries to be not UNIX specific, but I don't know beans about # XXX This tries to be not UNIX specific, but I don't know beans about
# how to choose a temp directory or filename on MS-DOS or other # how to choose a temp directory or filename on MS-DOS or other
# systems so it may have to be changed... # systems so it may have to be changed...
@ -14,9 +14,8 @@ tempdir = None
template = None template = None
# Function to calculate the directory to use
def gettempdir(): def gettempdir():
"""Function to calculate the directory to use."""
global tempdir global tempdir
if tempdir is not None: if tempdir is not None:
return tempdir return tempdir
@ -58,11 +57,10 @@ def gettempdir():
return tempdir return tempdir
# Function to calculate a prefix of the filename to use
_pid = None _pid = None
def gettempprefix(): def gettempprefix():
"""Function to calculate a prefix of the filename to use."""
global template, _pid global template, _pid
if os.name == 'posix' and _pid and _pid != os.getpid(): if os.name == 'posix' and _pid and _pid != os.getpid():
# Our pid changed; we must have forked -- zap the template # Our pid changed; we must have forked -- zap the template
@ -85,9 +83,8 @@ def gettempprefix():
counter = 0 counter = 0
# User-callable function to return a unique temporary file name
def mktemp(suffix=""): def mktemp(suffix=""):
"""User-callable function to return a unique temporary file name."""
global counter global counter
dir = gettempdir() dir = gettempdir()
pre = gettempprefix() pre = gettempprefix()
@ -126,6 +123,7 @@ class TemporaryFileWrapper:
def TemporaryFile(mode='w+b', bufsize=-1, suffix=""): def TemporaryFile(mode='w+b', bufsize=-1, suffix=""):
"""Create and return a temporary file (opened read-write by default)."""
name = mktemp(suffix) name = mktemp(suffix)
if os.name == 'posix': if os.name == 'posix':
# Unix -- be very careful # Unix -- be very careful

View File

@ -1,5 +1,4 @@
# threading.py: """Proposed new threading module, emulating a subset of Java's threading model."""
# Proposed new threading module, emulating a subset of Java's threading model
import sys import sys
import time import time

View File

@ -1,10 +1,12 @@
# Convert "arbitrary" sound files to AIFF files (Apple and SGI's audio format). """Convert "arbitrary" sound files to AIFF (Apple and SGI's audio format).
# Input may be compressed.
# Uncompressed file type may be AIFF, WAV, VOC, 8SVX, NeXT/Sun, and others. Input may be compressed.
# An exception is raised if the file is not of a recognized type. Uncompressed file type may be AIFF, WAV, VOC, 8SVX, NeXT/Sun, and others.
# Returned filename is either the input filename or a temporary filename; An exception is raised if the file is not of a recognized type.
# in the latter case the caller must ensure that it is removed. Returned filename is either the input filename or a temporary filename;
# Other temporary files used are removed by the function. in the latter case the caller must ensure that it is removed.
Other temporary files used are removed by the function.
"""
import os import os
import tempfile import tempfile

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python #! /usr/bin/env python
#
# Tokens (from "token.h") """Token constants (from "token.h")."""
#
# This file is automatically generated; please don't muck it up! # This file is automatically generated; please don't muck it up!
# #
# To update the symbols in this file, 'cd' to the top directory of # To update the symbols in this file, 'cd' to the top directory of

View File

@ -1,4 +1,4 @@
# Format and print Python stack traces """Extract, format and print information about Python stack traces."""
import linecache import linecache
import string import string
@ -10,6 +10,8 @@ def _print(file, str='', terminator='\n'):
def print_list(extracted_list, file=None): def print_list(extracted_list, file=None):
"""Print the list of tuples as returned by extract_tb() or
extract_stack() as a formatted stack trace to the given file."""
if not file: if not file:
file = sys.stderr file = sys.stderr
for filename, lineno, name, line in extracted_list: for filename, lineno, name, line in extracted_list:
@ -19,6 +21,12 @@ def print_list(extracted_list, file=None):
_print(file, ' %s' % string.strip(line)) _print(file, ' %s' % string.strip(line))
def format_list(extracted_list): def format_list(extracted_list):
"""Given a list of tuples as returned by extract_tb() or
extract_stack(), return a list of strings ready for printing.
Each string in the resulting list corresponds to the item with
the same index in the argument list. Each string ends in a
newline; the strings may contain internal newlines as well, for
those items whose source text line is not None."""
list = [] list = []
for filename, lineno, name, line in extracted_list: for filename, lineno, name, line in extracted_list:
item = ' File "%s", line %d, in %s\n' % (filename,lineno,name) item = ' File "%s", line %d, in %s\n' % (filename,lineno,name)
@ -29,6 +37,10 @@ def format_list(extracted_list):
def print_tb(tb, limit=None, file=None): def print_tb(tb, limit=None, file=None):
"""Print up to 'limit' stack trace entries from the traceback 'tb'.
If 'limit' is omitted or None, all entries are printed. If 'file' is
omitted or None, the output goes to sys.stderr; otherwise 'file'
should be an open file or file-like object with a write() method."""
if not file: if not file:
file = sys.stderr file = sys.stderr
if limit is None: if limit is None:
@ -49,9 +61,18 @@ def print_tb(tb, limit=None, file=None):
n = n+1 n = n+1
def format_tb(tb, limit = None): def format_tb(tb, limit = None):
"""A shorthand for 'format_list(extract_stack(f, limit))."""
return format_list(extract_tb(tb, limit)) return format_list(extract_tb(tb, limit))
def extract_tb(tb, limit = None): def extract_tb(tb, limit = None):
"""Return a list of up to 'limit' pre-processed stack trace entries
extracted from the traceback object 'traceback'. This is useful for
alternate formatting of stack traces. If 'limit' is omitted or None,
all entries are extracted. A pre-processed stack trace entry is a
quadruple (filename, line number, function name, text) representing
the information that is usually printed for a stack trace. The text
is a string with leading and trailing whitespace stripped; if the
source is not available it is None."""
if limit is None: if limit is None:
if hasattr(sys, 'tracebacklimit'): if hasattr(sys, 'tracebacklimit'):
limit = sys.tracebacklimit limit = sys.tracebacklimit
@ -73,6 +94,14 @@ def extract_tb(tb, limit = None):
def print_exception(etype, value, tb, limit=None, file=None): def print_exception(etype, value, tb, limit=None, file=None):
"""Print exception information and up to 'limit' stack trace entries
from the traceback 'tb' to 'file'. This differs from print_tb() in
the following ways: (1) if traceback is not None, it prints a header
"Traceback (innermost last):"; (2) it prints the exception type and
value after the stack trace; (3) if type is SyntaxError and value has
the appropriate format, it prints the line where the syntax error
occurred with a caret on the next line indicating the approximate
position of the error."""
if not file: if not file:
file = sys.stderr file = sys.stderr
if tb: if tb:
@ -84,6 +113,12 @@ def print_exception(etype, value, tb, limit=None, file=None):
_print(file, lines[-1], '') _print(file, lines[-1], '')
def format_exception(etype, value, tb, limit = None): def format_exception(etype, value, tb, limit = None):
"""Format a stack trace and the exception information. The arguments
have the same meaning as the corresponding arguments to
print_exception(). The return value is a list of strings, each
ending in a newline and some containing internal newlines. When
these lines are contatenated and printed, exactly the same text is
printed as does print_exception()."""
if tb: if tb:
list = ['Traceback (innermost last):\n'] list = ['Traceback (innermost last):\n']
list = list + format_tb(tb, limit) list = list + format_tb(tb, limit)
@ -93,6 +128,14 @@ def format_exception(etype, value, tb, limit = None):
return list return list
def format_exception_only(etype, value): def format_exception_only(etype, value):
"""Format the exception part of a traceback. The arguments are the
exception type and value such as given by sys.last_type and
sys.last_value. The return value is a list of strings, each ending
in a newline. Normally, the list contains a single string;
however, for SyntaxError exceptions, it contains several lines that
(when printed) display detailed information about where the syntax
error occurred. The message indicating which exception occurred is
the always last string in the list."""
list = [] list = []
if type(etype) == types.ClassType: if type(etype) == types.ClassType:
stype = etype.__name__ stype = etype.__name__
@ -128,6 +171,10 @@ def format_exception_only(etype, value):
def print_exc(limit=None, file=None): def print_exc(limit=None, file=None):
"""This is a shorthand for 'print_exception(sys.exc_type,
sys.exc_value, sys.exc_traceback, limit, file)'.
(In fact, it uses sys.exc_info() to retrieve the same information
in a thread-safe way.)"""
if not file: if not file:
file = sys.stderr file = sys.stderr
try: try:
@ -137,6 +184,8 @@ def print_exc(limit=None, file=None):
etype = value = tb = None etype = value = tb = None
def print_last(limit=None, file=None): def print_last(limit=None, file=None):
"""This is a shorthand for 'print_exception(sys.last_type,
sys.last_value, sys.last_traceback, limit, file)'."""
if not file: if not file:
file = sys.stderr file = sys.stderr
print_exception(sys.last_type, sys.last_value, sys.last_traceback, print_exception(sys.last_type, sys.last_value, sys.last_traceback,
@ -144,6 +193,10 @@ def print_last(limit=None, file=None):
def print_stack(f=None, limit=None, file=None): def print_stack(f=None, limit=None, file=None):
"""This function prints a stack trace from its invocation point.
The optional 'f' argument can be used to specify an alternate stack
frame at which to start. The optional 'limit' and 'file' arguments
have the same meaning as for print_exception()."""
if f is None: if f is None:
try: try:
raise ZeroDivisionError raise ZeroDivisionError
@ -152,6 +205,7 @@ def print_stack(f=None, limit=None, file=None):
print_list(extract_stack(f, limit), file) print_list(extract_stack(f, limit), file)
def format_stack(f=None, limit=None): def format_stack(f=None, limit=None):
"""A shorthand for 'format_list(extract_stack(f, limit))'."""
if f is None: if f is None:
try: try:
raise ZeroDivisionError raise ZeroDivisionError
@ -160,6 +214,12 @@ def format_stack(f=None, limit=None):
return format_list(extract_stack(f, limit)) return format_list(extract_stack(f, limit))
def extract_stack(f=None, limit = None): def extract_stack(f=None, limit = None):
"""Extract the raw traceback from the current stack frame. The
return value has the same format as for extract_tb(). The optional
'f' and 'limit' arguments have the same meaning as for print_stack().
Each item in the list is a quadruple (filename, line number,
function name, text), and the entries are in order from outermost
to innermost stack frame."""
if f is None: if f is None:
try: try:
raise ZeroDivisionError raise ZeroDivisionError
@ -184,13 +244,14 @@ def extract_stack(f=None, limit = None):
list.reverse() list.reverse()
return list return list
# Calculate the correct line number of the traceback given in tb (even
# with -O on).
# Coded by Marc-Andre Lemburg from the example of PyCode_Addr2Line()
# in compile.c.
# Revised version by Jim Hugunin to work with JPython too.
def tb_lineno(tb): def tb_lineno(tb):
"""Calculate the correct line number of the traceback given in tb
(even with -O on)."""
# Coded by Marc-Andre Lemburg from the example of PyCode_Addr2Line()
# in compile.c.
# Revised version by Jim Hugunin to work with JPython too.
c = tb.tb_frame.f_code c = tb.tb_frame.f_code
if not hasattr(c, 'co_lnotab'): if not hasattr(c, 'co_lnotab'):
return tb.tb_lineno return tb.tb_lineno

View File

@ -1,4 +1,5 @@
# tty.py -- Terminal utilities. """Terminal utilities."""
# Author: Steen Lumholt. # Author: Steen Lumholt.
from TERMIOS import * from TERMIOS import *
@ -13,8 +14,8 @@ ISPEED = 4
OSPEED = 5 OSPEED = 5
CC = 6 CC = 6
# Put terminal into a raw mode.
def setraw(fd, when=TCSAFLUSH): def setraw(fd, when=TCSAFLUSH):
"""Put terminal into a raw mode."""
mode = tcgetattr(fd) mode = tcgetattr(fd)
mode[IFLAG] = mode[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) mode[IFLAG] = mode[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
mode[OFLAG] = mode[OFLAG] & ~(OPOST) mode[OFLAG] = mode[OFLAG] & ~(OPOST)
@ -25,8 +26,8 @@ def setraw(fd, when=TCSAFLUSH):
mode[CC][VTIME] = 0 mode[CC][VTIME] = 0
tcsetattr(fd, when, mode) tcsetattr(fd, when, mode)
# Put terminal into a cbreak mode.
def setcbreak(fd, when=TCSAFLUSH): def setcbreak(fd, when=TCSAFLUSH):
"""Put terminal into a cbreak mode."""
mode = tcgetattr(fd) mode = tcgetattr(fd)
mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON) mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON)
mode[CC][VMIN] = 1 mode[CC][VMIN] = 1

View File

@ -1,5 +1,7 @@
# Define names for all type symbols known in the standard interpreter. """Define names for all type symbols known in the standard interpreter.
# Types that are part of optional modules (e.g. array) are not listed.
Types that are part of optional modules (e.g. array) are not listed.
"""
import sys import sys

View File

@ -1,4 +1,5 @@
# Parse a timezone specification. """Parse a timezone specification."""
# XXX Unfinished. # XXX Unfinished.
# XXX Only the typical form "XXXhhYYY;ddd/hh,ddd/hh" is currently supported. # XXX Only the typical form "XXXhhYYY;ddd/hh,ddd/hh" is currently supported.
@ -8,6 +9,12 @@ tzpat = ('^([A-Z][A-Z][A-Z])([-+]?[0-9]+)([A-Z][A-Z][A-Z]);'
tzprog = None tzprog = None
def tzparse(tzstr): def tzparse(tzstr):
"""Given a timezone spec, return a tuple of information
(tzname, delta, dstname, daystart, hourstart, dayend, hourend),
where 'tzname' is the name of the timezone, 'delta' is the offset
in hours from GMT, 'dstname' is the name of the daylight-saving
timezone, and 'daystart'/'hourstart' and 'dayend'/'hourend'
specify the starting and ending points for daylight saving time."""
global tzprog global tzprog
if tzprog == None: if tzprog == None:
import re import re
@ -24,6 +31,9 @@ def tzparse(tzstr):
return (tzname, delta, dstname, daystart, hourstart, dayend, hourend) return (tzname, delta, dstname, daystart, hourstart, dayend, hourend)
def tzlocaltime(secs, params): def tzlocaltime(secs, params):
"""Given a Unix time in seconds and a tuple of information about
a timezone as returned by tzparse(), return the local time in the
form (year, month, day, hour, min, sec, yday, wday, tzname)."""
import time import time
(tzname, delta, dstname, daystart, hourstart, dayend, hourend) = params (tzname, delta, dstname, daystart, hourstart, dayend, hourend) = params
year, month, days, hours, mins, secs, yday, wday, isdst = \ year, month, days, hours, mins, secs, yday, wday, isdst = \
@ -34,6 +44,7 @@ def tzlocaltime(secs, params):
return year, month, days, hours, mins, secs, yday, wday, tzname return year, month, days, hours, mins, secs, yday, wday, tzname
def tzset(): def tzset():
"""Determine the current timezone from the "TZ" environment variable."""
global tzparams, timezone, altzone, daylight, tzname global tzparams, timezone, altzone, daylight, tzname
import os import os
tzstr = os.environ['TZ'] tzstr = os.environ['TZ']
@ -44,6 +55,8 @@ def tzset():
tzname = tzparams[0], tzparams[2] tzname = tzparams[0], tzparams[2]
def isdst(secs): def isdst(secs):
"""Return true if daylight-saving time is in effect for the given
Unix time in the current timezone."""
import time import time
(tzname, delta, dstname, daystart, hourstart, dayend, hourend) = \ (tzname, delta, dstname, daystart, hourstart, dayend, hourend) = \
tzparams tzparams
@ -54,6 +67,7 @@ def isdst(secs):
tzset() tzset()
def localtime(secs): def localtime(secs):
"""Get the local time in the current timezone."""
return tzlocaltime(secs, tzparams) return tzlocaltime(secs, tzparams)
def test(): def test():

View File

@ -1,25 +1,26 @@
# Open an arbitrary URL """Open an arbitrary URL.
#
# See the following document for more info on URLs: See the following document for more info on URLs:
# "Names and Addresses, URIs, URLs, URNs, URCs", at "Names and Addresses, URIs, URLs, URNs, URCs", at
# http://www.w3.org/pub/WWW/Addressing/Overview.html http://www.w3.org/pub/WWW/Addressing/Overview.html
#
# See also the HTTP spec (from which the error codes are derived): See also the HTTP spec (from which the error codes are derived):
# "HTTP - Hypertext Transfer Protocol", at "HTTP - Hypertext Transfer Protocol", at
# http://www.w3.org/pub/WWW/Protocols/ http://www.w3.org/pub/WWW/Protocols/
#
# Related standards and specs: Related standards and specs:
# - RFC1808: the "relative URL" spec. (authoritative status) - RFC1808: the "relative URL" spec. (authoritative status)
# - RFC1738 - the "URL standard". (authoritative status) - RFC1738 - the "URL standard". (authoritative status)
# - RFC1630 - the "URI spec". (informational status) - RFC1630 - the "URI spec". (informational status)
#
# The object returned by URLopener().open(file) will differ per The object returned by URLopener().open(file) will differ per
# protocol. All you know is that is has methods read(), readline(), protocol. All you know is that is has methods read(), readline(),
# readlines(), fileno(), close() and info(). The read*(), fileno() readlines(), fileno(), close() and info(). The read*(), fileno()
# and close() methods work like those of open files. and close() methods work like those of open files.
# The info() method returns a mimetools.Message object which can be The info() method returns a mimetools.Message object which can be
# used to query various info about the object, if available. used to query various info about the object, if available.
# (mimetools.Message objects are queried with the getheader() method.) (mimetools.Message objects are queried with the getheader() method.)
"""
import string import string
import socket import socket
@ -69,14 +70,14 @@ def urlcleanup():
_urlopener.cleanup() _urlopener.cleanup()
# Class to open URLs.
# This is a class rather than just a subroutine because we may need
# more than one set of global protocol-specific options.
# Note -- this is a base class for those who don't want the
# automatic handling of errors type 302 (relocated) and 401
# (authorization needed).
ftpcache = {} ftpcache = {}
class URLopener: class URLopener:
"""Class to open URLs.
This is a class rather than just a subroutine because we may need
more than one set of global protocol-specific options.
Note -- this is a base class for those who don't want the
automatic handling of errors type 302 (relocated) and 401
(authorization needed)."""
__tempfiles = None __tempfiles = None
@ -125,14 +126,14 @@ class URLopener:
if self.tempcache: if self.tempcache:
self.tempcache.clear() self.tempcache.clear()
# Add a header to be used by the HTTP interface only
# e.g. u.addheader('Accept', 'sound/basic')
def addheader(self, *args): def addheader(self, *args):
"""Add a header to be used by the HTTP interface only
e.g. u.addheader('Accept', 'sound/basic')"""
self.addheaders.append(args) self.addheaders.append(args)
# External interface # External interface
# Use URLopener().open(file) instead of open(file, 'r')
def open(self, fullurl, data=None): def open(self, fullurl, data=None):
"""Use URLopener().open(file) instead of open(file, 'r')."""
fullurl = unwrap(fullurl) fullurl = unwrap(fullurl)
if self.tempcache and self.tempcache.has_key(fullurl): if self.tempcache and self.tempcache.has_key(fullurl):
filename, headers = self.tempcache[fullurl] filename, headers = self.tempcache[fullurl]
@ -163,15 +164,15 @@ class URLopener:
except socket.error, msg: except socket.error, msg:
raise IOError, ('socket error', msg), sys.exc_info()[2] raise IOError, ('socket error', msg), sys.exc_info()[2]
# Overridable interface to open unknown URL type
def open_unknown(self, fullurl, data=None): def open_unknown(self, fullurl, data=None):
"""Overridable interface to open unknown URL type."""
type, url = splittype(fullurl) type, url = splittype(fullurl)
raise IOError, ('url error', 'unknown url type', type) raise IOError, ('url error', 'unknown url type', type)
# External interface # External interface
# retrieve(url) returns (filename, None) for a local object
# or (tempfilename, headers) for a remote object
def retrieve(self, url, filename=None, reporthook=None): def retrieve(self, url, filename=None, reporthook=None):
"""retrieve(url) returns (filename, None) for a local object
or (tempfilename, headers) for a remote object."""
url = unwrap(url) url = unwrap(url)
if self.tempcache and self.tempcache.has_key(url): if self.tempcache and self.tempcache.has_key(url):
return self.tempcache[url] return self.tempcache[url]
@ -223,8 +224,8 @@ class URLopener:
# Each method named open_<type> knows how to open that type of URL # Each method named open_<type> knows how to open that type of URL
# Use HTTP protocol
def open_http(self, url, data=None): def open_http(self, url, data=None):
"""Use HTTP protocol."""
import httplib import httplib
user_passwd = None user_passwd = None
if type(url) is type(""): if type(url) is type(""):
@ -276,10 +277,10 @@ class URLopener:
else: else:
return self.http_error(url, fp, errcode, errmsg, headers, data) return self.http_error(url, fp, errcode, errmsg, headers, data)
# Handle http errors.
# Derived class can override this, or provide specific handlers
# named http_error_DDD where DDD is the 3-digit error code
def http_error(self, url, fp, errcode, errmsg, headers, data=None): def http_error(self, url, fp, errcode, errmsg, headers, data=None):
"""Handle http errors.
Derived class can override this, or provide specific handlers
named http_error_DDD where DDD is the 3-digit error code."""
# First check if there's a specific handler for this error # First check if there's a specific handler for this error
name = 'http_error_%d' % errcode name = 'http_error_%d' % errcode
if hasattr(self, name): if hasattr(self, name):
@ -291,15 +292,15 @@ class URLopener:
if result: return result if result: return result
return self.http_error_default(url, fp, errcode, errmsg, headers) return self.http_error_default(url, fp, errcode, errmsg, headers)
# Default http error handler: close the connection and raises IOError
def http_error_default(self, url, fp, errcode, errmsg, headers): def http_error_default(self, url, fp, errcode, errmsg, headers):
"""Default error handler: close the connection and raise IOError."""
void = fp.read() void = fp.read()
fp.close() fp.close()
raise IOError, ('http error', errcode, errmsg, headers) raise IOError, ('http error', errcode, errmsg, headers)
# Use HTTPS protocol
if hasattr(socket, "ssl"): if hasattr(socket, "ssl"):
def open_https(self, url): def open_https(self, url):
"""Use HTTPS protocol."""
import httplib import httplib
if type(url) is type(""): if type(url) is type(""):
host, selector = splithost(url) host, selector = splithost(url)
@ -333,8 +334,8 @@ class URLopener:
else: else:
return self.http_error(url, fp, errcode, errmsg, headers) return self.http_error(url, fp, errcode, errmsg, headers)
# Use Gopher protocol
def open_gopher(self, url): def open_gopher(self, url):
"""Use Gopher protocol."""
import gopherlib import gopherlib
host, selector = splithost(url) host, selector = splithost(url)
if not host: raise IOError, ('gopher error', 'no host given') if not host: raise IOError, ('gopher error', 'no host given')
@ -349,15 +350,15 @@ class URLopener:
fp = gopherlib.send_selector(selector, host) fp = gopherlib.send_selector(selector, host)
return addinfourl(fp, noheaders(), "gopher:" + url) return addinfourl(fp, noheaders(), "gopher:" + url)
# Use local file or FTP depending on form of URL
def open_file(self, url): def open_file(self, url):
"""Use local file or FTP depending on form of URL."""
if url[:2] == '//' and url[2:3] != '/': if url[:2] == '//' and url[2:3] != '/':
return self.open_ftp(url) return self.open_ftp(url)
else: else:
return self.open_local_file(url) return self.open_local_file(url)
# Use local file
def open_local_file(self, url): def open_local_file(self, url):
"""Use local file."""
import mimetypes, mimetools, StringIO import mimetypes, mimetools, StringIO
mtype = mimetypes.guess_type(url)[0] mtype = mimetypes.guess_type(url)[0]
headers = mimetools.Message(StringIO.StringIO( headers = mimetools.Message(StringIO.StringIO(
@ -379,8 +380,8 @@ class URLopener:
headers, urlfile) headers, urlfile)
raise IOError, ('local file error', 'not on local host') raise IOError, ('local file error', 'not on local host')
# Use FTP protocol
def open_ftp(self, url): def open_ftp(self, url):
"""Use FTP protocol."""
host, path = splithost(url) host, path = splithost(url)
if not host: raise IOError, ('ftp error', 'no host given') if not host: raise IOError, ('ftp error', 'no host given')
host, port = splitport(host) host, port = splitport(host)
@ -433,8 +434,8 @@ class URLopener:
except ftperrors(), msg: except ftperrors(), msg:
raise IOError, ('ftp error', msg), sys.exc_info()[2] raise IOError, ('ftp error', msg), sys.exc_info()[2]
# Use "data" URL
def open_data(self, url, data=None): def open_data(self, url, data=None):
"""Use "data" URL."""
# ignore POSTed data # ignore POSTed data
# #
# syntax of data URLs: # syntax of data URLs:
@ -474,20 +475,19 @@ class URLopener:
return addinfourl(f, headers, url) return addinfourl(f, headers, url)
# Derived class with handlers for errors we can handle (perhaps)
class FancyURLopener(URLopener): class FancyURLopener(URLopener):
"""Derived class with handlers for errors we can handle (perhaps)."""
def __init__(self, *args): def __init__(self, *args):
apply(URLopener.__init__, (self,) + args) apply(URLopener.__init__, (self,) + args)
self.auth_cache = {} self.auth_cache = {}
# Default error handling -- don't raise an exception
def http_error_default(self, url, fp, errcode, errmsg, headers): def http_error_default(self, url, fp, errcode, errmsg, headers):
"""Default error handling -- don't raise an exception."""
return addinfourl(fp, headers, "http:" + url) return addinfourl(fp, headers, "http:" + url)
# Error 302 -- relocated (temporarily) def http_error_302(self, url, fp, errcode, errmsg, headers, data=None):
def http_error_302(self, url, fp, errcode, errmsg, headers, """Error 302 -- relocated (temporarily)."""
data=None):
# XXX The server can force infinite recursion here! # XXX The server can force infinite recursion here!
if headers.has_key('location'): if headers.has_key('location'):
newurl = headers['location'] newurl = headers['location']
@ -504,14 +504,14 @@ class FancyURLopener(URLopener):
else: else:
return self.open(newurl, data) return self.open(newurl, data)
# Error 301 -- also relocated (permanently) def http_error_301(self, url, fp, errcode, errmsg, headers, data=None):
http_error_301 = http_error_302 """Error 301 -- also relocated (permanently)."""
return self.http_error_302(url, fp, errcode, errmsg, headers, data)
# Error 401 -- authentication required def http_error_401(self, url, fp, errcode, errmsg, headers, data=None):
# See this URL for a description of the basic authentication scheme: """Error 401 -- authentication required.
# http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt See this URL for a description of the basic authentication scheme:
def http_error_401(self, url, fp, errcode, errmsg, headers, http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt"""
data=None):
if headers.has_key('www-authenticate'): if headers.has_key('www-authenticate'):
stuff = headers['www-authenticate'] stuff = headers['www-authenticate']
import re import re
@ -560,7 +560,7 @@ class FancyURLopener(URLopener):
return user, passwd return user, passwd
def prompt_user_passwd(self, host, realm): def prompt_user_passwd(self, host, realm):
# Override this in a GUI environment! """Override this in a GUI environment!"""
import getpass import getpass
try: try:
user = raw_input("Enter username for %s at %s: " % (realm, user = raw_input("Enter username for %s at %s: " % (realm,
@ -575,34 +575,34 @@ class FancyURLopener(URLopener):
# Utility functions # Utility functions
# Return the IP address of the magic hostname 'localhost'
_localhost = None _localhost = None
def localhost(): def localhost():
"""Return the IP address of the magic hostname 'localhost'."""
global _localhost global _localhost
if not _localhost: if not _localhost:
_localhost = socket.gethostbyname('localhost') _localhost = socket.gethostbyname('localhost')
return _localhost return _localhost
# Return the IP address of the current host
_thishost = None _thishost = None
def thishost(): def thishost():
"""Return the IP address of the current host."""
global _thishost global _thishost
if not _thishost: if not _thishost:
_thishost = socket.gethostbyname(socket.gethostname()) _thishost = socket.gethostbyname(socket.gethostname())
return _thishost return _thishost
# Return the set of errors raised by the FTP class
_ftperrors = None _ftperrors = None
def ftperrors(): def ftperrors():
"""Return the set of errors raised by the FTP class."""
global _ftperrors global _ftperrors
if not _ftperrors: if not _ftperrors:
import ftplib import ftplib
_ftperrors = ftplib.all_errors _ftperrors = ftplib.all_errors
return _ftperrors return _ftperrors
# Return an empty mimetools.Message object
_noheaders = None _noheaders = None
def noheaders(): def noheaders():
"""Return an empty mimetools.Message object."""
global _noheaders global _noheaders
if not _noheaders: if not _noheaders:
import mimetools import mimetools
@ -614,8 +614,9 @@ def noheaders():
# Utility classes # Utility classes
# Class used by open_ftp() for cache of open FTP connections
class ftpwrapper: class ftpwrapper:
"""Class used by open_ftp() for cache of open FTP connections."""
def __init__(self, user, passwd, host, port, dirs): def __init__(self, user, passwd, host, port, dirs):
self.user = user self.user = user
self.passwd = passwd self.passwd = passwd
@ -623,6 +624,7 @@ class ftpwrapper:
self.port = port self.port = port
self.dirs = dirs self.dirs = dirs
self.init() self.init()
def init(self): def init(self):
import ftplib import ftplib
self.busy = 0 self.busy = 0
@ -631,6 +633,7 @@ class ftpwrapper:
self.ftp.login(self.user, self.passwd) self.ftp.login(self.user, self.passwd)
for dir in self.dirs: for dir in self.dirs:
self.ftp.cwd(dir) self.ftp.cwd(dir)
def retrfile(self, file, type): def retrfile(self, file, type):
import ftplib import ftplib
self.endtransfer() self.endtransfer()
@ -676,6 +679,7 @@ class ftpwrapper:
self.ftp.voidresp() self.ftp.voidresp()
except ftperrors(): except ftperrors():
pass pass
def close(self): def close(self):
self.endtransfer() self.endtransfer()
try: try:
@ -683,17 +687,20 @@ class ftpwrapper:
except ftperrors(): except ftperrors():
pass pass
# Base class for addinfo and addclosehook
class addbase: class addbase:
"""Base class for addinfo and addclosehook."""
def __init__(self, fp): def __init__(self, fp):
self.fp = fp self.fp = fp
self.read = self.fp.read self.read = self.fp.read
self.readline = self.fp.readline self.readline = self.fp.readline
if hasattr(self.fp, "readlines"): self.readlines = self.fp.readlines if hasattr(self.fp, "readlines"): self.readlines = self.fp.readlines
if hasattr(self.fp, "fileno"): self.fileno = self.fp.fileno if hasattr(self.fp, "fileno"): self.fileno = self.fp.fileno
def __repr__(self): def __repr__(self):
return '<%s at %s whose fp = %s>' % (self.__class__.__name__, return '<%s at %s whose fp = %s>' % (self.__class__.__name__,
`id(self)`, `self.fp`) `id(self)`, `self.fp`)
def close(self): def close(self):
self.read = None self.read = None
self.readline = None self.readline = None
@ -702,12 +709,14 @@ class addbase:
if self.fp: self.fp.close() if self.fp: self.fp.close()
self.fp = None self.fp = None
# Class to add a close hook to an open file
class addclosehook(addbase): class addclosehook(addbase):
"""Class to add a close hook to an open file."""
def __init__(self, fp, closehook, *hookargs): def __init__(self, fp, closehook, *hookargs):
addbase.__init__(self, fp) addbase.__init__(self, fp)
self.closehook = closehook self.closehook = closehook
self.hookargs = hookargs self.hookargs = hookargs
def close(self): def close(self):
if self.closehook: if self.closehook:
apply(self.closehook, self.hookargs) apply(self.closehook, self.hookargs)
@ -715,29 +724,33 @@ class addclosehook(addbase):
self.hookargs = None self.hookargs = None
addbase.close(self) addbase.close(self)
# class to add an info() method to an open file
class addinfo(addbase): class addinfo(addbase):
"""class to add an info() method to an open file."""
def __init__(self, fp, headers): def __init__(self, fp, headers):
addbase.__init__(self, fp) addbase.__init__(self, fp)
self.headers = headers self.headers = headers
def info(self): def info(self):
return self.headers return self.headers
# class to add info() and geturl() methods to an open file
class addinfourl(addbase): class addinfourl(addbase):
"""class to add info() and geturl() methods to an open file."""
def __init__(self, fp, headers, url): def __init__(self, fp, headers, url):
addbase.__init__(self, fp) addbase.__init__(self, fp)
self.headers = headers self.headers = headers
self.url = url self.url = url
def info(self): def info(self):
return self.headers return self.headers
def geturl(self): def geturl(self):
return self.url return self.url
# Utility to combine a URL with a base URL to form a new URL
def basejoin(base, url): def basejoin(base, url):
"""Utility to combine a URL with a base URL to form a new URL."""
type, path = splittype(url) type, path = splittype(url)
if type: if type:
# if url is complete (i.e., it contains a type), return it # if url is complete (i.e., it contains a type), return it
@ -809,6 +822,7 @@ def basejoin(base, url):
# quote('abc def') -> 'abc%20def') # quote('abc def') -> 'abc%20def')
def unwrap(url): def unwrap(url):
"""unwrap('<URL:type://host/path>') --> 'type://host/path'."""
url = string.strip(url) url = string.strip(url)
if url[:1] == '<' and url[-1:] == '>': if url[:1] == '<' and url[-1:] == '>':
url = string.strip(url[1:-1]) url = string.strip(url[1:-1])
@ -817,6 +831,7 @@ def unwrap(url):
_typeprog = None _typeprog = None
def splittype(url): def splittype(url):
"""splittype('type:opaquestring') --> 'type', 'opaquestring'."""
global _typeprog global _typeprog
if _typeprog is None: if _typeprog is None:
import re import re
@ -830,6 +845,7 @@ def splittype(url):
_hostprog = None _hostprog = None
def splithost(url): def splithost(url):
"""splithost('//host[:port]/path') --> 'host[:port]', '/path'."""
global _hostprog global _hostprog
if _hostprog is None: if _hostprog is None:
import re import re
@ -841,6 +857,7 @@ def splithost(url):
_userprog = None _userprog = None
def splituser(host): def splituser(host):
"""splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'."""
global _userprog global _userprog
if _userprog is None: if _userprog is None:
import re import re
@ -852,6 +869,7 @@ def splituser(host):
_passwdprog = None _passwdprog = None
def splitpasswd(user): def splitpasswd(user):
"""splitpasswd('user:passwd') -> 'user', 'passwd'."""
global _passwdprog global _passwdprog
if _passwdprog is None: if _passwdprog is None:
import re import re
@ -861,8 +879,10 @@ def splitpasswd(user):
if match: return match.group(1, 2) if match: return match.group(1, 2)
return user, None return user, None
# splittag('/path#tag') --> '/path', 'tag'
_portprog = None _portprog = None
def splitport(host): def splitport(host):
"""splitport('host:port') --> 'host', 'port'."""
global _portprog global _portprog
if _portprog is None: if _portprog is None:
import re import re
@ -872,12 +892,12 @@ def splitport(host):
if match: return match.group(1, 2) if match: return match.group(1, 2)
return host, None return host, None
# Split host and port, returning numeric port.
# Return given default port if no ':' found; defaults to -1.
# Return numerical port if a valid number are found after ':'.
# Return None if ':' but not a valid number.
_nportprog = None _nportprog = None
def splitnport(host, defport=-1): def splitnport(host, defport=-1):
"""Split host and port, returning numeric port.
Return given default port if no ':' found; defaults to -1.
Return numerical port if a valid number are found after ':'.
Return None if ':' but not a valid number."""
global _nportprog global _nportprog
if _nportprog is None: if _nportprog is None:
import re import re
@ -896,6 +916,7 @@ def splitnport(host, defport=-1):
_queryprog = None _queryprog = None
def splitquery(url): def splitquery(url):
"""splitquery('/path?query') --> '/path', 'query'."""
global _queryprog global _queryprog
if _queryprog is None: if _queryprog is None:
import re import re
@ -907,6 +928,7 @@ def splitquery(url):
_tagprog = None _tagprog = None
def splittag(url): def splittag(url):
"""splittag('/path#tag') --> '/path', 'tag'."""
global _tagprog global _tagprog
if _tagprog is None: if _tagprog is None:
import re import re
@ -917,11 +939,14 @@ def splittag(url):
return url, None return url, None
def splitattr(url): def splitattr(url):
"""splitattr('/path;attr1=value1;attr2=value2;...') ->
'/path', ['attr1=value1', 'attr2=value2', ...]."""
words = string.splitfields(url, ';') words = string.splitfields(url, ';')
return words[0], words[1:] return words[0], words[1:]
_valueprog = None _valueprog = None
def splitvalue(attr): def splitvalue(attr):
"""splitvalue('attr=value') --> 'attr', 'value'."""
global _valueprog global _valueprog
if _valueprog is None: if _valueprog is None:
import re import re
@ -932,11 +957,13 @@ def splitvalue(attr):
return attr, None return attr, None
def splitgophertype(selector): def splitgophertype(selector):
"""splitgophertype('/Xselector') --> 'X', 'selector'."""
if selector[:1] == '/' and selector[1:2]: if selector[:1] == '/' and selector[1:2]:
return selector[1], selector[2:] return selector[1], selector[2:]
return None, selector return None, selector
def unquote(s): def unquote(s):
"""unquote('abc%20def') -> 'abc def'."""
mychr = chr mychr = chr
myatoi = string.atoi myatoi = string.atoi
list = string.split(s, '%') list = string.split(s, '%')
@ -962,6 +989,7 @@ def unquote_plus(s):
always_safe = string.letters + string.digits + '_,.-' always_safe = string.letters + string.digits + '_,.-'
def quote(s, safe = '/'): def quote(s, safe = '/'):
"""quote('abc def') -> 'abc%20def')."""
# XXX Can speed this up an order of magnitude # XXX Can speed this up an order of magnitude
safe = always_safe + safe safe = always_safe + safe
res = list(s) res = list(s)
@ -983,12 +1011,13 @@ def quote_plus(s, safe = '/'):
return quote(s, safe) return quote(s, safe)
def urlencode(dict): def urlencode(dict):
l = [] """Encode a dictionary of form entries into a URL query string."""
for k, v in dict.items(): l = []
k = quote_plus(str(k)) for k, v in dict.items():
v = quote_plus(str(v)) k = quote_plus(str(k))
l.append(k + '=' + v) v = quote_plus(str(v))
return string.join(l, '&') l.append(k + '=' + v)
return string.join(l, '&')
# Proxy handling # Proxy handling

View File

@ -1,4 +1,4 @@
"""An extensible library for opening URLs using a variety protocols """An extensible library for opening URLs using a variety of protocols
The simplest way to use this module is to call the urlopen function, The simplest way to use this module is to call the urlopen function,
which accepts a string containing a URL or a Request object (described which accepts a string containing a URL or a Request object (described

View File

@ -1,5 +1,8 @@
# Parse (absolute and relative) URLs. See RFC 1808: "Relative Uniform """Parse (absolute and relative) URLs.
# Resource Locators", by R. Fielding, UC Irvine, June 1995.
See RFC 1808: "Relative Uniform Resource Locators", by R. Fielding,
UC Irvine, June 1995.
"""
# Standard/builtin Python modules # Standard/builtin Python modules
import string import string
@ -39,12 +42,12 @@ def clear_cache():
_parse_cache = {} _parse_cache = {}
# Parse a URL into 6 components:
# <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
# Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
# Note that we don't break the components up in smaller bits
# (e.g. netloc is a single string) and we don't expand % escapes.
def urlparse(url, scheme = '', allow_fragments = 1): def urlparse(url, scheme = '', allow_fragments = 1):
"""Parse a URL into 6 components:
<scheme>://<netloc>/<path>;<params>?<query>#<fragment>
Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
Note that we don't break the components up in smaller bits
(e.g. netloc is a single string) and we don't expand % escapes."""
key = url, scheme, allow_fragments key = url, scheme, allow_fragments
cached = _parse_cache.get(key, None) cached = _parse_cache.get(key, None)
if cached: if cached:
@ -107,11 +110,11 @@ def urlparse(url, scheme = '', allow_fragments = 1):
_parse_cache[key] = tuple _parse_cache[key] = tuple
return tuple return tuple
# Put a parsed URL back together again. This may result in a slightly
# different, but equivalent URL, if the URL that was parsed originally
# had redundant delimiters, e.g. a ? with an empty query (the draft
# states that these are equivalent).
def urlunparse((scheme, netloc, url, params, query, fragment)): def urlunparse((scheme, netloc, url, params, query, fragment)):
"""Put a parsed URL back together again. This may result in a
slightly different, but equivalent URL, if the URL that was parsed
originally had redundant delimiters, e.g. a ? with an empty query
(the draft states that these are equivalent)."""
if netloc or (scheme in uses_netloc and url[:2] == '//'): if netloc or (scheme in uses_netloc and url[:2] == '//'):
if url[:1] != '/': url = '/' + url if url[:1] != '/': url = '/' + url
url = '//' + (netloc or '') + url url = '//' + (netloc or '') + url
@ -125,9 +128,9 @@ def urlunparse((scheme, netloc, url, params, query, fragment)):
url = url + '#' + fragment url = url + '#' + fragment
return url return url
# Join a base URL and a possibly relative URL to form an absolute
# interpretation of the latter.
def urljoin(base, url, allow_fragments = 1): def urljoin(base, url, allow_fragments = 1):
"""Join a base URL and a possibly relative URL to form an absolute
interpretation of the latter."""
if not base: if not base:
return url return url
bscheme, bnetloc, bpath, bparams, bquery, bfragment = \ bscheme, bnetloc, bpath, bparams, bquery, bfragment = \

View File

@ -23,11 +23,12 @@
# between ascii and binary. This results in a 1000-fold speedup. The C # between ascii and binary. This results in a 1000-fold speedup. The C
# version is still 5 times faster, though. # version is still 5 times faster, though.
# - Arguments more compliant with python standard # - Arguments more compliant with python standard
#
# This file implements the UUencode and UUdecode functions.
# encode(in_file, out_file [,name, mode]) """Implementation of the UUencode and UUdecode functions.
# decode(in_file [, out_file, mode])
encode(in_file, out_file [,name, mode])
decode(in_file [, out_file, mode])
"""
import binascii import binascii
import os import os

View File

@ -1,74 +1,75 @@
# Stuff to parse WAVE files. """Stuff to parse WAVE files.
#
# Usage. Usage.
#
# Reading WAVE files: Reading WAVE files:
# f = wave.open(file, 'r') f = wave.open(file, 'r')
# where file is either the name of a file or an open file pointer. where file is either the name of a file or an open file pointer.
# The open file pointer must have methods read(), seek(), and close(). The open file pointer must have methods read(), seek(), and close().
# When the setpos() and rewind() methods are not used, the seek() When the setpos() and rewind() methods are not used, the seek()
# method is not necessary. method is not necessary.
#
# This returns an instance of a class with the following public methods: This returns an instance of a class with the following public methods:
# getnchannels() -- returns number of audio channels (1 for getnchannels() -- returns number of audio channels (1 for
# mono, 2 for stereo) mono, 2 for stereo)
# getsampwidth() -- returns sample width in bytes getsampwidth() -- returns sample width in bytes
# getframerate() -- returns sampling frequency getframerate() -- returns sampling frequency
# getnframes() -- returns number of audio frames getnframes() -- returns number of audio frames
# getcomptype() -- returns compression type ('NONE' for linear samples) getcomptype() -- returns compression type ('NONE' for linear samples)
# getcompname() -- returns human-readable version of getcompname() -- returns human-readable version of
# compression type ('not compressed' linear samples) compression type ('not compressed' linear samples)
# getparams() -- returns a tuple consisting of all of the getparams() -- returns a tuple consisting of all of the
# above in the above order above in the above order
# getmarkers() -- returns None (for compatibility with the getmarkers() -- returns None (for compatibility with the
# aifc module) aifc module)
# getmark(id) -- raises an error since the mark does not getmark(id) -- raises an error since the mark does not
# exist (for compatibility with the aifc module) exist (for compatibility with the aifc module)
# readframes(n) -- returns at most n frames of audio readframes(n) -- returns at most n frames of audio
# rewind() -- rewind to the beginning of the audio stream rewind() -- rewind to the beginning of the audio stream
# setpos(pos) -- seek to the specified position setpos(pos) -- seek to the specified position
# tell() -- return the current position tell() -- return the current position
# close() -- close the instance (make it unusable) close() -- close the instance (make it unusable)
# The position returned by tell() and the position given to setpos() The position returned by tell() and the position given to setpos()
# are compatible and have nothing to do with the actual postion in the are compatible and have nothing to do with the actual postion in the
# file. file.
# The close() method is called automatically when the class instance The close() method is called automatically when the class instance
# is destroyed. is destroyed.
#
# Writing WAVE files: Writing WAVE files:
# f = wave.open(file, 'w') f = wave.open(file, 'w')
# where file is either the name of a file or an open file pointer. where file is either the name of a file or an open file pointer.
# The open file pointer must have methods write(), tell(), seek(), and The open file pointer must have methods write(), tell(), seek(), and
# close(). close().
#
# This returns an instance of a class with the following public methods: This returns an instance of a class with the following public methods:
# setnchannels(n) -- set the number of channels setnchannels(n) -- set the number of channels
# setsampwidth(n) -- set the sample width setsampwidth(n) -- set the sample width
# setframerate(n) -- set the frame rate setframerate(n) -- set the frame rate
# setnframes(n) -- set the number of frames setnframes(n) -- set the number of frames
# setcomptype(type, name) setcomptype(type, name)
# -- set the compression type and the -- set the compression type and the
# human-readable compression type human-readable compression type
# setparams(tuple) setparams(tuple)
# -- set all parameters at once -- set all parameters at once
# tell() -- return current position in output file tell() -- return current position in output file
# writeframesraw(data) writeframesraw(data)
# -- write audio frames without pathing up the -- write audio frames without pathing up the
# file header file header
# writeframes(data) writeframes(data)
# -- write audio frames and patch up the file header -- write audio frames and patch up the file header
# close() -- patch up the file header and close the close() -- patch up the file header and close the
# output file output file
# You should set the parameters before the first writeframesraw or You should set the parameters before the first writeframesraw or
# writeframes. The total number of frames does not need to be set, writeframes. The total number of frames does not need to be set,
# but when it is set to the correct value, the header does not have to but when it is set to the correct value, the header does not have to
# be patched up. be patched up.
# It is best to first set all parameters, perhaps possibly the It is best to first set all parameters, perhaps possibly the
# compression type, and then write audio frames using writeframesraw. compression type, and then write audio frames using writeframesraw.
# When all frames have been written, either call writeframes('') or When all frames have been written, either call writeframes('') or
# close() to patch up the sizes in the header. close() to patch up the sizes in the header.
# The close() method is called automatically when the class instance The close() method is called automatically when the class instance
# is destroyed. is destroyed.
"""
import __builtin__ import __builtin__
@ -81,391 +82,393 @@ _array_fmts = None, 'b', 'h', None, 'l'
# Determine endian-ness # Determine endian-ness
import struct import struct
if struct.pack("h", 1) == "\000\001": if struct.pack("h", 1) == "\000\001":
big_endian = 1 big_endian = 1
else: else:
big_endian = 0 big_endian = 0
from chunk import Chunk from chunk import Chunk
class Wave_read: class Wave_read:
# Variables used in this class: """Variables used in this class:
#
# These variables are available to the user though appropriate
# methods of this class:
# _file -- the open file with methods read(), close(), and seek()
# set through the __init__() method
# _nchannels -- the number of audio channels
# available through the getnchannels() method
# _nframes -- the number of audio frames
# available through the getnframes() method
# _sampwidth -- the number of bytes per audio sample
# available through the getsampwidth() method
# _framerate -- the sampling frequency
# available through the getframerate() method
# _comptype -- the AIFF-C compression type ('NONE' if AIFF)
# available through the getcomptype() method
# _compname -- the human-readable AIFF-C compression type
# available through the getcomptype() method
# _soundpos -- the position in the audio stream
# available through the tell() method, set through the
# setpos() method
#
# These variables are used internally only:
# _fmt_chunk_read -- 1 iff the FMT chunk has been read
# _data_seek_needed -- 1 iff positioned correctly in audio
# file for readframes()
# _data_chunk -- instantiation of a chunk class for the DATA chunk
# _framesize -- size of one frame in the file
def initfp(self, file): These variables are available to the user though appropriate
self._convert = None methods of this class:
self._soundpos = 0 _file -- the open file with methods read(), close(), and seek()
self._file = Chunk(file, bigendian = 0) set through the __init__() method
if self._file.getname() != 'RIFF': _nchannels -- the number of audio channels
raise Error, 'file does not start with RIFF id' available through the getnchannels() method
if self._file.read(4) != 'WAVE': _nframes -- the number of audio frames
raise Error, 'not a WAVE file' available through the getnframes() method
self._fmt_chunk_read = 0 _sampwidth -- the number of bytes per audio sample
self._data_chunk = None available through the getsampwidth() method
while 1: _framerate -- the sampling frequency
self._data_seek_needed = 1 available through the getframerate() method
try: _comptype -- the AIFF-C compression type ('NONE' if AIFF)
chunk = Chunk(self._file, bigendian = 0) available through the getcomptype() method
except EOFError: _compname -- the human-readable AIFF-C compression type
break available through the getcomptype() method
chunkname = chunk.getname() _soundpos -- the position in the audio stream
if chunkname == 'fmt ': available through the tell() method, set through the
self._read_fmt_chunk(chunk) setpos() method
self._fmt_chunk_read = 1
elif chunkname == 'data':
if not self._fmt_chunk_read:
raise Error, 'data chunk before fmt chunk'
self._data_chunk = chunk
self._nframes = chunk.chunksize / self._framesize
self._data_seek_needed = 0
break
chunk.skip()
if not self._fmt_chunk_read or not self._data_chunk:
raise Error, 'fmt chunk and/or data chunk missing'
def __init__(self, f): These variables are used internally only:
if type(f) == type(''): _fmt_chunk_read -- 1 iff the FMT chunk has been read
f = __builtin__.open(f, 'rb') _data_seek_needed -- 1 iff positioned correctly in audio
# else, assume it is an open file object already file for readframes()
self.initfp(f) _data_chunk -- instantiation of a chunk class for the DATA chunk
_framesize -- size of one frame in the file
"""
# def initfp(self, file):
# User visible methods. self._convert = None
# self._soundpos = 0
def getfp(self): self._file = Chunk(file, bigendian = 0)
return self._file if self._file.getname() != 'RIFF':
raise Error, 'file does not start with RIFF id'
if self._file.read(4) != 'WAVE':
raise Error, 'not a WAVE file'
self._fmt_chunk_read = 0
self._data_chunk = None
while 1:
self._data_seek_needed = 1
try:
chunk = Chunk(self._file, bigendian = 0)
except EOFError:
break
chunkname = chunk.getname()
if chunkname == 'fmt ':
self._read_fmt_chunk(chunk)
self._fmt_chunk_read = 1
elif chunkname == 'data':
if not self._fmt_chunk_read:
raise Error, 'data chunk before fmt chunk'
self._data_chunk = chunk
self._nframes = chunk.chunksize / self._framesize
self._data_seek_needed = 0
break
chunk.skip()
if not self._fmt_chunk_read or not self._data_chunk:
raise Error, 'fmt chunk and/or data chunk missing'
def rewind(self): def __init__(self, f):
self._data_seek_needed = 1 if type(f) == type(''):
self._soundpos = 0 f = __builtin__.open(f, 'rb')
# else, assume it is an open file object already
self.initfp(f)
def close(self): #
self._file = None # User visible methods.
#
def getfp(self):
return self._file
def tell(self): def rewind(self):
return self._soundpos self._data_seek_needed = 1
self._soundpos = 0
def getnchannels(self): def close(self):
return self._nchannels self._file = None
def getnframes(self): def tell(self):
return self._nframes return self._soundpos
def getsampwidth(self): def getnchannels(self):
return self._sampwidth return self._nchannels
def getframerate(self): def getnframes(self):
return self._framerate return self._nframes
def getcomptype(self): def getsampwidth(self):
return self._comptype return self._sampwidth
def getcompname(self): def getframerate(self):
return self._compname return self._framerate
def getparams(self): def getcomptype(self):
return self.getnchannels(), self.getsampwidth(), \ return self._comptype
self.getframerate(), self.getnframes(), \
self.getcomptype(), self.getcompname()
def getmarkers(self): def getcompname(self):
return None return self._compname
def getmark(self, id): def getparams(self):
raise Error, 'no marks' return self.getnchannels(), self.getsampwidth(), \
self.getframerate(), self.getnframes(), \
self.getcomptype(), self.getcompname()
def setpos(self, pos): def getmarkers(self):
if pos < 0 or pos > self._nframes: return None
raise Error, 'position not in range'
self._soundpos = pos
self._data_seek_needed = 1
def readframes(self, nframes): def getmark(self, id):
if self._data_seek_needed: raise Error, 'no marks'
self._data_chunk.seek(0, 0)
pos = self._soundpos * self._framesize
if pos:
self._data_chunk.seek(pos, 0)
self._data_seek_needed = 0
if nframes == 0:
return ''
if self._sampwidth > 1 and big_endian:
# unfortunately the fromfile() method does not take
# something that only looks like a file object, so
# we have to reach into the innards of the chunk object
import array
chunk = self._data_chunk
data = array.array(_array_fmts[self._sampwidth])
nitems = nframes * self._nchannels
if nitems * self._sampwidth > chunk.chunksize - chunk.size_read:
nitems = (chunk.chunksize - chunk.size_read) / self._sampwidth
data.fromfile(chunk.file.file, nitems)
# "tell" data chunk how much was read
chunk.size_read = chunk.size_read + nitems * self._sampwidth
# do the same for the outermost chunk
chunk = chunk.file
chunk.size_read = chunk.size_read + nitems * self._sampwidth
data.byteswap()
data = data.tostring()
else:
data = self._data_chunk.read(nframes * self._framesize)
if self._convert and data:
data = self._convert(data)
self._soundpos = self._soundpos + len(data) / (self._nchannels * self._sampwidth)
return data
# def setpos(self, pos):
# Internal methods. if pos < 0 or pos > self._nframes:
# raise Error, 'position not in range'
self._soundpos = pos
self._data_seek_needed = 1
def _read_fmt_chunk(self, chunk): def readframes(self, nframes):
wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<hhllh', chunk.read(14)) if self._data_seek_needed:
if wFormatTag == WAVE_FORMAT_PCM: self._data_chunk.seek(0, 0)
sampwidth = struct.unpack('<h', chunk.read(2))[0] pos = self._soundpos * self._framesize
self._sampwidth = (sampwidth + 7) / 8 if pos:
else: self._data_chunk.seek(pos, 0)
raise Error, 'unknown format: ' + `wFormatTag` self._data_seek_needed = 0
self._framesize = self._nchannels * self._sampwidth if nframes == 0:
self._comptype = 'NONE' return ''
self._compname = 'not compressed' if self._sampwidth > 1 and big_endian:
# unfortunately the fromfile() method does not take
# something that only looks like a file object, so
# we have to reach into the innards of the chunk object
import array
chunk = self._data_chunk
data = array.array(_array_fmts[self._sampwidth])
nitems = nframes * self._nchannels
if nitems * self._sampwidth > chunk.chunksize - chunk.size_read:
nitems = (chunk.chunksize - chunk.size_read) / self._sampwidth
data.fromfile(chunk.file.file, nitems)
# "tell" data chunk how much was read
chunk.size_read = chunk.size_read + nitems * self._sampwidth
# do the same for the outermost chunk
chunk = chunk.file
chunk.size_read = chunk.size_read + nitems * self._sampwidth
data.byteswap()
data = data.tostring()
else:
data = self._data_chunk.read(nframes * self._framesize)
if self._convert and data:
data = self._convert(data)
self._soundpos = self._soundpos + len(data) / (self._nchannels * self._sampwidth)
return data
#
# Internal methods.
#
def _read_fmt_chunk(self, chunk):
wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<hhllh', chunk.read(14))
if wFormatTag == WAVE_FORMAT_PCM:
sampwidth = struct.unpack('<h', chunk.read(2))[0]
self._sampwidth = (sampwidth + 7) / 8
else:
raise Error, 'unknown format: ' + `wFormatTag`
self._framesize = self._nchannels * self._sampwidth
self._comptype = 'NONE'
self._compname = 'not compressed'
class Wave_write: class Wave_write:
# Variables used in this class: """Variables used in this class:
#
# These variables are user settable through appropriate methods
# of this class:
# _file -- the open file with methods write(), close(), tell(), seek()
# set through the __init__() method
# _comptype -- the AIFF-C compression type ('NONE' in AIFF)
# set through the setcomptype() or setparams() method
# _compname -- the human-readable AIFF-C compression type
# set through the setcomptype() or setparams() method
# _nchannels -- the number of audio channels
# set through the setnchannels() or setparams() method
# _sampwidth -- the number of bytes per audio sample
# set through the setsampwidth() or setparams() method
# _framerate -- the sampling frequency
# set through the setframerate() or setparams() method
# _nframes -- the number of audio frames written to the header
# set through the setnframes() or setparams() method
#
# These variables are used internally only:
# _datalength -- the size of the audio samples written to the header
# _nframeswritten -- the number of frames actually written
# _datawritten -- the size of the audio samples actually written
def __init__(self, f): These variables are user settable through appropriate methods
if type(f) == type(''): of this class:
f = __builtin__.open(f, 'wb') _file -- the open file with methods write(), close(), tell(), seek()
self.initfp(f) set through the __init__() method
_comptype -- the AIFF-C compression type ('NONE' in AIFF)
set through the setcomptype() or setparams() method
_compname -- the human-readable AIFF-C compression type
set through the setcomptype() or setparams() method
_nchannels -- the number of audio channels
set through the setnchannels() or setparams() method
_sampwidth -- the number of bytes per audio sample
set through the setsampwidth() or setparams() method
_framerate -- the sampling frequency
set through the setframerate() or setparams() method
_nframes -- the number of audio frames written to the header
set through the setnframes() or setparams() method
def initfp(self, file): These variables are used internally only:
self._file = file _datalength -- the size of the audio samples written to the header
self._convert = None _nframeswritten -- the number of frames actually written
self._nchannels = 0 _datawritten -- the size of the audio samples actually written
self._sampwidth = 0 """
self._framerate = 0
self._nframes = 0
self._nframeswritten = 0
self._datawritten = 0
self._datalength = 0
def __del__(self): def __init__(self, f):
if self._file: if type(f) == type(''):
self.close() f = __builtin__.open(f, 'wb')
self.initfp(f)
# def initfp(self, file):
# User visible methods. self._file = file
# self._convert = None
def setnchannels(self, nchannels): self._nchannels = 0
if self._datawritten: self._sampwidth = 0
raise Error, 'cannot change parameters after starting to write' self._framerate = 0
if nchannels < 1: self._nframes = 0
raise Error, 'bad # of channels' self._nframeswritten = 0
self._nchannels = nchannels self._datawritten = 0
self._datalength = 0
def getnchannels(self): def __del__(self):
if not self._nchannels: if self._file:
raise Error, 'number of channels not set' self.close()
return self._nchannels
def setsampwidth(self, sampwidth): #
if self._datawritten: # User visible methods.
raise Error, 'cannot change parameters after starting to write' #
if sampwidth < 1 or sampwidth > 4: def setnchannels(self, nchannels):
raise Error, 'bad sample width' if self._datawritten:
self._sampwidth = sampwidth raise Error, 'cannot change parameters after starting to write'
if nchannels < 1:
raise Error, 'bad # of channels'
self._nchannels = nchannels
def getsampwidth(self): def getnchannels(self):
if not self._sampwidth: if not self._nchannels:
raise Error, 'sample width not set' raise Error, 'number of channels not set'
return self._sampwidth return self._nchannels
def setframerate(self, framerate): def setsampwidth(self, sampwidth):
if self._datawritten: if self._datawritten:
raise Error, 'cannot change parameters after starting to write' raise Error, 'cannot change parameters after starting to write'
if framerate <= 0: if sampwidth < 1 or sampwidth > 4:
raise Error, 'bad frame rate' raise Error, 'bad sample width'
self._framerate = framerate self._sampwidth = sampwidth
def getframerate(self): def getsampwidth(self):
if not self._framerate: if not self._sampwidth:
raise Error, 'frame rate not set' raise Error, 'sample width not set'
return self._framerate return self._sampwidth
def setnframes(self, nframes): def setframerate(self, framerate):
if self._datawritten: if self._datawritten:
raise Error, 'cannot change parameters after starting to write' raise Error, 'cannot change parameters after starting to write'
self._nframes = nframes if framerate <= 0:
raise Error, 'bad frame rate'
self._framerate = framerate
def getnframes(self): def getframerate(self):
return self._nframeswritten if not self._framerate:
raise Error, 'frame rate not set'
return self._framerate
def setcomptype(self, comptype, compname): def setnframes(self, nframes):
if self._datawritten: if self._datawritten:
raise Error, 'cannot change parameters after starting to write' raise Error, 'cannot change parameters after starting to write'
if comptype not in ('NONE',): self._nframes = nframes
raise Error, 'unsupported compression type'
self._comptype = comptype
self._compname = compname
def getcomptype(self): def getnframes(self):
return self._comptype return self._nframeswritten
def getcompname(self): def setcomptype(self, comptype, compname):
return self._compname if self._datawritten:
raise Error, 'cannot change parameters after starting to write'
if comptype not in ('NONE',):
raise Error, 'unsupported compression type'
self._comptype = comptype
self._compname = compname
def setparams(self, (nchannels, sampwidth, framerate, nframes, comptype, compname)): def getcomptype(self):
if self._datawritten: return self._comptype
raise Error, 'cannot change parameters after starting to write'
self.setnchannels(nchannels)
self.setsampwidth(sampwidth)
self.setframerate(framerate)
self.setnframes(nframes)
self.setcomptype(comptype, compname)
def getparams(self): def getcompname(self):
if not self._nchannels or not self._sampwidth or not self._framerate: return self._compname
raise Error, 'not all parameters set'
return self._nchannels, self._sampwidth, self._framerate, \
self._nframes, self._comptype, self._compname
def setmark(self, id, pos, name): def setparams(self, (nchannels, sampwidth, framerate, nframes, comptype, compname)):
raise Error, 'setmark() not supported' if self._datawritten:
raise Error, 'cannot change parameters after starting to write'
self.setnchannels(nchannels)
self.setsampwidth(sampwidth)
self.setframerate(framerate)
self.setnframes(nframes)
self.setcomptype(comptype, compname)
def getmark(self, id): def getparams(self):
raise Error, 'no marks' if not self._nchannels or not self._sampwidth or not self._framerate:
raise Error, 'not all parameters set'
return self._nchannels, self._sampwidth, self._framerate, \
self._nframes, self._comptype, self._compname
def getmarkers(self): def setmark(self, id, pos, name):
return None raise Error, 'setmark() not supported'
def tell(self):
return self._nframeswritten
def writeframesraw(self, data): def getmark(self, id):
self._ensure_header_written(len(data)) raise Error, 'no marks'
nframes = len(data) / (self._sampwidth * self._nchannels)
if self._convert:
data = self._convert(data)
if self._sampwidth > 1 and big_endian:
import array
data = array.array(_array_fmts[self._sampwidth], data)
data.byteswap()
data.tofile(self._file)
self._datawritten = self._datawritten + len(data) * self._sampwidth
else:
self._file.write(data)
self._datawritten = self._datawritten + len(data)
self._nframeswritten = self._nframeswritten + nframes
def writeframes(self, data): def getmarkers(self):
self.writeframesraw(data) return None
if self._datalength != self._datawritten:
self._patchheader() def tell(self):
return self._nframeswritten
def close(self): def writeframesraw(self, data):
self._ensure_header_written(0) self._ensure_header_written(len(data))
if self._datalength != self._datawritten: nframes = len(data) / (self._sampwidth * self._nchannels)
self._patchheader() if self._convert:
self._file.flush() data = self._convert(data)
self._file = None if self._sampwidth > 1 and big_endian:
import array
data = array.array(_array_fmts[self._sampwidth], data)
data.byteswap()
data.tofile(self._file)
self._datawritten = self._datawritten + len(data) * self._sampwidth
else:
self._file.write(data)
self._datawritten = self._datawritten + len(data)
self._nframeswritten = self._nframeswritten + nframes
# def writeframes(self, data):
# Internal methods. self.writeframesraw(data)
# if self._datalength != self._datawritten:
self._patchheader()
def _ensure_header_written(self, datasize): def close(self):
if not self._datawritten: self._ensure_header_written(0)
if not self._nchannels: if self._datalength != self._datawritten:
raise Error, '# channels not specified' self._patchheader()
if not self._sampwidth: self._file.flush()
raise Error, 'sample width not specified' self._file = None
if not self._framerate:
raise Error, 'sampling rate not specified'
self._write_header(datasize)
def _write_header(self, initlength): #
self._file.write('RIFF') # Internal methods.
if not self._nframes: #
self._nframes = initlength / (self._nchannels * self._sampwidth)
self._datalength = self._nframes * self._nchannels * self._sampwidth
self._form_length_pos = self._file.tell()
self._file.write(struct.pack('<lsslhhllhhs',
36 + self._datalength, 'WAVE', 'fmt ', 16,
WAVE_FORMAT_PCM, self._nchannels, self._framerate,
self._nchannels * self._framerate * self._sampwidth,
self._nchannels * self._sampwidth,
self._sampwidth * 8, 'data'))
self._data_length_pos = self._file.tell()
self._file.write(struct.pack('<l', self._datalength))
def _patchheader(self): def _ensure_header_written(self, datasize):
if self._datawritten == self._datalength: if not self._datawritten:
return if not self._nchannels:
curpos = self._file.tell() raise Error, '# channels not specified'
self._file.seek(self._form_length_pos, 0) if not self._sampwidth:
self._file.write(struct.pack('<l', 36 + self._datawritten)) raise Error, 'sample width not specified'
self._file.seek(self._data_length_pos, 0) if not self._framerate:
self._file.write(struct.pack('<l', self._datawritten)) raise Error, 'sampling rate not specified'
self._file.seek(curpos, 0) self._write_header(datasize)
self._datalength = self._datawritten
def _write_header(self, initlength):
self._file.write('RIFF')
if not self._nframes:
self._nframes = initlength / (self._nchannels * self._sampwidth)
self._datalength = self._nframes * self._nchannels * self._sampwidth
self._form_length_pos = self._file.tell()
self._file.write(struct.pack('<lsslhhllhhs',
36 + self._datalength, 'WAVE', 'fmt ', 16,
WAVE_FORMAT_PCM, self._nchannels, self._framerate,
self._nchannels * self._framerate * self._sampwidth,
self._nchannels * self._sampwidth,
self._sampwidth * 8, 'data'))
self._data_length_pos = self._file.tell()
self._file.write(struct.pack('<l', self._datalength))
def _patchheader(self):
if self._datawritten == self._datalength:
return
curpos = self._file.tell()
self._file.seek(self._form_length_pos, 0)
self._file.write(struct.pack('<l', 36 + self._datawritten))
self._file.seek(self._data_length_pos, 0)
self._file.write(struct.pack('<l', self._datawritten))
self._file.seek(curpos, 0)
self._datalength = self._datawritten
def open(f, mode=None): def open(f, mode=None):
if mode is None: if mode is None:
if hasattr(f, 'mode'): if hasattr(f, 'mode'):
mode = f.mode mode = f.mode
else: else:
mode = 'rb' mode = 'rb'
if mode in ('r', 'rb'): if mode in ('r', 'rb'):
return Wave_read(f) return Wave_read(f)
elif mode in ('w', 'wb'): elif mode in ('w', 'wb'):
return Wave_write(f) return Wave_write(f)
else: else:
raise Error, "mode must be 'r', 'rb', 'w', or 'wb'" raise Error, "mode must be 'r', 'rb', 'w', or 'wb'"
openfp = open # B/W compatibility openfp = open # B/W compatibility

View File

@ -1,54 +1,52 @@
# WICHMANN-HILL RANDOM NUMBER GENERATOR """Wichman-Hill random number generator.
#
# Wichmann, B. A. & Hill, I. D. (1982) Wichmann, B. A. & Hill, I. D. (1982)
# Algorithm AS 183: Algorithm AS 183:
# An efficient and portable pseudo-random number generator An efficient and portable pseudo-random number generator
# Applied Statistics 31 (1982) 188-190 Applied Statistics 31 (1982) 188-190
#
# see also: see also:
# Correction to Algorithm AS 183 Correction to Algorithm AS 183
# Applied Statistics 33 (1984) 123 Applied Statistics 33 (1984) 123
#
# McLeod, A. I. (1985) McLeod, A. I. (1985)
# A remark on Algorithm AS 183 A remark on Algorithm AS 183
# Applied Statistics 34 (1985),198-200 Applied Statistics 34 (1985),198-200
#
#
# USE:
# whrandom.random() yields double precision random numbers
# uniformly distributed between 0 and 1.
#
# whrandom.seed(x, y, z) must be called before whrandom.random()
# to seed the generator
#
# There is also an interface to create multiple independent
# random generators, and to choose from other ranges.
# Translated by Guido van Rossum from C source provided by USE:
# Adrian Baddeley. whrandom.random() yields double precision random numbers
uniformly distributed between 0 and 1.
whrandom.seed(x, y, z) must be called before whrandom.random()
to seed the generator
There is also an interface to create multiple independent
random generators, and to choose from other ranges.
# Multi-threading note: the random number generator used here is not Translated by Guido van Rossum from C source provided by
# thread-safe; it is possible that nearly simultaneous calls in Adrian Baddeley.
# different theads return the same random value. To avoid this, you
# have to use a lock around all calls. (I didn't want to slow this
# down in the serial case by using a lock here.)
Multi-threading note: the random number generator used here is not
thread-safe; it is possible that nearly simultaneous calls in
different theads return the same random value. To avoid this, you
have to use a lock around all calls. (I didn't want to slow this
down in the serial case by using a lock here.)
"""
class whrandom: class whrandom:
#
# Initialize an instance.
# Without arguments, initialize from current time.
# With arguments (x, y, z), initialize from them.
#
def __init__(self, x = 0, y = 0, z = 0): def __init__(self, x = 0, y = 0, z = 0):
"""Initialize an instance.
Without arguments, initialize from current time.
With arguments (x, y, z), initialize from them."""
self.seed(x, y, z) self.seed(x, y, z)
#
# Set the seed from (x, y, z).
# These must be integers in the range [0, 256).
#
def seed(self, x = 0, y = 0, z = 0): def seed(self, x = 0, y = 0, z = 0):
"""Set the seed from (x, y, z).
These must be integers in the range [0, 256)."""
if not type(x) == type(y) == type(z) == type(0): if not type(x) == type(y) == type(z) == type(0):
raise TypeError, 'seeds must be integers' raise TypeError, 'seeds must be integers'
if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256): if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
@ -63,10 +61,9 @@ class whrandom:
t, z = divmod(t, 256) t, z = divmod(t, 256)
# Zero is a poor seed, so substitute 1 # Zero is a poor seed, so substitute 1
self._seed = (x or 1, y or 1, z or 1) self._seed = (x or 1, y or 1, z or 1)
#
# Get the next random number in the range [0.0, 1.0).
#
def random(self): def random(self):
"""Get the next random number in the range [0.0, 1.0)."""
# This part is thread-unsafe: # This part is thread-unsafe:
# BEGIN CRITICAL SECTION # BEGIN CRITICAL SECTION
x, y, z = self._seed x, y, z = self._seed
@ -79,30 +76,25 @@ class whrandom:
# END CRITICAL SECTION # END CRITICAL SECTION
# #
return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0 return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0
#
# Get a random number in the range [a, b).
#
def uniform(self, a, b): def uniform(self, a, b):
"""Get a random number in the range [a, b)."""
return a + (b-a) * self.random() return a + (b-a) * self.random()
#
# Get a random integer in the range [a, b] including both end points.
# (Deprecated; use randrange below.)
#
def randint(self, a, b): def randint(self, a, b):
"""Get a random integer in the range [a, b] including both end points.
(Deprecated; use randrange below.)"""
return self.randrange(a, b+1) return self.randrange(a, b+1)
#
# Choose a random element from a non-empty sequence.
#
def choice(self, seq): def choice(self, seq):
"""Choose a random element from a non-empty sequence."""
return seq[int(self.random() * len(seq))] return seq[int(self.random() * len(seq))]
#
# Choose a random item from range([start,] step[, stop]). def randrange(self, start, stop=None, step=1, int=int, default=None):
# This fixes the problem with randint() which includes the """Choose a random item from range([start,] step[, stop]).
# endpoint; in Python this is usually not what you want. This fixes the problem with randint() which includes the
# endpoint; in Python this is usually not what you want.
def randrange(self, start, stop=None, step=1, Do not supply the 'int' and 'default' arguments."""
# Do not supply the following arguments
int=int, default=None):
# This code is a bit messy to make it fast for the # This code is a bit messy to make it fast for the
# common case while still doing adequate error checking # common case while still doing adequate error checking
istart = int(start) istart = int(start)
@ -136,7 +128,6 @@ class whrandom:
# Initialize from the current time # Initialize from the current time
#
_inst = whrandom() _inst = whrandom()
seed = _inst.seed seed = _inst.seed
random = _inst.random random = _inst.random