Commit e03c0505 authored by Guido van Rossum's avatar Guido van Rossum

The usual.

parent 887d072c
...@@ -133,7 +133,10 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): ...@@ -133,7 +133,10 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
# AUTH_TYPE # AUTH_TYPE
# REMOTE_USER # REMOTE_USER
# REMOTE_IDENT # REMOTE_IDENT
env['CONTENT_TYPE'] = self.headers.type if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
else:
env['CONTENT_TYPE'] = self.headers.typeheader
length = self.headers.getheader('content-length') length = self.headers.getheader('content-length')
if length: if length:
env['CONTENT_LENGTH'] = length env['CONTENT_LENGTH'] = length
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
A setup file consists of sections, lead by a "[section]" header, A setup file consists of sections, lead by a "[section]" header,
and followed by "name: value" entries, with continuations and such in and followed by "name: value" entries, with continuations and such in
the style of rfc822. the style of RFC 822.
The option values can contain format strings which refer to other values in
the same section, or values in a special [DEFAULT] section.
The option values can contain format strings which refer to other
values in the same section, or values in a special [DEFAULT] section.
For example: For example:
something: %(dir)s/whatever something: %(dir)s/whatever
...@@ -27,7 +28,7 @@ ConfigParser -- responsible for for parsing a list of ...@@ -27,7 +28,7 @@ ConfigParser -- responsible for for parsing a list of
dictionary of intrinsic defaults. The dictionary of intrinsic defaults. The
keys must be strings, the values must keys must be strings, the values must
be appropriate for %()s string be appropriate for %()s string
interpolation. Note that `name' is interpolation. Note that `__name__' is
always an intrinsic default; it's value always an intrinsic default; it's value
is the section's name. is the section's name.
...@@ -55,14 +56,7 @@ ConfigParser -- responsible for for parsing a list of ...@@ -55,14 +56,7 @@ ConfigParser -- responsible for for parsing a list of
import sys import sys
import string import string
import regex import re
from types import ListType
SECTHEAD_RE = "^\[\([-A-Za-z0-9]*\)\][" + string.whitespace + "]*$"
secthead_cre = regex.compile(SECTHEAD_RE)
OPTION_RE = "^\([-A-Za-z0-9.]+\)\(:\|[" + string.whitespace + "]*=\)\(.*\)$"
option_cre = regex.compile(OPTION_RE)
DEFAULTSECT = "DEFAULT" DEFAULTSECT = "DEFAULT"
...@@ -71,9 +65,9 @@ DEFAULTSECT = "DEFAULT" ...@@ -71,9 +65,9 @@ DEFAULTSECT = "DEFAULT"
# exception classes # exception classes
class Error: class Error:
def __init__(self, msg=''): def __init__(self, msg=''):
self.__msg = msg self._msg = msg
def __repr__(self): def __repr__(self):
return self.__msg return self._msg
class NoSectionError(Error): class NoSectionError(Error):
def __init__(self, section): def __init__(self, section):
...@@ -93,14 +87,38 @@ class NoOptionError(Error): ...@@ -93,14 +87,38 @@ class NoOptionError(Error):
self.section = section self.section = section
class InterpolationError(Error): class InterpolationError(Error):
def __init__(self, reference, option, section): def __init__(self, reference, option, section, rawval):
Error.__init__(self, Error.__init__(self,
"Bad value substitution: sect `%s', opt `%s', ref `%s'" "Bad value substitution:\n"
% (section, option, reference)) "\tsection: [%s]\n"
"\toption : %s\n"
"\tkey : %s\n"
"\trawval : %s\n"
% (section, option, reference, rawval))
self.reference = reference self.reference = reference
self.option = option self.option = option
self.section = section self.section = section
class MissingSectionHeaderError(Error):
def __init__(self, filename, lineno, line):
Error.__init__(
self,
'File contains no section headers.\nfile: %s, line: %d\n%s' %
(filename, lineno, line))
self.filename = filename
self.lineno = lineno
self.line = line
class ParsingError(Error):
def __init__(self, filename):
Error.__init__(self, 'File contains parsing errors: %s' % filename)
self.filename = filename
self.errors = []
def append(self, lineno, line):
self.errors.append((lineno, line))
self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line)
class ConfigParser: class ConfigParser:
...@@ -159,7 +177,8 @@ class ConfigParser: ...@@ -159,7 +177,8 @@ class ConfigParser:
"""Get an option value for a given section. """Get an option value for a given section.
All % interpolations are expanded in the return values, based All % interpolations are expanded in the return values, based
on the defaults passed into the constructor. on the defaults passed into the constructor, unless the optional
argument `raw' is true.
The section DEFAULT is special. The section DEFAULT is special.
""" """
...@@ -183,7 +202,7 @@ class ConfigParser: ...@@ -183,7 +202,7 @@ class ConfigParser:
try: try:
return rawval % d return rawval % d
except KeyError, key: except KeyError, key:
raise InterpolationError(key, option, section) raise InterpolationError(key, option, section, rawval)
def __get(self, section, conv, option): def __get(self, section, conv, option):
return conv(self.get(section, option)) return conv(self.get(section, option))
...@@ -201,6 +220,24 @@ class ConfigParser: ...@@ -201,6 +220,24 @@ class ConfigParser:
raise ValueError, 'Not a boolean: %s' % v raise ValueError, 'Not a boolean: %s' % v
return val return val
#
# Regular expressions for parsing section headers and options. Note a
# slight semantic change from the previous version, because of the use
# of \w, _ is allowed in section header names.
__SECTCRE = re.compile(
r'\[' # [
r'(?P<header>[-\w]+)' # `-', `_' or any alphanum
r'\]' # ]
)
__OPTCRE = re.compile(
r'(?P<option>[-.\w]+)' # - . _ alphanum
r'[ \t]*[:=][ \t]*' # any number of space/tab,
# followed by separator
# (either : or =), followed
# by any # space/tab
r'(?P<value>.*)$' # everything up to eol
)
def __read(self, fp): def __read(self, fp):
"""Parse a sectioned setup file. """Parse a sectioned setup file.
...@@ -211,9 +248,10 @@ class ConfigParser: ...@@ -211,9 +248,10 @@ class ConfigParser:
leading whitespace. Blank lines, lines beginning with a '#', leading whitespace. Blank lines, lines beginning with a '#',
and just about everything else is ignored. and just about everything else is ignored.
""" """
cursect = None # None, or a dictionary cursect = None # None, or a dictionary
optname = None optname = None
lineno = 0 lineno = 0
e = None # None, or an exception
while 1: while 1:
line = fp.readline() line = fp.readline()
if not line: if not line:
...@@ -226,31 +264,47 @@ class ConfigParser: ...@@ -226,31 +264,47 @@ class ConfigParser:
and line[0] == "r": # no leading whitespace and line[0] == "r": # no leading whitespace
continue continue
# continuation line? # continuation line?
if line[0] in ' \t' and cursect <> None and optname: if line[0] in ' \t' and cursect is not None and optname:
value = string.strip(line) value = string.strip(line)
if value: if value:
cursect = cursect[optname] + '\n ' + value cursect[optname] = cursect[optname] + '\n ' + value
# a section header? # a section header or option header?
elif secthead_cre.match(line) >= 0:
sectname = secthead_cre.group(1)
if self.__sections.has_key(sectname):
cursect = self.__sections[sectname]
elif sectname == DEFAULTSECT:
cursect = self.__defaults
else:
cursect = {'name': sectname}
self.__sections[sectname] = cursect
# So sections can't start with a continuation line.
optname = None
# an option line?
elif option_cre.match(line) >= 0:
optname, optval = option_cre.group(1, 3)
optname = string.lower(optname)
optval = string.strip(optval)
# allow empty values
if optval == '""':
optval = ''
cursect[optname] = optval
# an error
else: else:
print 'Error in %s at %d: %s', (fp.name, lineno, `line`) # is it a section header?
mo = self.__SECTCRE.match(line)
if mo:
sectname = mo.group('header')
if self.__sections.has_key(sectname):
cursect = self.__sections[sectname]
elif sectname == DEFAULTSECT:
cursect = self.__defaults
else:
cursect = {'__name__': sectname}
self.__sections[sectname] = cursect
# So sections can't start with a continuation line
optname = None
# no section header in the file?
elif cursect is None:
raise MissingSectionHeaderError(fp.name, lineno, `line`)
# an option line?
else:
mo = self.__OPTCRE.match(line)
if mo:
optname, optval = mo.group('option', 'value')
optname = string.lower(optname)
optval = string.strip(optval)
# allow empty values
if optval == '""':
optval = ''
cursect[optname] = optval
else:
# a non-fatal parsing error occurred. set up the
# exception but keep going. the exception will be
# raised at the end of the file and will contain a
# list of all bogus lines
if not e:
e = ParsingError(fp.name)
e.append(lineno, `line`)
# if any parsing errors occurred, raise an exception
if e:
raise e
...@@ -80,15 +80,44 @@ class SyntaxError(StandardError): ...@@ -80,15 +80,44 @@ class SyntaxError(StandardError):
def __str__(self): def __str__(self):
return str(self.msg) return str(self.msg)
class IOError(StandardError): class EnvironmentError(StandardError):
"""Base class for exceptions that occur outside the Python system.
Primarily used as a base class for OSError and IOError."""
def __init__(self, *args): def __init__(self, *args):
self.args = args self.args = args
self.errno = None self.errno = None
self.strerror = None self.strerror = None
self.filename = None
if len(args) == 3:
# open() errors give third argument which is the filename. BUT,
# so common in-place unpacking doesn't break, e.g.:
#
# except IOError, (errno, strerror):
#
# we hack args so that it only contains two items. This also
# means we need our own __str__() which prints out the filename
# when it was supplied.
self.errno, self.strerror, self.filename = args
self.args = args[0:2]
if len(args) == 2: if len(args) == 2:
# common case: PyErr_SetFromErrno() # common case: PyErr_SetFromErrno()
self.errno = args[0] self.errno, self.strerror = args
self.strerror = args[1]
def __str__(self):
if self.filename is not None:
return '[Errno %s] %s: %s' % (self.errno, self.strerror,
repr(self.filename))
elif self.errno and self.strerror:
return '[Errno %s] %s' % (self.errno, self.strerror)
else:
return StandardError.__str__(self)
class IOError(EnvironmentError):
pass
class OSError(EnvironmentError):
"""Used by the posix module."""
pass
class RuntimeError(StandardError): class RuntimeError(StandardError):
pass pass
......
...@@ -142,6 +142,7 @@ class FileInput: ...@@ -142,6 +142,7 @@ class FileInput:
self._filelineno = 0 self._filelineno = 0
self._file = None self._file = None
self._isstdin = 0 self._isstdin = 0
self._backupfilename = None
def __del__(self): def __del__(self):
self.close() self.close()
......
...@@ -29,7 +29,7 @@ def url2pathname(pathname): ...@@ -29,7 +29,7 @@ def url2pathname(pathname):
i = i+1 i = i+1
if not components[0]: if not components[0]:
# Absolute unix path, don't start with colon # Absolute unix path, don't start with colon
return string.join(components[1:], ':') rv = string.join(components[1:], ':')
else: else:
# relative unix path, start with colon. First replace # relative unix path, start with colon. First replace
# leading .. by empty strings (giving ::file) # leading .. by empty strings (giving ::file)
...@@ -37,7 +37,9 @@ def url2pathname(pathname): ...@@ -37,7 +37,9 @@ def url2pathname(pathname):
while i < len(components) and components[i] == '..': while i < len(components) and components[i] == '..':
components[i] = '' components[i] = ''
i = i + 1 i = i + 1
return ':' + string.join(components, ':') rv = ':' + string.join(components, ':')
# and finally unquote slashes and other funny characters
return urllib.unquote(rv)
def pathname2url(pathname): def pathname2url(pathname):
"convert mac pathname to /-delimited pathname" "convert mac pathname to /-delimited pathname"
...@@ -54,13 +56,17 @@ def pathname2url(pathname): ...@@ -54,13 +56,17 @@ def pathname2url(pathname):
if components[i] == '': if components[i] == '':
components[i] = '..' components[i] = '..'
# Truncate names longer than 31 bytes # Truncate names longer than 31 bytes
components = map(lambda x: x[:31], components) components = map(_pncomp2url, components)
if os.path.isabs(pathname): if os.path.isabs(pathname):
return '/' + string.join(components, '/') return '/' + string.join(components, '/')
else: else:
return string.join(components, '/') return string.join(components, '/')
def _pncomp2url(component):
component = urllib.quote(component[:31], safe='') # We want to quote slashes
return component
def test(): def test():
for url in ["index.html", for url in ["index.html",
"bar/index.html", "bar/index.html",
......
...@@ -109,7 +109,7 @@ _prefix = None ...@@ -109,7 +109,7 @@ _prefix = None
def choose_boundary(): def choose_boundary():
global _prefix global _prefix
import time import time
import rand import random
if _prefix == None: if _prefix == None:
import socket import socket
import os import os
...@@ -122,10 +122,9 @@ def choose_boundary(): ...@@ -122,10 +122,9 @@ def choose_boundary():
pid = `os.getpid()` pid = `os.getpid()`
except: except:
pid = '1' pid = '1'
seed = `rand.rand()`
_prefix = hostid + '.' + uid + '.' + pid _prefix = hostid + '.' + uid + '.' + pid
timestamp = `int(time.time())` timestamp = '%.3f' % time.time()
seed = `rand.rand()` seed = `random.randint(0, 32767)`
return _prefix + '.' + timestamp + '.' + seed return _prefix + '.' + timestamp + '.' + seed
......
"""Guess the MIME type of a file. """Guess the MIME type of a file.
This module defines one useful function: This module defines two useful functions:
guess_type(url) -- guess the MIME type and encoding of a URL. guess_type(url) -- guess the MIME type and encoding of a URL.
guess_extension(type) -- guess the extension for a given MIME type.
It also contains the following, for tuning the behavior: It also contains the following, for tuning the behavior:
Data: Data:
...@@ -27,6 +29,8 @@ import posixpath ...@@ -27,6 +29,8 @@ import posixpath
knownfiles = [ knownfiles = [
"/usr/local/etc/httpd/conf/mime.types", "/usr/local/etc/httpd/conf/mime.types",
"/usr/local/lib/netscape/mime.types", "/usr/local/lib/netscape/mime.types",
"/usr/local/etc/httpd/conf/mime.types", # Apache 1.2
"/usr/local/etc/mime.types", # Apache 1.3
] ]
inited = 0 inited = 0
...@@ -44,7 +48,7 @@ def guess_type(url): ...@@ -44,7 +48,7 @@ def guess_type(url):
The suffixes .tgz, .taz and .tz (case sensitive!) are all mapped The suffixes .tgz, .taz and .tz (case sensitive!) are all mapped
to ".tar.gz". (This is table-driven too, using the dictionary to ".tar.gz". (This is table-driven too, using the dictionary
suffixes_map). suffix_map).
""" """
if not inited: if not inited:
...@@ -64,6 +68,24 @@ def guess_type(url): ...@@ -64,6 +68,24 @@ def guess_type(url):
else: else:
return None, encoding return None, encoding
def guess_extension(type):
"""Guess the extension for a file based on its MIME type.
Return value is a string giving a filename extension, including the
leading dot ('.'). The extension is not guaranteed to have been
associated with any particular data stream, but would be mapped to the
MIME type `type' by guess_type(). If no extension can be guessed for
`type', None is returned.
"""
global inited
if not inited:
init()
type = string.lower(type)
for ext, stype in types_map.items():
if type == stype:
return ext
return None
def init(files=None): def init(files=None):
global inited global inited
for file in files or knownfiles: for file in files or knownfiles:
...@@ -184,6 +206,7 @@ types_map = { ...@@ -184,6 +206,7 @@ types_map = {
'.ustar': 'application/x-ustar', '.ustar': 'application/x-ustar',
'.wav': 'audio/x-wav', '.wav': 'audio/x-wav',
'.xbm': 'image/x-xbitmap', '.xbm': 'image/x-xbitmap',
'.xml': 'text/xml',
'.xpm': 'image/x-xpixmap', '.xpm': 'image/x-xpixmap',
'.xwd': 'image/x-xwindowdump', '.xwd': 'image/x-xwindowdump',
'.zip': 'application/zip', '.zip': 'application/zip',
......
...@@ -125,4 +125,4 @@ class MimeWriter: ...@@ -125,4 +125,4 @@ class MimeWriter:
if __name__ == '__main__': if __name__ == '__main__':
print "To test the MimeWriter module, run TestMimeWriter.py." import test.test_MimeWriter
...@@ -18,26 +18,30 @@ ...@@ -18,26 +18,30 @@
# #
# The latter sequence may be used recursively at (A). # The latter sequence may be used recursively at (A).
# It is also allowed to use multiple push()...pop() sequences. # It is also allowed to use multiple push()...pop() sequences.
# Note that if a nested multipart message is terminated by a separator #
# for an outer message, this is not reported, even though it is really # If seekable is given as 0, the class code will not do the bookeeping
# illegal input. # it normally attempts in order to make seeks relative to the beginning of the
# current file part. This may be useful when using MultiFile with a non-
# seekable stream object.
import sys import sys
import string import string
err = sys.stderr.write
Error = 'multifile.Error' Error = 'multifile.Error'
class MultiFile: class MultiFile:
# #
def __init__(self, fp): seekable = 0
#
def __init__(self, fp, seekable=1):
self.fp = fp self.fp = fp
self.stack = [] # Grows down self.stack = [] # Grows down
self.level = 0 self.level = 0
self.last = 0 self.last = 0
self.start = self.fp.tell() if seekable:
self.posstack = [] # Grows down self.seekable = 1
self.start = self.fp.tell()
self.posstack = [] # Grows down
# #
def tell(self): def tell(self):
if self.level > 0: if self.level > 0:
...@@ -62,36 +66,44 @@ class MultiFile: ...@@ -62,36 +66,44 @@ class MultiFile:
self.last = 0 self.last = 0
# #
def readline(self): def readline(self):
if self.level > 0: return '' if self.level > 0:
return ''
line = self.fp.readline() line = self.fp.readline()
# Real EOF?
if not line: if not line:
self.level = len(self.stack) self.level = len(self.stack)
self.last = (self.level > 0) self.last = (self.level > 0)
if self.last: if self.last:
err('*** Sudden EOF in MultiFile.readline()\n') raise Error, 'sudden EOF in MultiFile.readline()'
return '' return ''
if line[:2] <> '--': return line assert self.level == 0
n = len(line) # Fast check to see if this is just data
k = n if self.is_data(line):
while k > 0 and line[k-1] in string.whitespace: k = k-1 return line
mark = line[2:k] else:
if mark[-2:] == '--': mark1 = mark[:-2] # Ignore trailing whitespace on marker lines
else: mark1 = None k = len(line) - 1;
while line[k] in string.whitespace:
k = k - 1
marker = line[:k+1]
# No? OK, try to match a boundary.
# Return the line (unstripped) if we don't.
for i in range(len(self.stack)): for i in range(len(self.stack)):
sep = self.stack[i] sep = self.stack[i]
if sep == mark: if marker == self.section_divider(sep):
self.last = 0 self.last = 0
break break
elif mark1 <> None and sep == mark1: elif marker == self.end_marker(sep):
self.last = 1 self.last = 1
break break
else: else:
return line return line
# Get here after break out of loop # We only get here if we see a section divider or EOM line
self.lastpos = self.tell() - len(line) if self.seekable:
self.lastpos = self.tell() - len(line)
self.level = i+1 self.level = i+1
if self.level > 1: if self.level > 1:
err('*** Missing endmarker in MultiFile.readline()\n') raise Error,'Missing endmarker in MultiFile.readline()'
return '' return ''
# #
def readlines(self): def readlines(self):
...@@ -111,15 +123,17 @@ class MultiFile: ...@@ -111,15 +123,17 @@ class MultiFile:
return 0 return 0
self.level = 0 self.level = 0
self.last = 0 self.last = 0
self.start = self.fp.tell() if self.seekable:
self.start = self.fp.tell()
return 1 return 1
# #
def push(self, sep): def push(self, sep):
if self.level > 0: if self.level > 0:
raise Error, 'bad MultiFile.push() call' raise Error, 'bad MultiFile.push() call'
self.stack.insert(0, sep) self.stack.insert(0, sep)
self.posstack.insert(0, self.start) if self.seekable:
self.start = self.fp.tell() self.posstack.insert(0, self.start)
self.start = self.fp.tell()
# #
def pop(self): def pop(self):
if self.stack == []: if self.stack == []:
...@@ -130,8 +144,17 @@ class MultiFile: ...@@ -130,8 +144,17 @@ class MultiFile:
abslastpos = self.lastpos + self.start abslastpos = self.lastpos + self.start
self.level = max(0, self.level - 1) self.level = max(0, self.level - 1)
del self.stack[0] del self.stack[0]
self.start = self.posstack[0] if self.seekable:
del self.posstack[0] self.start = self.posstack[0]
if self.level > 0: del self.posstack[0]
self.lastpos = abslastpos - self.start if self.level > 0:
self.lastpos = abslastpos - self.start
#
def is_data(self, line):
return line[:2] <> '--'
#
def section_divider(self, str):
return "--" + str
# #
def end_marker(self, str):
return "--" + str + "--"
...@@ -128,6 +128,24 @@ def commonprefix(m): ...@@ -128,6 +128,24 @@ def commonprefix(m):
return prefix return prefix
# Get size, mtime, atime of files.
def getsize(filename):
"""Return the size of a file, reported by os.stat()."""
st = os.stat(filename)
return st[stat.ST_SIZE]
def getmtime(filename):
"""Return the last modification time of a file, reported by os.stat()."""
st = os.stat(filename)
return st[stat.ST_MTIME]
def getatime(filename):
"""Return the last access time of a file, reported by os.stat()."""
st = os.stat(filename)
return st[stat.ST_MTIME]
# Is a path a symbolic link? # Is a path a symbolic link?
# This will always return false on systems where os.lstat doesn't exist. # This will always return false on systems where os.lstat doesn't exist.
......
...@@ -65,4 +65,3 @@ def compile(file, cfile=None, dfile=None): ...@@ -65,4 +65,3 @@ def compile(file, cfile=None, dfile=None):
if os.name == 'mac': if os.name == 'mac':
import macfs import macfs
macfs.FSSpec(cfile).SetCreatorType('Pyth', 'PYC ') macfs.FSSpec(cfile).SetCreatorType('Pyth', 'PYC ')
macfs.FSSpec(file).SetCreatorType('Pyth', 'TEXT')
...@@ -19,28 +19,28 @@ class Queue: ...@@ -19,28 +19,28 @@ class Queue:
self._init(maxsize) self._init(maxsize)
self.mutex = thread.allocate_lock() self.mutex = thread.allocate_lock()
self.esema = thread.allocate_lock() self.esema = thread.allocate_lock()
self.esema.acquire_lock() self.esema.acquire()
self.fsema = thread.allocate_lock() self.fsema = thread.allocate_lock()
def qsize(self): def qsize(self):
"""Returns the approximate size of the queue (not reliable!).""" """Returns the approximate size of the queue (not reliable!)."""
self.mutex.acquire_lock() self.mutex.acquire()
n = self._qsize() n = self._qsize()
self.mutex.release_lock() self.mutex.release()
return n return n
def empty(self): def empty(self):
"""Returns 1 if the queue is empty, 0 otherwise (not reliable!).""" """Returns 1 if the queue is empty, 0 otherwise (not reliable!)."""
self.mutex.acquire_lock() self.mutex.acquire()
n = self._empty() n = self._empty()
self.mutex.release_lock() self.mutex.release()
return n return n
def full(self): def full(self):
"""Returns 1 if the queue is full, 0 otherwise (not reliable!).""" """Returns 1 if the queue is full, 0 otherwise (not reliable!)."""
self.mutex.acquire_lock() self.mutex.acquire()
n = self._full() n = self._full()
self.mutex.release_lock() self.mutex.release()
return n return n
def put(self, item): def put(self, item):
...@@ -48,30 +48,30 @@ class Queue: ...@@ -48,30 +48,30 @@ class Queue:
If the queue is full, block until a free slot is avaiable. If the queue is full, block until a free slot is avaiable.
""" """
self.fsema.acquire_lock() self.fsema.acquire()
self.mutex.acquire_lock() self.mutex.acquire()
was_empty = self._empty() was_empty = self._empty()
self._put(item) self._put(item)
if was_empty: if was_empty:
self.esema.release_lock() self.esema.release()
if not self._full(): if not self._full():
self.fsema.release_lock() self.fsema.release()
self.mutex.release_lock() self.mutex.release()
def get(self): def get(self):
"""Gets and returns an item from the queue. """Gets and returns an item from the queue.
This method blocks if necessary until an item is available. This method blocks if necessary until an item is available.
""" """
self.esema.acquire_lock() self.esema.acquire()
self.mutex.acquire_lock() self.mutex.acquire()
was_full = self._full() was_full = self._full()
item = self._get() item = self._get()
if was_full: if was_full:
self.fsema.release_lock() self.fsema.release()
if not self._empty(): if not self._empty():
self.esema.release_lock() self.esema.release()
self.mutex.release_lock() self.mutex.release()
return item return item
# Get an item from the queue if one is immediately available, # Get an item from the queue if one is immediately available,
...@@ -83,27 +83,27 @@ class Queue: ...@@ -83,27 +83,27 @@ class Queue:
this raises the Empty exception if the queue is empty or this raises the Empty exception if the queue is empty or
temporarily unavailable. temporarily unavailable.
""" """
locked = self.esema.acquire_lock(0) locked = self.esema.acquire(0)
self.mutex.acquire_lock() self.mutex.acquire()
if self._empty(): if self._empty():
# The queue is empty -- we can't have esema # The queue is empty -- we can't have esema
self.mutex.release_lock() self.mutex.release()
raise Empty raise Empty
if not locked: if not locked:
locked = self.esema.acquire_lock(0) locked = self.esema.acquire(0)
if not locked: if not locked:
# Somebody else has esema # Somebody else has esema
# but we have mutex -- # but we have mutex --
# go out of their way # go out of their way
self.mutex.release_lock() self.mutex.release()
raise Empty raise Empty
was_full = self._full() was_full = self._full()
item = self._get() item = self._get()
if was_full: if was_full:
self.fsema.release_lock() self.fsema.release()
if not self._empty(): if not self._empty():
self.esema.release_lock() self.esema.release()
self.mutex.release_lock() self.mutex.release()
return item return item
# XXX Need to define put_nowait() as well. # XXX Need to define put_nowait() as well.
......
...@@ -58,7 +58,10 @@ class Completer: ...@@ -58,7 +58,10 @@ class Completer:
self.matches = self.attr_matches(text) self.matches = self.attr_matches(text)
else: else:
self.matches = self.global_matches(text) self.matches = self.global_matches(text)
return self.matches[state] try:
return self.matches[state]
except IndexError:
return None
def global_matches(self, text): def global_matches(self, text):
"""Compute matches when text is a simple name. """Compute matches when text is a simple name.
......
...@@ -265,7 +265,12 @@ class UDPServer(TCPServer): ...@@ -265,7 +265,12 @@ class UDPServer(TCPServer):
max_packet_size = 8192 max_packet_size = 8192
def get_request(self): def get_request(self):
return self.socket.recvfrom(self.max_packet_size) data, client_addr = self.socket.recvfrom(self.max_packet_size)
return (data, self.socket), client_addr
def server_activate(self):
# No need to call listen() for UDP.
pass
if hasattr(socket, 'AF_UNIX'): if hasattr(socket, 'AF_UNIX'):
...@@ -411,4 +416,4 @@ class DatagramRequestHandler(BaseRequestHandler): ...@@ -411,4 +416,4 @@ class DatagramRequestHandler(BaseRequestHandler):
self.wfile = StringIO.StringIO(self.packet) self.wfile = StringIO.StringIO(self.packet)
def finish(self): def finish(self):
self.socket.send(self.wfile.getvalue()) self.socket.sendto(self.wfile.getvalue(), self.client_address)
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
Roger E. Masse Roger E. Masse
""" """
import array import array
from test_support import verbose, TESTFN, unlink from test_support import verbose, TESTFN, unlink, TestFailed
def main(): def main():
...@@ -54,6 +54,33 @@ def testtype(type, example): ...@@ -54,6 +54,33 @@ def testtype(type, example):
print 'array of %s converted to a string: ' \ print 'array of %s converted to a string: ' \
% a.typecode, `a.tostring()` % a.typecode, `a.tostring()`
if type == 'c':
a = array.array(type, "abcde")
a[:-1] = a
if a != array.array(type, "abcdee"):
raise TestFailed, "array(%s) self-slice-assign (head)" % `type`
a = array.array(type, "abcde")
a[1:] = a
if a != array.array(type, "aabcde"):
raise TestFailed, "array(%s) self-slice-assign (tail)" % `type`
a = array.array(type, "abcde")
a[1:-1] = a
if a != array.array(type, "aabcdee"):
raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type`
else:
a = array.array(type, [1, 2, 3, 4, 5])
a[:-1] = a
if a != array.array(type, [1, 2, 3, 4, 5, 5]):
raise TestFailed, "array(%s) self-slice-assign (head)" % `type`
a = array.array(type, [1, 2, 3, 4, 5])
a[1:] = a
if a != array.array(type, [1, 1, 2, 3, 4, 5]):
raise TestFailed, "array(%s) self-slice-assign (tail)" % `type`
a = array.array(type, [1, 2, 3, 4, 5])
a[1:-1] = a
if a != array.array(type, [1, 1, 2, 3, 4, 5, 5]):
raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type`
main() main()
...@@ -16,7 +16,7 @@ rv = fcntl.fcntl(f.fileno(), FCNTL.F_SETFL, os.O_NONBLOCK) ...@@ -16,7 +16,7 @@ rv = fcntl.fcntl(f.fileno(), FCNTL.F_SETFL, os.O_NONBLOCK)
if verbose: if verbose:
print 'Status from fnctl with O_NONBLOCK: ', rv print 'Status from fnctl with O_NONBLOCK: ', rv
if sys.platform in ('netbsd1', 'freebsd2', 'freebsd3'): if sys.platform in ('netbsd1', 'freebsd2', 'freebsd3', 'bsdos2', 'bsdos3'):
lockdata = struct.pack('lxxxxlxxxxlhh', 0, 0, 0, FCNTL.F_WRLCK, 0) lockdata = struct.pack('lxxxxlxxxxlhh', 0, 0, 0, FCNTL.F_WRLCK, 0)
elif sys.platform in ['aix3', 'aix4']: elif sys.platform in ['aix3', 'aix4']:
lockdata = struct.pack('hhlllii', FCNTL.F_WRLCK, 0, 0, 0, 0, 0, 0) lockdata = struct.pack('hhlllii', FCNTL.F_WRLCK, 0, 0, 0, 0, 0, 0)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
Roger E. Masse Roger E. Masse
""" """
from test_support import verbose, unlink from test_support import verbose, unlink, findfile
import imgfile, uu, os import imgfile, uu, os
...@@ -23,14 +23,6 @@ def main(): ...@@ -23,14 +23,6 @@ def main():
unlink('test.rgb') unlink('test.rgb')
unlink('greytest.rgb') unlink('greytest.rgb')
def findfile(file):
if os.path.isabs(file): return file
import sys
for dn in sys.path:
fn = os.path.join(dn, file)
if os.path.exists(fn): return fn
return file
def testimage(name): def testimage(name):
"""Run through the imgfile's battery of possible methods """Run through the imgfile's battery of possible methods
on the image passed in name. on the image passed in name.
......
...@@ -2,25 +2,12 @@ ...@@ -2,25 +2,12 @@
import rgbimg, os, uu import rgbimg, os, uu
from test_support import verbose, unlink from test_support import verbose, unlink, findfile
error = 'test_rgbimg.error' error = 'test_rgbimg.error'
print 'RGBimg test suite:' print 'RGBimg test suite:'
def findfile(file):
if os.path.isabs(file): return file
import sys
path = sys.path
try:
path = [os.path.dirname(__file__)] + path
except NameError:
pass
for dn in path:
fn = os.path.join(dn, file)
if os.path.exists(fn): return fn
return file
def testimg(rgb_file, raw_file): def testimg(rgb_file, raw_file):
rgb_file = findfile(rgb_file) rgb_file = findfile(rgb_file)
raw_file = findfile(raw_file) raw_file = findfile(raw_file)
......
from test_support import verbose, TestFailed from test_support import verbose, findfile, TestFailed
import sunaudiodev import sunaudiodev
import os import os
def findfile(file):
if os.path.isabs(file): return file
import sys
path = sys.path
try:
path = [os.path.dirname(__file__)] + path
except NameError:
pass
for dn in path:
fn = os.path.join(dn, file)
if os.path.exists(fn): return fn
return file
def play_sound_file(path): def play_sound_file(path):
fp = open(path, 'r') fp = open(path, 'r')
data = fp.read() data = fp.read()
......
...@@ -41,3 +41,15 @@ def fcmp(x, y): # fuzzy comparison function ...@@ -41,3 +41,15 @@ def fcmp(x, y): # fuzzy comparison function
TESTFN = '@test' # Filename used for testing TESTFN = '@test' # Filename used for testing
from os import unlink from os import unlink
def findfile(file, here=__file__):
import os
if os.path.isabs(file):
return file
import sys
path = sys.path
path = [os.path.dirname(here)] + path
for dn in path:
fn = os.path.join(dn, file)
if os.path.exists(fn): return fn
return file
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
# Create a bunch of threads, let each do some work, wait until all are done # Create a bunch of threads, let each do some work, wait until all are done
from test_support import verbose from test_support import verbose
import whrandom import random
import thread import thread
import time import time
mutex = thread.allocate_lock() mutex = thread.allocate_lock()
whmutex = thread.allocate_lock() # for calls to whrandom rmutex = thread.allocate_lock() # for calls to random
running = 0 running = 0
done = thread.allocate_lock() done = thread.allocate_lock()
done.acquire() done.acquire()
...@@ -17,9 +17,9 @@ numtasks = 10 ...@@ -17,9 +17,9 @@ numtasks = 10
def task(ident): def task(ident):
global running global running
whmutex.acquire() rmutex.acquire()
delay = whrandom.random() * numtasks delay = random.random() * numtasks
whmutex.release() rmutex.release()
if verbose: if verbose:
print 'task', ident, 'will run for', round(delay, 1), 'sec' print 'task', ident, 'will run for', round(delay, 1), 'sec'
time.sleep(delay) time.sleep(delay)
...@@ -85,9 +85,9 @@ def task2(ident): ...@@ -85,9 +85,9 @@ def task2(ident):
# of the current one # of the current one
delay = 0.001 delay = 0.001
else: else:
whmutex.acquire() rmutex.acquire()
delay = whrandom.random() * numtasks delay = random.random() * numtasks
whmutex.release() rmutex.release()
if verbose: if verbose:
print 'task', ident, 'will run for', round(delay, 1), 'sec' print 'task', ident, 'will run for', round(delay, 1), 'sec'
time.sleep(delay) time.sleep(delay)
......
from test_support import verbose from test_support import verbose, findfile
import tokenize, os, sys import tokenize, os, sys
def findfile(file):
if os.path.isabs(file): return file
path = sys.path
try:
path = [os.path.dirname(__file__)] + path
except NameError:
pass
for dn in path:
fn = os.path.join(dn, file)
if os.path.exists(fn): return fn
return file
if verbose: if verbose:
print 'starting...' print 'starting...'
file = open(findfile('tokenize_tests.py')) file = open(findfile('tokenize_tests.py'))
......
...@@ -78,6 +78,18 @@ if (-12L) + 24L <> 12L: raise TestFailed, 'long op' ...@@ -78,6 +78,18 @@ if (-12L) + 24L <> 12L: raise TestFailed, 'long op'
if (-12L) + (-24L) <> -36L: raise TestFailed, 'long op' if (-12L) + (-24L) <> -36L: raise TestFailed, 'long op'
if not 12L < 24L: raise TestFailed, 'long op' if not 12L < 24L: raise TestFailed, 'long op'
if not -24L < -12L: raise TestFailed, 'long op' if not -24L < -12L: raise TestFailed, 'long op'
x = sys.maxint
if int(long(x)) != x: raise TestFailed, 'long op'
try: int(long(x)+1L)
except OverflowError: pass
else:raise TestFailed, 'long op'
x = -x
if int(long(x)) != x: raise TestFailed, 'long op'
x = x-1
if int(long(x)) != x: raise TestFailed, 'long op'
try: int(long(x)-1L)
except OverflowError: pass
else:raise TestFailed, 'long op'
print '6.4.3 Floating point numbers' print '6.4.3 Floating point numbers'
if 12.0 + 24.0 <> 36.0: raise TestFailed, 'float op' if 12.0 + 24.0 <> 36.0: raise TestFailed, 'float op'
if 12.0 + (-24.0) <> -12.0: raise TestFailed, 'float op' if 12.0 + (-24.0) <> -12.0: raise TestFailed, 'float op'
...@@ -122,6 +134,19 @@ if 0*[1,2,3] <> []: raise TestFailed, 'list repetition 0*' ...@@ -122,6 +134,19 @@ if 0*[1,2,3] <> []: raise TestFailed, 'list repetition 0*'
if min([1,2]) <> 1 or max([1,2]) <> 2: raise TestFailed, 'min/max list' if min([1,2]) <> 1 or max([1,2]) <> 2: raise TestFailed, 'min/max list'
if 0 in [0,1,2] and 1 in [0,1,2] and 2 in [0,1,2] and 3 not in [0,1,2]: pass if 0 in [0,1,2] and 1 in [0,1,2] and 2 in [0,1,2] and 3 not in [0,1,2]: pass
else: raise TestFailed, 'in/not in list' else: raise TestFailed, 'in/not in list'
a = [1, 2, 3, 4, 5]
a[:-1] = a
if a != [1, 2, 3, 4, 5, 5]:
raise TestFailed, "list self-slice-assign (head)"
a = [1, 2, 3, 4, 5]
a[1:] = a
if a != [1, 1, 2, 3, 4, 5]:
raise TestFailed, "list self-slice-assign (tail)"
a = [1, 2, 3, 4, 5]
a[1:-1] = a
if a != [1, 1, 2, 3, 4, 5, 5]:
raise TestFailed, "list self-slice-assign (center)"
print '6.5.3a Additional list operations' print '6.5.3a Additional list operations'
a = [0,1,2,3,4] a = [0,1,2,3,4]
......
...@@ -11,9 +11,9 @@ except ImportError: ...@@ -11,9 +11,9 @@ except ImportError:
buf = file.read() * 8 buf = file.read() * 8
file.close() file.close()
# test the chucksums # test the chucksums (hex so the test doesn't break on 64-bit machines)
print zlib.crc32('penguin'), zlib.crc32('penguin', 1) print hex(zlib.crc32('penguin')), hex(zlib.crc32('penguin', 1))
print zlib.adler32('penguin'), zlib.adler32('penguin', 1) print hex(zlib.adler32('penguin')), hex(zlib.adler32('penguin', 1))
# make sure we generate some expected errors # make sure we generate some expected errors
try: try:
......
...@@ -43,6 +43,7 @@ class UserList: ...@@ -43,6 +43,7 @@ class UserList:
__rmul__ = __mul__ __rmul__ = __mul__
def append(self, item): self.data.append(item) def append(self, item): self.data.append(item)
def insert(self, i, item): self.data.insert(i, item) def insert(self, i, item): self.data.insert(i, item)
def pop(self, i=-1): return self.data.pop(i)
def remove(self, item): self.data.remove(item) def remove(self, item): self.data.remove(item)
def count(self, item): return self.data.count(item) def count(self, item): return self.data.count(item)
def index(self, item): return self.data.index(item) def index(self, item): return self.data.index(item)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment