[Python-checkins] CVS: python/dist/src/Lib netrc.py,1.8,1.9 nntplib.py,1.21,1.22 ntpath.py,1.32,1.33 nturl2path.py,1.6,1.7 os.py,1.39,1.40 pdb.py,1.46,1.47 pickle.py,1.41,1.42 pipes.py,1.6,1.7 poplib.py,1.10,1.11 posixfile.py,1.16,1.17 posixpath.py,1.38,1.39 pre.py,1.3,1.4 profile.py,1.24,1.25 pstats.py,1.8,1.9 pty.py,1.5,1.6 pyclbr.py,1.15,1.16 quopri.py,1.8,1.9

Tim Peters python-dev@python.org
Sun, 14 Jan 2001 16:50:55 -0800


Update of /cvsroot/python/python/dist/src/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv3619/python/dist/src/lib

Modified Files:
	netrc.py nntplib.py ntpath.py nturl2path.py os.py pdb.py 
	pickle.py pipes.py poplib.py posixfile.py posixpath.py pre.py 
	profile.py pstats.py pty.py pyclbr.py quopri.py 
Log Message:
Whitespace normalization.


Index: netrc.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/netrc.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -r1.8 -r1.9
*** netrc.py	2000/12/23 14:20:24	1.8
--- netrc.py	2001/01/15 00:50:52	1.9
***************
*** 1,5 ****
  """An object-oriented interface to .netrc files."""
  
! # Module and documentation by Eric S. Raymond, 21 Dec 1998 
  
  import os, shlex
--- 1,5 ----
  """An object-oriented interface to .netrc files."""
  
! # Module and documentation by Eric S. Raymond, 21 Dec 1998
  
  import os, shlex
***************
*** 13,17 ****
          self.macros = {}
          lexer = shlex.shlex(fp)
! 	# Allows @ in hostnames.  Not a big deal...
          lexer.wordchars = lexer.wordchars + '.-@'
          while 1:
--- 13,17 ----
          self.macros = {}
          lexer = shlex.shlex(fp)
!         # Allows @ in hostnames.  Not a big deal...
          lexer.wordchars = lexer.wordchars + '.-@'
          while 1:
***************
*** 24,28 ****
              elif tt == 'default':
                  entryname = 'default'
!             elif tt == 'macdef':		# Just skip to end of macdefs
                  entryname = lexer.get_token()
                  self.macros[entryname] = []
--- 24,28 ----
              elif tt == 'default':
                  entryname = 'default'
!             elif tt == 'macdef':                # Just skip to end of macdefs
                  entryname = lexer.get_token()
                  self.macros[entryname] = []
***************
*** 37,41 ****
              else:
                  raise SyntaxError, "bad toplevel token %s, file %s, line %d" \
!             				% (tt, file, lexer.lineno) 
  
              # We're looking at start of an entry for a named machine or default.
--- 37,41 ----
              else:
                  raise SyntaxError, "bad toplevel token %s, file %s, line %d" \
!                                         % (tt, file, lexer.lineno)
  
              # We're looking at start of an entry for a named machine or default.
***************
*** 88,92 ****
          return rep
  
! if __name__ == '__main__': 
      print netrc()
- 
--- 88,91 ----
          return rep
  
! if __name__ == '__main__':
      print netrc()

Index: nntplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/nntplib.py,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -r1.21 -r1.22
*** nntplib.py	2000/12/12 23:20:45	1.21
--- nntplib.py	2001/01/15 00:50:52	1.22
***************
*** 35,68 ****
  
  
! 
  # Exceptions raised when an error or invalid response is received
  class NNTPError(Exception):
! 	"""Base class for all nntplib exceptions"""
! 	def __init__(self, *args):
! 		apply(Exception.__init__, (self,)+args)
! 		try:
! 			self.response = args[0]
! 		except IndexError:
! 			self.response = 'No response given'
  
  class NNTPReplyError(NNTPError):
! 	"""Unexpected [123]xx reply"""
! 	pass
  
  class NNTPTemporaryError(NNTPError):
! 	"""4xx errors"""
! 	pass
  
  class NNTPPermanentError(NNTPError):
! 	"""5xx errors"""
! 	pass
  
  class NNTPProtocolError(NNTPError):
! 	"""Response does not begin with [1-5]"""
! 	pass
  
  class NNTPDataError(NNTPError):
! 	"""Error in response data"""
! 	pass
  
  # for backwards compatibility
--- 35,68 ----
  
  
! 
  # Exceptions raised when an error or invalid response is received
  class NNTPError(Exception):
!     """Base class for all nntplib exceptions"""
!     def __init__(self, *args):
!         apply(Exception.__init__, (self,)+args)
!         try:
!             self.response = args[0]
!         except IndexError:
!             self.response = 'No response given'
  
  class NNTPReplyError(NNTPError):
!     """Unexpected [123]xx reply"""
!     pass
  
  class NNTPTemporaryError(NNTPError):
!     """4xx errors"""
!     pass
  
  class NNTPPermanentError(NNTPError):
!     """5xx errors"""
!     pass
  
  class NNTPProtocolError(NNTPError):
!     """Response does not begin with [1-5]"""
!     pass
  
  class NNTPDataError(NNTPError):
!     """Error in response data"""
!     pass
  
  # for backwards compatibility
***************
*** 73,78 ****
  error_data = NNTPDataError
  
  
- 
  # Standard port used by NNTP servers
  NNTP_PORT = 119
--- 73,78 ----
  error_data = NNTPDataError
  
+ 
  
  # Standard port used by NNTP servers
  NNTP_PORT = 119
***************
*** 86,535 ****
  CRLF = '\r\n'
  
  
- 
  # The class itself
  class NNTP:
! 	def __init__(self, host, port=NNTP_PORT, user=None, password=None,
! 		     readermode=None):
! 		"""Initialize an instance.  Arguments:
! 		- host: hostname to connect to
! 		- port: port to connect to (default the standard NNTP port)
! 		- user: username to authenticate with
! 		- password: password to use with username
! 		- readermode: if true, send 'mode reader' command after
! 		              connecting.
! 
! 	        readermode is sometimes necessary if you are connecting to an
! 	        NNTP server on the local machine and intend to call
! 	        reader-specific comamnds, such as `group'.  If you get
! 	        unexpected NNTPPermanentErrors, you might need to set
! 	        readermode.
! 		"""
! 		self.host = host
! 		self.port = port
! 		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
! 		self.sock.connect((self.host, self.port))
! 		self.file = self.sock.makefile('rb')
! 		self.debugging = 0
! 		self.welcome = self.getresp()
! 		if readermode:
! 			try:
! 				self.welcome = self.shortcmd('mode reader')
! 			except NNTPPermanentError:
! 				# error 500, probably 'not implemented'
! 				pass
! 		if user:
! 			resp = self.shortcmd('authinfo user '+user)
! 			if resp[:3] == '381':
! 				if not password:
! 					raise NNTPReplyError(resp)
! 				else:
! 					resp = self.shortcmd(
! 						'authinfo pass '+password)
! 					if resp[:3] != '281':
! 						raise NNTPPermanentError(resp)
! 
! 	# Get the welcome message from the server
! 	# (this is read and squirreled away by __init__()).
! 	# If the response code is 200, posting is allowed;
! 	# if it 201, posting is not allowed
! 
! 	def getwelcome(self):
! 		"""Get the welcome message from the server
! 		(this is read and squirreled away by __init__()).
! 		If the response code is 200, posting is allowed;
! 		if it 201, posting is not allowed."""
! 
! 		if self.debugging: print '*welcome*', `self.welcome`
! 		return self.welcome
! 
! 	def set_debuglevel(self, level):
! 		"""Set the debugging level.  Argument 'level' means:
! 		0: no debugging output (default)
! 		1: print commands and responses but not body text etc.
! 		2: also print raw lines read and sent before stripping CR/LF"""
! 
! 		self.debugging = level
! 	debug = set_debuglevel
! 
! 	def putline(self, line):
! 		"""Internal: send one line to the server, appending CRLF."""
! 		line = line + CRLF
! 		if self.debugging > 1: print '*put*', `line`
! 		self.sock.send(line)
! 
! 	def putcmd(self, line):
! 		"""Internal: send one command to the server (through putline())."""
! 		if self.debugging: print '*cmd*', `line`
! 		self.putline(line)
! 
! 	def getline(self):
! 		"""Internal: return one line from the server, stripping CRLF.
! 		Raise EOFError if the connection is closed."""
! 		line = self.file.readline()
! 		if self.debugging > 1:
! 			print '*get*', `line`
! 		if not line: raise EOFError
! 		if line[-2:] == CRLF: line = line[:-2]
! 		elif line[-1:] in CRLF: line = line[:-1]
! 		return line
! 
! 	def getresp(self):
! 		"""Internal: get a response from the server.
! 		Raise various errors if the response indicates an error."""
! 		resp = self.getline()
! 		if self.debugging: print '*resp*', `resp`
! 		c = resp[:1]
! 		if c == '4':
! 			raise NNTPTemporaryError(resp)
! 		if c == '5':
! 			raise NNTPPermanentError(resp)
! 		if c not in '123':
! 			raise NNTPProtocolError(resp)
! 		return resp
! 
! 	def getlongresp(self):
! 		"""Internal: get a response plus following text from the server.
! 		Raise various errors if the response indicates an error."""
! 		resp = self.getresp()
! 		if resp[:3] not in LONGRESP:
! 			raise NNTPReplyError(resp)
! 		list = []
! 		while 1:
! 			line = self.getline()
! 			if line == '.':
! 				break
! 			if line[:2] == '..':
! 				line = line[1:]
! 			list.append(line)
! 		return resp, list
! 
! 	def shortcmd(self, line):
! 		"""Internal: send a command and get the response."""
! 		self.putcmd(line)
! 		return self.getresp()
! 
! 	def longcmd(self, line):
! 		"""Internal: send a command and get the response plus following text."""
! 		self.putcmd(line)
! 		return self.getlongresp()
! 
! 	def newgroups(self, date, time):
! 		"""Process a NEWGROUPS command.  Arguments:
! 		- date: string 'yymmdd' indicating the date
! 		- time: string 'hhmmss' indicating the time
! 		Return:
! 		- resp: server response if successful
! 		- list: list of newsgroup names"""
! 
! 		return self.longcmd('NEWGROUPS ' + date + ' ' + time)
! 
! 	def newnews(self, group, date, time):
! 		"""Process a NEWNEWS command.  Arguments:
! 		- group: group name or '*'
! 		- date: string 'yymmdd' indicating the date
! 		- time: string 'hhmmss' indicating the time
! 		Return:
! 		- resp: server response if successful
! 		- list: list of article ids"""
! 
! 		cmd = 'NEWNEWS ' + group + ' ' + date + ' ' + time
! 		return self.longcmd(cmd)
! 
! 	def list(self):
! 		"""Process a LIST command.  Return:
! 		- resp: server response if successful
! 		- list: list of (group, last, first, flag) (strings)"""
! 
! 		resp, list = self.longcmd('LIST')
! 		for i in range(len(list)):
! 			# Parse lines into "group last first flag"
! 			list[i] = tuple(string.split(list[i]))
! 		return resp, list
! 
! 	def group(self, name):
! 		"""Process a GROUP command.  Argument:
! 		- group: the group name
! 		Returns:
! 		- resp: server response if successful
! 		- count: number of articles (string)
! 		- first: first article number (string)
! 		- last: last article number (string)
! 		- name: the group name"""
! 
! 		resp = self.shortcmd('GROUP ' + name)
! 		if resp[:3] != '211':
! 			raise NNTPReplyError(resp)
! 		words = string.split(resp)
! 		count = first = last = 0
! 		n = len(words)
! 		if n > 1:
! 			count = words[1]
! 			if n > 2:
! 				first = words[2]
! 				if n > 3:
! 					last = words[3]
! 					if n > 4:
! 						name = string.lower(words[4])
! 		return resp, count, first, last, name
! 
! 	def help(self):
! 		"""Process a HELP command.  Returns:
! 		- resp: server response if successful
! 		- list: list of strings"""
! 
! 		return self.longcmd('HELP')
! 
! 	def statparse(self, resp):
! 		"""Internal: parse the response of a STAT, NEXT or LAST command."""
! 		if resp[:2] != '22':
! 			raise NNTPReplyError(resp)
! 		words = string.split(resp)
! 		nr = 0
! 		id = ''
! 		n = len(words)
! 		if n > 1:
! 			nr = words[1]
! 			if n > 2:
! 				id = words[2]
! 		return resp, nr, id
! 
! 	def statcmd(self, line):
! 		"""Internal: process a STAT, NEXT or LAST command."""
! 		resp = self.shortcmd(line)
! 		return self.statparse(resp)
! 
! 	def stat(self, id):
! 		"""Process a STAT command.  Argument:
! 		- id: article number or message id
! 		Returns:
! 		- resp: server response if successful
! 		- nr:   the article number
! 		- id:   the article id"""
! 
! 		return self.statcmd('STAT ' + id)
! 
! 	def next(self):
! 		"""Process a NEXT command.  No arguments.  Return as for STAT."""
! 		return self.statcmd('NEXT')
! 
! 	def last(self):
! 		"""Process a LAST command.  No arguments.  Return as for STAT."""
! 		return self.statcmd('LAST')
! 
! 	def artcmd(self, line):
! 		"""Internal: process a HEAD, BODY or ARTICLE command."""
! 		resp, list = self.longcmd(line)
! 		resp, nr, id = self.statparse(resp)
! 		return resp, nr, id, list
! 
! 	def head(self, id):
! 		"""Process a HEAD command.  Argument:
! 		- id: article number or message id
! 		Returns:
! 		- resp: server response if successful
! 		- nr: article number
! 		- id: message id
! 		- list: the lines of the article's header"""
! 
! 		return self.artcmd('HEAD ' + id)
! 
! 	def body(self, id):
! 		"""Process a BODY command.  Argument:
! 		- id: article number or message id
! 		Returns:
! 		- resp: server response if successful
! 		- nr: article number
! 		- id: message id
! 		- list: the lines of the article's body"""
! 
! 		return self.artcmd('BODY ' + id)
! 
! 	def article(self, id):
! 		"""Process an ARTICLE command.  Argument:
! 		- id: article number or message id
! 		Returns:
! 		- resp: server response if successful
! 		- nr: article number
! 		- id: message id
! 		- list: the lines of the article"""
! 
! 		return self.artcmd('ARTICLE ' + id)
! 
! 	def slave(self):
! 		"""Process a SLAVE command.  Returns:
! 		- resp: server response if successful"""
! 
! 		return self.shortcmd('SLAVE')
! 
! 	def xhdr(self, hdr, str):
! 		"""Process an XHDR command (optional server extension).  Arguments:
! 		- hdr: the header type (e.g. 'subject')
! 		- str: an article nr, a message id, or a range nr1-nr2
! 		Returns:
! 		- resp: server response if successful
! 		- list: list of (nr, value) strings"""
! 
! 		pat = re.compile('^([0-9]+) ?(.*)\n?')
! 		resp, lines = self.longcmd('XHDR ' + hdr + ' ' + str)
! 		for i in range(len(lines)):
! 			line = lines[i]
! 			m = pat.match(line)
! 			if m:
! 				lines[i] = m.group(1, 2)
! 		return resp, lines
! 
! 	def xover(self,start,end):
! 		"""Process an XOVER command (optional server extension) Arguments:
! 		- start: start of range
! 		- end: end of range
! 		Returns:
! 		- resp: server response if successful
! 		- list: list of (art-nr, subject, poster, date,
! 		                 id, references, size, lines)"""
! 
! 		resp, lines = self.longcmd('XOVER ' + start + '-' + end)
! 		xover_lines = []
! 		for line in lines:
! 			elem = string.splitfields(line,"\t")
! 			try:
! 				xover_lines.append((elem[0],
! 						    elem[1],
! 						    elem[2],
! 						    elem[3],
! 						    elem[4],
! 						    string.split(elem[5]),
! 						    elem[6],
! 						    elem[7]))
! 			except IndexError:
! 				raise NNTPDataError(line)
! 		return resp,xover_lines
! 
! 	def xgtitle(self, group):
! 		"""Process an XGTITLE command (optional server extension) Arguments:
! 		- group: group name wildcard (i.e. news.*)
! 		Returns:
! 		- resp: server response if successful
! 		- list: list of (name,title) strings"""
! 
! 		line_pat = re.compile("^([^ \t]+)[ \t]+(.*)$")
! 		resp, raw_lines = self.longcmd('XGTITLE ' + group)
! 		lines = []
! 		for raw_line in raw_lines:
! 			match = line_pat.search(string.strip(raw_line))
! 			if match:
! 				lines.append(match.group(1, 2))
! 		return resp, lines
! 
! 	def xpath(self,id):
! 		"""Process an XPATH command (optional server extension) Arguments:
! 		- id: Message id of article
! 		Returns:
! 		resp: server response if successful
! 		path: directory path to article"""
! 
! 		resp = self.shortcmd("XPATH " + id)
! 		if resp[:3] != '223':
! 			raise NNTPReplyError(resp)
! 		try:
! 			[resp_num, path] = string.split(resp)
! 		except ValueError:
! 			raise NNTPReplyError(resp)
! 		else:
! 			return resp, path
! 
! 	def date (self):
! 		"""Process the DATE command. Arguments:
! 		None
! 		Returns:
! 		resp: server response if successful
! 		date: Date suitable for newnews/newgroups commands etc.
! 		time: Time suitable for newnews/newgroups commands etc."""
! 
! 		resp = self.shortcmd("DATE")
! 		if resp[:3] != '111':
! 			raise NNTPReplyError(resp)
! 		elem = string.split(resp)
! 		if len(elem) != 2:
! 			raise NNTPDataError(resp)
! 		date = elem[1][2:8]
! 		time = elem[1][-6:]
! 		if len(date) != 6 or len(time) != 6:
! 			raise NNTPDataError(resp)
! 		return resp, date, time
! 
! 
! 	def post(self, f):
! 		"""Process a POST command.  Arguments:
! 		- f: file containing the article
! 		Returns:
! 		- resp: server response if successful"""
! 
! 		resp = self.shortcmd('POST')
! 		# Raises error_??? if posting is not allowed
! 		if resp[0] != '3':
! 			raise NNTPReplyError(resp)
! 		while 1:
! 			line = f.readline()
! 			if not line:
! 				break
! 			if line[-1] == '\n':
! 				line = line[:-1]
! 			if line[:1] == '.':
! 				line = '.' + line
! 			self.putline(line)
! 		self.putline('.')
! 		return self.getresp()
! 
! 	def ihave(self, id, f):
! 		"""Process an IHAVE command.  Arguments:
! 		- id: message-id of the article
! 		- f:  file containing the article
! 		Returns:
! 		- resp: server response if successful
! 		Note that if the server refuses the article an exception is raised."""
! 
! 		resp = self.shortcmd('IHAVE ' + id)
! 		# Raises error_??? if the server already has it
! 		if resp[0] != '3':
! 			raise NNTPReplyError(resp)
! 		while 1:
! 			line = f.readline()
! 			if not line:
! 				break
! 			if line[-1] == '\n':
! 				line = line[:-1]
! 			if line[:1] == '.':
! 				line = '.' + line
! 			self.putline(line)
! 		self.putline('.')
! 		return self.getresp()
! 
! 	def quit(self):
! 		"""Process a QUIT command and close the socket.  Returns:
! 		- resp: server response if successful"""
! 
! 		resp = self.shortcmd('QUIT')
! 		self.file.close()
! 		self.sock.close()
! 		del self.file, self.sock
! 		return resp
  
  
  def _test():
! 	"""Minimal test function."""
! 	s = NNTP('news', readermode='reader')
! 	resp, count, first, last, name = s.group('comp.lang.python')
! 	print resp
! 	print 'Group', name, 'has', count, 'articles, range', first, 'to', last
! 	resp, subs = s.xhdr('subject', first + '-' + last)
! 	print resp
! 	for item in subs:
! 		print "%7s %s" % item
! 	resp = s.quit()
! 	print resp
  
  
  # Run the test when run as a script
  if __name__ == '__main__':
! 	_test()
--- 86,535 ----
  CRLF = '\r\n'
  
+ 
  
  # The class itself
  class NNTP:
!     def __init__(self, host, port=NNTP_PORT, user=None, password=None,
!                  readermode=None):
!         """Initialize an instance.  Arguments:
!         - host: hostname to connect to
!         - port: port to connect to (default the standard NNTP port)
!         - user: username to authenticate with
!         - password: password to use with username
!         - readermode: if true, send 'mode reader' command after
!                       connecting.
! 
!         readermode is sometimes necessary if you are connecting to an
!         NNTP server on the local machine and intend to call
!         reader-specific comamnds, such as `group'.  If you get
!         unexpected NNTPPermanentErrors, you might need to set
!         readermode.
!         """
!         self.host = host
!         self.port = port
!         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
!         self.sock.connect((self.host, self.port))
!         self.file = self.sock.makefile('rb')
!         self.debugging = 0
!         self.welcome = self.getresp()
!         if readermode:
!             try:
!                 self.welcome = self.shortcmd('mode reader')
!             except NNTPPermanentError:
!                 # error 500, probably 'not implemented'
!                 pass
!         if user:
!             resp = self.shortcmd('authinfo user '+user)
!             if resp[:3] == '381':
!                 if not password:
!                     raise NNTPReplyError(resp)
!                 else:
!                     resp = self.shortcmd(
!                             'authinfo pass '+password)
!                     if resp[:3] != '281':
!                         raise NNTPPermanentError(resp)
! 
!     # Get the welcome message from the server
!     # (this is read and squirreled away by __init__()).
!     # If the response code is 200, posting is allowed;
!     # if it 201, posting is not allowed
! 
!     def getwelcome(self):
!         """Get the welcome message from the server
!         (this is read and squirreled away by __init__()).
!         If the response code is 200, posting is allowed;
!         if it 201, posting is not allowed."""
! 
!         if self.debugging: print '*welcome*', `self.welcome`
!         return self.welcome
! 
!     def set_debuglevel(self, level):
!         """Set the debugging level.  Argument 'level' means:
!         0: no debugging output (default)
!         1: print commands and responses but not body text etc.
!         2: also print raw lines read and sent before stripping CR/LF"""
! 
!         self.debugging = level
!     debug = set_debuglevel
! 
!     def putline(self, line):
!         """Internal: send one line to the server, appending CRLF."""
!         line = line + CRLF
!         if self.debugging > 1: print '*put*', `line`
!         self.sock.send(line)
! 
!     def putcmd(self, line):
!         """Internal: send one command to the server (through putline())."""
!         if self.debugging: print '*cmd*', `line`
!         self.putline(line)
! 
!     def getline(self):
!         """Internal: return one line from the server, stripping CRLF.
!         Raise EOFError if the connection is closed."""
!         line = self.file.readline()
!         if self.debugging > 1:
!             print '*get*', `line`
!         if not line: raise EOFError
!         if line[-2:] == CRLF: line = line[:-2]
!         elif line[-1:] in CRLF: line = line[:-1]
!         return line
! 
!     def getresp(self):
!         """Internal: get a response from the server.
!         Raise various errors if the response indicates an error."""
!         resp = self.getline()
!         if self.debugging: print '*resp*', `resp`
!         c = resp[:1]
!         if c == '4':
!             raise NNTPTemporaryError(resp)
!         if c == '5':
!             raise NNTPPermanentError(resp)
!         if c not in '123':
!             raise NNTPProtocolError(resp)
!         return resp
! 
!     def getlongresp(self):
!         """Internal: get a response plus following text from the server.
!         Raise various errors if the response indicates an error."""
!         resp = self.getresp()
!         if resp[:3] not in LONGRESP:
!             raise NNTPReplyError(resp)
!         list = []
!         while 1:
!             line = self.getline()
!             if line == '.':
!                 break
!             if line[:2] == '..':
!                 line = line[1:]
!             list.append(line)
!         return resp, list
! 
!     def shortcmd(self, line):
!         """Internal: send a command and get the response."""
!         self.putcmd(line)
!         return self.getresp()
! 
!     def longcmd(self, line):
!         """Internal: send a command and get the response plus following text."""
!         self.putcmd(line)
!         return self.getlongresp()
! 
!     def newgroups(self, date, time):
!         """Process a NEWGROUPS command.  Arguments:
!         - date: string 'yymmdd' indicating the date
!         - time: string 'hhmmss' indicating the time
!         Return:
!         - resp: server response if successful
!         - list: list of newsgroup names"""
! 
!         return self.longcmd('NEWGROUPS ' + date + ' ' + time)
! 
!     def newnews(self, group, date, time):
!         """Process a NEWNEWS command.  Arguments:
!         - group: group name or '*'
!         - date: string 'yymmdd' indicating the date
!         - time: string 'hhmmss' indicating the time
!         Return:
!         - resp: server response if successful
!         - list: list of article ids"""
! 
!         cmd = 'NEWNEWS ' + group + ' ' + date + ' ' + time
!         return self.longcmd(cmd)
! 
!     def list(self):
!         """Process a LIST command.  Return:
!         - resp: server response if successful
!         - list: list of (group, last, first, flag) (strings)"""
! 
!         resp, list = self.longcmd('LIST')
!         for i in range(len(list)):
!             # Parse lines into "group last first flag"
!             list[i] = tuple(string.split(list[i]))
!         return resp, list
! 
!     def group(self, name):
!         """Process a GROUP command.  Argument:
!         - group: the group name
!         Returns:
!         - resp: server response if successful
!         - count: number of articles (string)
!         - first: first article number (string)
!         - last: last article number (string)
!         - name: the group name"""
! 
!         resp = self.shortcmd('GROUP ' + name)
!         if resp[:3] != '211':
!             raise NNTPReplyError(resp)
!         words = string.split(resp)
!         count = first = last = 0
!         n = len(words)
!         if n > 1:
!             count = words[1]
!             if n > 2:
!                 first = words[2]
!                 if n > 3:
!                     last = words[3]
!                     if n > 4:
!                         name = string.lower(words[4])
!         return resp, count, first, last, name
! 
!     def help(self):
!         """Process a HELP command.  Returns:
!         - resp: server response if successful
!         - list: list of strings"""
! 
!         return self.longcmd('HELP')
! 
!     def statparse(self, resp):
!         """Internal: parse the response of a STAT, NEXT or LAST command."""
!         if resp[:2] != '22':
!             raise NNTPReplyError(resp)
!         words = string.split(resp)
!         nr = 0
!         id = ''
!         n = len(words)
!         if n > 1:
!             nr = words[1]
!             if n > 2:
!                 id = words[2]
!         return resp, nr, id
! 
!     def statcmd(self, line):
!         """Internal: process a STAT, NEXT or LAST command."""
!         resp = self.shortcmd(line)
!         return self.statparse(resp)
! 
!     def stat(self, id):
!         """Process a STAT command.  Argument:
!         - id: article number or message id
!         Returns:
!         - resp: server response if successful
!         - nr:   the article number
!         - id:   the article id"""
! 
!         return self.statcmd('STAT ' + id)
! 
!     def next(self):
!         """Process a NEXT command.  No arguments.  Return as for STAT."""
!         return self.statcmd('NEXT')
! 
!     def last(self):
!         """Process a LAST command.  No arguments.  Return as for STAT."""
!         return self.statcmd('LAST')
! 
!     def artcmd(self, line):
!         """Internal: process a HEAD, BODY or ARTICLE command."""
!         resp, list = self.longcmd(line)
!         resp, nr, id = self.statparse(resp)
!         return resp, nr, id, list
! 
!     def head(self, id):
!         """Process a HEAD command.  Argument:
!         - id: article number or message id
!         Returns:
!         - resp: server response if successful
!         - nr: article number
!         - id: message id
!         - list: the lines of the article's header"""
! 
!         return self.artcmd('HEAD ' + id)
! 
!     def body(self, id):
!         """Process a BODY command.  Argument:
!         - id: article number or message id
!         Returns:
!         - resp: server response if successful
!         - nr: article number
!         - id: message id
!         - list: the lines of the article's body"""
! 
!         return self.artcmd('BODY ' + id)
! 
!     def article(self, id):
!         """Process an ARTICLE command.  Argument:
!         - id: article number or message id
!         Returns:
!         - resp: server response if successful
!         - nr: article number
!         - id: message id
!         - list: the lines of the article"""
! 
!         return self.artcmd('ARTICLE ' + id)
! 
!     def slave(self):
!         """Process a SLAVE command.  Returns:
!         - resp: server response if successful"""
! 
!         return self.shortcmd('SLAVE')
! 
!     def xhdr(self, hdr, str):
!         """Process an XHDR command (optional server extension).  Arguments:
!         - hdr: the header type (e.g. 'subject')
!         - str: an article nr, a message id, or a range nr1-nr2
!         Returns:
!         - resp: server response if successful
!         - list: list of (nr, value) strings"""
! 
!         pat = re.compile('^([0-9]+) ?(.*)\n?')
!         resp, lines = self.longcmd('XHDR ' + hdr + ' ' + str)
!         for i in range(len(lines)):
!             line = lines[i]
!             m = pat.match(line)
!             if m:
!                 lines[i] = m.group(1, 2)
!         return resp, lines
! 
!     def xover(self,start,end):
!         """Process an XOVER command (optional server extension) Arguments:
!         - start: start of range
!         - end: end of range
!         Returns:
!         - resp: server response if successful
!         - list: list of (art-nr, subject, poster, date,
!                          id, references, size, lines)"""
! 
!         resp, lines = self.longcmd('XOVER ' + start + '-' + end)
!         xover_lines = []
!         for line in lines:
!             elem = string.splitfields(line,"\t")
!             try:
!                 xover_lines.append((elem[0],
!                                     elem[1],
!                                     elem[2],
!                                     elem[3],
!                                     elem[4],
!                                     string.split(elem[5]),
!                                     elem[6],
!                                     elem[7]))
!             except IndexError:
!                 raise NNTPDataError(line)
!         return resp,xover_lines
! 
!     def xgtitle(self, group):
!         """Process an XGTITLE command (optional server extension) Arguments:
!         - group: group name wildcard (i.e. news.*)
!         Returns:
!         - resp: server response if successful
!         - list: list of (name,title) strings"""
! 
!         line_pat = re.compile("^([^ \t]+)[ \t]+(.*)$")
!         resp, raw_lines = self.longcmd('XGTITLE ' + group)
!         lines = []
!         for raw_line in raw_lines:
!             match = line_pat.search(string.strip(raw_line))
!             if match:
!                 lines.append(match.group(1, 2))
!         return resp, lines
! 
!     def xpath(self,id):
!         """Process an XPATH command (optional server extension) Arguments:
!         - id: Message id of article
!         Returns:
!         resp: server response if successful
!         path: directory path to article"""
! 
!         resp = self.shortcmd("XPATH " + id)
!         if resp[:3] != '223':
!             raise NNTPReplyError(resp)
!         try:
!             [resp_num, path] = string.split(resp)
!         except ValueError:
!             raise NNTPReplyError(resp)
!         else:
!             return resp, path
! 
!     def date (self):
!         """Process the DATE command. Arguments:
!         None
!         Returns:
!         resp: server response if successful
!         date: Date suitable for newnews/newgroups commands etc.
!         time: Time suitable for newnews/newgroups commands etc."""
! 
!         resp = self.shortcmd("DATE")
!         if resp[:3] != '111':
!             raise NNTPReplyError(resp)
!         elem = string.split(resp)
!         if len(elem) != 2:
!             raise NNTPDataError(resp)
!         date = elem[1][2:8]
!         time = elem[1][-6:]
!         if len(date) != 6 or len(time) != 6:
!             raise NNTPDataError(resp)
!         return resp, date, time
! 
! 
!     def post(self, f):
!         """Process a POST command.  Arguments:
!         - f: file containing the article
!         Returns:
!         - resp: server response if successful"""
! 
!         resp = self.shortcmd('POST')
!         # Raises error_??? if posting is not allowed
!         if resp[0] != '3':
!             raise NNTPReplyError(resp)
!         while 1:
!             line = f.readline()
!             if not line:
!                 break
!             if line[-1] == '\n':
!                 line = line[:-1]
!             if line[:1] == '.':
!                 line = '.' + line
!             self.putline(line)
!         self.putline('.')
!         return self.getresp()
! 
!     def ihave(self, id, f):
!         """Process an IHAVE command.  Arguments:
!         - id: message-id of the article
!         - f:  file containing the article
!         Returns:
!         - resp: server response if successful
!         Note that if the server refuses the article an exception is raised."""
! 
!         resp = self.shortcmd('IHAVE ' + id)
!         # Raises error_??? if the server already has it
!         if resp[0] != '3':
!             raise NNTPReplyError(resp)
!         while 1:
!             line = f.readline()
!             if not line:
!                 break
!             if line[-1] == '\n':
!                 line = line[:-1]
!             if line[:1] == '.':
!                 line = '.' + line
!             self.putline(line)
!         self.putline('.')
!         return self.getresp()
! 
!     def quit(self):
!         """Process a QUIT command and close the socket.  Returns:
!         - resp: server response if successful"""
! 
!         resp = self.shortcmd('QUIT')
!         self.file.close()
!         self.sock.close()
!         del self.file, self.sock
!         return resp
  
  
  def _test():
!     """Minimal test function."""
!     s = NNTP('news', readermode='reader')
!     resp, count, first, last, name = s.group('comp.lang.python')
!     print resp
!     print 'Group', name, 'has', count, 'articles, range', first, 'to', last
!     resp, subs = s.xhdr('subject', first + '-' + last)
!     print resp
!     for item in subs:
!         print "%7s %s" % item
!     resp = s.quit()
!     print resp
  
  
  # Run the test when run as a script
  if __name__ == '__main__':
!     _test()

Index: ntpath.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/ntpath.py,v
retrieving revision 1.32
retrieving revision 1.33
diff -C2 -r1.32 -r1.33
*** ntpath.py	2000/12/12 23:20:45	1.32
--- ntpath.py	2001/01/15 00:50:52	1.33
***************
*** 1,4 ****
  # Module 'ntpath' -- common operations on WinNT/Win95 pathnames
! """Common pathname manipulations, WindowsNT/95 version. 
  
  Instead of importing this module directly, import os and refer to this
--- 1,4 ----
  # Module 'ntpath' -- common operations on WinNT/Win95 pathnames
! """Common pathname manipulations, WindowsNT/95 version.
  
  Instead of importing this module directly, import os and refer to this
***************
*** 255,259 ****
      """Directory tree walk whth callback function.
  
!     walk(top, func, arg) calls func(arg, d, files) for each directory d 
      in the tree rooted at top (including top itself); files is a list
      of all the files and subdirs in directory d."""
--- 255,259 ----
      """Directory tree walk whth callback function.
  
!     walk(top, func, arg) calls func(arg, d, files) for each directory d
      in the tree rooted at top (including top itself); files is a list
      of all the files and subdirs in directory d."""
***************
*** 314,318 ****
  # XXX except '^|<>='.
  
! def expandvars(path):  
      """Expand shell variables of form $var and ${var}.
  
--- 314,318 ----
  # XXX except '^|<>='.
  
! def expandvars(path):
      """Expand shell variables of form $var and ${var}.
  

Index: nturl2path.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/nturl2path.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -C2 -r1.6 -r1.7
*** nturl2path.py	2000/05/30 13:25:34	1.6
--- nturl2path.py	2001/01/15 00:50:52	1.7
***************
*** 2,66 ****
  
  def url2pathname(url):
! 	r"""Convert a URL to a DOS path.
  
! 		///C|/foo/bar/spam.foo
  
! 			becomes
  
! 		C:\foo\bar\spam.foo
! 	"""
! 	import string, urllib
! 	if not '|' in url:
! 	    # No drive specifier, just convert slashes
! 	    if url[:4] == '////':
! 	        # path is something like ////host/path/on/remote/host
! 	        # convert this to \\host\path\on\remote\host
! 	        # (notice halving of slashes at the start of the path)
! 	        url = url[2:]
! 	    components = string.split(url, '/')
! 	    # make sure not to convert quoted slashes :-)
! 	    return urllib.unquote(string.join(components, '\\'))
! 	comp = string.split(url, '|')
! 	if len(comp) != 2 or comp[0][-1] not in string.letters:
! 		error = 'Bad URL: ' + url
! 		raise IOError, error
! 	drive = string.upper(comp[0][-1])
! 	components = string.split(comp[1], '/')
! 	path = drive + ':'
! 	for  comp in components:
! 		if comp:
! 			path = path + '\\' + urllib.unquote(comp)
! 	return path
  
  def pathname2url(p):
! 	r"""Convert a DOS path name to a file url.
  
! 		C:\foo\bar\spam.foo
  
! 			becomes
  
! 		///C|/foo/bar/spam.foo
! 	"""
  
! 	import string, urllib
! 	if not ':' in p:
! 	    # No drive specifier, just convert slashes and quote the name
! 	    if p[:2] == '\\\\':
! 	        # path is something like \\host\path\on\remote\host
! 	        # convert this to ////host/path/on/remote/host
! 	        # (notice doubling of slashes at the start of the path)
! 	        p = '\\\\' + p
! 	    components = string.split(p, '\\')
! 	    return urllib.quote(string.join(components, '/'))
! 	comp = string.split(p, ':')
! 	if len(comp) != 2 or len(comp[0]) > 1:
! 		error = 'Bad path: ' + p
! 		raise IOError, error
! 
! 	drive = urllib.quote(string.upper(comp[0]))
! 	components = string.split(comp[1], '\\')
! 	path = '///' + drive + '|'
! 	for comp in components:
! 		if comp:
! 			path = path + '/' + urllib.quote(comp)
! 	return path
--- 2,66 ----
  
  def url2pathname(url):
!     r"""Convert a URL to a DOS path.
  
!             ///C|/foo/bar/spam.foo
  
!                     becomes
  
!             C:\foo\bar\spam.foo
!     """
!     import string, urllib
!     if not '|' in url:
!         # No drive specifier, just convert slashes
!         if url[:4] == '////':
!             # path is something like ////host/path/on/remote/host
!             # convert this to \\host\path\on\remote\host
!             # (notice halving of slashes at the start of the path)
!             url = url[2:]
!         components = string.split(url, '/')
!         # make sure not to convert quoted slashes :-)
!         return urllib.unquote(string.join(components, '\\'))
!     comp = string.split(url, '|')
!     if len(comp) != 2 or comp[0][-1] not in string.letters:
!         error = 'Bad URL: ' + url
!         raise IOError, error
!     drive = string.upper(comp[0][-1])
!     components = string.split(comp[1], '/')
!     path = drive + ':'
!     for  comp in components:
!         if comp:
!             path = path + '\\' + urllib.unquote(comp)
!     return path
  
  def pathname2url(p):
!     r"""Convert a DOS path name to a file url.
  
!             C:\foo\bar\spam.foo
  
!                     becomes
  
!             ///C|/foo/bar/spam.foo
!     """
  
!     import string, urllib
!     if not ':' in p:
!         # No drive specifier, just convert slashes and quote the name
!         if p[:2] == '\\\\':
!         # path is something like \\host\path\on\remote\host
!         # convert this to ////host/path/on/remote/host
!         # (notice doubling of slashes at the start of the path)
!             p = '\\\\' + p
!         components = string.split(p, '\\')
!         return urllib.quote(string.join(components, '/'))
!     comp = string.split(p, ':')
!     if len(comp) != 2 or len(comp[0]) > 1:
!         error = 'Bad path: ' + p
!         raise IOError, error
! 
!     drive = urllib.quote(string.upper(comp[0]))
!     components = string.split(comp[1], '\\')
!     path = '///' + drive + '|'
!     for comp in components:
!         if comp:
!             path = path + '/' + urllib.quote(comp)
!     return path

Index: os.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/os.py,v
retrieving revision 1.39
retrieving revision 1.40
diff -C2 -r1.39 -r1.40
*** os.py	2000/09/28 19:10:56	1.39
--- os.py	2001/01/15 00:50:52	1.40
***************
*** 214,218 ****
      Execute the executable file (which is searched for along $PATH)
      with argument list args and environment env, replacing the current
!     process. """    
      env = args[-1]
      execvpe(file, args[:-1], env)
--- 214,218 ----
      Execute the executable file (which is searched for along $PATH)
      with argument list args and environment env, replacing the current
!     process. """
      env = args[-1]
      execvpe(file, args[:-1], env)
***************
*** 232,236 ****
      with argument list args and environment env , replacing the
      current process.
!     args may be a list or tuple of strings. """    
      _execvpe(file, args, env)
  
--- 232,236 ----
      with argument list args and environment env , replacing the
      current process.
!     args may be a list or tuple of strings. """
      _execvpe(file, args, env)
  
***************
*** 371,375 ****
  If mode == P_NOWAIT return the pid of the process.
  If mode == P_WAIT return the process's exit code if it exits normally;
! otherwise return -SIG, where SIG is the signal that killed it. """   
          return _spawnvef(mode, file, args, None, execv)
  
--- 371,375 ----
  If mode == P_NOWAIT return the pid of the process.
  If mode == P_WAIT return the process's exit code if it exits normally;
! otherwise return -SIG, where SIG is the signal that killed it. """
          return _spawnvef(mode, file, args, None, execv)
  

Index: pdb.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pdb.py,v
retrieving revision 1.46
retrieving revision 1.47
diff -C2 -r1.46 -r1.47
*** pdb.py	2001/01/14 23:29:48	1.46
--- pdb.py	2001/01/15 00:50:52	1.47
***************
*** 15,36 ****
  
  def find_function(funcname, filename):
! 	cre = re.compile(r'def\s+%s\s*[(]' % funcname)
! 	try:
! 		fp = open(filename)
! 	except IOError:
! 		return None
! 	# consumer of this info expects the first line to be 1
! 	lineno = 1
! 	answer = None
[...1826 lines suppressed...]
  
! 	run('execfile(' + `filename` + ')')
--- 928,944 ----
  # When invoked as main program, invoke the debugger on a script
  if __name__=='__main__':
!     if not sys.argv[1:]:
!         print "usage: pdb.py scriptfile [arg] ..."
!         sys.exit(2)
! 
!     mainpyfile = filename = sys.argv[1]     # Get script filename
!     if not os.path.exists(filename):
!         print 'Error:', `filename`, 'does not exist'
!         sys.exit(1)
!     mainmodule = os.path.basename(filename)
!     del sys.argv[0]         # Hide "pdb.py" from argument list
  
!     # Insert script directory in front of module search path
!     sys.path.insert(0, os.path.dirname(filename))
  
!     run('execfile(' + `filename` + ')')

Index: pickle.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pickle.py,v
retrieving revision 1.41
retrieving revision 1.42
diff -C2 -r1.41 -r1.42
*** pickle.py	2000/12/19 01:29:00	1.41
--- pickle.py	2001/01/15 00:50:52	1.42
***************
*** 124,128 ****
  
          return GET + `i` + '\n'
!         
      def save(self, object, pers_save = 0):
          memo = self.memo
--- 124,128 ----
  
          return GET + `i` + '\n'
! 
      def save(self, object, pers_save = 0):
          memo = self.memo
***************
*** 135,139 ****
  
          d = id(object)
!  
          t = type(object)
  
--- 135,139 ----
  
          d = id(object)
! 
          t = type(object)
  
***************
*** 180,184 ****
  
              l = len(tup)
!    
              if ((l != 2) and (l != 3)):
                  raise PicklingError, "tuple returned by %s must contain " \
--- 180,184 ----
  
              l = len(tup)
! 
              if ((l != 2) and (l != 3)):
                  raise PicklingError, "tuple returned by %s must contain " \
***************
*** 187,191 ****
              callable = tup[0]
              arg_tup  = tup[1]
!           
              if (l > 2):
                  state = tup[2]
--- 187,191 ----
              callable = tup[0]
              arg_tup  = tup[1]
! 
              if (l > 2):
                  state = tup[2]
***************
*** 197,201 ****
                                       "by %s must be a tuple" % reduce
  
!             self.save_reduce(callable, arg_tup, state) 
              memo_len = len(memo)
              self.write(self.put(memo_len))
--- 197,201 ----
                                       "by %s must be a tuple" % reduce
  
!             self.save_reduce(callable, arg_tup, state)
              memo_len = len(memo)
              self.write(self.put(memo_len))
***************
*** 225,229 ****
          save(arg_tup)
          write(REDUCE)
!         
          if (state is not None):
              save(state)
--- 225,229 ----
          save(arg_tup)
          write(REDUCE)
! 
          if (state is not None):
              save(state)
***************
*** 318,322 ****
                  write(POP_MARK + self.get(memo[d][0]))
                  return
!            
              write(POP * (len(object) + 1) + self.get(memo[d][0]))
              return
--- 318,322 ----
                  write(POP_MARK + self.get(memo[d][0]))
                  return
! 
              write(POP * (len(object) + 1) + self.get(memo[d][0]))
              return
***************
*** 353,357 ****
          for element in object:
              save(element)
!   
              if (not using_appends):
                  write(APPEND)
--- 353,357 ----
          for element in object:
              save(element)
! 
              if (not using_appends):
                  write(APPEND)
***************
*** 543,547 ****
      def load_binpersid(self):
          stack = self.stack
!          
          pid = stack[-1]
          del stack[-1]
--- 543,547 ----
      def load_binpersid(self):
          stack = self.stack
! 
          pid = stack[-1]
          del stack[-1]
***************
*** 569,573 ****
          self.append(mloads('i' + self.read(2) + '\000\000'))
      dispatch[BININT2] = load_binint2
!  
      def load_long(self):
          self.append(long(self.readline()[:-1], 0))
--- 569,573 ----
          self.append(mloads('i' + self.read(2) + '\000\000'))
      dispatch[BININT2] = load_binint2
! 
      def load_long(self):
          self.append(long(self.readline()[:-1], 0))
***************
*** 711,715 ****
          klass = stack[k + 1]
          del stack[k + 1]
!         args = tuple(stack[k + 1:]) 
          del stack[k:]
          instantiated = 0
--- 711,715 ----
          klass = stack[k + 1]
          del stack[k + 1]
!         args = tuple(stack[k + 1:])
          del stack[k:]
          instantiated = 0
***************
*** 727,731 ****
              value = apply(klass, args)
          self.append(value)
!     dispatch[OBJ] = load_obj                
  
      def load_global(self):
--- 727,731 ----
              value = apply(klass, args)
          self.append(value)
!     dispatch[OBJ] = load_obj
  
      def load_global(self):
***************
*** 762,767 ****
  
                  if (not safe):
!                    raise UnpicklingError, "%s is not safe for " \
!                                           "unpickling" % callable
  
          if arg_tup is None:
--- 762,767 ----
  
                  if (not safe):
!                     raise UnpicklingError, "%s is not safe for " \
!                                            "unpickling" % callable
  
          if arg_tup is None:
***************
*** 830,834 ****
          del stack[mark:]
      dispatch[APPENDS] = load_appends
!            
      def load_setitem(self):
          stack = self.stack
--- 830,834 ----
          del stack[mark:]
      dispatch[APPENDS] = load_appends
! 
      def load_setitem(self):
          stack = self.stack

Index: pipes.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pipes.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -C2 -r1.6 -r1.7
*** pipes.py	2000/12/12 23:20:45	1.6
--- pipes.py	2001/01/15 00:50:52	1.7
***************
*** 70,284 ****
  # Conversion step kinds
  
! FILEIN_FILEOUT = 'ff'			# Must read & write real files
! STDIN_FILEOUT  = '-f'			# Must write a real file
! FILEIN_STDOUT  = 'f-'			# Must read a real file
! STDIN_STDOUT   = '--'			# Normal pipeline element
! SOURCE         = '.-'			# Must be first, writes stdout
! SINK           = '-.'			# Must be last, reads stdin
  
  stepkinds = [FILEIN_FILEOUT, STDIN_FILEOUT, FILEIN_STDOUT, STDIN_STDOUT, \
! 	     SOURCE, SINK]
  
  
  class Template:
! 	"""Class representing a pipeline template."""
  
! 	def __init__(self):
! 		"""Template() returns a fresh pipeline template."""
! 		self.debugging = 0
! 		self.reset()
! 
! 	def __repr__(self):
! 		"""t.__repr__() implements `t`."""
! 		return '<Template instance, steps=' + `self.steps` + '>'
! 
! 	def reset(self):
! 		"""t.reset() restores a pipeline template to its initial state."""
! 		self.steps = []
! 
! 	def clone(self):
! 		"""t.clone() returns a new pipeline template with identical
! 		initial state as the current one."""
! 		t = Template()
! 		t.steps = self.steps[:]
! 		t.debugging = self.debugging
! 		return t
! 
! 	def debug(self, flag):
! 		"""t.debug(flag) turns debugging on or off."""
! 		self.debugging = flag
! 
! 	def append(self, cmd, kind):
! 		"""t.append(cmd, kind) adds a new step at the end."""
! 		if type(cmd) is not type(''):
! 			raise TypeError, \
! 			      'Template.append: cmd must be a string'
! 		if kind not in stepkinds:
! 			raise ValueError, \
! 			      'Template.append: bad kind ' + `kind`
! 		if kind == SOURCE:
! 			raise ValueError, \
! 			      'Template.append: SOURCE can only be prepended'
! 		if self.steps and self.steps[-1][1] == SINK:
! 			raise ValueError, \
! 			      'Template.append: already ends with SINK'
! 		if kind[0] == 'f' and not re.search('\$IN\b', cmd):
! 			raise ValueError, \
! 			      'Template.append: missing $IN in cmd'
! 		if kind[1] == 'f' and not re.search('\$OUT\b', cmd):
! 			raise ValueError, \
! 			      'Template.append: missing $OUT in cmd'
! 		self.steps.append((cmd, kind))
! 
! 	def prepend(self, cmd, kind):
! 		"""t.prepend(cmd, kind) adds a new step at the front."""
! 		if type(cmd) is not type(''):
! 			raise TypeError, \
! 			      'Template.prepend: cmd must be a string'
! 		if kind not in stepkinds:
! 			raise ValueError, \
! 			      'Template.prepend: bad kind ' + `kind`
! 		if kind == SINK:
! 			raise ValueError, \
! 			      'Template.prepend: SINK can only be appended'
! 		if self.steps and self.steps[0][1] == SOURCE:
! 			raise ValueError, \
! 			      'Template.prepend: already begins with SOURCE'
! 		if kind[0] == 'f' and not re.search('\$IN\b', cmd):
! 			raise ValueError, \
! 			      'Template.prepend: missing $IN in cmd'
! 		if kind[1] == 'f' and not re.search('\$OUT\b', cmd):
! 			raise ValueError, \
! 			      'Template.prepend: missing $OUT in cmd'
! 		self.steps.insert(0, (cmd, kind))
! 
! 	def open(self, file, rw):
! 		"""t.open(file, rw) returns a pipe or file object open for
! 		reading or writing; the file is the other end of the pipeline."""
! 		if rw == 'r':
! 			return self.open_r(file)
! 		if rw == 'w':
! 			return self.open_w(file)
! 		raise ValueError, \
! 		      'Template.open: rw must be \'r\' or \'w\', not ' + `rw`
! 
! 	def open_r(self, file):
! 		"""t.open_r(file) and t.open_w(file) implement
! 		t.open(file, 'r') and t.open(file, 'w') respectively."""
! 		if not self.steps:
! 			return open(file, 'r')
! 		if self.steps[-1][1] == SINK:
! 			raise ValueError, \
! 			      'Template.open_r: pipeline ends width SINK'
! 		cmd = self.makepipeline(file, '')
! 		return os.popen(cmd, 'r')
! 
! 	def open_w(self, file):
! 		if not self.steps:
! 			return open(file, 'w')
! 		if self.steps[0][1] == SOURCE:
! 			raise ValueError, \
! 			      'Template.open_w: pipeline begins with SOURCE'
! 		cmd = self.makepipeline('', file)
! 		return os.popen(cmd, 'w')
! 
! 	def copy(self, infile, outfile):
! 		return os.system(self.makepipeline(infile, outfile))
! 
! 	def makepipeline(self, infile, outfile):
! 		cmd = makepipeline(infile, self.steps, outfile)
! 		if self.debugging:
! 			print cmd
! 			cmd = 'set -x; ' + cmd
! 		return cmd
  
  
  def makepipeline(infile, steps, outfile):
! 	# Build a list with for each command:
! 	# [input filename or '', command string, kind, output filename or '']
! 	
! 	list = []
! 	for cmd, kind in steps:
! 		list.append(['', cmd, kind, ''])
! 	#
! 	# Make sure there is at least one step
! 	#
! 	if not list:
! 		list.append(['', 'cat', '--', ''])
! 	#
! 	# Take care of the input and output ends
! 	#
! 	[cmd, kind] = list[0][1:3]
! 	if kind[0] == 'f' and not infile:
! 		list.insert(0, ['', 'cat', '--', ''])
! 	list[0][0] = infile
! 	#
! 	[cmd, kind] = list[-1][1:3]
! 	if kind[1] == 'f' and not outfile:
! 		list.append(['', 'cat', '--', ''])
! 	list[-1][-1] = outfile
! 	#
! 	# Invent temporary files to connect stages that need files
! 	#
! 	garbage = []
! 	for i in range(1, len(list)):
! 		lkind = list[i-1][2]
! 		rkind = list[i][2]
! 		if lkind[1] == 'f' or rkind[0] == 'f':
! 			temp = tempfile.mktemp()
! 			garbage.append(temp)
! 			list[i-1][-1] = list[i][0] = temp
! 	#
! 	for item in list:
! 		[inf, cmd, kind, outf] = item
! 		if kind[1] == 'f':
! 			cmd = 'OUT=' + quote(outf) + '; ' + cmd
! 		if kind[0] == 'f':
! 			cmd = 'IN=' + quote(inf) + '; ' + cmd
! 		if kind[0] == '-' and inf:
! 			cmd = cmd + ' <' + quote(inf)
! 		if kind[1] == '-' and outf:
! 			cmd = cmd + ' >' + quote(outf)
! 		item[1] = cmd
! 	#
! 	cmdlist = list[0][1]
! 	for item in list[1:]:
! 		[cmd, kind] = item[1:3]
! 		if item[0] == '':
! 			if 'f' in kind:
! 				cmd = '{ ' + cmd + '; }'
! 			cmdlist = cmdlist + ' |\n' + cmd
! 		else:
! 			cmdlist = cmdlist + '\n' + cmd
! 	#
! 	if garbage:
! 		rmcmd = 'rm -f'
! 		for file in garbage:
! 			rmcmd = rmcmd + ' ' + quote(file)
! 		trapcmd = 'trap ' + quote(rmcmd + '; exit') + ' 1 2 3 13 14 15'
! 		cmdlist = trapcmd + '\n' + cmdlist + '\n' + rmcmd
! 	#
! 	return cmdlist
  
  
  # Reliably quote a string as a single argument for /bin/sh
  
! _safechars = string.letters + string.digits + '!@%_-+=:,./'	# Safe unquoted
! _funnychars = '"`$\\'				# Unsafe inside "double quotes"
  
  def quote(file):
! 	for c in file:
! 		if c not in _safechars:
! 			break
! 	else:
! 		return file
! 	if '\'' not in file:
! 		return '\'' + file + '\''
! 	res = ''
! 	for c in file:
! 		if c in _funnychars:
! 			c = '\\' + c
! 		res = res + c
! 	return '"' + res + '"'
  
  
--- 70,284 ----
  # Conversion step kinds
  
! FILEIN_FILEOUT = 'ff'                   # Must read & write real files
! STDIN_FILEOUT  = '-f'                   # Must write a real file
! FILEIN_STDOUT  = 'f-'                   # Must read a real file
! STDIN_STDOUT   = '--'                   # Normal pipeline element
! SOURCE         = '.-'                   # Must be first, writes stdout
! SINK           = '-.'                   # Must be last, reads stdin
  
  stepkinds = [FILEIN_FILEOUT, STDIN_FILEOUT, FILEIN_STDOUT, STDIN_STDOUT, \
!              SOURCE, SINK]
  
  
  class Template:
!     """Class representing a pipeline template."""
  
!     def __init__(self):
!         """Template() returns a fresh pipeline template."""
!         self.debugging = 0
!         self.reset()
! 
!     def __repr__(self):
!         """t.__repr__() implements `t`."""
!         return '<Template instance, steps=' + `self.steps` + '>'
! 
!     def reset(self):
!         """t.reset() restores a pipeline template to its initial state."""
!         self.steps = []
! 
!     def clone(self):
!         """t.clone() returns a new pipeline template with identical
!         initial state as the current one."""
!         t = Template()
!         t.steps = self.steps[:]
!         t.debugging = self.debugging
!         return t
! 
!     def debug(self, flag):
!         """t.debug(flag) turns debugging on or off."""
!         self.debugging = flag
! 
!     def append(self, cmd, kind):
!         """t.append(cmd, kind) adds a new step at the end."""
!         if type(cmd) is not type(''):
!             raise TypeError, \
!                   'Template.append: cmd must be a string'
!         if kind not in stepkinds:
!             raise ValueError, \
!                   'Template.append: bad kind ' + `kind`
!         if kind == SOURCE:
!             raise ValueError, \
!                   'Template.append: SOURCE can only be prepended'
!         if self.steps and self.steps[-1][1] == SINK:
!             raise ValueError, \
!                   'Template.append: already ends with SINK'
!         if kind[0] == 'f' and not re.search('\$IN\b', cmd):
!             raise ValueError, \
!                   'Template.append: missing $IN in cmd'
!         if kind[1] == 'f' and not re.search('\$OUT\b', cmd):
!             raise ValueError, \
!                   'Template.append: missing $OUT in cmd'
!         self.steps.append((cmd, kind))
! 
!     def prepend(self, cmd, kind):
!         """t.prepend(cmd, kind) adds a new step at the front."""
!         if type(cmd) is not type(''):
!             raise TypeError, \
!                   'Template.prepend: cmd must be a string'
!         if kind not in stepkinds:
!             raise ValueError, \
!                   'Template.prepend: bad kind ' + `kind`
!         if kind == SINK:
!             raise ValueError, \
!                   'Template.prepend: SINK can only be appended'
!         if self.steps and self.steps[0][1] == SOURCE:
!             raise ValueError, \
!                   'Template.prepend: already begins with SOURCE'
!         if kind[0] == 'f' and not re.search('\$IN\b', cmd):
!             raise ValueError, \
!                   'Template.prepend: missing $IN in cmd'
!         if kind[1] == 'f' and not re.search('\$OUT\b', cmd):
!             raise ValueError, \
!                   'Template.prepend: missing $OUT in cmd'
!         self.steps.insert(0, (cmd, kind))
! 
!     def open(self, file, rw):
!         """t.open(file, rw) returns a pipe or file object open for
!         reading or writing; the file is the other end of the pipeline."""
!         if rw == 'r':
!             return self.open_r(file)
!         if rw == 'w':
!             return self.open_w(file)
!         raise ValueError, \
!               'Template.open: rw must be \'r\' or \'w\', not ' + `rw`
! 
!     def open_r(self, file):
!         """t.open_r(file) and t.open_w(file) implement
!         t.open(file, 'r') and t.open(file, 'w') respectively."""
!         if not self.steps:
!             return open(file, 'r')
!         if self.steps[-1][1] == SINK:
!             raise ValueError, \
!                   'Template.open_r: pipeline ends width SINK'
!         cmd = self.makepipeline(file, '')
!         return os.popen(cmd, 'r')
! 
!     def open_w(self, file):
!         if not self.steps:
!             return open(file, 'w')
!         if self.steps[0][1] == SOURCE:
!             raise ValueError, \
!                   'Template.open_w: pipeline begins with SOURCE'
!         cmd = self.makepipeline('', file)
!         return os.popen(cmd, 'w')
! 
!     def copy(self, infile, outfile):
!         return os.system(self.makepipeline(infile, outfile))
! 
!     def makepipeline(self, infile, outfile):
!         cmd = makepipeline(infile, self.steps, outfile)
!         if self.debugging:
!             print cmd
!             cmd = 'set -x; ' + cmd
!         return cmd
  
  
  def makepipeline(infile, steps, outfile):
!     # Build a list with for each command:
!     # [input filename or '', command string, kind, output filename or '']
  
+     list = []
+     for cmd, kind in steps:
+         list.append(['', cmd, kind, ''])
+     #
+     # Make sure there is at least one step
+     #
+     if not list:
+         list.append(['', 'cat', '--', ''])
+     #
+     # Take care of the input and output ends
+     #
+     [cmd, kind] = list[0][1:3]
+     if kind[0] == 'f' and not infile:
+         list.insert(0, ['', 'cat', '--', ''])
+     list[0][0] = infile
+     #
+     [cmd, kind] = list[-1][1:3]
+     if kind[1] == 'f' and not outfile:
+         list.append(['', 'cat', '--', ''])
+     list[-1][-1] = outfile
+     #
+     # Invent temporary files to connect stages that need files
+     #
+     garbage = []
+     for i in range(1, len(list)):
+         lkind = list[i-1][2]
+         rkind = list[i][2]
+         if lkind[1] == 'f' or rkind[0] == 'f':
+             temp = tempfile.mktemp()
+             garbage.append(temp)
+             list[i-1][-1] = list[i][0] = temp
+     #
+     for item in list:
+         [inf, cmd, kind, outf] = item
+         if kind[1] == 'f':
+             cmd = 'OUT=' + quote(outf) + '; ' + cmd
+         if kind[0] == 'f':
+             cmd = 'IN=' + quote(inf) + '; ' + cmd
+         if kind[0] == '-' and inf:
+             cmd = cmd + ' <' + quote(inf)
+         if kind[1] == '-' and outf:
+             cmd = cmd + ' >' + quote(outf)
+         item[1] = cmd
+     #
+     cmdlist = list[0][1]
+     for item in list[1:]:
+         [cmd, kind] = item[1:3]
+         if item[0] == '':
+             if 'f' in kind:
+                 cmd = '{ ' + cmd + '; }'
+             cmdlist = cmdlist + ' |\n' + cmd
+         else:
+             cmdlist = cmdlist + '\n' + cmd
+     #
+     if garbage:
+         rmcmd = 'rm -f'
+         for file in garbage:
+             rmcmd = rmcmd + ' ' + quote(file)
+         trapcmd = 'trap ' + quote(rmcmd + '; exit') + ' 1 2 3 13 14 15'
+         cmdlist = trapcmd + '\n' + cmdlist + '\n' + rmcmd
+     #
+     return cmdlist
  
+ 
  # Reliably quote a string as a single argument for /bin/sh
  
! _safechars = string.letters + string.digits + '!@%_-+=:,./'     # Safe unquoted
! _funnychars = '"`$\\'                           # Unsafe inside "double quotes"
  
  def quote(file):
!     for c in file:
!         if c not in _safechars:
!             break
!     else:
!         return file
!     if '\'' not in file:
!         return '\'' + file + '\''
!     res = ''
!     for c in file:
!         if c in _funnychars:
!             c = '\\' + c
!         res = res + c
!     return '"' + res + '"'
  
  
***************
*** 286,297 ****
  
  def test():
! 	print 'Testing...'
! 	t = Template()
! 	t.append('togif $IN $OUT', 'ff')
! 	t.append('giftoppm', '--')
! 	t.append('ppmtogif >$OUT', '-f')
! 	t.append('fromgif $IN $OUT', 'ff')
! 	t.debug(1)
! 	FILE = '/usr/local/images/rgb/rogues/guido.rgb'
! 	t.copy(FILE, '@temp')
! 	print 'Done.'
--- 286,297 ----
  
  def test():
!     print 'Testing...'
!     t = Template()
!     t.append('togif $IN $OUT', 'ff')
!     t.append('giftoppm', '--')
!     t.append('ppmtogif >$OUT', '-f')
!     t.append('fromgif $IN $OUT', 'ff')
!     t.debug(1)
!     FILE = '/usr/local/images/rgb/rogues/guido.rgb'
!     t.copy(FILE, '@temp')
!     print 'Done.'

Index: poplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/poplib.py,v
retrieving revision 1.10
retrieving revision 1.11
diff -C2 -r1.10 -r1.11
*** poplib.py	2000/07/16 12:04:30	1.10
--- poplib.py	2001/01/15 00:50:52	1.11
***************
*** 33,321 ****
  class POP3:
  
! 	"""This class supports both the minimal and optional command sets.
! 	Arguments can be strings or integers (where appropriate)
! 	(e.g.: retr(1) and retr('1') both work equally well.
  
! 	Minimal Command Set:
! 		USER name		user(name)
! 		PASS string		pass_(string)
! 		STAT			stat()
! 		LIST [msg]		list(msg = None)
! 		RETR msg		retr(msg)
! 		DELE msg		dele(msg)
! 		NOOP			noop()
! 		RSET			rset()
! 		QUIT			quit()
  
! 	Optional Commands (some servers support these):
! 		RPOP name		rpop(name)
! 		APOP name digest	apop(name, digest)
! 		TOP msg n		top(msg, n)
! 		UIDL [msg]		uidl(msg = None)
  
! 	Raises one exception: 'error_proto'.
  
! 	Instantiate with:
! 		POP3(hostname, port=110)
  
! 	NB:	the POP protocol locks the mailbox from user
! 		authorization until QUIT, so be sure to get in, suck
! 		the messages, and quit, each time you access the
! 		mailbox.
  
! 		POP is a line-based protocol, which means large mail
! 		messages consume lots of python cycles reading them
! 		line-by-line.
  
! 		If it's available on your mail server, use IMAP4
! 		instead, it doesn't suffer from the two problems
! 		above.
! 	"""
  
  
! 	def __init__(self, host, port = POP3_PORT):
! 		self.host = host
! 		self.port = port
! 		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
! 		self.sock.connect((self.host, self.port))
! 		self.file = self.sock.makefile('rb')
! 		self._debugging = 0
! 		self.welcome = self._getresp()
  
  
! 	def _putline(self, line):
! 		#if self._debugging > 1: print '*put*', `line`
! 		self.sock.send('%s%s' % (line, CRLF))
  
  
! 	# Internal: send one command to the server (through _putline())
  
! 	def _putcmd(self, line):
! 		#if self._debugging: print '*cmd*', `line`
! 		self._putline(line)
  
  
! 	# Internal: return one line from the server, stripping CRLF.
! 	# This is where all the CPU time of this module is consumed.
! 	# Raise error_proto('-ERR EOF') if the connection is closed.
  
! 	def _getline(self):
! 		line = self.file.readline()
! 		#if self._debugging > 1: print '*get*', `line`
! 		if not line: raise error_proto('-ERR EOF')
! 		octets = len(line)
! 		# server can send any combination of CR & LF
! 		# however, 'readline()' returns lines ending in LF
! 		# so only possibilities are ...LF, ...CRLF, CR...LF
! 		if line[-2:] == CRLF:
! 			return line[:-2], octets
! 		if line[0] == CR:
! 			return line[1:-1], octets
! 		return line[:-1], octets
  
  
! 	# Internal: get a response from the server.
! 	# Raise 'error_proto' if the response doesn't start with '+'.
  
! 	def _getresp(self):
! 		resp, o = self._getline()
! 		#if self._debugging > 1: print '*resp*', `resp`
! 		c = resp[:1]
! 		if c != '+':
! 			raise error_proto(resp)
! 		return resp
  
  
! 	# Internal: get a response plus following text from the server.
  
! 	def _getlongresp(self):
! 		resp = self._getresp()
! 		list = []; octets = 0
! 		line, o = self._getline()
! 		while line != '.':
! 			if line[:2] == '..':
! 				o = o-1
! 				line = line[1:]
! 			octets = octets + o
! 			list.append(line)
! 			line, o = self._getline()
! 		return resp, list, octets
  
  
! 	# Internal: send a command and get the response
  
! 	def _shortcmd(self, line):
! 		self._putcmd(line)
! 		return self._getresp()
  
  
! 	# Internal: send a command and get the response plus following text
  
! 	def _longcmd(self, line):
! 		self._putcmd(line)
! 		return self._getlongresp()
  
  
! 	# These can be useful:
  
! 	def getwelcome(self): 
! 		return self.welcome
  
  
! 	def set_debuglevel(self, level):
! 		self._debugging = level
  
  
! 	# Here are all the POP commands:
  
! 	def user(self, user):
! 		"""Send user name, return response
! 		
! 		(should indicate password required).
! 		"""
! 		return self._shortcmd('USER %s' % user)
  
  
- 	def pass_(self, pswd):
- 		"""Send password, return response
- 		
- 		(response includes message count, mailbox size).
  
! 		NB: mailbox is locked by server from here to 'quit()'
! 		"""
! 		return self._shortcmd('PASS %s' % pswd)
  
  
! 	def stat(self):
! 		"""Get mailbox status.
! 		
! 		Result is tuple of 2 ints (message count, mailbox size)
! 		"""
! 		retval = self._shortcmd('STAT')
! 		rets = string.split(retval)
! 		#if self._debugging: print '*stat*', `rets`
! 		numMessages = string.atoi(rets[1])
! 		sizeMessages = string.atoi(rets[2])
! 		return (numMessages, sizeMessages)
  
  
! 	def list(self, which=None):
! 		"""Request listing, return result.
  
! 		Result without a message number argument is in form
! 		['response', ['mesg_num octets', ...]].
  
- 		Result when a message number argument is given is a
- 		single response: the "scan listing" for that message.
- 		"""
- 		if which:
- 			return self._shortcmd('LIST %s' % which)
- 		return self._longcmd('LIST')
  
  
! 	def retr(self, which):
! 		"""Retrieve whole message number 'which'.
  
! 		Result is in form ['response', ['line', ...], octets].
! 		"""
! 		return self._longcmd('RETR %s' % which)
  
  
! 	def dele(self, which):
! 		"""Delete message number 'which'.
  
! 		Result is 'response'.
! 		"""
! 		return self._shortcmd('DELE %s' % which)
  
  
! 	def noop(self):
! 		"""Does nothing.
! 		
! 		One supposes the response indicates the server is alive.
! 		"""
! 		return self._shortcmd('NOOP')
  
  
- 	def rset(self):
- 		"""Not sure what this does."""
- 		return self._shortcmd('RSET')
  
  
! 	def quit(self):
! 		"""Signoff: commit changes on server, unlock mailbox, close connection."""
! 		try:
! 			resp = self._shortcmd('QUIT')
! 		except error_proto, val:
! 			resp = val
! 		self.file.close()
! 		self.sock.close()
! 		del self.file, self.sock
! 		return resp
  
- 	#__del__ = quit
  
  
- 	# optional commands:
  
! 	def rpop(self, user):
! 		"""Not sure what this does."""
! 		return self._shortcmd('RPOP %s' % user)
  
  
- 	timestamp = regex.compile('\+OK.*\(<[^>]+>\)')
  
! 	def apop(self, user, secret):
! 		"""Authorisation
! 		
! 		- only possible if server has supplied a timestamp in initial greeting.
  
! 		Args:
! 			user	- mailbox user;
! 			secret	- secret shared between client and server.
  
- 		NB: mailbox is locked by server from here to 'quit()'
- 		"""
- 		if self.timestamp.match(self.welcome) <= 0:
- 			raise error_proto('-ERR APOP not supported by server')
- 		import md5
- 		digest = md5.new(self.timestamp.group(1)+secret).digest()
- 		digest = string.join(map(lambda x:'%02x'%ord(x), digest), '')
- 		return self._shortcmd('APOP %s %s' % (user, digest))
  
  
! 	def top(self, which, howmuch):
! 		"""Retrieve message header of message number 'which'
! 		and first 'howmuch' lines of message body.
  
! 		Result is in form ['response', ['line', ...], octets].
! 		"""
! 		return self._longcmd('TOP %s %s' % (which, howmuch))
  
  
! 	def uidl(self, which=None):
! 		"""Return message digest (unique id) list.
  
- 		If 'which', result contains unique id for that message
- 		in the form 'response mesgnum uid', otherwise result is
- 		the list ['response', ['mesgnum uid', ...], octets]
- 		"""
- 		if which:
- 			return self._shortcmd('UIDL %s' % which)
- 		return self._longcmd('UIDL')
  
! 				
  if __name__ == "__main__":
! 	a = POP3(TESTSERVER)
! 	print a.getwelcome()
! 	a.user(TESTACCOUNT)
! 	a.pass_(TESTPASSWORD)
! 	a.list()
! 	(numMsgs, totalSize) = a.stat()
! 	for i in range(1, numMsgs + 1):
! 		(header, msg, octets) = a.retr(i)
! 		print "Message ", `i`, ':'
! 		for line in msg:
! 			print '   ' + line
! 		print '-----------------------'
! 	a.quit()
--- 33,321 ----
  class POP3:
  
!     """This class supports both the minimal and optional command sets.
!     Arguments can be strings or integers (where appropriate)
!     (e.g.: retr(1) and retr('1') both work equally well.
  
!     Minimal Command Set:
!             USER name               user(name)
!             PASS string             pass_(string)
!             STAT                    stat()
!             LIST [msg]              list(msg = None)
!             RETR msg                retr(msg)
!             DELE msg                dele(msg)
!             NOOP                    noop()
!             RSET                    rset()
!             QUIT                    quit()
  
!     Optional Commands (some servers support these):
!             RPOP name               rpop(name)
!             APOP name digest        apop(name, digest)
!             TOP msg n               top(msg, n)
!             UIDL [msg]              uidl(msg = None)
  
!     Raises one exception: 'error_proto'.
  
!     Instantiate with:
!             POP3(hostname, port=110)
  
!     NB:     the POP protocol locks the mailbox from user
!             authorization until QUIT, so be sure to get in, suck
!             the messages, and quit, each time you access the
!             mailbox.
  
!             POP is a line-based protocol, which means large mail
!             messages consume lots of python cycles reading them
!             line-by-line.
  
!             If it's available on your mail server, use IMAP4
!             instead, it doesn't suffer from the two problems
!             above.
!     """
  
  
!     def __init__(self, host, port = POP3_PORT):
!         self.host = host
!         self.port = port
!         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
!         self.sock.connect((self.host, self.port))
!         self.file = self.sock.makefile('rb')
!         self._debugging = 0
!         self.welcome = self._getresp()
  
  
!     def _putline(self, line):
!         #if self._debugging > 1: print '*put*', `line`
!         self.sock.send('%s%s' % (line, CRLF))
  
  
!     # Internal: send one command to the server (through _putline())
  
!     def _putcmd(self, line):
!         #if self._debugging: print '*cmd*', `line`
!         self._putline(line)
  
  
!     # Internal: return one line from the server, stripping CRLF.
!     # This is where all the CPU time of this module is consumed.
!     # Raise error_proto('-ERR EOF') if the connection is closed.
  
!     def _getline(self):
!         line = self.file.readline()
!         #if self._debugging > 1: print '*get*', `line`
!         if not line: raise error_proto('-ERR EOF')
!         octets = len(line)
!         # server can send any combination of CR & LF
!         # however, 'readline()' returns lines ending in LF
!         # so only possibilities are ...LF, ...CRLF, CR...LF
!         if line[-2:] == CRLF:
!             return line[:-2], octets
!         if line[0] == CR:
!             return line[1:-1], octets
!         return line[:-1], octets
  
  
!     # Internal: get a response from the server.
!     # Raise 'error_proto' if the response doesn't start with '+'.
  
!     def _getresp(self):
!         resp, o = self._getline()
!         #if self._debugging > 1: print '*resp*', `resp`
!         c = resp[:1]
!         if c != '+':
!             raise error_proto(resp)
!         return resp
  
  
!     # Internal: get a response plus following text from the server.
  
!     def _getlongresp(self):
!         resp = self._getresp()
!         list = []; octets = 0
!         line, o = self._getline()
!         while line != '.':
!             if line[:2] == '..':
!                 o = o-1
!                 line = line[1:]
!             octets = octets + o
!             list.append(line)
!             line, o = self._getline()
!         return resp, list, octets
  
  
!     # Internal: send a command and get the response
  
!     def _shortcmd(self, line):
!         self._putcmd(line)
!         return self._getresp()
  
  
!     # Internal: send a command and get the response plus following text
  
!     def _longcmd(self, line):
!         self._putcmd(line)
!         return self._getlongresp()
  
  
!     # These can be useful:
  
!     def getwelcome(self):
!         return self.welcome
  
  
!     def set_debuglevel(self, level):
!         self._debugging = level
  
  
!     # Here are all the POP commands:
  
!     def user(self, user):
!         """Send user name, return response
  
+         (should indicate password required).
+         """
+         return self._shortcmd('USER %s' % user)
  
  
!     def pass_(self, pswd):
!         """Send password, return response
  
+         (response includes message count, mailbox size).
  
!         NB: mailbox is locked by server from here to 'quit()'
!         """
!         return self._shortcmd('PASS %s' % pswd)
  
  
!     def stat(self):
!         """Get mailbox status.
  
!         Result is tuple of 2 ints (message count, mailbox size)
!         """
!         retval = self._shortcmd('STAT')
!         rets = string.split(retval)
!         #if self._debugging: print '*stat*', `rets`
!         numMessages = string.atoi(rets[1])
!         sizeMessages = string.atoi(rets[2])
!         return (numMessages, sizeMessages)
  
  
+     def list(self, which=None):
+         """Request listing, return result.
  
!         Result without a message number argument is in form
!         ['response', ['mesg_num octets', ...]].
  
!         Result when a message number argument is given is a
!         single response: the "scan listing" for that message.
!         """
!         if which:
!             return self._shortcmd('LIST %s' % which)
!         return self._longcmd('LIST')
  
  
!     def retr(self, which):
!         """Retrieve whole message number 'which'.
  
!         Result is in form ['response', ['line', ...], octets].
!         """
!         return self._longcmd('RETR %s' % which)
  
  
!     def dele(self, which):
!         """Delete message number 'which'.
  
+         Result is 'response'.
+         """
+         return self._shortcmd('DELE %s' % which)
  
  
+     def noop(self):
+         """Does nothing.
  
!         One supposes the response indicates the server is alive.
!         """
!         return self._shortcmd('NOOP')
  
  
+     def rset(self):
+         """Not sure what this does."""
+         return self._shortcmd('RSET')
  
  
!     def quit(self):
!         """Signoff: commit changes on server, unlock mailbox, close connection."""
!         try:
!             resp = self._shortcmd('QUIT')
!         except error_proto, val:
!             resp = val
!         self.file.close()
!         self.sock.close()
!         del self.file, self.sock
!         return resp
  
+     #__del__ = quit
  
  
!     # optional commands:
  
!     def rpop(self, user):
!         """Not sure what this does."""
!         return self._shortcmd('RPOP %s' % user)
  
  
+     timestamp = regex.compile('\+OK.*\(<[^>]+>\)')
  
!     def apop(self, user, secret):
!         """Authorisation
  
!         - only possible if server has supplied a timestamp in initial greeting.
  
+         Args:
+                 user    - mailbox user;
+                 secret  - secret shared between client and server.
  
!         NB: mailbox is locked by server from here to 'quit()'
!         """
!         if self.timestamp.match(self.welcome) <= 0:
!             raise error_proto('-ERR APOP not supported by server')
!         import md5
!         digest = md5.new(self.timestamp.group(1)+secret).digest()
!         digest = string.join(map(lambda x:'%02x'%ord(x), digest), '')
!         return self._shortcmd('APOP %s %s' % (user, digest))
  
  
!     def top(self, which, howmuch):
!         """Retrieve message header of message number 'which'
!         and first 'howmuch' lines of message body.
! 
!         Result is in form ['response', ['line', ...], octets].
!         """
!         return self._longcmd('TOP %s %s' % (which, howmuch))
! 
! 
!     def uidl(self, which=None):
!         """Return message digest (unique id) list.
! 
!         If 'which', result contains unique id for that message
!         in the form 'response mesgnum uid', otherwise result is
!         the list ['response', ['mesgnum uid', ...], octets]
!         """
!         if which:
!             return self._shortcmd('UIDL %s' % which)
!         return self._longcmd('UIDL')
! 
! 
  if __name__ == "__main__":
!     a = POP3(TESTSERVER)
!     print a.getwelcome()
!     a.user(TESTACCOUNT)
!     a.pass_(TESTPASSWORD)
!     a.list()
!     (numMsgs, totalSize) = a.stat()
!     for i in range(1, numMsgs + 1):
!         (header, msg, octets) = a.retr(i)
!         print "Message ", `i`, ':'
!         for line in msg:
!             print '   ' + line
!         print '-----------------------'
!     a.quit()

Index: posixfile.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/posixfile.py,v
retrieving revision 1.16
retrieving revision 1.17
diff -C2 -r1.16 -r1.17
*** posixfile.py	2000/09/09 06:29:35	1.16
--- posixfile.py	2001/01/15 00:50:52	1.17
***************
*** 130,134 ****
          l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
  
!         if 'c' in which:        
              arg = ('!' not in which)    # 0 is don't, 1 is do close on exec
              l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
--- 130,134 ----
          l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
  
!         if 'c' in which:
              arg = ('!' not in which)    # 0 is don't, 1 is do close on exec
              l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
***************
*** 143,147 ****
              if FCNTL.O_SYNC & l_flags: which = which + 's'
              return which
!         
      def lock(self, how, *args):
          import struct, fcntl, FCNTL
--- 143,147 ----
              if FCNTL.O_SYNC & l_flags: which = which + 's'
              return which
! 
      def lock(self, how, *args):
          import struct, fcntl, FCNTL
***************
*** 177,181 ****
                              'bsdos2', 'bsdos3', 'bsdos4'):
              flock = struct.pack('lxxxxlxxxxlhh', \
!                   l_start, l_len, os.getpid(), l_type, l_whence) 
          elif sys.platform in ['aix3', 'aix4']:
              flock = struct.pack('hhlllii', \
--- 177,181 ----
                              'bsdos2', 'bsdos3', 'bsdos4'):
              flock = struct.pack('lxxxxlxxxxlhh', \
!                   l_start, l_len, os.getpid(), l_type, l_whence)
          elif sys.platform in ['aix3', 'aix4']:
              flock = struct.pack('hhlllii', \

Index: posixpath.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/posixpath.py,v
retrieving revision 1.38
retrieving revision 1.39
diff -C2 -r1.38 -r1.39
*** posixpath.py	2000/12/12 23:20:45	1.38
--- posixpath.py	2001/01/15 00:50:52	1.39
***************
*** 56,60 ****
  
  def split(p):
!     """Split a pathname.  Returns tuple "(head, tail)" where "tail" is 
      everything after the final slash.  Either part may be empty."""
      i = p.rfind('/') + 1
--- 56,60 ----
  
  def split(p):
!     """Split a pathname.  Returns tuple "(head, tail)" where "tail" is
      everything after the final slash.  Either part may be empty."""
      i = p.rfind('/') + 1
***************
*** 94,98 ****
  
  def splitdrive(p):
!     """Split a pathname into drive and path. On Posix, drive is always 
      empty."""
      return '', p
--- 94,98 ----
  
  def splitdrive(p):
!     """Split a pathname into drive and path. On Posix, drive is always
      empty."""
      return '', p
***************
*** 221,225 ****
      """Test whether two stat buffers reference the same file"""
      return s1[stat.ST_INO] == s2[stat.ST_INO] and \
! 	   s1[stat.ST_DEV] == s2[stat.ST_DEV]
  
  
--- 221,225 ----
      """Test whether two stat buffers reference the same file"""
      return s1[stat.ST_INO] == s2[stat.ST_INO] and \
!            s1[stat.ST_DEV] == s2[stat.ST_DEV]
  
  
***************
*** 254,258 ****
  
  def walk(top, func, arg):
!     """walk(top,func,arg) calls func(arg, d, files) for each directory "d" 
      in the tree  rooted at "top" (including "top" itself).  "files" is a list
      of all the files and subdirs in directory "d".
--- 254,258 ----
  
  def walk(top, func, arg):
!     """walk(top,func,arg) calls func(arg, d, files) for each directory "d"
      in the tree  rooted at "top" (including "top" itself).  "files" is a list
      of all the files and subdirs in directory "d".
***************
*** 264,271 ****
      func(arg, top, names)
      for name in names:
!             name = join(top, name)
!             st = os.lstat(name)
!             if stat.S_ISDIR(st[stat.ST_MODE]):
!                 walk(name, func, arg)
  
  
--- 264,271 ----
      func(arg, top, names)
      for name in names:
!         name = join(top, name)
!         st = os.lstat(name)
!         if stat.S_ISDIR(st[stat.ST_MODE]):
!             walk(name, func, arg)
  
  
***************
*** 280,284 ****
  
  def expanduser(path):
!     """Expand ~ and ~user constructions.  If user or $HOME is unknown, 
      do nothing."""
      if path[:1] != '~':
--- 280,284 ----
  
  def expanduser(path):
!     """Expand ~ and ~user constructions.  If user or $HOME is unknown,
      do nothing."""
      if path[:1] != '~':
***************
*** 350,354 ****
          if comp in ('', '.'):
              continue
!         if (comp != '..' or (not initial_slash and not new_comps) or 
               (new_comps and new_comps[-1] == '..')):
              new_comps.append(comp)
--- 350,354 ----
          if comp in ('', '.'):
              continue
!         if (comp != '..' or (not initial_slash and not new_comps) or
               (new_comps and new_comps[-1] == '..')):
              new_comps.append(comp)

Index: pre.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pre.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -r1.3 -r1.4
*** pre.py	2000/09/04 03:19:48	1.3
--- pre.py	2001/01/15 00:50:52	1.4
***************
*** 45,49 ****
      \\number  Matches the contents of the group of the same number.
      \\A       Matches only at the start of the string.
!     \\Z       Matches only at the end of the string. 
      \\b       Matches the empty string, but only at the start or end of a word.
      \\B       Matches the empty string, but not at the start or end of a word.
--- 45,49 ----
      \\number  Matches the contents of the group of the same number.
      \\A       Matches only at the start of the string.
!     \\Z       Matches only at the end of the string.
      \\b       Matches the empty string, but only at the start or end of a word.
      \\B       Matches the empty string, but not at the start or end of a word.
***************
*** 56,60 ****
               as letters for the current locale.
      \\W       Matches the complement of \\w.
!     \\\\       Matches a literal backslash. 
  
  This module exports the following functions:
--- 56,60 ----
               as letters for the current locale.
      \\W       Matches the complement of \\w.
!     \\\\       Matches a literal backslash.
  
  This module exports the following functions:
***************
*** 101,106 ****
  L = LOCALE
  M = MULTILINE
! S = DOTALL 
! X = VERBOSE 
  
  
--- 101,106 ----
  L = LOCALE
  M = MULTILINE
! S = DOTALL
! X = VERBOSE
  
  
***************
*** 126,130 ****
  def match(pattern, string, flags=0):
      """match (pattern, string[, flags]) -> MatchObject or None
!     
      If zero or more characters at the beginning of string match the
      regular expression pattern, return a corresponding MatchObject
--- 126,130 ----
  def match(pattern, string, flags=0):
      """match (pattern, string[, flags]) -> MatchObject or None
! 
      If zero or more characters at the beginning of string match the
      regular expression pattern, return a corresponding MatchObject
***************
*** 136,145 ****
  
      """
!     
      return _cachecompile(pattern, flags).match(string)
!   
  def search(pattern, string, flags=0):
      """search (pattern, string[, flags]) -> MatchObject or None
!     
      Scan through string looking for a location where the regular
      expression pattern produces a match, and return a corresponding
--- 136,145 ----
  
      """
! 
      return _cachecompile(pattern, flags).match(string)
! 
  def search(pattern, string, flags=0):
      """search (pattern, string[, flags]) -> MatchObject or None
! 
      Scan through string looking for a location where the regular
      expression pattern produces a match, and return a corresponding
***************
*** 150,157 ****
      """
      return _cachecompile(pattern, flags).search(string)
!   
  def sub(pattern, repl, string, count=0):
      """sub(pattern, repl, string[, count=0]) -> string
!     
      Return the string obtained by replacing the leftmost
      non-overlapping occurrences of pattern in string by the
--- 150,157 ----
      """
      return _cachecompile(pattern, flags).search(string)
! 
  def sub(pattern, repl, string, count=0):
      """sub(pattern, repl, string[, count=0]) -> string
! 
      Return the string obtained by replacing the leftmost
      non-overlapping occurrences of pattern in string by the
***************
*** 178,182 ****
  def subn(pattern, repl, string, count=0):
      """subn(pattern, repl, string[, count=0]) -> (string, num substitutions)
!     
      Perform the same operation as sub(), but return a tuple
      (new_string, number_of_subs_made).
--- 178,182 ----
  def subn(pattern, repl, string, count=0):
      """subn(pattern, repl, string[, count=0]) -> (string, num substitutions)
! 
      Perform the same operation as sub(), but return a tuple
      (new_string, number_of_subs_made).
***************
*** 186,193 ****
          pattern = _cachecompile(pattern)
      return pattern.subn(repl, string, count)
!   
  def split(pattern, string, maxsplit=0):
      """split(pattern, string[, maxsplit=0]) -> list of strings
!     
      Split string by the occurrences of pattern. If capturing
      parentheses are used in pattern, then the text of all groups in
--- 186,193 ----
          pattern = _cachecompile(pattern)
      return pattern.subn(repl, string, count)
! 
  def split(pattern, string, maxsplit=0):
      """split(pattern, string[, maxsplit=0]) -> list of strings
! 
      Split string by the occurrences of pattern. If capturing
      parentheses are used in pattern, then the text of all groups in
***************
*** 204,208 ****
  def findall(pattern, string):
      """findall(pattern, string) -> list
!     
      Return a list of all non-overlapping matches of pattern in
      string. If one or more groups are present in the pattern, return a
--- 204,208 ----
  def findall(pattern, string):
      """findall(pattern, string) -> list
! 
      Return a list of all non-overlapping matches of pattern in
      string. If one or more groups are present in the pattern, return a
***************
*** 217,221 ****
  def escape(pattern):
      """escape(string) -> string
!     
      Return string with all non-alphanumerics backslashed; this is
      useful if you want to match an arbitrary literal string that may
--- 217,221 ----
  def escape(pattern):
      """escape(string) -> string
! 
      Return string with all non-alphanumerics backslashed; this is
      useful if you want to match an arbitrary literal string that may
***************
*** 243,247 ****
      code=pcre_compile(pattern, flags, groupindex)
      return RegexObject(pattern, flags, code, groupindex)
!     
  
  #
--- 243,247 ----
      code=pcre_compile(pattern, flags, groupindex)
      return RegexObject(pattern, flags, code, groupindex)
! 
  
  #
***************
*** 259,267 ****
      split    Split a string by the occurrences of the pattern.
      findall  Find all occurrences of the pattern in a string.
!     
      """
  
      def __init__(self, pattern, flags, code, groupindex):
!         self.code = code 
          self.flags = flags
          self.pattern = pattern
--- 259,267 ----
      split    Split a string by the occurrences of the pattern.
      findall  Find all occurrences of the pattern in a string.
! 
      """
  
      def __init__(self, pattern, flags, code, groupindex):
!         self.code = code
          self.flags = flags
          self.pattern = pattern
***************
*** 270,274 ****
      def search(self, string, pos=0, endpos=None):
          """search(string[, pos][, endpos]) -> MatchObject or None
!         
          Scan through string looking for a location where this regular
          expression produces a match, and return a corresponding
--- 270,274 ----
      def search(self, string, pos=0, endpos=None):
          """search(string[, pos][, endpos]) -> MatchObject or None
! 
          Scan through string looking for a location where this regular
          expression produces a match, and return a corresponding
***************
*** 278,284 ****
          pos and endpos parameters have the same meaning as for the
          match() method.
!     
          """
!         if endpos is None or endpos>len(string): 
              endpos=len(string)
          if endpos<pos: endpos=pos
--- 278,284 ----
          pos and endpos parameters have the same meaning as for the
          match() method.
! 
          """
!         if endpos is None or endpos>len(string):
              endpos=len(string)
          if endpos<pos: endpos=pos
***************
*** 287,299 ****
              return None
          self._num_regs=len(regs)
!         
          return MatchObject(self,
                             string,
                             pos, endpos,
                             regs)
!     
      def match(self, string, pos=0, endpos=None):
          """match(string[, pos][, endpos]) -> MatchObject or None
!         
          If zero or more characters at the beginning of string match
          this regular expression, return a corresponding MatchObject
--- 287,299 ----
              return None
          self._num_regs=len(regs)
! 
          return MatchObject(self,
                             string,
                             pos, endpos,
                             regs)
! 
      def match(self, string, pos=0, endpos=None):
          """match(string[, pos][, endpos]) -> MatchObject or None
! 
          If zero or more characters at the beginning of string match
          this regular expression, return a corresponding MatchObject
***************
*** 317,321 ****
  
          """
!         if endpos is None or endpos>len(string): 
              endpos=len(string)
          if endpos<pos: endpos=pos
--- 317,321 ----
  
          """
!         if endpos is None or endpos>len(string):
              endpos=len(string)
          if endpos<pos: endpos=pos
***************
*** 328,335 ****
                             pos, endpos,
                             regs)
!     
      def sub(self, repl, string, count=0):
          """sub(repl, string[, count=0]) -> string
!         
          Return the string obtained by replacing the leftmost
          non-overlapping occurrences of the compiled pattern in string
--- 328,335 ----
                             pos, endpos,
                             regs)
! 
      def sub(self, repl, string, count=0):
          """sub(repl, string[, count=0]) -> string
! 
          Return the string obtained by replacing the leftmost
          non-overlapping occurrences of the compiled pattern in string
***************
*** 338,348 ****
  
          Identical to the sub() function, using the compiled pattern.
!         
          """
          return self.subn(repl, string, count)[0]
!     
!     def subn(self, repl, source, count=0): 
          """subn(repl, string[, count=0]) -> tuple
!         
          Perform the same operation as sub(), but return a tuple
          (new_string, number_of_subs_made).
--- 338,348 ----
  
          Identical to the sub() function, using the compiled pattern.
! 
          """
          return self.subn(repl, string, count)[0]
! 
!     def subn(self, repl, source, count=0):
          """subn(repl, string[, count=0]) -> tuple
! 
          Perform the same operation as sub(), but return a tuple
          (new_string, number_of_subs_made).
***************
*** 400,407 ****
          append(source[pos:])
          return (string.join(results, ''), n)
!                                                                             
      def split(self, source, maxsplit=0):
          """split(source[, maxsplit=0]) -> list of strings
!     
          Split string by the occurrences of the compiled pattern. If
          capturing parentheses are used in the pattern, then the text
--- 400,407 ----
          append(source[pos:])
          return (string.join(results, ''), n)
! 
      def split(self, source, maxsplit=0):
          """split(source[, maxsplit=0]) -> list of strings
! 
          Split string by the occurrences of the compiled pattern. If
          capturing parentheses are used in the pattern, then the text
***************
*** 410,414 ****
          splits occur, and the remainder of the string is returned as
          the final element of the list.
!         
          """
          if maxsplit < 0:
--- 410,414 ----
          splits occur, and the remainder of the string is returned as
          the final element of the list.
! 
          """
          if maxsplit < 0:
***************
*** 450,454 ****
      def findall(self, source):
          """findall(source) -> list
!     
          Return a list of all non-overlapping matches of the compiled
          pattern in string. If one or more groups are present in the
--- 450,454 ----
      def findall(self, source):
          """findall(source) -> list
! 
          Return a list of all non-overlapping matches of the compiled
          pattern in string. If one or more groups are present in the
***************
*** 488,492 ****
          return (None,None,None,None) # any 4 elements, to work around
                                       # problems with the
!                                      # pickle/cPickle modules not yet 
                                       # ignoring the __init__ function
      def __getstate__(self):
--- 488,492 ----
          return (None,None,None,None) # any 4 elements, to work around
                                       # problems with the
!                                      # pickle/cPickle modules not yet
                                       # ignoring the __init__ function
      def __getstate__(self):
***************
*** 518,528 ****
          self.re = re
          self.string = string
!         self.pos = pos 
          self.endpos = endpos
          self.regs = regs
!         
      def start(self, g = 0):
          """start([group=0]) -> int or None
!         
          Return the index of the start of the substring matched by
          group; group defaults to zero (meaning the whole matched
--- 518,528 ----
          self.re = re
          self.string = string
!         self.pos = pos
          self.endpos = endpos
          self.regs = regs
! 
      def start(self, g = 0):
          """start([group=0]) -> int or None
! 
          Return the index of the start of the substring matched by
          group; group defaults to zero (meaning the whole matched
***************
*** 537,544 ****
                  raise IndexError, 'group %s is undefined' % `g`
          return self.regs[g][0]
!     
      def end(self, g = 0):
          """end([group=0]) -> int or None
!         
          Return the indices of the end of the substring matched by
          group; group defaults to zero (meaning the whole matched
--- 537,544 ----
                  raise IndexError, 'group %s is undefined' % `g`
          return self.regs[g][0]
! 
      def end(self, g = 0):
          """end([group=0]) -> int or None
! 
          Return the indices of the end of the substring matched by
          group; group defaults to zero (meaning the whole matched
***************
*** 553,560 ****
                  raise IndexError, 'group %s is undefined' % `g`
          return self.regs[g][1]
!     
      def span(self, g = 0):
          """span([group=0]) -> tuple
!         
          Return the 2-tuple (m.start(group), m.end(group)). Note that
          if group did not contribute to the match, this is (-1,
--- 553,560 ----
                  raise IndexError, 'group %s is undefined' % `g`
          return self.regs[g][1]
! 
      def span(self, g = 0):
          """span([group=0]) -> tuple
! 
          Return the 2-tuple (m.start(group), m.end(group)). Note that
          if group did not contribute to the match, this is (-1,
***************
*** 569,576 ****
                  raise IndexError, 'group %s is undefined' % `g`
          return self.regs[g]
!     
      def groups(self, default=None):
          """groups([default=None]) -> tuple
!         
          Return a tuple containing all the subgroups of the match, from
          1 up to however many groups are in the pattern. The default
--- 569,576 ----
                  raise IndexError, 'group %s is undefined' % `g`
          return self.regs[g]
! 
      def groups(self, default=None):
          """groups([default=None]) -> tuple
! 
          Return a tuple containing all the subgroups of the match, from
          1 up to however many groups are in the pattern. The default
***************
*** 590,594 ****
      def group(self, *groups):
          """group([group1, group2, ...]) -> string or tuple
!         
          Return one or more subgroups of the match. If there is a
          single argument, the result is a single string; if there are
--- 590,594 ----
      def group(self, *groups):
          """group([group1, group2, ...]) -> string or tuple
! 
          Return one or more subgroups of the match. If there is a
          single argument, the result is a single string; if there are
***************
*** 637,641 ****
      def groupdict(self, default=None):
          """groupdict([default=None]) -> dictionary
!         
          Return a dictionary containing all the named subgroups of the
          match, keyed by the subgroup name. The default argument is
--- 637,641 ----
      def groupdict(self, default=None):
          """groupdict([default=None]) -> dictionary
! 
          Return a dictionary containing all the named subgroups of the
          match, keyed by the subgroup name. The default argument is

Index: profile.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/profile.py,v
retrieving revision 1.24
retrieving revision 1.25
diff -C2 -r1.24 -r1.25
*** profile.py	2000/08/10 04:23:29	1.24
--- profile.py	2001/01/15 00:50:52	1.25
***************
*** 12,16 ****
  # Copyright 1994, by InfoSeek Corporation, all rights reserved.
  # Written by James Roskind
! # 
  # Permission to use, copy, modify, and distribute this Python software
  # and its associated documentation for any purpose (subject to the
--- 12,16 ----
  # Copyright 1994, by InfoSeek Corporation, all rights reserved.
  # Written by James Roskind
! #
  # Permission to use, copy, modify, and distribute this Python software
[...1048 lines suppressed...]
  def Stats(*args):
!     print 'Report generating functions are in the "pstats" module\a'
  
  
  # When invoked as main program, invoke the profiler on a script
  if __name__ == '__main__':
!     import sys
!     import os
!     if not sys.argv[1:]:
!         print "usage: profile.py scriptfile [arg] ..."
!         sys.exit(2)
  
!     filename = sys.argv[1]  # Get script filename
  
!     del sys.argv[0]         # Hide "profile.py" from argument list
  
!     # Insert script directory in front of module search path
!     sys.path.insert(0, os.path.dirname(filename))
  
!     run('execfile(' + `filename` + ')')

Index: pstats.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pstats.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -r1.8 -r1.9
*** pstats.py	2000/07/16 12:04:30	1.8
--- pstats.py	2001/01/15 00:50:52	1.9
***************
*** 10,14 ****
  # Copyright 1994, by InfoSeek Corporation, all rights reserved.
  # Written by James Roskind
! # 
  # Permission to use, copy, modify, and distribute this Python software
  # and its associated documentation for any purpose (subject to the
--- 10,14 ----
  # Copyright 1994, by InfoSeek Corporation, all rights reserved.
  # Written by James Roskind
! #
  # Permission to use, copy, modify, and distribute this Python software
[...965 lines suppressed...]
!     return new_callers
  
  def count_calls(callers):
!     """Sum the caller statistics to get total number of calls received."""
!     nc = 0
!     for func in callers.keys():
!         nc = nc + callers[func]
!     return nc
  
  #**************************************************************************
***************
*** 523,526 ****
  
  def f8(x):
! 	return string.rjust(fpformat.fix(x, 3), 8)
! 
--- 523,525 ----
  
  def f8(x):
!     return string.rjust(fpformat.fix(x, 3), 8)

Index: pty.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pty.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -r1.5 -r1.6
*** pty.py	2000/07/03 13:44:25	1.5
--- pty.py	2001/01/15 00:50:52	1.6
***************
*** 2,8 ****
  
  # Bugs: No signal handling.  Doesn't set slave termios and window size.
! #	Only tested on Linux.
! # See:  W. Richard Stevens. 1992.  Advanced Programming in the 
! #	UNIX Environment.  Chapter 19.
  # Author: Steen Lumholt -- with additions by Guido.
  
--- 2,8 ----
  
  # Bugs: No signal handling.  Doesn't set slave termios and window size.
! #       Only tested on Linux.
! # See:  W. Richard Stevens. 1992.  Advanced Programming in the
! #       UNIX Environment.  Chapter 19.
  # Author: Steen Lumholt -- with additions by Guido.
  
***************
*** 18,149 ****
  
  def openpty():
! 	"""openpty() -> (master_fd, slave_fd)
! 	Open a pty master/slave pair, using os.openpty() if possible."""
  
! 	try:
! 		return os.openpty()
! 	except (AttributeError, OSError):
! 		pass
! 	master_fd, slave_name = _open_terminal()
! 	slave_fd = slave_open(slave_name)
! 	return master_fd, slave_fd
  
  def master_open():
! 	"""master_open() -> (master_fd, slave_name)
! 	Open a pty master and return the fd, and the filename of the slave end.
! 	Deprecated, use openpty() instead."""
! 
! 	try:
! 		master_fd, slave_fd = os.openpty()
! 	except (AttributeError, OSError):
! 		pass
! 	else:
! 		slave_name = os.ttyname(slave_fd)
! 		os.close(slave_fd)
! 		return master_fd, slave_name
  
! 	return _open_terminal()
  
  def _open_terminal():
! 	"""Open pty master and return (master_fd, tty_name).
! 	SGI and generic BSD version, for when openpty() fails."""
! 	try:
! 		import sgi
! 	except ImportError:
! 		pass
! 	else:
! 		try:
! 		    tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
! 		except IOError, msg:
! 			raise os.error, msg
! 		return master_fd, tty_name
! 	for x in 'pqrstuvwxyzPQRST':
! 		for y in '0123456789abcdef':
! 			pty_name = '/dev/pty' + x + y
! 			try:
! 				fd = os.open(pty_name, FCNTL.O_RDWR)
! 			except os.error:
! 				continue
! 			return (fd, '/dev/tty' + x + y)
! 	raise os.error, 'out of pty devices'
  
  def slave_open(tty_name):
! 	"""slave_open(tty_name) -> slave_fd
! 	Open the pty slave and acquire the controlling terminal, returning
! 	opened filedescriptor.
! 	Deprecated, use openpty() instead."""
  
! 	return os.open(tty_name, FCNTL.O_RDWR)
  
  def fork():
! 	"""fork() -> (pid, master_fd)
! 	Fork and make the child a session leader with a controlling terminal."""
  
! 	try:
! 		pid, fd = os.forkpty()
! 	except (AttributeError, OSError):
! 		pass
! 	else:
! 		if pid == CHILD:
! 			try:
! 				os.setsid()
! 			except OSError:
! 				# os.forkpty() already set us session leader
! 				pass
! 		return pid, fd
! 
! 	master_fd, slave_fd = openpty() 
! 	pid = os.fork()
! 	if pid == CHILD:
! 		# Establish a new session.
! 		os.setsid()
! 		os.close(master_fd)
! 
! 		# Slave becomes stdin/stdout/stderr of child.
! 		os.dup2(slave_fd, STDIN_FILENO)
! 		os.dup2(slave_fd, STDOUT_FILENO)
! 		os.dup2(slave_fd, STDERR_FILENO)
! 		if (slave_fd > STDERR_FILENO):
! 			os.close (slave_fd)
  
! 	# Parent and child process.
! 	return pid, master_fd
  
  def _writen(fd, data):
! 	"""Write all the data to a descriptor."""
! 	while data != '':
! 		n = os.write(fd, data)
! 		data = data[n:]
  
  def _read(fd):
! 	"""Default read function."""
! 	return os.read(fd, 1024)
  
  def _copy(master_fd, master_read=_read, stdin_read=_read):
! 	"""Parent copy loop.
! 	Copies  
! 	  	pty master -> standard output	(master_read)
! 	  	standard input -> pty master	(stdin_read)"""
! 	while 1:
! 		rfds, wfds, xfds = select(
! 			[master_fd, STDIN_FILENO], [], [])
! 		if master_fd in rfds:
! 			data = master_read(master_fd)
! 			os.write(STDOUT_FILENO, data)
! 		if STDIN_FILENO in rfds:
! 			data = stdin_read(STDIN_FILENO)
! 			_writen(master_fd, data)
  
  def spawn(argv, master_read=_read, stdin_read=_read):
! 	"""Create a spawned process."""
! 	if type(argv) == type(''):
! 		argv = (argv,)
! 	pid, master_fd = fork()
! 	if pid == CHILD:
! 		apply(os.execlp, (argv[0],) + argv)
! 	mode = tty.tcgetattr(STDIN_FILENO)
! 	tty.setraw(STDIN_FILENO)
! 	try:
! 		_copy(master_fd, master_read, stdin_read)
! 	except:
! 		tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
--- 18,149 ----
  
  def openpty():
!     """openpty() -> (master_fd, slave_fd)
!     Open a pty master/slave pair, using os.openpty() if possible."""
  
!     try:
!         return os.openpty()
!     except (AttributeError, OSError):
!         pass
!     master_fd, slave_name = _open_terminal()
!     slave_fd = slave_open(slave_name)
!     return master_fd, slave_fd
  
  def master_open():
!     """master_open() -> (master_fd, slave_name)
!     Open a pty master and return the fd, and the filename of the slave end.
!     Deprecated, use openpty() instead."""
! 
!     try:
!         master_fd, slave_fd = os.openpty()
!     except (AttributeError, OSError):
!         pass
!     else:
!         slave_name = os.ttyname(slave_fd)
!         os.close(slave_fd)
!         return master_fd, slave_name
  
!     return _open_terminal()
  
  def _open_terminal():
!     """Open pty master and return (master_fd, tty_name).
!     SGI and generic BSD version, for when openpty() fails."""
!     try:
!         import sgi
!     except ImportError:
!         pass
!     else:
!         try:
!             tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
!         except IOError, msg:
!             raise os.error, msg
!         return master_fd, tty_name
!     for x in 'pqrstuvwxyzPQRST':
!         for y in '0123456789abcdef':
!             pty_name = '/dev/pty' + x + y
!             try:
!                 fd = os.open(pty_name, FCNTL.O_RDWR)
!             except os.error:
!                 continue
!             return (fd, '/dev/tty' + x + y)
!     raise os.error, 'out of pty devices'
  
  def slave_open(tty_name):
!     """slave_open(tty_name) -> slave_fd
!     Open the pty slave and acquire the controlling terminal, returning
!     opened filedescriptor.
!     Deprecated, use openpty() instead."""
  
!     return os.open(tty_name, FCNTL.O_RDWR)
  
  def fork():
!     """fork() -> (pid, master_fd)
!     Fork and make the child a session leader with a controlling terminal."""
  
!     try:
!         pid, fd = os.forkpty()
!     except (AttributeError, OSError):
!         pass
!     else:
!         if pid == CHILD:
!             try:
!                 os.setsid()
!             except OSError:
!                 # os.forkpty() already set us session leader
!                 pass
!         return pid, fd
! 
!     master_fd, slave_fd = openpty()
!     pid = os.fork()
!     if pid == CHILD:
!         # Establish a new session.
!         os.setsid()
!         os.close(master_fd)
! 
!         # Slave becomes stdin/stdout/stderr of child.
!         os.dup2(slave_fd, STDIN_FILENO)
!         os.dup2(slave_fd, STDOUT_FILENO)
!         os.dup2(slave_fd, STDERR_FILENO)
!         if (slave_fd > STDERR_FILENO):
!             os.close (slave_fd)
  
!     # Parent and child process.
!     return pid, master_fd
  
  def _writen(fd, data):
!     """Write all the data to a descriptor."""
!     while data != '':
!         n = os.write(fd, data)
!         data = data[n:]
  
  def _read(fd):
!     """Default read function."""
!     return os.read(fd, 1024)
  
  def _copy(master_fd, master_read=_read, stdin_read=_read):
!     """Parent copy loop.
!     Copies
!             pty master -> standard output   (master_read)
!             standard input -> pty master    (stdin_read)"""
!     while 1:
!         rfds, wfds, xfds = select(
!                 [master_fd, STDIN_FILENO], [], [])
!         if master_fd in rfds:
!             data = master_read(master_fd)
!             os.write(STDOUT_FILENO, data)
!         if STDIN_FILENO in rfds:
!             data = stdin_read(STDIN_FILENO)
!             _writen(master_fd, data)
  
  def spawn(argv, master_read=_read, stdin_read=_read):
!     """Create a spawned process."""
!     if type(argv) == type(''):
!         argv = (argv,)
!     pid, master_fd = fork()
!     if pid == CHILD:
!         apply(os.execlp, (argv[0],) + argv)
!     mode = tty.tcgetattr(STDIN_FILENO)
!     tty.setraw(STDIN_FILENO)
!     try:
!         _copy(master_fd, master_read, stdin_read)
!     except:
!         tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)

Index: pyclbr.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pyclbr.py,v
retrieving revision 1.15
retrieving revision 1.16
diff -C2 -r1.15 -r1.16
*** pyclbr.py	2000/02/04 15:39:30	1.15
--- pyclbr.py	2001/01/15 00:50:52	1.16
***************
*** 5,9 ****
  
  The interface consists of a single function:
! 	readmodule(module, path)
  module is the name of a Python module, path is an optional list of
  directories where the module is to be searched.  If present, path is
--- 5,9 ----
  
  The interface consists of a single function:
!         readmodule(module, path)
  module is the name of a Python module, path is an optional list of
  directories where the module is to be searched.  If present, path is
***************
*** 16,24 ****
  A class is described by the class Class in this module.  Instances
  of this class have the following instance variables:
! 	name -- the name of the class
! 	super -- a list of super classes (Class instances)
! 	methods -- a dictionary of methods
! 	file -- the file in which the class was defined
! 	lineno -- the line in the file on which the class statement occurred
  The dictionary of methods uses the method names as keys and the line
  numbers on which the method was defined as values.
--- 16,24 ----
  A class is described by the class Class in this module.  Instances
  of this class have the following instance variables:
!         name -- the name of the class
!         super -- a list of super classes (Class instances)
!         methods -- a dictionary of methods
!         file -- the file in which the class was defined
!         lineno -- the line in the file on which the class statement occurred
  The dictionary of methods uses the method names as keys and the line
  numbers on which the method was defined as values.
***************
*** 65,114 ****
      (?P<String>
         \""" [^"\\]* (?:
! 			(?: \\. | "(?!"") )
! 			[^"\\]*
! 		    )*
         \"""
  
      |   ''' [^'\\]* (?:
! 			(?: \\. | '(?!'') )
! 			[^'\\]*
! 		    )*
! 	'''
      )
  
  |   (?P<Method>
! 	^
! 	(?P<MethodIndent> [ \t]* )
! 	def [ \t]+
! 	(?P<MethodName> [a-zA-Z_] \w* )
! 	[ \t]* \(
      )
  
  |   (?P<Class>
! 	^
! 	(?P<ClassIndent> [ \t]* )
! 	class [ \t]+
! 	(?P<ClassName> [a-zA-Z_] \w* )
! 	[ \t]*
! 	(?P<ClassSupers> \( [^)\n]* \) )?
! 	[ \t]* :
      )
  
  |   (?P<Import>
! 	^ import [ \t]+
! 	(?P<ImportList> [^#;\n]+ )
      )
  
  |   (?P<ImportFrom>
! 	^ from [ \t]+
! 	(?P<ImportFromPath>
! 	    [a-zA-Z_] \w*
! 	    (?:
! 		[ \t]* \. [ \t]* [a-zA-Z_] \w*
! 	    )*
! 	)
! 	[ \t]+
! 	import [ \t]+
! 	(?P<ImportFromList> [^#;\n]+ )
      )
  """, re.VERBOSE | re.DOTALL | re.MULTILINE).search
--- 65,114 ----
      (?P<String>
         \""" [^"\\]* (?:
!                         (?: \\. | "(?!"") )
!                         [^"\\]*
!                     )*
         \"""
  
      |   ''' [^'\\]* (?:
!                         (?: \\. | '(?!'') )
!                         [^'\\]*
!                     )*
!         '''
      )
  
  |   (?P<Method>
!         ^
!         (?P<MethodIndent> [ \t]* )
!         def [ \t]+
!         (?P<MethodName> [a-zA-Z_] \w* )
!         [ \t]* \(
      )
  
  |   (?P<Class>
!         ^
!         (?P<ClassIndent> [ \t]* )
!         class [ \t]+
!         (?P<ClassName> [a-zA-Z_] \w* )
!         [ \t]*
!         (?P<ClassSupers> \( [^)\n]* \) )?
!         [ \t]* :
      )
  
  |   (?P<Import>
!         ^ import [ \t]+
!         (?P<ImportList> [^#;\n]+ )
      )
  
  |   (?P<ImportFrom>
!         ^ from [ \t]+
!         (?P<ImportFromPath>
!             [a-zA-Z_] \w*
!             (?:
!                 [ \t]* \. [ \t]* [a-zA-Z_] \w*
!             )*
!         )
!         [ \t]+
!         import [ \t]+
!         (?P<ImportFromList> [^#;\n]+ )
      )
  """, re.VERBOSE | re.DOTALL | re.MULTILINE).search
***************
*** 118,336 ****
  # each Python class is represented by an instance of this class
  class Class:
! 	'''Class to represent a Python class.'''
! 	def __init__(self, module, name, super, file, lineno):
! 		self.module = module
! 		self.name = name
! 		if super is None:
! 			super = []
! 		self.super = super
! 		self.methods = {}
! 		self.file = file
! 		self.lineno = lineno
  
! 	def _addmethod(self, name, lineno):
! 		self.methods[name] = lineno
  
  class Function(Class):
! 	'''Class to represent a top-level Python function'''
! 	def __init__(self, module, name, file, lineno):
! 		Class.__init__(self, module, name, None, file, lineno)
! 	def _addmethod(self, name, lineno):
! 		assert 0, "Function._addmethod() shouldn't be called"
  
  def readmodule(module, path=[], inpackage=0):
! 	'''Backwards compatible interface.
  
! 	Like readmodule_ex() but strips Function objects from the
! 	resulting dictionary.'''
  
! 	dict = readmodule_ex(module, path, inpackage)
! 	res = {}
! 	for key, value in dict.items():
! 		if not isinstance(value, Function):
! 			res[key] = value
! 	return res
  
  def readmodule_ex(module, path=[], inpackage=0):
! 	'''Read a module file and return a dictionary of classes.
  
! 	Search for MODULE in PATH and sys.path, read and parse the
! 	module and return a dictionary with one entry for each class
! 	found in the module.'''
! 
! 	dict = {}
! 
! 	i = string.rfind(module, '.')
! 	if i >= 0:
! 		# Dotted module name
! 		package = string.strip(module[:i])
! 		submodule = string.strip(module[i+1:])
! 		parent = readmodule(package, path, inpackage)
! 		child = readmodule(submodule, parent['__path__'], 1)
! 		return child
! 
! 	if _modules.has_key(module):
! 		# we've seen this module before...
! 		return _modules[module]
! 	if module in sys.builtin_module_names:
! 		# this is a built-in module
! 		_modules[module] = dict
! 		return dict
! 
! 	# search the path for the module
! 	f = None
! 	if inpackage:
! 		try:
! 			f, file, (suff, mode, type) = \
! 				imp.find_module(module, path)
! 		except ImportError:
! 			f = None
! 	if f is None:
! 		fullpath = list(path) + sys.path
! 		f, file, (suff, mode, type) = imp.find_module(module, fullpath)
! 	if type == imp.PKG_DIRECTORY:
! 		dict['__path__'] = [file]
! 		_modules[module] = dict
! 		path = [file] + path
! 		f, file, (suff, mode, type) = \
! 				imp.find_module('__init__', [file])
! 	if type != imp.PY_SOURCE:
! 		# not Python source, can't do anything with this module
! 		f.close()
! 		_modules[module] = dict
! 		return dict
! 
! 	_modules[module] = dict
! 	imports = []
! 	classstack = []	# stack of (class, indent) pairs
! 	src = f.read()
! 	f.close()
! 
! 	# To avoid having to stop the regexp at each newline, instead
! 	# when we need a line number we simply string.count the number of
! 	# newlines in the string since the last time we did this; i.e.,
! 	#    lineno = lineno + \
! 	#             string.count(src, '\n', last_lineno_pos, here)
! 	#    last_lineno_pos = here
! 	countnl = string.count
! 	lineno, last_lineno_pos = 1, 0
! 	i = 0
! 	while 1:
! 		m = _getnext(src, i)
! 		if not m:
! 			break
! 		start, i = m.span()
! 
! 		if m.start("Method") >= 0:
! 			# found a method definition or function
! 			thisindent = _indent(m.group("MethodIndent"))
! 			meth_name = m.group("MethodName")
! 			lineno = lineno + \
! 				 countnl(src, '\n',
! 					 last_lineno_pos, start)
! 			last_lineno_pos = start
! 			# close all classes indented at least as much
! 			while classstack and \
! 			      classstack[-1][1] >= thisindent:
! 				del classstack[-1]
! 			if classstack:
! 				# it's a class method
! 				cur_class = classstack[-1][0]
! 				cur_class._addmethod(meth_name, lineno)
! 			else:
! 				# it's a function
! 				f = Function(module, meth_name,
! 					     file, lineno)
! 				dict[meth_name] = f
! 
! 		elif m.start("String") >= 0:
! 			pass
! 
! 		elif m.start("Class") >= 0:
! 			# we found a class definition
! 			thisindent = _indent(m.group("ClassIndent"))
! 			# close all classes indented at least as much
! 			while classstack and \
! 			      classstack[-1][1] >= thisindent:
! 				del classstack[-1]
! 			lineno = lineno + \
! 				 countnl(src, '\n', last_lineno_pos, start)
! 			last_lineno_pos = start
! 			class_name = m.group("ClassName")
! 			inherit = m.group("ClassSupers")
! 			if inherit:
! 				# the class inherits from other classes
! 				inherit = string.strip(inherit[1:-1])
! 				names = []
! 				for n in string.splitfields(inherit, ','):
! 					n = string.strip(n)
! 					if dict.has_key(n):
! 						# we know this super class
! 						n = dict[n]
! 					else:
! 						c = string.splitfields(n, '.')
! 						if len(c) > 1:
! 							# super class
! 							# is of the
! 							# form module.class:
! 							# look in
! 							# module for class
! 							m = c[-2]
! 							c = c[-1]
! 							if _modules.has_key(m):
! 								d = _modules[m]
! 								if d.has_key(c):
! 									n = d[c]
! 					names.append(n)
! 				inherit = names
! 			# remember this class
! 			cur_class = Class(module, class_name, inherit,
! 					  file, lineno)
! 			dict[class_name] = cur_class
! 			classstack.append((cur_class, thisindent))
! 
! 		elif m.start("Import") >= 0:
! 			# import module
! 			for n in string.split(m.group("ImportList"), ','):
! 				n = string.strip(n)
! 				try:
! 					# recursively read the imported module
! 					d = readmodule(n, path, inpackage)
! 				except:
! 					##print 'module', n, 'not found'
! 					pass
! 
! 		elif m.start("ImportFrom") >= 0:
! 			# from module import stuff
! 			mod = m.group("ImportFromPath")
! 			names = string.split(m.group("ImportFromList"), ',')
! 			try:
! 				# recursively read the imported module
! 				d = readmodule(mod, path, inpackage)
! 			except:
! 				##print 'module', mod, 'not found'
! 				continue
! 			# add any classes that were defined in the
! 			# imported module to our name space if they
! 			# were mentioned in the list
! 			for n in names:
! 				n = string.strip(n)
! 				if d.has_key(n):
! 					dict[n] = d[n]
! 				elif n == '*':
! 					# only add a name if not
! 					# already there (to mimic what
! 					# Python does internally)
! 					# also don't add names that
! 					# start with _
! 					for n in d.keys():
! 						if n[0] != '_' and \
! 						   not dict.has_key(n):
! 							dict[n] = d[n]
! 		else:
! 			assert 0, "regexp _getnext found something unexpected"
  
! 	return dict
  
  def _indent(ws, _expandtabs=string.expandtabs):
! 	return len(_expandtabs(ws, TABWIDTH))
--- 118,336 ----
  # each Python class is represented by an instance of this class
  class Class:
!     '''Class to represent a Python class.'''
!     def __init__(self, module, name, super, file, lineno):
!         self.module = module
!         self.name = name
!         if super is None:
!             super = []
!         self.super = super
!         self.methods = {}
!         self.file = file
!         self.lineno = lineno
  
!     def _addmethod(self, name, lineno):
!         self.methods[name] = lineno
  
  class Function(Class):
!     '''Class to represent a top-level Python function'''
!     def __init__(self, module, name, file, lineno):
!         Class.__init__(self, module, name, None, file, lineno)
!     def _addmethod(self, name, lineno):
!         assert 0, "Function._addmethod() shouldn't be called"
  
  def readmodule(module, path=[], inpackage=0):
!     '''Backwards compatible interface.
  
!     Like readmodule_ex() but strips Function objects from the
!     resulting dictionary.'''
  
!     dict = readmodule_ex(module, path, inpackage)
!     res = {}
!     for key, value in dict.items():
!         if not isinstance(value, Function):
!             res[key] = value
!     return res
  
  def readmodule_ex(module, path=[], inpackage=0):
!     '''Read a module file and return a dictionary of classes.
  
!     Search for MODULE in PATH and sys.path, read and parse the
!     module and return a dictionary with one entry for each class
!     found in the module.'''
! 
!     dict = {}
! 
!     i = string.rfind(module, '.')
!     if i >= 0:
!         # Dotted module name
!         package = string.strip(module[:i])
!         submodule = string.strip(module[i+1:])
!         parent = readmodule(package, path, inpackage)
!         child = readmodule(submodule, parent['__path__'], 1)
!         return child
! 
!     if _modules.has_key(module):
!         # we've seen this module before...
!         return _modules[module]
!     if module in sys.builtin_module_names:
!         # this is a built-in module
!         _modules[module] = dict
!         return dict
! 
!     # search the path for the module
!     f = None
!     if inpackage:
!         try:
!             f, file, (suff, mode, type) = \
!                     imp.find_module(module, path)
!         except ImportError:
!             f = None
!     if f is None:
!         fullpath = list(path) + sys.path
!         f, file, (suff, mode, type) = imp.find_module(module, fullpath)
!     if type == imp.PKG_DIRECTORY:
!         dict['__path__'] = [file]
!         _modules[module] = dict
!         path = [file] + path
!         f, file, (suff, mode, type) = \
!                         imp.find_module('__init__', [file])
!     if type != imp.PY_SOURCE:
!         # not Python source, can't do anything with this module
!         f.close()
!         _modules[module] = dict
!         return dict
! 
!     _modules[module] = dict
!     imports = []
!     classstack = [] # stack of (class, indent) pairs
!     src = f.read()
!     f.close()
! 
!     # To avoid having to stop the regexp at each newline, instead
!     # when we need a line number we simply string.count the number of
!     # newlines in the string since the last time we did this; i.e.,
!     #    lineno = lineno + \
!     #             string.count(src, '\n', last_lineno_pos, here)
!     #    last_lineno_pos = here
!     countnl = string.count
!     lineno, last_lineno_pos = 1, 0
!     i = 0
!     while 1:
!         m = _getnext(src, i)
!         if not m:
!             break
!         start, i = m.span()
! 
!         if m.start("Method") >= 0:
!             # found a method definition or function
!             thisindent = _indent(m.group("MethodIndent"))
!             meth_name = m.group("MethodName")
!             lineno = lineno + \
!                      countnl(src, '\n',
!                              last_lineno_pos, start)
!             last_lineno_pos = start
!             # close all classes indented at least as much
!             while classstack and \
!                   classstack[-1][1] >= thisindent:
!                 del classstack[-1]
!             if classstack:
!                 # it's a class method
!                 cur_class = classstack[-1][0]
!                 cur_class._addmethod(meth_name, lineno)
!             else:
!                 # it's a function
!                 f = Function(module, meth_name,
!                              file, lineno)
!                 dict[meth_name] = f
! 
!         elif m.start("String") >= 0:
!             pass
! 
!         elif m.start("Class") >= 0:
!             # we found a class definition
!             thisindent = _indent(m.group("ClassIndent"))
!             # close all classes indented at least as much
!             while classstack and \
!                   classstack[-1][1] >= thisindent:
!                 del classstack[-1]
!             lineno = lineno + \
!                      countnl(src, '\n', last_lineno_pos, start)
!             last_lineno_pos = start
!             class_name = m.group("ClassName")
!             inherit = m.group("ClassSupers")
!             if inherit:
!                 # the class inherits from other classes
!                 inherit = string.strip(inherit[1:-1])
!                 names = []
!                 for n in string.splitfields(inherit, ','):
!                     n = string.strip(n)
!                     if dict.has_key(n):
!                         # we know this super class
!                         n = dict[n]
!                     else:
!                         c = string.splitfields(n, '.')
!                         if len(c) > 1:
!                             # super class
!                             # is of the
!                             # form module.class:
!                             # look in
!                             # module for class
!                             m = c[-2]
!                             c = c[-1]
!                             if _modules.has_key(m):
!                                 d = _modules[m]
!                                 if d.has_key(c):
!                                     n = d[c]
!                     names.append(n)
!                 inherit = names
!             # remember this class
!             cur_class = Class(module, class_name, inherit,
!                               file, lineno)
!             dict[class_name] = cur_class
!             classstack.append((cur_class, thisindent))
! 
!         elif m.start("Import") >= 0:
!             # import module
!             for n in string.split(m.group("ImportList"), ','):
!                 n = string.strip(n)
!                 try:
!                     # recursively read the imported module
!                     d = readmodule(n, path, inpackage)
!                 except:
!                     ##print 'module', n, 'not found'
!                     pass
! 
!         elif m.start("ImportFrom") >= 0:
!             # from module import stuff
!             mod = m.group("ImportFromPath")
!             names = string.split(m.group("ImportFromList"), ',')
!             try:
!                 # recursively read the imported module
!                 d = readmodule(mod, path, inpackage)
!             except:
!                 ##print 'module', mod, 'not found'
!                 continue
!             # add any classes that were defined in the
!             # imported module to our name space if they
!             # were mentioned in the list
!             for n in names:
!                 n = string.strip(n)
!                 if d.has_key(n):
!                     dict[n] = d[n]
!                 elif n == '*':
!                     # only add a name if not
!                     # already there (to mimic what
!                     # Python does internally)
!                     # also don't add names that
!                     # start with _
!                     for n in d.keys():
!                         if n[0] != '_' and \
!                            not dict.has_key(n):
!                             dict[n] = d[n]
!         else:
!             assert 0, "regexp _getnext found something unexpected"
  
!     return dict
  
  def _indent(ws, _expandtabs=string.expandtabs):
!     return len(_expandtabs(ws, TABWIDTH))

Index: quopri.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/quopri.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -r1.8 -r1.9
*** quopri.py	2000/12/12 23:20:45	1.8
--- quopri.py	2001/01/15 00:50:52	1.9
***************
*** 27,31 ****
      'input' and 'output' are files with readline() and write() methods.
      The 'quotetabs' flag indicates whether tabs should be quoted.
! 	"""
      while 1:
          line = input.readline()
--- 27,31 ----
      'input' and 'output' are files with readline() and write() methods.
      The 'quotetabs' flag indicates whether tabs should be quoted.
!         """
      while 1:
          line = input.readline()