[pypy-svn] r55367 - in pypy/dist/pypy/lib: . app_test

fijal at codespeak.net fijal at codespeak.net
Wed May 28 20:17:37 CEST 2008


Author: fijal
Date: Wed May 28 20:17:36 2008
New Revision: 55367

Modified:
   pypy/dist/pypy/lib/app_test/test_pyexpat.py
   pypy/dist/pypy/lib/pyexpat.py
Log:
A bit of error reporting.
Pass all tests, even those failing on cpy 2.5


Modified: pypy/dist/pypy/lib/app_test/test_pyexpat.py
==============================================================================
--- pypy/dist/pypy/lib/app_test/test_pyexpat.py	(original)
+++ pypy/dist/pypy/lib/app_test/test_pyexpat.py	Wed May 28 20:17:36 2008
@@ -371,7 +371,6 @@
         raise RuntimeError(name)
 
     def test(self):
-        py.test.skip("not implemented")
         parser = expat.ParserCreate()
         parser.StartElementHandler = self.StartElementHandler
         try:
@@ -447,7 +446,8 @@
         try:
             import __pypy__
         except ImportError:
-            py.test.skip("Doesn't work on cpy 2.5")
+            pass
+            #py.test.skip("Doesn't work on cpy 2.5")
 
     def test_1025_bytes(self):
         assert self.small_buffer_test(1025) == 2

Modified: pypy/dist/pypy/lib/pyexpat.py
==============================================================================
--- pypy/dist/pypy/lib/pyexpat.py	(original)
+++ pypy/dist/pypy/lib/pyexpat.py	Wed May 28 20:17:36 2008
@@ -2,7 +2,8 @@
 import ctypes
 import ctypes.util
 from ctypes_configure import configure
-from ctypes import c_char_p, c_int, c_void_p, POINTER, c_char
+from ctypes import c_char_p, c_int, c_void_p, POINTER, c_char, c_wchar_p
+import sys
 
 lib = ctypes.CDLL(ctypes.util.find_library('expat'))
 
@@ -21,21 +22,31 @@
                  'XML_PARAM_ENTITY_PARSING_ALWAYS']:
         locals()[name] = configure.ConstantInteger(name)
 
+    XML_Encoding = configure.Struct('XML_Encoding',[
+                                    ('data', c_void_p),
+                                    ('convert', c_void_p),
+                                    ('release', c_void_p),
+                                    ('map', c_int * 256)])
+    # this is insanely stupid
+    XML_FALSE = configure.ConstantInteger('XML_FALSE')
+    XML_TRUE = configure.ConstantInteger('XML_TRUE')
+
 info = configure.configure(CConfigure)
 for k, v in info.items():
     globals()[k] = v
 XML_Parser = ctypes.c_void_p # an opaque pointer
 assert XML_Char is ctypes.c_char # this assumption is everywhere in
 # cpython's expat, let's explode
-XML_ParserCreate = lib.XML_ParserCreate
-XML_ParserCreate.args = [ctypes.c_char_p]
-XML_ParserCreate.result = XML_Parser
-XML_ParserCreateNS = lib.XML_ParserCreateNS
-XML_ParserCreateNS.args = [c_char_p, c_char]
-XML_ParserCreateNS.result = XML_Parser
-XML_Parse = lib.XML_Parse
-XML_Parse.args = [XML_Parser, ctypes.c_char_p, ctypes.c_int, ctypes.c_int]
-XML_Parse.result = ctypes.c_int
+
+def declare_external(name, args, res):
+    func = getattr(lib, name)
+    func.args = args
+    func.result = res
+    globals()[name] = func
+
+declare_external('XML_ParserCreate', [c_char_p], XML_Parser)
+declare_external('XML_ParserCreateNS', [c_char_p, c_char], XML_Parser)
+declare_external('XML_Parse', [XML_Parser, c_char_p, c_int, c_int], c_int)
 currents = ['CurrentLineNumber', 'CurrentColumnNumber',
             'CurrentByteIndex']
 for name in currents:
@@ -43,15 +54,22 @@
     func.args = [XML_Parser]
     func.result = c_int
 
-XML_SetReturnNSTriplet = lib.XML_SetReturnNSTriplet
-XML_SetReturnNSTriplet.args = [XML_Parser, c_int]
-XML_SetReturnNSTriplet.result = None
-XML_GetSpecifiedAttributeCount = lib.XML_GetSpecifiedAttributeCount
-XML_GetSpecifiedAttributeCount.args = [XML_Parser]
-XML_GetSpecifiedAttributeCount.result = c_int
-XML_SetParamEntityParsing = lib.XML_SetParamEntityParsing
-XML_SetParamEntityParsing.args = [XML_Parser, c_int]
-XML_SetParamEntityParsing.result = None
+declare_external('XML_SetReturnNSTriplet', [XML_Parser, c_int], None)
+declare_external('XML_GetSpecifiedAttributeCount', [XML_Parser], c_int)
+declare_external('XML_SetParamEntityParsing', [XML_Parser, c_int], None)
+declare_external('XML_GetErrorCode', [XML_Parser], c_int)
+declare_external('XML_StopParser', [XML_Parser, c_int], None)
+lib.XML_ErrorString.args = [c_int]
+lib.XML_ErrorString.result = c_int
+
+declare_external('XML_SetUnknownEncodingHandler', [XML_Parser, c_void_p,
+                                                   c_void_p], None)
+
+def XML_ErrorString(code):
+    res = lib.XML_ErrorString(code)
+    p = c_char_p()
+    p.value = res
+    return p.value
 
 handler_names = [
     'StartElement',
@@ -92,7 +110,8 @@
     setters[name] = cfunc
 
 class ExpatError(Exception):
-    pass
+    def __str__(self):
+        return self.s
 
 error = ExpatError
 
@@ -111,6 +130,7 @@
             self.itself = XML_ParserCreateNS(encoding, ord(namespace_separator))
         if not self.itself:
             raise RuntimeError("Creating parser failed")
+        self._set_unknown_encoding_handler()
         self.storage = {}
         self.buffer = None
         self.buffer_size = 8192
@@ -128,10 +148,42 @@
         if self.character_data_handler:
             self.character_data_handler(buf)
 
-    def Parse(self, data, is_final):
+    def _set_unknown_encoding_handler(self):
+        def UnknownEncoding(encodingData, name, info_p):
+            info = info_p.contents
+            s = ''.join([chr(i) for i in range(256)])
+            u = s.decode(self.encoding, 'replace')
+            for i in range(len(u)):
+                if u[i] == u'\xfffd':
+                    info.map[i] = -1
+                else:
+                    info.map[i] = ord(u[i])
+            info.data = None
+            info.convert = None
+            info.release = None
+            return 1
+        
+        CB = ctypes.CFUNCTYPE(c_int, c_void_p, c_char_p, POINTER(XML_Encoding))
+        cb = CB(UnknownEncoding)
+        self._unknown_encoding_handler = (cb, UnknownEncoding)
+        XML_SetUnknownEncodingHandler(self.itself, cb, None)
+
+    def _set_error(self, code):
+        e = ExpatError()
+        e.code = code
+        lineno = lib.XML_GetCurrentLineNumber(self.itself)
+        colno = lib.XML_GetCurrentColumnNumber(self.itself)
+        e.offset = colno
+        e.lineno = lineno
+        err = XML_ErrorString(code)[:200]
+        e.s = "%s: line: %d, column: %d" % (err, lineno, colno)
+        self._error = e
+
+    def Parse(self, data, is_final=0):
         res = XML_Parse(self.itself, data, len(data), is_final)
         if res == 0:
-            xxx
+            self._set_error(XML_GetErrorCode(self.itself))
+            raise self.__exc_info[0], self.__exc_info[1], self.__exc_info[2]
         self._flush_character_buffer()
         return res
 
@@ -147,6 +199,15 @@
             cb = getattr(self, 'get_cb_for_%s' % name)(real_cb)
         setter(self.itself, cb)
 
+    def _wrap_cb(self, cb):
+        def f(*args):
+            try:
+                return cb(*args)
+            except:
+                self.__exc_info = sys.exc_info()
+                XML_StopParser(self.itself, XML_FALSE)
+        return f
+
     def get_cb_for_StartElementHandler(self, real_cb):
         def StartElement(unused, name, attrs):
             # unpack name and attrs
@@ -165,6 +226,7 @@
                 for i in range(0, max, 2):
                     res[conv(attrs[i])] = conv(attrs[i + 1])
             real_cb(conv(name), res)
+        StartElement = self._wrap_cb(StartElement)
         CB = ctypes.CFUNCTYPE(None, c_void_p, c_char_p, POINTER(c_char_p))
         return CB(StartElement)
 
@@ -177,6 +239,7 @@
             if res is None:
                 return 0
             return res
+        ExternalEntity = self._wrap_cb(ExternalEntity)
         CB = ctypes.CFUNCTYPE(c_int, c_void_p, *([c_char_p] * 4))
         return CB(ExternalEntity)
 
@@ -189,11 +252,12 @@
                     self._flush_character_buffer()
                     if self.character_data_handler is None:
                         return
-                if lgt > self.buffer_size:
+                if lgt >= self.buffer_size:
                     self._call_character_handler(s[:lgt])
                     self.buffer = []
                 else:
                     self.buffer.append(s[:lgt])
+        CharacterData = self._wrap_cb(CharacterData)
         CB = ctypes.CFUNCTYPE(None, c_void_p, POINTER(c_char), c_int)
         return CB(CharacterData)
 
@@ -206,6 +270,7 @@
                     pub_id, not_name]
             args = [self.conv(arg) for arg in args]
             real_cb(*args)
+        EntityDecl = self._wrap_cb(EntityDecl)
         CB = ctypes.CFUNCTYPE(None, c_void_p, c_char_p, c_int, c_char_p,
                                c_int, c_char_p, c_char_p, c_char_p, c_char_p)
         return CB(EntityDecl)
@@ -213,7 +278,8 @@
     def get_cb_for_ElementDeclHandler(self, real_cb):
         # XXX this is broken, needs tests
         def ElementDecl(unused, *args):
-            pass
+            print "WARNING! ElementDeclHandler Not supported"
+        ElementDecl = self._wrap_cb(ElementDecl)
         CB = ctypes.CFUNCTYPE(None, c_void_p, c_char_p, c_void_p)
         return CB(ElementDecl)
 
@@ -224,6 +290,7 @@
                 arg = self.conv(s[:len])
                 real_cb(arg)
             func.func_name = name
+            func = self._wrap_cb(func)
             CB = ctypes.CFUNCTYPE(*sign)
             return CB(func)
         get_callback_for_.func_name = 'get_cb_for_' + name
@@ -242,6 +309,7 @@
                 args = [self.conv(arg) for arg in args]
                 real_cb(*args)
             func.func_name = name
+            func = self._wrap_cb(func)
             CB = ctypes.CFUNCTYPE(*sign)
             return CB(func)
         get_callback_for_.func_name = 'get_cb_for_' + name
@@ -293,6 +361,12 @@
             else:
                 self._flush_character_buffer()
                 self.buffer = None
+        elif name == 'buffer_size':
+            if not isinstance(value, int):
+                raise TypeError("Expected int")
+            if value <= 0:
+                raise ValueError("Expected positive int")
+            self.__dict__[name] = value
         elif name == 'namespace_prefixes':
             XML_SetReturnNSTriplet(self.itself, int(bool(value)))
         elif name in setters:



More information about the Pypy-commit mailing list