Commit b925589f authored by Philip Jenvey's avatar Philip Jenvey

branch for stdlib 2.7.8

parents 7dffd95a f257ab3e
...@@ -84,7 +84,7 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): ...@@ -84,7 +84,7 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
path begins with one of the strings in self.cgi_directories path begins with one of the strings in self.cgi_directories
(and the next character is a '/' or the end of the string). (and the next character is a '/' or the end of the string).
""" """
collapsed_path = _url_collapse_path(self.path) collapsed_path = _url_collapse_path(urllib.unquote(self.path))
dir_sep = collapsed_path.find('/', 1) dir_sep = collapsed_path.find('/', 1)
head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:] head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:]
if head in self.cgi_directories: if head in self.cgi_directories:
......
#!/usr/bin/env python
#
#### ####
# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu> # Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
# #
......
...@@ -22,9 +22,12 @@ charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]') ...@@ -22,9 +22,12 @@ charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]')
starttagopen = re.compile('<[a-zA-Z]') starttagopen = re.compile('<[a-zA-Z]')
piclose = re.compile('>') piclose = re.compile('>')
commentclose = re.compile(r'--\s*>') commentclose = re.compile(r'--\s*>')
tagfind = re.compile('([a-zA-Z][-.a-zA-Z0-9:_]*)(?:\s|/(?!>))*')
# see http://www.w3.org/TR/html5/tokenization.html#tag-open-state # see http://www.w3.org/TR/html5/tokenization.html#tag-open-state
# and http://www.w3.org/TR/html5/tokenization.html#tag-name-state # and http://www.w3.org/TR/html5/tokenization.html#tag-name-state
# note: if you change tagfind/attrfind remember to update locatestarttagend too
tagfind = re.compile('([a-zA-Z][^\t\n\r\f />\x00]*)(?:\s|/(?!>))*')
# this regex is currently unused, but left for backward compatibility
tagfind_tolerant = re.compile('[a-zA-Z][^\t\n\r\f />\x00]*') tagfind_tolerant = re.compile('[a-zA-Z][^\t\n\r\f />\x00]*')
attrfind = re.compile( attrfind = re.compile(
...@@ -32,7 +35,7 @@ attrfind = re.compile( ...@@ -32,7 +35,7 @@ attrfind = re.compile(
r'(\'[^\']*\'|"[^"]*"|(?![\'"])[^>\s]*))?(?:\s|/(?!>))*') r'(\'[^\']*\'|"[^"]*"|(?![\'"])[^>\s]*))?(?:\s|/(?!>))*')
locatestarttagend = re.compile(r""" locatestarttagend = re.compile(r"""
<[a-zA-Z][-.a-zA-Z0-9:_]* # tag name <[a-zA-Z][^\t\n\r\f />\x00]* # tag name
(?:[\s/]* # optional whitespace before attribute name (?:[\s/]* # optional whitespace before attribute name
(?:(?<=['"\s/])[^\s/>][^\s/=>]* # attribute name (?:(?<=['"\s/])[^\s/>][^\s/=>]* # attribute name
(?:\s*=+\s* # value indicator (?:\s*=+\s* # value indicator
...@@ -192,9 +195,9 @@ class HTMLParser(markupbase.ParserBase): ...@@ -192,9 +195,9 @@ class HTMLParser(markupbase.ParserBase):
i = self.updatepos(i, k) i = self.updatepos(i, k)
continue continue
else: else:
if ";" in rawdata[i:]: #bail by consuming &# if ";" in rawdata[i:]: # bail by consuming '&#'
self.handle_data(rawdata[0:2]) self.handle_data(rawdata[i:i+2])
i = self.updatepos(i, 2) i = self.updatepos(i, i+2)
break break
elif startswith('&', i): elif startswith('&', i):
match = entityref.match(rawdata, i) match = entityref.match(rawdata, i)
...@@ -373,14 +376,14 @@ class HTMLParser(markupbase.ParserBase): ...@@ -373,14 +376,14 @@ class HTMLParser(markupbase.ParserBase):
self.handle_data(rawdata[i:gtpos]) self.handle_data(rawdata[i:gtpos])
return gtpos return gtpos
# find the name: w3.org/TR/html5/tokenization.html#tag-name-state # find the name: w3.org/TR/html5/tokenization.html#tag-name-state
namematch = tagfind_tolerant.match(rawdata, i+2) namematch = tagfind.match(rawdata, i+2)
if not namematch: if not namematch:
# w3.org/TR/html5/tokenization.html#end-tag-open-state # w3.org/TR/html5/tokenization.html#end-tag-open-state
if rawdata[i:i+3] == '</>': if rawdata[i:i+3] == '</>':
return i+3 return i+3
else: else:
return self.parse_bogus_comment(i) return self.parse_bogus_comment(i)
tagname = namematch.group().lower() tagname = namematch.group(1).lower()
# consume and ignore other stuff between the name and the > # consume and ignore other stuff between the name and the >
# Note: this is not 100% correct, since we might have things like # Note: this is not 100% correct, since we might have things like
# </tag attr=">">, but looking for > after tha name should cover # </tag attr=">">, but looking for > after tha name should cover
......
...@@ -43,8 +43,10 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): ...@@ -43,8 +43,10 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""Serve a GET request.""" """Serve a GET request."""
f = self.send_head() f = self.send_head()
if f: if f:
self.copyfile(f, self.wfile) try:
f.close() self.copyfile(f, self.wfile)
finally:
f.close()
def do_HEAD(self): def do_HEAD(self):
"""Serve a HEAD request.""" """Serve a HEAD request."""
...@@ -88,13 +90,17 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): ...@@ -88,13 +90,17 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
except IOError: except IOError:
self.send_error(404, "File not found") self.send_error(404, "File not found")
return None return None
self.send_response(200) try:
self.send_header("Content-type", ctype) self.send_response(200)
fs = os.fstat(f.fileno()) self.send_header("Content-type", ctype)
self.send_header("Content-Length", str(fs[6])) fs = os.fstat(f.fileno())
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.send_header("Content-Length", str(fs[6]))
self.end_headers() self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
return f self.end_headers()
return f
except:
f.close()
raise
def list_directory(self, path): def list_directory(self, path):
"""Helper to produce a directory listing (absent index.html). """Helper to produce a directory listing (absent index.html).
......
...@@ -704,4 +704,5 @@ if __name__ == '__main__': ...@@ -704,4 +704,5 @@ if __name__ == '__main__':
server = SimpleXMLRPCServer(("localhost", 8000)) server = SimpleXMLRPCServer(("localhost", 8000))
server.register_function(pow) server.register_function(pow)
server.register_function(lambda x,y: x+y, 'add') server.register_function(lambda x,y: x+y, 'add')
server.register_multicall_functions()
server.serve_forever() server.serve_forever()
...@@ -513,35 +513,37 @@ class ForkingMixIn: ...@@ -513,35 +513,37 @@ class ForkingMixIn:
def collect_children(self): def collect_children(self):
"""Internal routine to wait for children that have exited.""" """Internal routine to wait for children that have exited."""
if self.active_children is None: return if self.active_children is None:
return
# If we're above the max number of children, wait and reap them until
# we go back below threshold. Note that we use waitpid(-1) below to be
# able to collect children in size(<defunct children>) syscalls instead
# of size(<children>): the downside is that this might reap children
# which we didn't spawn, which is why we only resort to this when we're
# above max_children.
while len(self.active_children) >= self.max_children: while len(self.active_children) >= self.max_children:
# XXX: This will wait for any child process, not just ones
# spawned by this library. This could confuse other
# libraries that expect to be able to wait for their own
# children.
try:
pid, status = os.waitpid(0, 0)
except os.error:
pid = None
if pid not in self.active_children: continue
self.active_children.remove(pid)
# XXX: This loop runs more system calls than it ought
# to. There should be a way to put the active_children into a
# process group and then use os.waitpid(-pgid) to wait for any
# of that set, but I couldn't find a way to allocate pgids
# that couldn't collide.
for child in self.active_children:
try: try:
pid, status = os.waitpid(child, os.WNOHANG) pid, _ = os.waitpid(-1, 0)
except os.error: self.active_children.discard(pid)
pid = None except OSError as e:
if not pid: continue if e.errno == errno.ECHILD:
# we don't have any children, we're done
self.active_children.clear()
elif e.errno != errno.EINTR:
break
# Now reap all defunct children.
for pid in self.active_children.copy():
try: try:
self.active_children.remove(pid) pid, _ = os.waitpid(pid, os.WNOHANG)
except ValueError, e: # if the child hasn't exited yet, pid will be 0 and ignored by
raise ValueError('%s. x=%d and list=%r' % (e.message, pid, # discard() below
self.active_children)) self.active_children.discard(pid)
except OSError as e:
if e.errno == errno.ECHILD:
# someone else reaped it
self.active_children.discard(pid)
def handle_timeout(self): def handle_timeout(self):
"""Wait for zombies after self.timeout seconds of inactivity. """Wait for zombies after self.timeout seconds of inactivity.
...@@ -557,8 +559,8 @@ class ForkingMixIn: ...@@ -557,8 +559,8 @@ class ForkingMixIn:
if pid: if pid:
# Parent process # Parent process
if self.active_children is None: if self.active_children is None:
self.active_children = [] self.active_children = set()
self.active_children.append(pid) self.active_children.add(pid)
self.close_request(request) #close handle in parent process self.close_request(request) #close handle in parent process
return return
else: else:
......
...@@ -39,7 +39,7 @@ class MozillaCookieJar(FileCookieJar): ...@@ -39,7 +39,7 @@ class MozillaCookieJar(FileCookieJar):
magic_re = "#( Netscape)? HTTP Cookie File" magic_re = "#( Netscape)? HTTP Cookie File"
header = """\ header = """\
# Netscape HTTP Cookie File # Netscape HTTP Cookie File
# http://www.netscape.com/newsref/std/cookie_spec.html # http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit. # This is a generated file! Do not edit.
""" """
......
...@@ -165,12 +165,17 @@ class Set(Sized, Iterable, Container): ...@@ -165,12 +165,17 @@ class Set(Sized, Iterable, Container):
def __gt__(self, other): def __gt__(self, other):
if not isinstance(other, Set): if not isinstance(other, Set):
return NotImplemented return NotImplemented
return other < self return len(self) > len(other) and self.__ge__(other)
def __ge__(self, other): def __ge__(self, other):
if not isinstance(other, Set): if not isinstance(other, Set):
return NotImplemented return NotImplemented
return other <= self if len(self) < len(other):
return False
for elem in other:
if elem not in self:
return False
return True
def __eq__(self, other): def __eq__(self, other):
if not isinstance(other, Set): if not isinstance(other, Set):
...@@ -194,6 +199,8 @@ class Set(Sized, Iterable, Container): ...@@ -194,6 +199,8 @@ class Set(Sized, Iterable, Container):
return NotImplemented return NotImplemented
return self._from_iterable(value for value in other if value in self) return self._from_iterable(value for value in other if value in self)
__rand__ = __and__
def isdisjoint(self, other): def isdisjoint(self, other):
'Return True if two sets have a null intersection.' 'Return True if two sets have a null intersection.'
for value in other: for value in other:
...@@ -207,6 +214,8 @@ class Set(Sized, Iterable, Container): ...@@ -207,6 +214,8 @@ class Set(Sized, Iterable, Container):
chain = (e for s in (self, other) for e in s) chain = (e for s in (self, other) for e in s)
return self._from_iterable(chain) return self._from_iterable(chain)
__ror__ = __or__
def __sub__(self, other): def __sub__(self, other):
if not isinstance(other, Set): if not isinstance(other, Set):
if not isinstance(other, Iterable): if not isinstance(other, Iterable):
...@@ -215,6 +224,14 @@ class Set(Sized, Iterable, Container): ...@@ -215,6 +224,14 @@ class Set(Sized, Iterable, Container):
return self._from_iterable(value for value in self return self._from_iterable(value for value in self
if value not in other) if value not in other)
def __rsub__(self, other):
if not isinstance(other, Set):
if not isinstance(other, Iterable):
return NotImplemented
other = self._from_iterable(other)
return self._from_iterable(value for value in other
if value not in self)
def __xor__(self, other): def __xor__(self, other):
if not isinstance(other, Set): if not isinstance(other, Set):
if not isinstance(other, Iterable): if not isinstance(other, Iterable):
...@@ -222,6 +239,8 @@ class Set(Sized, Iterable, Container): ...@@ -222,6 +239,8 @@ class Set(Sized, Iterable, Container):
other = self._from_iterable(other) other = self._from_iterable(other)
return (self - other) | (other - self) return (self - other) | (other - self)
__rxor__ = __xor__
# Sets are not hashable by default, but subclasses can change this # Sets are not hashable by default, but subclasses can change this
__hash__ = None __hash__ = None
......
...@@ -182,7 +182,7 @@ def _find_appropriate_compiler(_config_vars): ...@@ -182,7 +182,7 @@ def _find_appropriate_compiler(_config_vars):
# Compiler is GCC, check if it is LLVM-GCC # Compiler is GCC, check if it is LLVM-GCC
data = _read_output("'%s' --version" data = _read_output("'%s' --version"
% (cc.replace("'", "'\"'\"'"),)) % (cc.replace("'", "'\"'\"'"),))
if 'llvm-gcc' in data: if data and 'llvm-gcc' in data:
# Found LLVM-GCC, fall back to clang # Found LLVM-GCC, fall back to clang
cc = _find_build_tool('clang') cc = _find_build_tool('clang')
...@@ -450,8 +450,16 @@ def get_platform_osx(_config_vars, osname, release, machine): ...@@ -450,8 +450,16 @@ def get_platform_osx(_config_vars, osname, release, machine):
# case and disallow installs. # case and disallow installs.
cflags = _config_vars.get(_INITPRE+'CFLAGS', cflags = _config_vars.get(_INITPRE+'CFLAGS',
_config_vars.get('CFLAGS', '')) _config_vars.get('CFLAGS', ''))
if ((macrelease + '.') >= '10.4.' and if macrelease:
'-arch' in cflags.strip()): try:
macrelease = tuple(int(i) for i in macrelease.split('.')[0:2])
except ValueError:
macrelease = (10, 0)
else:
# assume no universal support
macrelease = (10, 0)
if (macrelease >= (10, 4)) and '-arch' in cflags.strip():
# The universal build will build fat binaries, but not on # The universal build will build fat binaries, but not on
# systems before 10.4 # systems before 10.4
......
...@@ -192,38 +192,45 @@ def open(file, mode="r", buffering=-1, ...@@ -192,38 +192,45 @@ def open(file, mode="r", buffering=-1,
(appending and "a" or "") + (appending and "a" or "") +
(updating and "+" or ""), (updating and "+" or ""),
closefd) closefd)
line_buffering = False result = raw
if buffering == 1 or buffering < 0 and raw.isatty(): try:
buffering = -1 line_buffering = False
line_buffering = True if buffering == 1 or buffering < 0 and raw.isatty():
if buffering < 0: buffering = -1
buffering = DEFAULT_BUFFER_SIZE line_buffering = True
try: if buffering < 0:
bs = os.fstat(raw.fileno()).st_blksize buffering = DEFAULT_BUFFER_SIZE
except (os.error, AttributeError): try:
pass bs = os.fstat(raw.fileno()).st_blksize
except (os.error, AttributeError):
pass
else:
if bs > 1:
buffering = bs
if buffering < 0:
raise ValueError("invalid buffering size")
if buffering == 0:
if binary:
return result
raise ValueError("can't have unbuffered text I/O")
if updating:
buffer = BufferedRandom(raw, buffering)
elif writing or appending:
buffer = BufferedWriter(raw, buffering)
elif reading:
buffer = BufferedReader(raw, buffering)
else: else:
if bs > 1: raise ValueError("unknown mode: %r" % mode)
buffering = bs result = buffer
if buffering < 0:
raise ValueError("invalid buffering size")
if buffering == 0:
if binary: if binary:
return raw return result
raise ValueError("can't have unbuffered text I/O") text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
if updating: result = text
buffer = BufferedRandom(raw, buffering) text.mode = mode
elif writing or appending: return result
buffer = BufferedWriter(raw, buffering) except:
elif reading: result.close()
buffer = BufferedReader(raw, buffering) raise
else:
raise ValueError("unknown mode: %r" % mode)
if binary:
return buffer
text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
text.mode = mode
return text
class DocDescriptor: class DocDescriptor:
...@@ -1997,7 +2004,13 @@ class StringIO(TextIOWrapper): ...@@ -1997,7 +2004,13 @@ class StringIO(TextIOWrapper):
def getvalue(self): def getvalue(self):
self.flush() self.flush()
return self.buffer.getvalue().decode(self._encoding, self._errors) decoder = self._decoder or self._get_decoder()
old_state = decoder.getstate()
decoder.reset()
try:
return decoder.decode(self.buffer.getvalue(), final=True)
finally:
decoder.setstate(old_state)
def __repr__(self): def __repr__(self):
# TextIOWrapper tells the encoding in its repr. In StringIO, # TextIOWrapper tells the encoding in its repr. In StringIO,
......
...@@ -60,6 +60,8 @@ class WeakSet(object): ...@@ -60,6 +60,8 @@ class WeakSet(object):
for itemref in self.data: for itemref in self.data:
item = itemref() item = itemref()
if item is not None: if item is not None:
# Caveat: the iterator will keep a strong reference to
# `item` until it is resumed or closed.
yield item yield item
def __len__(self): def __len__(self):
......
...@@ -778,7 +778,7 @@ class Aifc_write: ...@@ -778,7 +778,7 @@ class Aifc_write:
def _ensure_header_written(self, datasize): def _ensure_header_written(self, datasize):
if not self._nframeswritten: if not self._nframeswritten:
if self._comptype in ('ULAW', 'ALAW'): if self._comptype in ('ULAW', 'ulaw', 'ALAW', 'alaw'):
if not self._sampwidth: if not self._sampwidth:
self._sampwidth = 2 self._sampwidth = 2
if self._sampwidth != 2: if self._sampwidth != 2:
...@@ -844,7 +844,7 @@ class Aifc_write: ...@@ -844,7 +844,7 @@ class Aifc_write:
if self._datalength & 1: if self._datalength & 1:
self._datalength = self._datalength + 1 self._datalength = self._datalength + 1
if self._aifc: if self._aifc: