Kaydet (Commit) 0c9886d5 authored tarafından Tim Peters's avatar Tim Peters

Whitespace normalization.

üst 2344fae6
...@@ -28,101 +28,101 @@ from math import log, exp, pi, e, sqrt, acos, cos, sin ...@@ -28,101 +28,101 @@ from math import log, exp, pi, e, sqrt, acos, cos, sin
# XXX TO DO: make the distribution functions below into methods. # XXX TO DO: make the distribution functions below into methods.
def makeseed(a=None): def makeseed(a=None):
"""Turn a hashable value into three seed values for whrandom.seed(). """Turn a hashable value into three seed values for whrandom.seed().
None or no argument returns (0, 0, 0), to seed from current time. None or no argument returns (0, 0, 0), to seed from current time.
""" """
if a is None: if a is None:
return (0, 0, 0) return (0, 0, 0)
a = hash(a) a = hash(a)
a, x = divmod(a, 256) a, x = divmod(a, 256)
a, y = divmod(a, 256) a, y = divmod(a, 256)
a, z = divmod(a, 256) a, z = divmod(a, 256)
x = (x + a) % 256 or 1 x = (x + a) % 256 or 1
y = (y + a) % 256 or 1 y = (y + a) % 256 or 1
z = (z + a) % 256 or 1 z = (z + a) % 256 or 1
return (x, y, z) return (x, y, z)
def seed(a=None): def seed(a=None):
"""Seed the default generator from any hashable value. """Seed the default generator from any hashable value.
None or no argument seeds from current time. None or no argument seeds from current time.
""" """
x, y, z = makeseed(a) x, y, z = makeseed(a)
whrandom.seed(x, y, z) whrandom.seed(x, y, z)
class generator(whrandom.whrandom): class generator(whrandom.whrandom):
"""Random generator class.""" """Random generator class."""
def __init__(self, a=None): def __init__(self, a=None):
"""Constructor. Seed from current time or hashable value.""" """Constructor. Seed from current time or hashable value."""
self.seed(a) self.seed(a)
def seed(self, a=None): def seed(self, a=None):
"""Seed the generator from current time or hashable value.""" """Seed the generator from current time or hashable value."""
x, y, z = makeseed(a) x, y, z = makeseed(a)
whrandom.whrandom.seed(self, x, y, z) whrandom.whrandom.seed(self, x, y, z)
def new_generator(a=None): def new_generator(a=None):
"""Return a new random generator instance.""" """Return a new random generator instance."""
return generator(a) return generator(a)
# Housekeeping function to verify that magic constants have been # Housekeeping function to verify that magic constants have been
# computed correctly # computed correctly
def verify(name, expected): def verify(name, expected):
computed = eval(name) computed = eval(name)
if abs(computed - expected) > 1e-7: if abs(computed - expected) > 1e-7:
raise ValueError, \ raise ValueError, \
'computed value for %s deviates too much (computed %g, expected %g)' % \ 'computed value for %s deviates too much (computed %g, expected %g)' % \
(name, computed, expected) (name, computed, expected)
# -------------------- normal distribution -------------------- # -------------------- normal distribution --------------------
NV_MAGICCONST = 4*exp(-0.5)/sqrt(2.0) NV_MAGICCONST = 4*exp(-0.5)/sqrt(2.0)
verify('NV_MAGICCONST', 1.71552776992141) verify('NV_MAGICCONST', 1.71552776992141)
def normalvariate(mu, sigma): def normalvariate(mu, sigma):
# mu = mean, sigma = standard deviation # mu = mean, sigma = standard deviation
# Uses Kinderman and Monahan method. Reference: Kinderman, # Uses Kinderman and Monahan method. Reference: Kinderman,
# A.J. and Monahan, J.F., "Computer generation of random # A.J. and Monahan, J.F., "Computer generation of random
# variables using the ratio of uniform deviates", ACM Trans # variables using the ratio of uniform deviates", ACM Trans
# Math Software, 3, (1977), pp257-260. # Math Software, 3, (1977), pp257-260.
while 1: while 1:
u1 = random() u1 = random()
u2 = random() u2 = random()
z = NV_MAGICCONST*(u1-0.5)/u2 z = NV_MAGICCONST*(u1-0.5)/u2
zz = z*z/4.0 zz = z*z/4.0
if zz <= -log(u2): if zz <= -log(u2):
break break
return mu+z*sigma return mu+z*sigma
# -------------------- lognormal distribution -------------------- # -------------------- lognormal distribution --------------------
def lognormvariate(mu, sigma): def lognormvariate(mu, sigma):
return exp(normalvariate(mu, sigma)) return exp(normalvariate(mu, sigma))
# -------------------- circular uniform -------------------- # -------------------- circular uniform --------------------
def cunifvariate(mean, arc): def cunifvariate(mean, arc):
# mean: mean angle (in radians between 0 and pi) # mean: mean angle (in radians between 0 and pi)
# arc: range of distribution (in radians between 0 and pi) # arc: range of distribution (in radians between 0 and pi)
return (mean + arc * (random() - 0.5)) % pi return (mean + arc * (random() - 0.5)) % pi
# -------------------- exponential distribution -------------------- # -------------------- exponential distribution --------------------
def expovariate(lambd): def expovariate(lambd):
# lambd: rate lambd = 1/mean # lambd: rate lambd = 1/mean
# ('lambda' is a Python reserved word) # ('lambda' is a Python reserved word)
u = random() u = random()
while u <= 1e-7: while u <= 1e-7:
u = random() u = random()
return -log(u)/lambd return -log(u)/lambd
# -------------------- von Mises distribution -------------------- # -------------------- von Mises distribution --------------------
...@@ -130,43 +130,43 @@ TWOPI = 2.0*pi ...@@ -130,43 +130,43 @@ TWOPI = 2.0*pi
verify('TWOPI', 6.28318530718) verify('TWOPI', 6.28318530718)
def vonmisesvariate(mu, kappa): def vonmisesvariate(mu, kappa):
# mu: mean angle (in radians between 0 and 2*pi) # mu: mean angle (in radians between 0 and 2*pi)
# kappa: concentration parameter kappa (>= 0) # kappa: concentration parameter kappa (>= 0)
# if kappa = 0 generate uniform random angle # if kappa = 0 generate uniform random angle
# Based upon an algorithm published in: Fisher, N.I., # Based upon an algorithm published in: Fisher, N.I.,
# "Statistical Analysis of Circular Data", Cambridge # "Statistical Analysis of Circular Data", Cambridge
# University Press, 1993. # University Press, 1993.
# Thanks to Magnus Kessler for a correction to the # Thanks to Magnus Kessler for a correction to the
# implementation of step 4. # implementation of step 4.
if kappa <= 1e-6: if kappa <= 1e-6:
return TWOPI * random() return TWOPI * random()
a = 1.0 + sqrt(1.0 + 4.0 * kappa * kappa) a = 1.0 + sqrt(1.0 + 4.0 * kappa * kappa)
b = (a - sqrt(2.0 * a))/(2.0 * kappa) b = (a - sqrt(2.0 * a))/(2.0 * kappa)
r = (1.0 + b * b)/(2.0 * b) r = (1.0 + b * b)/(2.0 * b)
while 1: while 1:
u1 = random() u1 = random()
z = cos(pi * u1) z = cos(pi * u1)
f = (1.0 + r * z)/(r + z) f = (1.0 + r * z)/(r + z)
c = kappa * (r - f) c = kappa * (r - f)
u2 = random() u2 = random()
if not (u2 >= c * (2.0 - c) and u2 > c * exp(1.0 - c)): if not (u2 >= c * (2.0 - c) and u2 > c * exp(1.0 - c)):
break break
u3 = random() u3 = random()
if u3 > 0.5: if u3 > 0.5:
theta = (mu % TWOPI) + acos(f) theta = (mu % TWOPI) + acos(f)
else: else:
theta = (mu % TWOPI) - acos(f) theta = (mu % TWOPI) - acos(f)
return theta return theta
# -------------------- gamma distribution -------------------- # -------------------- gamma distribution --------------------
...@@ -174,62 +174,62 @@ LOG4 = log(4.0) ...@@ -174,62 +174,62 @@ LOG4 = log(4.0)
verify('LOG4', 1.38629436111989) verify('LOG4', 1.38629436111989)
def gammavariate(alpha, beta): def gammavariate(alpha, beta):
# beta times standard gamma # beta times standard gamma
ainv = sqrt(2.0 * alpha - 1.0) ainv = sqrt(2.0 * alpha - 1.0)
return beta * stdgamma(alpha, ainv, alpha - LOG4, alpha + ainv) return beta * stdgamma(alpha, ainv, alpha - LOG4, alpha + ainv)
SG_MAGICCONST = 1.0 + log(4.5) SG_MAGICCONST = 1.0 + log(4.5)
verify('SG_MAGICCONST', 2.50407739677627) verify('SG_MAGICCONST', 2.50407739677627)
def stdgamma(alpha, ainv, bbb, ccc): def stdgamma(alpha, ainv, bbb, ccc):
# ainv = sqrt(2 * alpha - 1) # ainv = sqrt(2 * alpha - 1)
# bbb = alpha - log(4) # bbb = alpha - log(4)
# ccc = alpha + ainv # ccc = alpha + ainv
if alpha <= 0.0: if alpha <= 0.0:
raise ValueError, 'stdgamma: alpha must be > 0.0' raise ValueError, 'stdgamma: alpha must be > 0.0'
if alpha > 1.0: if alpha > 1.0:
# Uses R.C.H. Cheng, "The generation of Gamma # Uses R.C.H. Cheng, "The generation of Gamma
# variables with non-integral shape parameters", # variables with non-integral shape parameters",
# Applied Statistics, (1977), 26, No. 1, p71-74 # Applied Statistics, (1977), 26, No. 1, p71-74
while 1: while 1:
u1 = random() u1 = random()
u2 = random() u2 = random()
v = log(u1/(1.0-u1))/ainv v = log(u1/(1.0-u1))/ainv
x = alpha*exp(v) x = alpha*exp(v)
z = u1*u1*u2 z = u1*u1*u2
r = bbb+ccc*v-x r = bbb+ccc*v-x
if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= log(z): if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= log(z):
return x return x
elif alpha == 1.0: elif alpha == 1.0:
# expovariate(1) # expovariate(1)
u = random() u = random()
while u <= 1e-7: while u <= 1e-7:
u = random() u = random()
return -log(u) return -log(u)
else: # alpha is between 0 and 1 (exclusive) else: # alpha is between 0 and 1 (exclusive)
# Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
while 1: while 1:
u = random() u = random()
b = (e + alpha)/e b = (e + alpha)/e
p = b*u p = b*u
if p <= 1.0: if p <= 1.0:
x = pow(p, 1.0/alpha) x = pow(p, 1.0/alpha)
else: else:
# p > 1 # p > 1
x = -log((b-p)/alpha) x = -log((b-p)/alpha)
u1 = random() u1 = random()
if not (((p <= 1.0) and (u1 > exp(-x))) or if not (((p <= 1.0) and (u1 > exp(-x))) or
((p > 1) and (u1 > pow(x, alpha - 1.0)))): ((p > 1) and (u1 > pow(x, alpha - 1.0)))):
break break
return x return x
# -------------------- Gauss (faster alternative) -------------------- # -------------------- Gauss (faster alternative) --------------------
...@@ -237,61 +237,61 @@ def stdgamma(alpha, ainv, bbb, ccc): ...@@ -237,61 +237,61 @@ def stdgamma(alpha, ainv, bbb, ccc):
gauss_next = None gauss_next = None
def gauss(mu, sigma): def gauss(mu, sigma):
# When x and y are two variables from [0, 1), uniformly # When x and y are two variables from [0, 1), uniformly
# distributed, then # distributed, then
# #
# cos(2*pi*x)*sqrt(-2*log(1-y)) # cos(2*pi*x)*sqrt(-2*log(1-y))
# sin(2*pi*x)*sqrt(-2*log(1-y)) # sin(2*pi*x)*sqrt(-2*log(1-y))
# #
# are two *independent* variables with normal distribution # are two *independent* variables with normal distribution
# (mu = 0, sigma = 1). # (mu = 0, sigma = 1).
# (Lambert Meertens) # (Lambert Meertens)
# (corrected version; bug discovered by Mike Miller, fixed by LM) # (corrected version; bug discovered by Mike Miller, fixed by LM)
# Multithreading note: When two threads call this function # Multithreading note: When two threads call this function
# simultaneously, it is possible that they will receive the # simultaneously, it is possible that they will receive the
# same return value. The window is very small though. To # same return value. The window is very small though. To
# avoid this, you have to use a lock around all calls. (I # 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 # didn't want to slow this down in the serial case by using a
# lock here.) # lock here.)
global gauss_next global gauss_next
z = gauss_next z = gauss_next
gauss_next = None gauss_next = None
if z is None: if z is None:
x2pi = random() * TWOPI x2pi = random() * TWOPI
g2rad = sqrt(-2.0 * log(1.0 - random())) g2rad = sqrt(-2.0 * log(1.0 - random()))
z = cos(x2pi) * g2rad z = cos(x2pi) * g2rad
gauss_next = sin(x2pi) * g2rad gauss_next = sin(x2pi) * g2rad
return mu + z*sigma return mu + z*sigma
# -------------------- beta -------------------- # -------------------- beta --------------------
def betavariate(alpha, beta): def betavariate(alpha, beta):
# Discrete Event Simulation in C, pp 87-88. # Discrete Event Simulation in C, pp 87-88.
y = expovariate(alpha) y = expovariate(alpha)
z = expovariate(1.0/beta) z = expovariate(1.0/beta)
return z/(y+z) return z/(y+z)
# -------------------- Pareto -------------------- # -------------------- Pareto --------------------
def paretovariate(alpha): def paretovariate(alpha):
# Jain, pg. 495 # Jain, pg. 495
u = random() u = random()
return 1.0 / pow(u, 1.0/alpha) return 1.0 / pow(u, 1.0/alpha)
# -------------------- Weibull -------------------- # -------------------- Weibull --------------------
def weibullvariate(alpha, beta): def weibullvariate(alpha, beta):
# Jain, pg. 499; bug fix courtesy Bill Arms # Jain, pg. 499; bug fix courtesy Bill Arms
u = random() u = random()
return alpha * pow(-log(u), 1.0/beta) return alpha * pow(-log(u), 1.0/beta)
# -------------------- shuffle -------------------- # -------------------- shuffle --------------------
# Not quite a random distribution, but a standard algorithm. # Not quite a random distribution, but a standard algorithm.
...@@ -310,55 +310,55 @@ def shuffle(x, random=random, int=int): ...@@ -310,55 +310,55 @@ def shuffle(x, random=random, int=int):
""" """
for i in xrange(len(x)-1, 0, -1): for i in xrange(len(x)-1, 0, -1):
# pick an element in x[:i+1] with which to exchange x[i] # pick an element in x[:i+1] with which to exchange x[i]
j = int(random() * (i+1)) j = int(random() * (i+1))
x[i], x[j] = x[j], x[i] x[i], x[j] = x[j], x[i]
# -------------------- test program -------------------- # -------------------- test program --------------------
def test(N = 200): def test(N = 200):
print 'TWOPI =', TWOPI print 'TWOPI =', TWOPI
print 'LOG4 =', LOG4 print 'LOG4 =', LOG4
print 'NV_MAGICCONST =', NV_MAGICCONST print 'NV_MAGICCONST =', NV_MAGICCONST
print 'SG_MAGICCONST =', SG_MAGICCONST print 'SG_MAGICCONST =', SG_MAGICCONST
test_generator(N, 'random()') test_generator(N, 'random()')
test_generator(N, 'normalvariate(0.0, 1.0)') test_generator(N, 'normalvariate(0.0, 1.0)')
test_generator(N, 'lognormvariate(0.0, 1.0)') test_generator(N, 'lognormvariate(0.0, 1.0)')
test_generator(N, 'cunifvariate(0.0, 1.0)') test_generator(N, 'cunifvariate(0.0, 1.0)')
test_generator(N, 'expovariate(1.0)') test_generator(N, 'expovariate(1.0)')
test_generator(N, 'vonmisesvariate(0.0, 1.0)') test_generator(N, 'vonmisesvariate(0.0, 1.0)')
test_generator(N, 'gammavariate(0.5, 1.0)') test_generator(N, 'gammavariate(0.5, 1.0)')
test_generator(N, 'gammavariate(0.9, 1.0)') test_generator(N, 'gammavariate(0.9, 1.0)')
test_generator(N, 'gammavariate(1.0, 1.0)') test_generator(N, 'gammavariate(1.0, 1.0)')
test_generator(N, 'gammavariate(2.0, 1.0)') test_generator(N, 'gammavariate(2.0, 1.0)')
test_generator(N, 'gammavariate(20.0, 1.0)') test_generator(N, 'gammavariate(20.0, 1.0)')
test_generator(N, 'gammavariate(200.0, 1.0)') test_generator(N, 'gammavariate(200.0, 1.0)')
test_generator(N, 'gauss(0.0, 1.0)') test_generator(N, 'gauss(0.0, 1.0)')
test_generator(N, 'betavariate(3.0, 3.0)') test_generator(N, 'betavariate(3.0, 3.0)')
test_generator(N, 'paretovariate(1.0)') test_generator(N, 'paretovariate(1.0)')
test_generator(N, 'weibullvariate(1.0, 1.0)') test_generator(N, 'weibullvariate(1.0, 1.0)')
def test_generator(n, funccall): def test_generator(n, funccall):
import time import time
print n, 'times', funccall print n, 'times', funccall
code = compile(funccall, funccall, 'eval') code = compile(funccall, funccall, 'eval')
sum = 0.0 sum = 0.0
sqsum = 0.0 sqsum = 0.0
smallest = 1e10 smallest = 1e10
largest = -1e10 largest = -1e10
t0 = time.time() t0 = time.time()
for i in range(n): for i in range(n):
x = eval(code) x = eval(code)
sum = sum + x sum = sum + x
sqsum = sqsum + x*x sqsum = sqsum + x*x
smallest = min(x, smallest) smallest = min(x, smallest)
largest = max(x, largest) largest = max(x, largest)
t1 = time.time() t1 = time.time()
print round(t1-t0, 3), 'sec,', print round(t1-t0, 3), 'sec,',
avg = sum/n avg = sum/n
stddev = sqrt(sqsum/n - avg*avg) stddev = sqrt(sqsum/n - avg*avg)
print 'avg %g, stddev %g, min %g, max %g' % \ print 'avg %g, stddev %g, min %g, max %g' % \
(avg, stddev, smallest, largest) (avg, stddev, smallest, largest)
if __name__ == '__main__': if __name__ == '__main__':
test() test()
...@@ -61,7 +61,7 @@ XXX To be done... ...@@ -61,7 +61,7 @@ XXX To be done...
import regex import regex
from regex_syntax import * # RE_* from regex_syntax import * # RE_*
# Default translation table # Default translation table
mastertable = { mastertable = {
......
...@@ -33,9 +33,9 @@ RE_NEWLINE_OR = 16 ...@@ -33,9 +33,9 @@ RE_NEWLINE_OR = 16
# their special meaning regardless of the surrounding context. # their special meaning regardless of the surrounding context.
# 1 means that special characters may act as normal characters in some # 1 means that special characters may act as normal characters in some
# contexts. Specifically, this applies to: # contexts. Specifically, this applies to:
# ^ - only special at the beginning, or after ( or | # ^ - only special at the beginning, or after ( or |
# $ - only special at the end, or before ) or | # $ - only special at the end, or before ) or |
# *, +, ? - only special when not after the beginning, (, or | # *, +, ? - only special when not after the beginning, (, or |
RE_CONTEXT_INDEP_OPS = 32 RE_CONTEXT_INDEP_OPS = 32
# ANSI sequences (\n etc) and \xhh # ANSI sequences (\n etc) and \xhh
......
...@@ -12,7 +12,7 @@ splitx(str, pat, maxsplit): split string using pattern as delimiter plus ...@@ -12,7 +12,7 @@ splitx(str, pat, maxsplit): split string using pattern as delimiter plus
import warnings import warnings
warnings.warn("the regsub module is deprecated; please use re.sub()", warnings.warn("the regsub module is deprecated; please use re.sub()",
DeprecationWarning) DeprecationWarning)
# Ignore further deprecation warnings about this module # Ignore further deprecation warnings about this module
warnings.filterwarnings("ignore", "", DeprecationWarning, __name__) warnings.filterwarnings("ignore", "", DeprecationWarning, __name__)
...@@ -27,12 +27,12 @@ import regex ...@@ -27,12 +27,12 @@ import regex
# compiled pattern. # compiled pattern.
def sub(pat, repl, str): def sub(pat, repl, str):
prog = compile(pat) prog = compile(pat)
if prog.search(str) >= 0: if prog.search(str) >= 0:
regs = prog.regs regs = prog.regs
a, b = regs[0] a, b = regs[0]
str = str[:a] + expand(repl, regs, str) + str[b:] str = str[:a] + expand(repl, regs, str) + str[b:]
return str return str
# Replace all (non-overlapping) occurrences of pattern pat in string # Replace all (non-overlapping) occurrences of pattern pat in string
...@@ -41,23 +41,23 @@ def sub(pat, repl, str): ...@@ -41,23 +41,23 @@ def sub(pat, repl, str):
# a previous match, so e.g. gsub('', '-', 'abc') returns '-a-b-c-'. # a previous match, so e.g. gsub('', '-', 'abc') returns '-a-b-c-'.
def gsub(pat, repl, str): def gsub(pat, repl, str):
prog = compile(pat) prog = compile(pat)
new = '' new = ''
start = 0 start = 0
first = 1 first = 1
while prog.search(str, start) >= 0: while prog.search(str, start) >= 0:
regs = prog.regs regs = prog.regs
a, b = regs[0] a, b = regs[0]
if a == b == start and not first: if a == b == start and not first:
if start >= len(str) or prog.search(str, start+1) < 0: if start >= len(str) or prog.search(str, start+1) < 0:
break break
regs = prog.regs regs = prog.regs
a, b = regs[0] a, b = regs[0]
new = new + str[start:a] + expand(repl, regs, str) new = new + str[start:a] + expand(repl, regs, str)
start = b start = b
first = 0 first = 0
new = new + str[start:] new = new + str[start:]
return new return new
# Split string str in fields separated by delimiters matching pattern # Split string str in fields separated by delimiters matching pattern
...@@ -66,7 +66,7 @@ def gsub(pat, repl, str): ...@@ -66,7 +66,7 @@ def gsub(pat, repl, str):
# The optional 3rd argument sets the number of splits that are performed. # The optional 3rd argument sets the number of splits that are performed.
def split(str, pat, maxsplit = 0): def split(str, pat, maxsplit = 0):
return intsplit(str, pat, maxsplit, 0) return intsplit(str, pat, maxsplit, 0)
# Split string str in fields separated by delimiters matching pattern # Split string str in fields separated by delimiters matching pattern
# pat. Only non-empty matches for the pattern are considered, so e.g. # pat. Only non-empty matches for the pattern are considered, so e.g.
...@@ -76,42 +76,42 @@ def split(str, pat, maxsplit = 0): ...@@ -76,42 +76,42 @@ def split(str, pat, maxsplit = 0):
def splitx(str, pat, maxsplit = 0): def splitx(str, pat, maxsplit = 0):
return intsplit(str, pat, maxsplit, 1) return intsplit(str, pat, maxsplit, 1)
# Internal function used to implement split() and splitx(). # Internal function used to implement split() and splitx().
def intsplit(str, pat, maxsplit, retain): def intsplit(str, pat, maxsplit, retain):
prog = compile(pat) prog = compile(pat)
res = [] res = []
start = next = 0 start = next = 0
splitcount = 0 splitcount = 0
while prog.search(str, next) >= 0: while prog.search(str, next) >= 0:
regs = prog.regs regs = prog.regs
a, b = regs[0] a, b = regs[0]
if a == b: if a == b:
next = next + 1 next = next + 1
if next >= len(str): if next >= len(str):
break break
else: else:
res.append(str[start:a]) res.append(str[start:a])
if retain: if retain:
res.append(str[a:b]) res.append(str[a:b])
start = next = b start = next = b
splitcount = splitcount + 1 splitcount = splitcount + 1
if (maxsplit and (splitcount >= maxsplit)): if (maxsplit and (splitcount >= maxsplit)):
break break
res.append(str[start:]) res.append(str[start:])
return res return res
# Capitalize words split using a pattern # Capitalize words split using a pattern
def capwords(str, pat='[^a-zA-Z0-9_]+'): def capwords(str, pat='[^a-zA-Z0-9_]+'):
import string import string
words = splitx(str, pat) words = splitx(str, pat)
for i in range(0, len(words), 2): for i in range(0, len(words), 2):
words[i] = string.capitalize(words[i]) words[i] = string.capitalize(words[i])
return string.joinfields(words, "") return string.joinfields(words, "")
# Internal subroutines: # Internal subroutines:
...@@ -131,19 +131,19 @@ def capwords(str, pat='[^a-zA-Z0-9_]+'): ...@@ -131,19 +131,19 @@ def capwords(str, pat='[^a-zA-Z0-9_]+'):
cache = {} cache = {}
def compile(pat): def compile(pat):
if type(pat) != type(''): if type(pat) != type(''):
return pat # Assume it is a compiled regex return pat # Assume it is a compiled regex
key = (pat, regex.get_syntax()) key = (pat, regex.get_syntax())
if cache.has_key(key): if cache.has_key(key):
prog = cache[key] # Get it from the cache prog = cache[key] # Get it from the cache
else: else:
prog = cache[key] = regex.compile(pat) prog = cache[key] = regex.compile(pat)
return prog return prog
def clear_cache(): def clear_cache():
global cache global cache
cache = {} cache = {}
# Expand \digit in the replacement. # Expand \digit in the replacement.
...@@ -153,46 +153,46 @@ def clear_cache(): ...@@ -153,46 +153,46 @@ def clear_cache():
# the \ and the following character are both copied). # the \ and the following character are both copied).
def expand(repl, regs, str): def expand(repl, regs, str):
if '\\' not in repl: if '\\' not in repl:
return repl return repl
new = '' new = ''
i = 0 i = 0
ord0 = ord('0') ord0 = ord('0')
while i < len(repl): while i < len(repl):
c = repl[i]; i = i+1 c = repl[i]; i = i+1
if c != '\\' or i >= len(repl): if c != '\\' or i >= len(repl):
new = new + c new = new + c
else: else:
c = repl[i]; i = i+1 c = repl[i]; i = i+1
if '0' <= c <= '9': if '0' <= c <= '9':
a, b = regs[ord(c)-ord0] a, b = regs[ord(c)-ord0]
new = new + str[a:b] new = new + str[a:b]
elif c == '\\': elif c == '\\':
new = new + c new = new + c
else: else:
new = new + '\\' + c new = new + '\\' + c
return new return new
# Test program, reads sequences "pat repl str" from stdin. # Test program, reads sequences "pat repl str" from stdin.
# Optional argument specifies pattern used to split lines. # Optional argument specifies pattern used to split lines.
def test(): def test():
import sys import sys
if sys.argv[1:]: if sys.argv[1:]:
delpat = sys.argv[1] delpat = sys.argv[1]
else: else:
delpat = '[ \t\n]+' delpat = '[ \t\n]+'
while 1: while 1:
if sys.stdin.isatty(): sys.stderr.write('--> ') if sys.stdin.isatty(): sys.stderr.write('--> ')
line = sys.stdin.readline() line = sys.stdin.readline()
if not line: break if not line: break
if line[-1] == '\n': line = line[:-1] if line[-1] == '\n': line = line[:-1]
fields = split(line, delpat) fields = split(line, delpat)
if len(fields) != 3: if len(fields) != 3:
print 'Sorry, not three fields' print 'Sorry, not three fields'
print 'split:', `fields` print 'split:', `fields`
continue continue
[pat, repl, str] = split(line, delpat) [pat, repl, str] = split(line, delpat)
print 'sub :', `sub(pat, repl, str)` print 'sub :', `sub(pat, repl, str)`
print 'gsub:', `gsub(pat, repl, str)` print 'gsub:', `gsub(pat, repl, str)`
...@@ -3,93 +3,93 @@ ...@@ -3,93 +3,93 @@
import string import string
class Repr: class Repr:
def __init__(self): def __init__(self):
self.maxlevel = 6 self.maxlevel = 6
self.maxtuple = 6 self.maxtuple = 6
self.maxlist = 6 self.maxlist = 6
self.maxdict = 4 self.maxdict = 4
self.maxstring = 30 self.maxstring = 30
self.maxlong = 40 self.maxlong = 40
self.maxother = 20 self.maxother = 20
def repr(self, x): def repr(self, x):
return self.repr1(x, self.maxlevel) return self.repr1(x, self.maxlevel)
def repr1(self, x, level): def repr1(self, x, level):
typename = `type(x)`[7:-2] # "<type '......'>" typename = `type(x)`[7:-2] # "<type '......'>"
if ' ' in typename: if ' ' in typename:
parts = string.split(typename) parts = string.split(typename)
typename = string.joinfields(parts, '_') typename = string.joinfields(parts, '_')
if hasattr(self, 'repr_' + typename): if hasattr(self, 'repr_' + typename):
return getattr(self, 'repr_' + typename)(x, level) return getattr(self, 'repr_' + typename)(x, level)
else: else:
s = `x` s = `x`
if len(s) > self.maxother: if len(s) > self.maxother:
i = max(0, (self.maxother-3)/2) i = max(0, (self.maxother-3)/2)
j = max(0, self.maxother-3-i) j = max(0, self.maxother-3-i)
s = s[:i] + '...' + s[len(s)-j:] s = s[:i] + '...' + s[len(s)-j:]
return s return s
def repr_tuple(self, x, level): def repr_tuple(self, x, level):
n = len(x) n = len(x)
if n == 0: return '()' if n == 0: return '()'
if level <= 0: return '(...)' if level <= 0: return '(...)'
s = '' s = ''
for i in range(min(n, self.maxtuple)): for i in range(min(n, self.maxtuple)):
if s: s = s + ', ' if s: s = s + ', '
s = s + self.repr1(x[i], level-1) s = s + self.repr1(x[i], level-1)
if n > self.maxtuple: s = s + ', ...' if n > self.maxtuple: s = s + ', ...'
elif n == 1: s = s + ',' elif n == 1: s = s + ','
return '(' + s + ')' return '(' + s + ')'
def repr_list(self, x, level): def repr_list(self, x, level):
n = len(x) n = len(x)
if n == 0: return '[]' if n == 0: return '[]'
if level <= 0: return '[...]' if level <= 0: return '[...]'
s = '' s = ''
for i in range(min(n, self.maxlist)): for i in range(min(n, self.maxlist)):
if s: s = s + ', ' if s: s = s + ', '
s = s + self.repr1(x[i], level-1) s = s + self.repr1(x[i], level-1)
if n > self.maxlist: s = s + ', ...' if n > self.maxlist: s = s + ', ...'
return '[' + s + ']' return '[' + s + ']'
def repr_dictionary(self, x, level): def repr_dictionary(self, x, level):
n = len(x) n = len(x)
if n == 0: return '{}' if n == 0: return '{}'
if level <= 0: return '{...}' if level <= 0: return '{...}'
s = '' s = ''
keys = x.keys() keys = x.keys()
keys.sort() keys.sort()
for i in range(min(n, self.maxdict)): for i in range(min(n, self.maxdict)):
if s: s = s + ', ' if s: s = s + ', '
key = keys[i] key = keys[i]
s = s + self.repr1(key, level-1) s = s + self.repr1(key, level-1)
s = s + ': ' + self.repr1(x[key], level-1) s = s + ': ' + self.repr1(x[key], level-1)
if n > self.maxdict: s = s + ', ...' if n > self.maxdict: s = s + ', ...'
return '{' + s + '}' return '{' + s + '}'
def repr_string(self, x, level): def repr_string(self, x, level):
s = `x[:self.maxstring]` s = `x[:self.maxstring]`
if len(s) > self.maxstring: if len(s) > self.maxstring:
i = max(0, (self.maxstring-3)/2) i = max(0, (self.maxstring-3)/2)
j = max(0, self.maxstring-3-i) j = max(0, self.maxstring-3-i)
s = `x[:i] + x[len(x)-j:]` s = `x[:i] + x[len(x)-j:]`
s = s[:i] + '...' + s[len(s)-j:] s = s[:i] + '...' + s[len(s)-j:]
return s return s
def repr_long_int(self, x, level): def repr_long_int(self, x, level):
s = `x` # XXX Hope this isn't too slow... s = `x` # XXX Hope this isn't too slow...
if len(s) > self.maxlong: if len(s) > self.maxlong:
i = max(0, (self.maxlong-3)/2) i = max(0, (self.maxlong-3)/2)
j = max(0, self.maxlong-3-i) j = max(0, self.maxlong-3-i)
s = s[:i] + '...' + s[len(s)-j:] s = s[:i] + '...' + s[len(s)-j:]
return s return s
def repr_instance(self, x, level): def repr_instance(self, x, level):
try: try:
s = `x` s = `x`
# Bugs in x.__repr__() can cause arbitrary # Bugs in x.__repr__() can cause arbitrary
# exceptions -- then make up something # exceptions -- then make up something
except: except:
return '<' + x.__class__.__name__ + ' instance at ' + \ return '<' + x.__class__.__name__ + ' instance at ' + \
hex(id(x))[2:] + '>' hex(id(x))[2:] + '>'
if len(s) > self.maxstring: if len(s) > self.maxstring:
i = max(0, (self.maxstring-3)/2) i = max(0, (self.maxstring-3)/2)
j = max(0, self.maxstring-3-i) j = max(0, self.maxstring-3-i)
s = s[:i] + '...' + s[len(s)-j:] s = s[:i] + '...' + s[len(s)-j:]
return s return s
aRepr = Repr() aRepr = Repr()
repr = aRepr.repr repr = aRepr.repr
...@@ -278,7 +278,7 @@ class RExec(ihooks._Verbose): ...@@ -278,7 +278,7 @@ class RExec(ihooks._Verbose):
def r_unload(self, m): def r_unload(self, m):
return self.importer.unload(m) return self.importer.unload(m)
# The s_* methods are similar but also swap std{in,out,err} # The s_* methods are similar but also swap std{in,out,err}
def make_delegate_files(self): def make_delegate_files(self):
...@@ -309,7 +309,7 @@ class RExec(ihooks._Verbose): ...@@ -309,7 +309,7 @@ class RExec(ihooks._Verbose):
self.restricted_stdin = s.stdin self.restricted_stdin = s.stdin
self.restricted_stdout = s.stdout self.restricted_stdout = s.stdout
self.restricted_stderr = s.stderr self.restricted_stderr = s.stderr
def save_files(self): def save_files(self):
self.save_stdin = sys.stdin self.save_stdin = sys.stdin
...@@ -320,7 +320,7 @@ class RExec(ihooks._Verbose): ...@@ -320,7 +320,7 @@ class RExec(ihooks._Verbose):
sys.stdin = self.save_stdin sys.stdin = self.save_stdin
sys.stdout = self.save_stdout sys.stdout = self.save_stdout
sys.stderr = self.save_stderr sys.stderr = self.save_stderr
def s_apply(self, func, args=(), kw=None): def s_apply(self, func, args=(), kw=None):
self.save_files() self.save_files()
try: try:
...@@ -331,27 +331,27 @@ class RExec(ihooks._Verbose): ...@@ -331,27 +331,27 @@ class RExec(ihooks._Verbose):
r = apply(func, args) r = apply(func, args)
finally: finally:
self.restore_files() self.restore_files()
def s_exec(self, *args): def s_exec(self, *args):
self.s_apply(self.r_exec, args) self.s_apply(self.r_exec, args)
def s_eval(self, *args): def s_eval(self, *args):
self.s_apply(self.r_eval, args) self.s_apply(self.r_eval, args)
def s_execfile(self, *args): def s_execfile(self, *args):
self.s_apply(self.r_execfile, args) self.s_apply(self.r_execfile, args)
def s_import(self, *args): def s_import(self, *args):
self.s_apply(self.r_import, args) self.s_apply(self.r_import, args)
def s_reload(self, *args): def s_reload(self, *args):
self.s_apply(self.r_reload, args) self.s_apply(self.r_reload, args)
def s_unload(self, *args): def s_unload(self, *args):
self.s_apply(self.r_unload, args) self.s_apply(self.r_unload, args)
# Restricted open(...) # Restricted open(...)
def r_open(self, file, mode='r', buf=-1): def r_open(self, file, mode='r', buf=-1):
if mode not in ('r', 'rb'): if mode not in ('r', 'rb'):
raise IOError, "can't open files for writing in restricted mode" raise IOError, "can't open files for writing in restricted mode"
......
...@@ -28,7 +28,7 @@ portability, you should set the seekable argument to zero to prevent ...@@ -28,7 +28,7 @@ portability, you should set the seekable argument to zero to prevent
that initial \code{tell} when passing in an unseekable object such as that initial \code{tell} when passing in an unseekable object such as
a a file object created from a socket object. If it is 1 on entry -- a a file object created from a socket object. If it is 1 on entry --
which it is by default -- the tell() method of the open file object is which it is by default -- the tell() method of the open file object is
called once; if this raises an exception, seekable is reset to 0. For called once; if this raises an exception, seekable is reset to 0. For
other nonzero values of seekable, this test is not made. other nonzero values of seekable, this test is not made.
To get the text of a particular header there are several methods: To get the text of a particular header there are several methods:
...@@ -65,7 +65,7 @@ _blanklines = ('\r\n', '\n') # Optimization for islast() ...@@ -65,7 +65,7 @@ _blanklines = ('\r\n', '\n') # Optimization for islast()
class Message: class Message:
"""Represents a single RFC-822-compliant message.""" """Represents a single RFC-822-compliant message."""
def __init__(self, fp, seekable = 1): def __init__(self, fp, seekable = 1):
"""Initialize the class instance and read the headers.""" """Initialize the class instance and read the headers."""
if seekable == 1: if seekable == 1:
...@@ -95,23 +95,23 @@ class Message: ...@@ -95,23 +95,23 @@ class Message:
self.startofbody = self.fp.tell() self.startofbody = self.fp.tell()
except IOError: except IOError:
self.seekable = 0 self.seekable = 0
def rewindbody(self): def rewindbody(self):
"""Rewind the file to the start of the body (if seekable).""" """Rewind the file to the start of the body (if seekable)."""
if not self.seekable: if not self.seekable:
raise IOError, "unseekable file" raise IOError, "unseekable file"
self.fp.seek(self.startofbody) self.fp.seek(self.startofbody)
def readheaders(self): def readheaders(self):
"""Read header lines. """Read header lines.
Read header lines up to the entirely blank line that Read header lines up to the entirely blank line that
terminates them. The (normally blank) line that ends the terminates them. The (normally blank) line that ends the
headers is skipped, but not included in the returned list. headers is skipped, but not included in the returned list.
If a non-header line ends the headers, (which is an error), If a non-header line ends the headers, (which is an error),
an attempt is made to backspace over it; it is never an attempt is made to backspace over it; it is never
included in the returned list. included in the returned list.
The variable self.status is set to the empty string if all The variable self.status is set to the empty string if all
went well, otherwise it is an error message. went well, otherwise it is an error message.
The variable self.headers is a completely uninterpreted list The variable self.headers is a completely uninterpreted list
...@@ -190,15 +190,15 @@ class Message: ...@@ -190,15 +190,15 @@ class Message:
return line[:i].lower() return line[:i].lower()
else: else:
return None return None
def islast(self, line): def islast(self, line):
"""Determine whether a line is a legal end of RFC-822 headers. """Determine whether a line is a legal end of RFC-822 headers.
You may override this method if your application wants You may override this method if your application wants
to bend the rules, e.g. to strip trailing whitespace, to bend the rules, e.g. to strip trailing whitespace,
or to recognize MH template separators ('--------'). or to recognize MH template separators ('--------').
For convenience (e.g. for code reading from sockets) a For convenience (e.g. for code reading from sockets) a
line consisting of \r\n also matches. line consisting of \r\n also matches.
""" """
return line in _blanklines return line in _blanklines
...@@ -210,10 +210,10 @@ class Message: ...@@ -210,10 +210,10 @@ class Message:
comments or free-text data. comments or free-text data.
""" """
return None return None
def getallmatchingheaders(self, name): def getallmatchingheaders(self, name):
"""Find all header lines matching a given header name. """Find all header lines matching a given header name.
Look through the list of headers and find all lines Look through the list of headers and find all lines
matching a given header name (and their continuation matching a given header name (and their continuation
lines). A list of the lines is returned, without lines). A list of the lines is returned, without
...@@ -234,10 +234,10 @@ class Message: ...@@ -234,10 +234,10 @@ class Message:
if hit: if hit:
list.append(line) list.append(line)
return list return list
def getfirstmatchingheader(self, name): def getfirstmatchingheader(self, name):
"""Get the first header line matching name. """Get the first header line matching name.
This is similar to getallmatchingheaders, but it returns This is similar to getallmatchingheaders, but it returns
only the first matching header (and its continuation only the first matching header (and its continuation
lines). lines).
...@@ -255,26 +255,26 @@ class Message: ...@@ -255,26 +255,26 @@ class Message:
if hit: if hit:
list.append(line) list.append(line)
return list return list
def getrawheader(self, name): def getrawheader(self, name):
"""A higher-level interface to getfirstmatchingheader(). """A higher-level interface to getfirstmatchingheader().
Return a string containing the literal text of the Return a string containing the literal text of the
header but with the keyword stripped. All leading, header but with the keyword stripped. All leading,
trailing and embedded whitespace is kept in the trailing and embedded whitespace is kept in the
string, however. string, however.
Return None if the header does not occur. Return None if the header does not occur.
""" """
list = self.getfirstmatchingheader(name) list = self.getfirstmatchingheader(name)
if not list: if not list:
return None return None
list[0] = list[0][len(name) + 1:] list[0] = list[0][len(name) + 1:]
return ''.join(list) return ''.join(list)
def getheader(self, name, default=None): def getheader(self, name, default=None):
"""Get the header value for a name. """Get the header value for a name.
This is the normal interface: it returns a stripped This is the normal interface: it returns a stripped
version of the header value for a given header name, version of the header value for a given header name,
or None if it doesn't exist. This uses the dictionary or None if it doesn't exist. This uses the dictionary
...@@ -311,10 +311,10 @@ class Message: ...@@ -311,10 +311,10 @@ class Message:
if have_header: if have_header:
result.append(current) result.append(current)
return result return result
def getaddr(self, name): def getaddr(self, name):
"""Get a single address from a header, as a tuple. """Get a single address from a header, as a tuple.
An example return value: An example return value:
('Guido van Rossum', 'guido@cwi.nl') ('Guido van Rossum', 'guido@cwi.nl')
""" """
...@@ -324,7 +324,7 @@ class Message: ...@@ -324,7 +324,7 @@ class Message:
return alist[0] return alist[0]
else: else:
return (None, None) return (None, None)
def getaddrlist(self, name): def getaddrlist(self, name):
"""Get a list of addresses from a header. """Get a list of addresses from a header.
...@@ -347,10 +347,10 @@ class Message: ...@@ -347,10 +347,10 @@ class Message:
alladdrs = ''.join(raw) alladdrs = ''.join(raw)
a = AddrlistClass(alladdrs) a = AddrlistClass(alladdrs)
return a.getaddrlist() return a.getaddrlist()
def getdate(self, name): def getdate(self, name):
"""Retrieve a date field from a header. """Retrieve a date field from a header.
Retrieves a date field from the named header, returning Retrieves a date field from the named header, returning
a tuple compatible with time.mktime(). a tuple compatible with time.mktime().
""" """
...@@ -359,10 +359,10 @@ class Message: ...@@ -359,10 +359,10 @@ class Message:
except KeyError: except KeyError:
return None return None
return parsedate(data) return parsedate(data)
def getdate_tz(self, name): def getdate_tz(self, name):
"""Retrieve a date field from a header as a 10-tuple. """Retrieve a date field from a header as a 10-tuple.
The first 9 elements make up a tuple compatible with The first 9 elements make up a tuple compatible with
time.mktime(), and the 10th is the offset of the poster's time.mktime(), and the 10th is the offset of the poster's
time zone from GMT/UTC. time zone from GMT/UTC.
...@@ -372,14 +372,14 @@ class Message: ...@@ -372,14 +372,14 @@ class Message:
except KeyError: except KeyError:
return None return None
return parsedate_tz(data) return parsedate_tz(data)
# Access as a dictionary (only finds *last* header of each type): # Access as a dictionary (only finds *last* header of each type):
def __len__(self): def __len__(self):
"""Get the number of headers in a message.""" """Get the number of headers in a message."""
return len(self.dict) return len(self.dict)
def __getitem__(self, name): def __getitem__(self, name):
"""Get a specific header, as from a dictionary.""" """Get a specific header, as from a dictionary."""
return self.dict[name.lower()] return self.dict[name.lower()]
...@@ -387,7 +387,7 @@ class Message: ...@@ -387,7 +387,7 @@ class Message:
def __setitem__(self, name, value): def __setitem__(self, name, value):
"""Set the value of a header. """Set the value of a header.
Note: This is not a perfect inversion of __getitem__, because Note: This is not a perfect inversion of __getitem__, because
any changed headers get stuck at the end of the raw-headers list any changed headers get stuck at the end of the raw-headers list
rather than where the altered header was. rather than where the altered header was.
""" """
...@@ -397,7 +397,7 @@ class Message: ...@@ -397,7 +397,7 @@ class Message:
lines = text.split("\n") lines = text.split("\n")
for line in lines: for line in lines:
self.headers.append(line + "\n") self.headers.append(line + "\n")
def __delitem__(self, name): def __delitem__(self, name):
"""Delete all occurrences of a specific header, if it is present.""" """Delete all occurrences of a specific header, if it is present."""
name = name.lower() name = name.lower()
...@@ -423,18 +423,18 @@ class Message: ...@@ -423,18 +423,18 @@ class Message:
def has_key(self, name): def has_key(self, name):
"""Determine whether a message contains the named header.""" """Determine whether a message contains the named header."""
return self.dict.has_key(name.lower()) return self.dict.has_key(name.lower())
def keys(self): def keys(self):
"""Get all of a message's header field names.""" """Get all of a message's header field names."""
return self.dict.keys() return self.dict.keys()
def values(self): def values(self):
"""Get all of a message's header field values.""" """Get all of a message's header field values."""
return self.dict.values() return self.dict.values()
def items(self): def items(self):
"""Get all of a message's headers. """Get all of a message's headers.
Returns a list of name, value tuples. Returns a list of name, value tuples.
""" """
return self.dict.items() return self.dict.items()
...@@ -480,17 +480,17 @@ def parseaddr(address): ...@@ -480,17 +480,17 @@ def parseaddr(address):
class AddrlistClass: class AddrlistClass:
"""Address parser class by Ben Escoto. """Address parser class by Ben Escoto.
To understand what this class does, it helps to have a copy of To understand what this class does, it helps to have a copy of
RFC-822 in front of you. RFC-822 in front of you.
Note: this class interface is deprecated and may be removed in the future. Note: this class interface is deprecated and may be removed in the future.
Use rfc822.AddressList instead. Use rfc822.AddressList instead.
""" """
def __init__(self, field): def __init__(self, field):
"""Initialize a new instance. """Initialize a new instance.
`field' is an unparsed address header field, containing `field' is an unparsed address header field, containing
one or more addresses. one or more addresses.
""" """
...@@ -501,7 +501,7 @@ class AddrlistClass: ...@@ -501,7 +501,7 @@ class AddrlistClass:
self.atomends = self.specials + self.LWS + self.CR self.atomends = self.specials + self.LWS + self.CR
self.field = field self.field = field
self.commentlist = [] self.commentlist = []
def gotonext(self): def gotonext(self):
"""Parse up to the start of the next address.""" """Parse up to the start of the next address."""
while self.pos < len(self.field): while self.pos < len(self.field):
...@@ -510,34 +510,34 @@ class AddrlistClass: ...@@ -510,34 +510,34 @@ class AddrlistClass:
elif self.field[self.pos] == '(': elif self.field[self.pos] == '(':
self.commentlist.append(self.getcomment()) self.commentlist.append(self.getcomment())
else: break else: break
def getaddrlist(self): def getaddrlist(self):
"""Parse all addresses. """Parse all addresses.
Returns a list containing all of the addresses. Returns a list containing all of the addresses.
""" """
ad = self.getaddress() ad = self.getaddress()
if ad: if ad:
return ad + self.getaddrlist() return ad + self.getaddrlist()
else: return [] else: return []
def getaddress(self): def getaddress(self):
"""Parse the next address.""" """Parse the next address."""
self.commentlist = [] self.commentlist = []
self.gotonext() self.gotonext()
oldpos = self.pos oldpos = self.pos
oldcl = self.commentlist oldcl = self.commentlist
plist = self.getphraselist() plist = self.getphraselist()
self.gotonext() self.gotonext()
returnlist = [] returnlist = []
if self.pos >= len(self.field): if self.pos >= len(self.field):
# Bad email address technically, no domain. # Bad email address technically, no domain.
if plist: if plist:
returnlist = [(' '.join(self.commentlist), plist[0])] returnlist = [(' '.join(self.commentlist), plist[0])]
elif self.field[self.pos] in '.@': elif self.field[self.pos] in '.@':
# email address is just an addrspec # email address is just an addrspec
# this isn't very efficient since we start over # this isn't very efficient since we start over
...@@ -545,11 +545,11 @@ class AddrlistClass: ...@@ -545,11 +545,11 @@ class AddrlistClass:
self.commentlist = oldcl self.commentlist = oldcl
addrspec = self.getaddrspec() addrspec = self.getaddrspec()
returnlist = [(' '.join(self.commentlist), addrspec)] returnlist = [(' '.join(self.commentlist), addrspec)]
elif self.field[self.pos] == ':': elif self.field[self.pos] == ':':
# address is a group # address is a group
returnlist = [] returnlist = []
fieldlen = len(self.field) fieldlen = len(self.field)
self.pos = self.pos + 1 self.pos = self.pos + 1
while self.pos < len(self.field): while self.pos < len(self.field):
...@@ -558,35 +558,35 @@ class AddrlistClass: ...@@ -558,35 +558,35 @@ class AddrlistClass:
self.pos = self.pos + 1 self.pos = self.pos + 1
break break
returnlist = returnlist + self.getaddress() returnlist = returnlist + self.getaddress()
elif self.field[self.pos] == '<': elif self.field[self.pos] == '<':
# Address is a phrase then a route addr # Address is a phrase then a route addr
routeaddr = self.getrouteaddr() routeaddr = self.getrouteaddr()
if self.commentlist: if self.commentlist:
returnlist = [(' '.join(plist) + ' (' + \ returnlist = [(' '.join(plist) + ' (' + \
' '.join(self.commentlist) + ')', routeaddr)] ' '.join(self.commentlist) + ')', routeaddr)]
else: returnlist = [(' '.join(plist), routeaddr)] else: returnlist = [(' '.join(plist), routeaddr)]
else: else:
if plist: if plist:
returnlist = [(' '.join(self.commentlist), plist[0])] returnlist = [(' '.join(self.commentlist), plist[0])]
elif self.field[self.pos] in self.specials: elif self.field[self.pos] in self.specials:
self.pos = self.pos + 1 self.pos = self.pos + 1
self.gotonext() self.gotonext()
if self.pos < len(self.field) and self.field[self.pos] == ',': if self.pos < len(self.field) and self.field[self.pos] == ',':
self.pos = self.pos + 1 self.pos = self.pos + 1
return returnlist return returnlist
def getrouteaddr(self): def getrouteaddr(self):
"""Parse a route address (Return-path value). """Parse a route address (Return-path value).
This method just skips all the route stuff and returns the addrspec. This method just skips all the route stuff and returns the addrspec.
""" """
if self.field[self.pos] != '<': if self.field[self.pos] != '<':
return return
expectroute = 0 expectroute = 0
self.pos = self.pos + 1 self.pos = self.pos + 1
self.gotonext() self.gotonext()
...@@ -609,13 +609,13 @@ class AddrlistClass: ...@@ -609,13 +609,13 @@ class AddrlistClass:
self.pos = self.pos + 1 self.pos = self.pos + 1
break break
self.gotonext() self.gotonext()
return adlist return adlist
def getaddrspec(self): def getaddrspec(self):
"""Parse an RFC-822 addr-spec.""" """Parse an RFC-822 addr-spec."""
aslist = [] aslist = []
self.gotonext() self.gotonext()
while self.pos < len(self.field): while self.pos < len(self.field):
if self.field[self.pos] == '.': if self.field[self.pos] == '.':
...@@ -627,15 +627,15 @@ class AddrlistClass: ...@@ -627,15 +627,15 @@ class AddrlistClass:
break break
else: aslist.append(self.getatom()) else: aslist.append(self.getatom())
self.gotonext() self.gotonext()
if self.pos >= len(self.field) or self.field[self.pos] != '@': if self.pos >= len(self.field) or self.field[self.pos] != '@':
return ''.join(aslist) return ''.join(aslist)
aslist.append('@') aslist.append('@')
self.pos = self.pos + 1 self.pos = self.pos + 1
self.gotonext() self.gotonext()
return ''.join(aslist) + self.getdomain() return ''.join(aslist) + self.getdomain()
def getdomain(self): def getdomain(self):
"""Get the complete domain name from an address.""" """Get the complete domain name from an address."""
sdlist = [] sdlist = []
...@@ -653,23 +653,23 @@ class AddrlistClass: ...@@ -653,23 +653,23 @@ class AddrlistClass:
break break
else: sdlist.append(self.getatom()) else: sdlist.append(self.getatom())
return ''.join(sdlist) return ''.join(sdlist)
def getdelimited(self, beginchar, endchars, allowcomments = 1): def getdelimited(self, beginchar, endchars, allowcomments = 1):
"""Parse a header fragment delimited by special characters. """Parse a header fragment delimited by special characters.
`beginchar' is the start character for the fragment. `beginchar' is the start character for the fragment.
If self is not looking at an instance of `beginchar' then If self is not looking at an instance of `beginchar' then
getdelimited returns the empty string. getdelimited returns the empty string.
`endchars' is a sequence of allowable end-delimiting characters. `endchars' is a sequence of allowable end-delimiting characters.
Parsing stops when one of these is encountered. Parsing stops when one of these is encountered.
If `allowcomments' is non-zero, embedded RFC-822 comments If `allowcomments' is non-zero, embedded RFC-822 comments
are allowed within the parsed fragment. are allowed within the parsed fragment.
""" """
if self.field[self.pos] != beginchar: if self.field[self.pos] != beginchar:
return '' return ''
slist = [''] slist = ['']
quote = 0 quote = 0
self.pos = self.pos + 1 self.pos = self.pos + 1
...@@ -687,42 +687,42 @@ class AddrlistClass: ...@@ -687,42 +687,42 @@ class AddrlistClass:
else: else:
slist.append(self.field[self.pos]) slist.append(self.field[self.pos])
self.pos = self.pos + 1 self.pos = self.pos + 1
return ''.join(slist) return ''.join(slist)
def getquote(self): def getquote(self):
"""Get a quote-delimited fragment from self's field.""" """Get a quote-delimited fragment from self's field."""
return self.getdelimited('"', '"\r', 0) return self.getdelimited('"', '"\r', 0)
def getcomment(self): def getcomment(self):
"""Get a parenthesis-delimited fragment from self's field.""" """Get a parenthesis-delimited fragment from self's field."""
return self.getdelimited('(', ')\r', 1) return self.getdelimited('(', ')\r', 1)
def getdomainliteral(self): def getdomainliteral(self):
"""Parse an RFC-822 domain-literal.""" """Parse an RFC-822 domain-literal."""
return '[%s]' % self.getdelimited('[', ']\r', 0) return '[%s]' % self.getdelimited('[', ']\r', 0)
def getatom(self): def getatom(self):
"""Parse an RFC-822 atom.""" """Parse an RFC-822 atom."""
atomlist = [''] atomlist = ['']
while self.pos < len(self.field): while self.pos < len(self.field):
if self.field[self.pos] in self.atomends: if self.field[self.pos] in self.atomends:
break break
else: atomlist.append(self.field[self.pos]) else: atomlist.append(self.field[self.pos])
self.pos = self.pos + 1 self.pos = self.pos + 1
return ''.join(atomlist) return ''.join(atomlist)
def getphraselist(self): def getphraselist(self):
"""Parse a sequence of RFC-822 phrases. """Parse a sequence of RFC-822 phrases.
A phrase is a sequence of words, which are in turn either A phrase is a sequence of words, which are in turn either
RFC-822 atoms or quoted-strings. Phrases are canonicalized RFC-822 atoms or quoted-strings. Phrases are canonicalized
by squeezing all runs of continuous whitespace into one space. by squeezing all runs of continuous whitespace into one space.
""" """
plist = [] plist = []
while self.pos < len(self.field): while self.pos < len(self.field):
if self.field[self.pos] in self.LWS: if self.field[self.pos] in self.LWS:
self.pos = self.pos + 1 self.pos = self.pos + 1
...@@ -733,7 +733,7 @@ class AddrlistClass: ...@@ -733,7 +733,7 @@ class AddrlistClass:
elif self.field[self.pos] in self.atomends: elif self.field[self.pos] in self.atomends:
break break
else: plist.append(self.getatom()) else: plist.append(self.getatom())
return plist return plist
class AddressList(AddrlistClass): class AddressList(AddrlistClass):
...@@ -807,18 +807,18 @@ _daynames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] ...@@ -807,18 +807,18 @@ _daynames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
# zones. RFC1123 recommends that numeric timezone indicators be used # zones. RFC1123 recommends that numeric timezone indicators be used
# instead of timezone names. # instead of timezone names.
_timezones = {'UT':0, 'UTC':0, 'GMT':0, 'Z':0, _timezones = {'UT':0, 'UTC':0, 'GMT':0, 'Z':0,
'AST': -400, 'ADT': -300, # Atlantic (used in Canada) 'AST': -400, 'ADT': -300, # Atlantic (used in Canada)
'EST': -500, 'EDT': -400, # Eastern 'EST': -500, 'EDT': -400, # Eastern
'CST': -600, 'CDT': -500, # Central 'CST': -600, 'CDT': -500, # Central
'MST': -700, 'MDT': -600, # Mountain 'MST': -700, 'MDT': -600, # Mountain
'PST': -800, 'PDT': -700 # Pacific 'PST': -800, 'PDT': -700 # Pacific
} }
def parsedate_tz(data): def parsedate_tz(data):
"""Convert a date string to a time tuple. """Convert a date string to a time tuple.
Accounts for military timezones. Accounts for military timezones.
""" """
data = data.split() data = data.split()
...@@ -879,9 +879,9 @@ def parsedate_tz(data): ...@@ -879,9 +879,9 @@ def parsedate_tz(data):
if _timezones.has_key(tz): if _timezones.has_key(tz):
tzoffset = _timezones[tz] tzoffset = _timezones[tz]
else: else:
try: try:
tzoffset = int(tz) tzoffset = int(tz)
except ValueError: except ValueError:
pass pass
# Convert a timezone offset into seconds ; -0500 -> -18000 # Convert a timezone offset into seconds ; -0500 -> -18000
if tzoffset: if tzoffset:
...@@ -900,7 +900,7 @@ def parsedate(data): ...@@ -900,7 +900,7 @@ def parsedate(data):
t = parsedate_tz(data) t = parsedate_tz(data)
if type(t) == type( () ): if type(t) == type( () ):
return t[:9] return t[:9]
else: return t else: return t
def mktime_tz(data): def mktime_tz(data):
......
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