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

Guess... :-)

parent 3d20986d
"""Configuration file parser.
A setup file consists of sections, lead by a "[section]" header,
and followed by "name: value" entries, with continuations and such in
the style of rfc822.
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:
something: %(dir)s/whatever
would resolve the "%(dir)s" to the value of dir. All reference
expansions are done late, on demand.
Intrinsic defaults can be specified by passing them into the
ConfigParser constructor as a dictionary.
class:
ConfigParser -- responsible for for parsing a list of
configuration files, and managing the parsed database.
methods:
__init__(defaults=None) -- create the parser and specify a
dictionary of intrinsic defaults. The
keys must be strings, the values must
be appropriate for %()s string
interpolation. Note that `name' is
always an intrinsic default; it's value
is the section's name.
sections() -- return all the configuration section names, sans DEFAULT
options(section) -- return list of configuration options for the named
section
read(*filenames) -- read and parse the list of named configuration files
get(section, option, raw=0) -- return a string value for the named
option. All % interpolations are
expanded in the return values, based on
the defaults passed into the constructor
and the DEFAULT section.
getint(section, options) -- like get(), but convert value to an integer
getfloat(section, options) -- like get(), but convert value to a float
getboolean(section, options) -- like get(), but convert value to
a boolean (currently defined as 0
or 1, only)
"""
import sys
import string
import regex
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"
# exception classes
class Error:
def __init__(self, msg=''):
self.__msg = msg
def __repr__(self):
return self.__msg
class NoSectionError(Error):
def __init__(self, section):
Error.__init__(self, 'No section: %s' % section)
self.section = section
class DuplicateSectionError(Error):
def __init__(self, section):
Error.__init__(self, "Section %s already exists" % section)
self.section = section
class NoOptionError(Error):
def __init__(self, option, section):
Error.__init__(self, "No option `%s' in section: %s" %
(option, section))
self.option = option
self.section = section
class InterpolationError(Error):
def __init__(self, reference, option, section):
Error.__init__(self,
"Bad value substitution: sect `%s', opt `%s', ref `%s'"
% (section, option, reference))
self.reference = reference
self.option = option
self.section = section
class ConfigParser:
def __init__(self, defaults=None):
self.__sections = {}
if defaults is None:
self.__defaults = {}
else:
self.__defaults = defaults
def defaults(self):
return self.__defaults
def sections(self):
"""Return a list of section names, excluding [DEFAULT]"""
# self.__sections will never have [DEFAULT] in it
return self.__sections.keys()
def add_section(self, section):
"""Create a new section in the configuration.
Raise DuplicateSectionError if a section by the specified name
already exists.
"""
if self.__sections.has_key(section):
raise DuplicateSectionError(section)
self.__sections[section] = {}
def has_section(self, section):
"""Indicate whether the named section is present in the configuration.
The DEFAULT section is not acknowledged.
"""
return self.__sections.has_key(section)
def options(self, section):
try:
opts = self.__sections[section].copy()
except KeyError:
raise NoSectionError(section)
opts.update(self.__defaults)
return opts.keys()
def read(self, filenames):
"""Read and parse a list of filenames."""
if type(filenames) is type(''):
filenames = [filenames]
for file in filenames:
try:
fp = open(file, 'r')
self.__read(fp)
except IOError:
pass
def get(self, section, option, raw=0):
"""Get an option value for a given section.
All % interpolations are expanded in the return values, based
on the defaults passed into the constructor.
The section DEFAULT is special.
"""
try:
d = self.__sections[section].copy()
except KeyError:
if section == DEFAULTSECT:
d = {}
else:
raise NoSectionError(section)
d.update(self.__defaults)
option = string.lower(option)
try:
rawval = d[option]
except KeyError:
raise NoOptionError(option, section)
# do the string interpolation
if raw:
return rawval
try:
return rawval % d
except KeyError, key:
raise InterpolationError(key, option, section)
def __get(self, section, conv, option):
return conv(self.get(section, option))
def getint(self, section, option):
return self.__get(section, string.atoi, option)
def getfloat(self, section, option):
return self.__get(section, string.atof, option)
def getboolean(self, section, option):
v = self.get(section, option)
val = string.atoi(v)
if val not in (0, 1):
raise ValueError, 'Not a boolean: %s' % v
return val
def __read(self, fp):
"""Parse a sectioned setup file.
The sections in setup file contains a title line at the top,
indicated by a name in square brackets (`[]'), plus key/value
options lines, indicated by `name: value' format lines.
Continuation are represented by an embedded newline then
leading whitespace. Blank lines, lines beginning with a '#',
and just about everything else is ignored.
"""
cursect = None # None, or a dictionary
optname = None
lineno = 0
while 1:
line = fp.readline()
if not line:
break
lineno = lineno + 1
# comment or blank line?
if string.strip(line) == '' or line[0] in '#;':
continue
if string.lower(string.split(line)[0]) == 'rem' \
and line[0] == "r": # no leading whitespace
continue
# continuation line?
if line[0] in ' \t' and cursect <> None and optname:
value = string.strip(line)
if value:
cursect = cursect[optname] + '\n ' + value
# a section 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:
print 'Error in %s at %d: %s', (fp.name, lineno, `line`)
...@@ -177,7 +177,7 @@ class _posixfile_: ...@@ -177,7 +177,7 @@ class _posixfile_:
# Hack by davem@magnet.com to get locking to go on freebsd; # Hack by davem@magnet.com to get locking to go on freebsd;
# additions for AIX by Vladimir.Marangozov@imag.fr # additions for AIX by Vladimir.Marangozov@imag.fr
import sys, os import sys, os
if sys.platform == 'freebsd2': if sys.platform in ('netbsd1', 'freebsd2', 'freebsd3'):
flock = struct.pack('lxxxxlxxxxlhh', \ flock = struct.pack('lxxxxlxxxxlhh', \
l_start, l_len, os.getpid(), l_type, l_whence) l_start, l_len, os.getpid(), l_type, l_whence)
elif sys.platform in ['aix3', 'aix4']: elif sys.platform in ['aix3', 'aix4']:
...@@ -190,7 +190,7 @@ class _posixfile_: ...@@ -190,7 +190,7 @@ class _posixfile_:
flock = fcntl.fcntl(self._file_.fileno(), cmd, flock) flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
if '?' in how: if '?' in how:
if sys.platform == 'freebsd2': if sys.platform in ('netbsd1', 'freebsd2', 'freebsd3'):
l_start, l_len, l_pid, l_type, l_whence = \ l_start, l_len, l_pid, l_type, l_whence = \
struct.unpack('lxxxxlxxxxlhh', flock) struct.unpack('lxxxxlxxxxlhh', flock)
elif sys.platform in ['aix3', 'aix4']: elif sys.platform in ['aix3', 'aix4']:
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
# on other systems (e.g. Mac, Windows), os.path provides the same # on other systems (e.g. Mac, Windows), os.path provides the same
# operations in a manner specific to that platform, and is an alias # operations in a manner specific to that platform, and is an alias
# to another module (e.g. macpath, ntpath). # to another module (e.g. macpath, ntpath).
"""Common pathname manipulations, Posix version.
Instead of importing this module
directly, import os and refer to this module as os.path.
"""
import os import os
import stat import stat
...@@ -16,14 +20,16 @@ import stat ...@@ -16,14 +20,16 @@ import stat
# (another function should be defined to do that). # (another function should be defined to do that).
def normcase(s): def normcase(s):
return s """Normalize case of pathname. Has no effect under Posix"""
return s
# Return wheter a path is absolute. # Return wheter a path is absolute.
# Trivial in Posix, harder on the Mac or MS-DOS. # Trivial in Posix, harder on the Mac or MS-DOS.
def isabs(s): def isabs(s):
return s[:1] == '/' """Test whether a path is absolute"""
return s[:1] == '/'
# Join pathnames. # Join pathnames.
...@@ -31,15 +37,16 @@ def isabs(s): ...@@ -31,15 +37,16 @@ def isabs(s):
# Insert a '/' unless the first part is empty or already ends in '/'. # Insert a '/' unless the first part is empty or already ends in '/'.
def join(a, *p): def join(a, *p):
path = a """Join two or more pathname components, inserting '/' as needed"""
for b in p: path = a
if b[:1] == '/': for b in p:
path = b if b[:1] == '/':
elif path == '' or path[-1:] == '/': path = b
path = path + b elif path == '' or path[-1:] == '/':
else: path = path + b
path = path + '/' + b else:
return path path = path + '/' + b
return path
# Split a path in head (everything up to the last '/') and tail (the # Split a path in head (everything up to the last '/') and tail (the
...@@ -48,13 +55,15 @@ def join(a, *p): ...@@ -48,13 +55,15 @@ def join(a, *p):
# Trailing '/'es are stripped from head unless it is the root. # Trailing '/'es are stripped from head unless it is the root.
def split(p): def split(p):
import string """Split a pathname. Returns tuple "(head, tail)" where "tail" is
i = string.rfind(p, '/') + 1 everything after the final slash. Either part may be empty"""
head, tail = p[:i], p[i:] import string
if head and head <> '/'*len(head): i = string.rfind(p, '/') + 1
while head[-1] == '/': head, tail = p[:i], p[i:]
head = head[:-1] if head and head <> '/'*len(head):
return head, tail while head[-1] == '/':
head = head[:-1]
return head, tail
# Split a path in root and extension. # Split a path in root and extension.
...@@ -63,75 +72,84 @@ def split(p): ...@@ -63,75 +72,84 @@ def split(p):
# It is always true that root + ext == p. # It is always true that root + ext == p.
def splitext(p): def splitext(p):
root, ext = '', '' """Split the extension from a pathname. Extension is everything from the
for c in p: last dot to the end. Returns "(root, ext)", either part may be empty"""
if c == '/': root, ext = '', ''
root, ext = root + ext + c, '' for c in p:
elif c == '.': if c == '/':
if ext: root, ext = root + ext + c, ''
root, ext = root + ext, c elif c == '.':
else: if ext:
ext = c root, ext = root + ext, c
elif ext: else:
ext = ext + c ext = c
else: elif ext:
root = root + c ext = ext + c
return root, ext else:
root = root + c
return root, ext
# Split a pathname into a drive specification and the rest of the # Split a pathname into a drive specification and the rest of the
# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty. # path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
def splitdrive(p): def splitdrive(p):
return '', p """Split a pathname into drive and path. On Posix, drive is always
empty"""
return '', p
# Return the tail (basename) part of a path. # Return the tail (basename) part of a path.
def basename(p): def basename(p):
return split(p)[1] """Returns the final component of a pathname"""
return split(p)[1]
# Return the head (dirname) part of a path. # Return the head (dirname) part of a path.
def dirname(p): def dirname(p):
return split(p)[0] """Returns the directory component of a pathname"""
return split(p)[0]
# Return the longest prefix of all list elements. # Return the longest prefix of all list elements.
def commonprefix(m): def commonprefix(m):
if not m: return '' "Given a list of pathnames, returns the longest common leading component"
prefix = m[0] if not m: return ''
for item in m: prefix = m[0]
for i in range(len(prefix)): for item in m:
if prefix[:i+1] <> item[:i+1]: for i in range(len(prefix)):
prefix = prefix[:i] if prefix[:i+1] <> item[:i+1]:
if i == 0: return '' prefix = prefix[:i]
break if i == 0: return ''
return prefix break
return prefix
# 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.
def islink(path): def islink(path):
try: """Test whether a path is a symbolic link"""
st = os.lstat(path) try:
except (os.error, AttributeError): st = os.lstat(path)
return 0 except (os.error, AttributeError):
return stat.S_ISLNK(st[stat.ST_MODE]) return 0
return stat.S_ISLNK(st[stat.ST_MODE])
# Does a path exist? # Does a path exist?
# This is false for dangling symbolic links. # This is false for dangling symbolic links.
def exists(path): def exists(path):
try: """Test whether a path exists. Returns false for broken symbolic links"""
st = os.stat(path) try:
except os.error: st = os.stat(path)
return 0 except os.error:
return 1 return 0
return 1
# Is a path a directory? # Is a path a directory?
...@@ -139,11 +157,12 @@ def exists(path): ...@@ -139,11 +157,12 @@ def exists(path):
# for the same path. # for the same path.
def isdir(path): def isdir(path):
try: """Test whether a path is a directory"""
st = os.stat(path) try:
except os.error: st = os.stat(path)
return 0 except os.error:
return stat.S_ISDIR(st[stat.ST_MODE]) return 0
return stat.S_ISDIR(st[stat.ST_MODE])
# Is a path a regular file? # Is a path a regular file?
...@@ -151,78 +170,87 @@ def isdir(path): ...@@ -151,78 +170,87 @@ def isdir(path):
# for the same path. # for the same path.
def isfile(path): def isfile(path):
try: """Test whether a path is a regular file"""
st = os.stat(path) try:
except os.error: st = os.stat(path)
return 0 except os.error:
return stat.S_ISREG(st[stat.ST_MODE]) return 0
return stat.S_ISREG(st[stat.ST_MODE])
# Are two filenames really pointing to the same file? # Are two filenames really pointing to the same file?
def samefile(f1, f2): def samefile(f1, f2):
s1 = os.stat(f1) """Test whether two pathnames reference the same actual file"""
s2 = os.stat(f2) s1 = os.stat(f1)
return samestat(s1, s2) s2 = os.stat(f2)
return samestat(s1, s2)
# Are two open files really referencing the same file? # Are two open files really referencing the same file?
# (Not necessarily the same file descriptor!) # (Not necessarily the same file descriptor!)
def sameopenfile(fp1, fp2): def sameopenfile(fp1, fp2):
s1 = os.fstat(fp1) """Test whether two open file objects reference the same file"""
s2 = os.fstat(fp2) s1 = os.fstat(fp1)
return samestat(s1, s2) s2 = os.fstat(fp2)
return samestat(s1, s2)
# Are two stat buffers (obtained from stat, fstat or lstat) # Are two stat buffers (obtained from stat, fstat or lstat)
# describing the same file? # describing the same file?
def samestat(s1, s2): def samestat(s1, s2):
return s1[stat.ST_INO] == s2[stat.ST_INO] and \ """Test whether two stat buffers reference the same file"""
s1[stat.ST_DEV] == s2[stat.ST_DEV] return s1[stat.ST_INO] == s2[stat.ST_INO] and \
s1[stat.ST_DEV] == s2[stat.ST_DEV]
# Is a path a mount point? # Is a path a mount point?
# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?) # (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
def ismount(path): def ismount(path):
try: """Test whether a path is a mount point"""
s1 = os.stat(path) try:
s2 = os.stat(join(path, '..')) s1 = os.stat(path)
except os.error: s2 = os.stat(join(path, '..'))
return 0 # It doesn't exist -- so not a mount point :-) except os.error:
dev1 = s1[stat.ST_DEV] return 0 # It doesn't exist -- so not a mount point :-)
dev2 = s2[stat.ST_DEV] dev1 = s1[stat.ST_DEV]
if dev1 != dev2: dev2 = s2[stat.ST_DEV]
return 1 # path/.. on a different device as path if dev1 != dev2:
ino1 = s1[stat.ST_INO] return 1 # path/.. on a different device as path
ino2 = s2[stat.ST_INO] ino1 = s1[stat.ST_INO]
if ino1 == ino2: ino2 = s2[stat.ST_INO]
return 1 # path/.. is the same i-node as path if ino1 == ino2:
return 0 return 1 # path/.. is the same i-node as path
return 0
# Directory tree walk. # Directory tree walk.
# For each directory under top (including top itself, but excluding # For each directory under top (including top itself, but excluding
# '.' and '..'), func(arg, dirname, filenames) is called, where # '.' and '..'), func(arg, dirname, filenames) is called, where
# dirname is the name of the directory and filenames is the list # dirname is the name of the directory and filenames is the list
# files files (and subdirectories etc.) in the directory. # of files (and subdirectories etc.) in the directory.
# The func may modify the filenames list, to implement a filter, # The func may modify the filenames list, to implement a filter,
# or to impose a different order of visiting. # or to impose a different order of visiting.
def walk(top, func, arg): def walk(top, func, arg):
try: """walk(top,func,args) calls func(arg, d, files) for each directory "d"
names = os.listdir(top) in the tree rooted at "top" (including "top" itself). "files" is a list
except os.error: of all the files and subdirs in directory "d".
return """
func(arg, top, names) try:
exceptions = ('.', '..') names = os.listdir(top)
for name in names: except os.error:
if name not in exceptions: return
name = join(top, name) func(arg, top, names)
if isdir(name) and not islink(name): exceptions = ('.', '..')
walk(name, func, arg) for name in names:
if name not in exceptions:
name = join(top, name)
if isdir(name) and not islink(name):
walk(name, func, arg)
# Expand paths beginning with '~' or '~user'. # Expand paths beginning with '~' or '~user'.
...@@ -235,24 +263,26 @@ def walk(top, func, arg): ...@@ -235,24 +263,26 @@ def walk(top, func, arg):
# variable expansion.) # variable expansion.)
def expanduser(path): def expanduser(path):
if path[:1] <> '~': """Expand ~ and ~user constructions. If user or $HOME is unknown,
return path do nothing"""
i, n = 1, len(path) if path[:1] <> '~':
while i < n and path[i] <> '/': return path
i = i+1 i, n = 1, len(path)
if i == 1: while i < n and path[i] <> '/':
if not os.environ.has_key('HOME'): i = i+1
return path if i == 1:
userhome = os.environ['HOME'] if not os.environ.has_key('HOME'):
else: return path
import pwd userhome = os.environ['HOME']
try: else:
pwent = pwd.getpwnam(path[1:i]) import pwd
except KeyError: try:
return path pwent = pwd.getpwnam(path[1:i])
userhome = pwent[5] except KeyError:
if userhome[-1:] == '/': i = i+1 return path
return userhome + path[i:] userhome = pwent[5]
if userhome[-1:] == '/': i = i+1
return userhome + path[i:]
# Expand paths containing shell variable substitutions. # Expand paths containing shell variable substitutions.
...@@ -262,29 +292,31 @@ def expanduser(path): ...@@ -262,29 +292,31 @@ def expanduser(path):
_varprog = None _varprog = None
def expandvars(path): def expandvars(path):
global _varprog """Expand shell variables of form $var and ${var}. Unknown variables
if '$' not in path: are left unchanged"""
return path global _varprog
if not _varprog: if '$' not in path:
import re return path
_varprog = re.compile(r'\$(\w+|\{[^}]*\})') if not _varprog:
i = 0 import re
while 1: _varprog = re.compile(r'\$(\w+|\{[^}]*\})')
m = _varprog.search(path, i) i = 0
if not m: while 1:
break m = _varprog.search(path, i)
i, j = m.span(0) if not m:
name = m.group(1) break
if name[:1] == '{' and name[-1:] == '}': i, j = m.span(0)
name = name[1:-1] name = m.group(1)
if os.environ.has_key(name): if name[:1] == '{' and name[-1:] == '}':
tail = path[j:] name = name[1:-1]
path = path[:i] + os.environ[name] if os.environ.has_key(name):
i = len(path) tail = path[j:]
path = path + tail path = path[:i] + os.environ[name]
else: i = len(path)
i = j path = path + tail
return path else:
i = j
return path
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
...@@ -292,26 +324,26 @@ def expandvars(path): ...@@ -292,26 +324,26 @@ def expandvars(path):
# if it contains symbolic links! # if it contains symbolic links!
def normpath(path): def normpath(path):
import string """Normalize path, eliminating double slashes, etc."""
# Treat initial slashes specially import string
slashes = '' # Treat initial slashes specially
while path[:1] == '/': slashes = ''
slashes = slashes + '/' while path[:1] == '/':
path = path[1:] slashes = slashes + '/'
comps = string.splitfields(path, '/') path = path[1:]
i = 0 comps = string.splitfields(path, '/')
while i < len(comps): i = 0
if comps[i] == '.': while i < len(comps):
del comps[i] if comps[i] == '.':
elif comps[i] == '..' and i > 0 and \ del comps[i]
comps[i-1] not in ('', '..'): elif comps[i] == '..' and i > 0 and comps[i-1] not in ('', '..'):
del comps[i-1:i+1] del comps[i-1:i+1]
i = i-1 i = i-1
elif comps[i] == '' and i > 0 and comps[i-1] <> '': elif comps[i] == '' and i > 0 and comps[i-1] <> '':
del comps[i] del comps[i]
else: else:
i = i+1 i = i+1
# If the path is now empty, substitute '.' # If the path is now empty, substitute '.'
if not comps and not slashes: if not comps and not slashes:
comps.append('.') comps.append('.')
return slashes + string.joinfields(comps, '/') return slashes + string.joinfields(comps, '/')
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import struct import struct
import fcntl import fcntl
import FCNTL import FCNTL
import os import os, sys
from test_support import verbose from test_support import verbose
filename = '/tmp/delete-me' filename = '/tmp/delete-me'
...@@ -16,7 +16,12 @@ rv = fcntl.fcntl(f.fileno(), FCNTL.F_SETFL, os.O_NONBLOCK) ...@@ -16,7 +16,12 @@ 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
lockdata = struct.pack('hhllhh', FCNTL.F_WRLCK, 0, 0, 0, 0, 0) if sys.platform in ('netbsd1', 'freebsd2', 'freebsd3'):
lockdata = struct.pack('lxxxxlxxxxlhh', 0, 0, 0, FCNTL.F_WRLCK, 0)
elif sys.platform in ['aix3', 'aix4']:
lockdata = struct.pack('hhlllii', FCNTL.F_WRLCK, 0, 0, 0, 0, 0, 0)
else:
lockdata = struct.pack('hhllhh', FCNTL.F_WRLCK, 0, 0, 0, 0, 0)
if verbose: if verbose:
print 'struct.pack: ', `lockdata` print 'struct.pack: ', `lockdata`
......
...@@ -45,6 +45,12 @@ test('split', 'this is the split function', ...@@ -45,6 +45,12 @@ test('split', 'this is the split function',
['this', 'is', 'the', 'split', 'function']) ['this', 'is', 'the', 'split', 'function'])
test('split', 'a|b|c|d', ['a', 'b', 'c', 'd'], '|') test('split', 'a|b|c|d', ['a', 'b', 'c', 'd'], '|')
test('split', 'a|b|c|d', ['a', 'b', 'c|d'], '|', 2) test('split', 'a|b|c|d', ['a', 'b', 'c|d'], '|', 2)
test('split', 'a b c d', ['a', 'b c d'], None, 1)
test('split', 'a b c d', ['a', 'b', 'c d'], None, 2)
test('split', 'a b c d', ['a', 'b', 'c', 'd'], None, 3)
test('split', 'a b c d', ['a', 'b', 'c', 'd'], None, 4)
test('split', 'a b c d', ['a', 'b', 'c', 'd'], None, 0)
test('split', 'a b c d', ['a', 'b', 'c d'], None, 2)
# join now works with any sequence type # join now works with any sequence type
class Sequence: class Sequence:
...@@ -67,6 +73,15 @@ test('rstrip', ' hello ', ' hello') ...@@ -67,6 +73,15 @@ test('rstrip', ' hello ', ' hello')
test('swapcase', 'HeLLo cOmpUteRs', 'hEllO CoMPuTErS') test('swapcase', 'HeLLo cOmpUteRs', 'hEllO CoMPuTErS')
test('translate', 'xyzabcdef', 'xyzxyz', transtable, 'def') test('translate', 'xyzabcdef', 'xyzxyz', transtable, 'def')
test('replace', 'one!two!three!', 'one@two!three!', '!', '@', 1)
test('replace', 'one!two!three!', 'one@two@three!', '!', '@', 2)
test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 3)
test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 4)
test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 0)
test('replace', 'one!two!three!', 'one@two@three@', '!', '@')
test('replace', 'one!two!three!', 'one!two!three!', 'x', '@')
test('replace', 'one!two!three!', 'one!two!three!', 'x', '@', 2)
strop.whitespace strop.whitespace
strop.lowercase strop.lowercase
strop.uppercase strop.uppercase
...@@ -8,7 +8,7 @@ if time.ctime(t) <> time.asctime(time.localtime(t)): ...@@ -8,7 +8,7 @@ if time.ctime(t) <> time.asctime(time.localtime(t)):
print 'time.ctime(t) <> time.asctime(time.localtime(t))' print 'time.ctime(t) <> time.asctime(time.localtime(t))'
time.daylight time.daylight
if int(time.mktime(time.localtime(t))) <> int(t): if long(time.mktime(time.localtime(t))) <> long(t):
print 'time.mktime(time.localtime(t)) <> t' print 'time.mktime(time.localtime(t)) <> t'
time.sleep(1.2) time.sleep(1.2)
......
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