[XML-SIG] Python 1.5.2b1's xmllib.py Considered Harmful

Fredrik Lundh fredrik@pythonware.com
Mon, 1 Feb 1999 09:57:21 +0100


This is a multi-part message in MIME format.

------=_NextPart_000_0026_01BE4DC9.42E0DA30
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

I wrote:
>xmllib.py currently got a completely new interface in 1.5.2b1.
>The new interface silently breaks all existing implementations
>(it no longer calls start and end handlers), something that has
>caused us a LOT of trouble lately.  For example, our highly
>successful xmlrpclib.py implementation doesn't work at all
>under 1.5.2b1.

The attached patch solves some of the compatibility
problems introduced by the new xmllib.py.  The most
important change is that it now preloads the elements
dictionary with pointers to any "start" and "end" handlers
defined by subclasses, like earlier versions. It also adds
some code to avoid cyclic references and unexpected
modifications to the elements dictionary.

With this in place, xmlrpclib.py works just fine also
with the new version of xmllib.py.

Cheers /F
fredrik@pythonware.com
http://www.pythonware.com

------=_NextPart_000_0026_01BE4DC9.42E0DA30
Content-Type: application/octet-stream;
	name="patch1"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="patch1"

*** r:\BleedingEdge\python\dist\src\Lib\xmllib.py	Mon Dec 28 15:38:03 1998
--- xmllib.py	Mon Feb 01 09:36:26 1999
***************
*** 90,95 ****
--- 90,132 ----
      def __init__(self):
          self.reset()
  
+         # duplicate class dictionaries
+         self.attributes = self.attributes.copy()
+         self.elements = self.elements.copy()
+ 
+         # COMPATIBILITY: find all start and end handlers and add them
+         # to the elements dictionary.  Don't override already installed
+         # versions.
+         self.__preload(self.__class__)
+ 
+     def __preload(self, cls):
+         # find all start/end handlers declared by this class
+         for event in dir(cls):
+             # look for start and end tag handlers
+             if event[:6] == "start_":
+                 tag = event[6:]
+             elif event[:4] == "end_":
+                 tag = event[4:]
+             else:
+                 continue
+             # don't override already installed handlers
+             if self.elements.has_key(tag):
+                 continue
+             # fetch start and end handlers.  use None for
+             # missing handlers
+             try:
+                 start = getattr(self, "start_" + tag)
+             except AttributeError:
+                 start = None
+             try:
+                 end = getattr(self, "end_" + tag)
+             except AttributeError:
+                 end = None
+             self.elements[tag] = (start, end)
+         # check base classes
+         for base in cls.__bases__:
+             self.__preload(base)
+ 
      # Interface -- reset this instance.  Loses all unprocessed data
      def reset(self):
          self.rawdata = ''
***************
*** 122,127 ****
--- 159,165 ----
      # Interface -- handle the remaining data
      def close(self):
          self.goahead(1)
+         self.elements = {} # nuke potential cyclic reference
  
      # Interface -- translate references
      def translate_references(self, data, all = 1):

------=_NextPart_000_0026_01BE4DC9.42E0DA30--