[Lxml-checkins] r44189 - in lxml/branch/lxml-1.3: doc src/lxml src/lxml/tests

scoder at codespeak.net scoder at codespeak.net
Tue Jun 12 19:18:17 CEST 2007


Author: scoder
Date: Tue Jun 12 19:18:17 2007
New Revision: 44189

Modified:
   lxml/branch/lxml-1.3/doc/api.txt
   lxml/branch/lxml-1.3/doc/capi.txt
   lxml/branch/lxml-1.3/src/lxml/classlookup.pxi
   lxml/branch/lxml-1.3/src/lxml/etreepublic.pxd
   lxml/branch/lxml-1.3/src/lxml/tests/test_classlookup.py
   lxml/branch/lxml-1.3/src/lxml/xmlerror.pxi
Log:
merged in doc updates and revs 43349:43352 from trunk

Modified: lxml/branch/lxml-1.3/doc/api.txt
==============================================================================
--- lxml/branch/lxml-1.3/doc/api.txt	(original)
+++ lxml/branch/lxml-1.3/doc/api.txt	Tue Jun 12 19:18:17 2007
@@ -31,9 +31,10 @@
    3  Trees and Documents
    4  Iteration
    5  Error handling on exceptions
-   6  Serialisation
-   7  XInclude and ElementInclude
-   8  write_c14n on ElementTree
+   6  Error logging
+   7  Serialisation
+   8  XInclude and ElementInclude
+   9  write_c14n on ElementTree
 
 
 lxml.etree
@@ -188,29 +189,46 @@
 ----------------------------
 
 Libxml2 provides error messages for failures, be it during parsing, XPath
-evaluation or schema validation.  Whenever an exception is raised, you can
-retrieve the errors that occured and "might have" lead to the problem::
+evaluation or schema validation.  The preferred way of accessing them is
+through the local ``error_log`` property of the respective evaluator or
+transformer object.  See their documentation for details.
+
+However, lxml also keeps a global error log of all errors that occurred at the
+application level.  Whenever an exception is raised, you can retrieve the
+errors that occured and "might have" lead to the problem from the error log
+copy attached to the exception::
 
   >>> etree.clearErrorLog()
-  >>> broken_xml = '<a>'
+  >>> broken_xml = '''
+  ... <root>
+  ...   <a>
+  ... </root>
+  ... '''
   >>> try:
   ...   etree.parse(StringIO(broken_xml))
   ... except etree.XMLSyntaxError, e:
   ...   pass # just put the exception into e
-  >>> log = e.error_log.filter_levels(etree.ErrorLevels.FATAL)
+
+Once you have caught this exception, you can access its ``error_log`` property
+to retrieve the log entries or filter them by a specific type, error domain or
+error level::
+
+  >>> log = e.error_log.filter_from_level(etree.ErrorLevels.FATAL)
   >>> print log
-  <string>:1:FATAL:PARSER:ERR_TAG_NOT_FINISHED: Premature end of data in tag a line 1
+  <string>:4:FATAL:PARSER:ERR_TAG_NAME_MISMATCH: Opening and ending tag mismatch: a line 3 and root
+  <string>:5:FATAL:PARSER:ERR_TAG_NOT_FINISHED: Premature end of data in tag root line 2
 
 This might look a little cryptic at first, but it is the information that
 libxml2 gives you.  At least the message at the end should give you a hint
-what went wrong and you can see that the fatal error (FATAL) happened during
-parsing (PARSER) line 1 of a string (<string>, or filename if available).
-Here, PARSER is the so-called error domain, see lxml.etree.ErrorDomains for
-that.  You can get it from a log entry like this::
+what went wrong and you can see that the fatal errors (FATAL) happened during
+parsing (PARSER) lines 4 and 5 of a string (<string>, or the filename if
+available).  Here, PARSER is the so-called error domain, see
+``lxml.etree.ErrorDomains`` for that.  You can get it from a log entry like
+this::
 
   >>> entry = log[0]
   >>> print entry.domain_name, entry.type_name, entry.filename
-  PARSER ERR_TAG_NOT_FINISHED <string>
+  PARSER ERR_TAG_NAME_MISMATCH <string>
 
 There is also a convenience attribute ``last_error`` that returns the last
 error or fatal error that occurred::
@@ -219,13 +237,16 @@
   >>> print entry.domain_name, entry.type_name, entry.filename
   PARSER ERR_TAG_NOT_FINISHED <string>
 
-Alternatively, lxml.etree supports logging libxml2 messages to the Python
-stdlib logging module.  This is done through the ``etree.PyErrorLog`` class.
-It disables the error reporting from exceptions and forwards log messages to a
-Python logger.  To use it, see the descriptions of the function
-``etree.useGlobalPythonLog`` and the class ``etree.PyErrorLog`` for help.
-Note that this does not affect the local error logs of XSLT, XMLSchema,
-etc. which are described in their respective sections below.
+
+Error logging
+-------------
+
+lxml.etree supports logging libxml2 messages to the Python stdlib logging
+module.  This is done through the ``etree.PyErrorLog`` class.  It disables the
+error reporting from exceptions and forwards log messages to a Python logger.
+To use it, see the descriptions of the function ``etree.useGlobalPythonLog``
+and the class ``etree.PyErrorLog`` for help.  Note that this does not affect
+the local error logs of XSLT, XMLSchema, etc.
 
 
 Serialisation

Modified: lxml/branch/lxml-1.3/doc/capi.txt
==============================================================================
--- lxml/branch/lxml-1.3/doc/capi.txt	(original)
+++ lxml/branch/lxml-1.3/doc/capi.txt	Tue Jun 12 19:18:17 2007
@@ -9,7 +9,7 @@
 The API is described in the file `etreepublic.pxd`_, which is directly
 c-importable by Pyrex modules.
 
-.. _`etreepublic.pxd`: http://codespeak.net/svn/lxml/branch/capi/src/lxml/etreepublic.pxd
+.. _`etreepublic.pxd`: http://codespeak.net/svn/lxml/trunk/src/lxml/etreepublic.pxd
 
 .. contents::
 ..
@@ -23,6 +23,8 @@
 This is the easiest way of extending lxml at the C level.  A Pyrex module
 should start like this::
 
+    # My Pyrex extension
+
     # import the public functions and classes of lxml.etree
     cimport etreepublic as cetree
 
@@ -47,7 +49,8 @@
          def setValue(self, myval):
              self.set("my_attribute", myval)
 
-    etree.setDefaultElementClass(NewElementClass)
+    etree.setElementClassLookup(
+         DefaultElementClassLookup(element=NewElementClass))
 
 
 Writing external modules in C

Modified: lxml/branch/lxml-1.3/src/lxml/classlookup.pxi
==============================================================================
--- lxml/branch/lxml-1.3/src/lxml/classlookup.pxi	(original)
+++ lxml/branch/lxml-1.3/src/lxml/classlookup.pxi	Tue Jun 12 19:18:17 2007
@@ -79,6 +79,9 @@
 cdef class ElementDefaultClassLookup(ElementClassLookup):
     """Element class lookup scheme that always returns the default Element
     class.
+
+    The keyword arguments ``element``, ``comment`` and ``pi`` accept the
+    respective Element classes.
     """
     cdef readonly object element_class
     cdef readonly object comment_class
@@ -86,21 +89,21 @@
     def __init__(self, element=None, comment=None, pi=None):
         self._lookup_function = _lookupDefaultElementClass
         if element is None:
-            self.element_class = _Element
+            self.element_class = None
         elif issubclass(element, ElementBase):
             self.element_class = element
         else:
             raise TypeError, "element class must be subclass of ElementBase"
 
         if comment is None:
-            self.comment_class = _Comment
+            self.comment_class = None
         elif issubclass(comment, CommentBase):
             self.comment_class = comment
         else:
             raise TypeError, "comment class must be subclass of CommentBase"
 
         if pi is None:
-            self.pi_class = _ProcessingInstruction
+            self.pi_class = None
         elif issubclass(pi, PIBase):
             self.pi_class = pi
         else:
@@ -109,17 +112,23 @@
 cdef object _lookupDefaultElementClass(state, _Document _doc, xmlNode* c_node):
     "Trivial class lookup function that always returns the default class."
     if c_node.type == tree.XML_ELEMENT_NODE:
-        if state is None:
+        if state is not None:
+            cls =  (<ElementDefaultClassLookup>state).element_class
+        if cls is None:
             return _Element
         else:
-            return (<ElementDefaultClassLookup>state).element_class
+            return cls
     elif c_node.type == tree.XML_COMMENT_NODE:
-        if state is None:
+        if state is not None:
+            cls = (<ElementDefaultClassLookup>state).comment_class
+        if cls is None:
             return _Comment
         else:
-            return (<ElementDefaultClassLookup>state).comment_class
+            return cls
     elif c_node.type == tree.XML_PI_NODE:
-        if state is None:
+        if state is not None:
+            cls = (<ElementDefaultClassLookup>state).pi_class
+        if cls is None:
             # special case XSLT-PI
             if c_node.name is not NULL and c_node.content is not NULL:
                 if cstd.strcmp(c_node.name, "xml-stylesheet") == 0:
@@ -128,7 +137,7 @@
                         return _XSLTProcessingInstruction
             return _ProcessingInstruction
         else:
-            return (<ElementDefaultClassLookup>state).pi_class
+            return cls
     else:
         assert 0, "Unknown node type: %s" % c_node.type
 
@@ -145,9 +154,9 @@
     dictionary.  
 
     Arguments:
-    * attribute name ('{ns}name' style string)
-    * class mapping  (Python dict mapping attribute values to Element classes)
-    * fallback       (optional fallback lookup mechanism)
+    * attribute name - '{ns}name' style string
+    * class mapping  - Python dict mapping attribute values to Element classes
+    * fallback       - optional fallback lookup mechanism
 
     A None key in the class mapping will be checked if the attribute is
     missing.
@@ -194,10 +203,9 @@
 cdef object _parser_class_lookup(state, _Document doc, xmlNode* c_node):
     cdef FallbackElementClassLookup lookup
     lookup = <FallbackElementClassLookup>state
-    if c_node.type == tree.XML_ELEMENT_NODE:
-        if doc._parser._class_lookup is not None:
-            return doc._parser._class_lookup._lookup_function(
-                doc._parser._class_lookup, doc, c_node)
+    if doc._parser._class_lookup is not None:
+        return doc._parser._class_lookup._lookup_function(
+            doc._parser._class_lookup, doc, c_node)
     return lookup._callFallback(doc, c_node)
 
 

Modified: lxml/branch/lxml-1.3/src/lxml/etreepublic.pxd
==============================================================================
--- lxml/branch/lxml-1.3/src/lxml/etreepublic.pxd	(original)
+++ lxml/branch/lxml-1.3/src/lxml/etreepublic.pxd	Tue Jun 12 19:18:17 2007
@@ -36,7 +36,7 @@
 
     cdef class lxml.etree._ElementTree [ object LxmlElementTree ]:
         cdef _Document _doc
-        cdef _Element  _element
+        cdef _Element  _context_node
 
     cdef class lxml.etree.ElementClassLookup [ object LxmlElementClassLookup ]:
         cdef object (*_lookup_function)(object, _Document, tree.xmlNode*)
@@ -82,7 +82,7 @@
     cdef object lookupNamespaceElementClass(_1, _Document _2,
                                             tree.xmlNode* c_node)
 
-    # call the fallback lookup function of an FallbackElementClassLookup
+    # call the fallback lookup function of a FallbackElementClassLookup
     cdef object callLookupFallback(FallbackElementClassLookup lookup,
                                    _Document doc, tree.xmlNode* c_node)
 

Modified: lxml/branch/lxml-1.3/src/lxml/tests/test_classlookup.py
==============================================================================
--- lxml/branch/lxml-1.3/src/lxml/tests/test_classlookup.py	(original)
+++ lxml/branch/lxml-1.3/src/lxml/tests/test_classlookup.py	Tue Jun 12 19:18:17 2007
@@ -51,6 +51,31 @@
 
     def test_default_class_lookup(self):
         class TestElement(etree.ElementBase):
+            FIND_ME = "default element"
+        class TestComment(etree.CommentBase):
+            FIND_ME = "default comment"
+        class TestPI(etree.PIBase):
+            FIND_ME = "default pi"
+
+        parser = etree.XMLParser()
+
+        lookup = etree.ElementDefaultClassLookup(
+            element=TestElement, comment=TestComment, pi=TestPI)
+        parser.setElementClassLookup(lookup)
+
+        root = etree.XML("""<?xml version='1.0'?>
+        <root>
+          <?myPI?>
+          <!-- hi -->
+        </root>
+        """, parser)
+
+        self.assertEquals("default element", root.FIND_ME)
+        self.assertEquals("default pi", root[0].FIND_ME)
+        self.assertEquals("default comment", root[1].FIND_ME)
+
+    def test_default_class_lookup_is_not_nslookup(self):
+        class TestElement(etree.ElementBase):
             FIND_ME = "namespace class"
 
         ns = etree.Namespace("myNS")

Modified: lxml/branch/lxml-1.3/src/lxml/xmlerror.pxi
==============================================================================
--- lxml/branch/lxml-1.3/src/lxml/xmlerror.pxi	(original)
+++ lxml/branch/lxml-1.3/src/lxml/xmlerror.pxi	Tue Jun 12 19:18:17 2007
@@ -128,6 +128,9 @@
         self._entries = entries
 
     def copy(self):
+        """Creates a shallow copy of this error log.  Reuses the list of
+        entries.
+        """
         return _ListErrorLog(self._entries, self.last_error)
 
     def __iter__(self):
@@ -146,6 +149,9 @@
         return len(self._entries)
 
     def filter_domains(self, domains):
+        """Filter the errors by the given domains and return a new error log
+        containing the matches.
+        """
         cdef _LogEntry entry
         filtered = []
         if not python.PySequence_Check(domains):
@@ -156,6 +162,9 @@
         return _ListErrorLog(filtered)
 
     def filter_types(self, types):
+        """Filter the errors by the given types and return a new error log
+        containing the matches.
+        """
         cdef _LogEntry entry
         if not python.PySequence_Check(types):
             types = (types,)
@@ -166,8 +175,9 @@
         return _ListErrorLog(filtered)
 
     def filter_levels(self, levels):
-        """Return a log with all messages of the requested level(s). Takes a
-        single log level or a sequence."""
+        """Filter the errors by the given error levels and return a new error
+        log containing the matches.
+        """
         cdef _LogEntry entry
         if not python.PySequence_Check(levels):
             levels = (levels,)
@@ -213,6 +223,8 @@
         del self._entries[:]
 
     def copy(self):
+        """Creates a shallow copy of this error log and the list of entries.
+        """
         return _ListErrorLog(self._entries[:], self.last_error)
 
     def __iter__(self):
@@ -260,7 +272,8 @@
     object and calls ``self.log(log_entry, format_string, arg1, arg2, ...)``
     with appropriate data.
     """
-    cdef public object level_map
+    cdef readonly object level_map
+    cdef object _map_level
     cdef object _log
     def __init__(self, logger_name=None):
         _BaseErrorLog.__init__(self)
@@ -270,6 +283,7 @@
             ErrorLevels.ERROR   : logging.ERROR,
             ErrorLevels.FATAL   : logging.CRITICAL
             }
+        self._map_level = self.level_map.get
         if logger_name:
             logger = logging.getLogger(logger_name)
         else:
@@ -277,11 +291,13 @@
         self._log = logger.log
 
     def copy(self):
+        """Dummy method that returns an empty error log.
+        """
         return _ListErrorLog([])
 
     def log(self, entry, message_format_string, *args):
         self._log(
-            self.level_map.get(entry.level, 0),
+            self._map_level(entry.level, 0),
             message_format_string, *args
             )
 
@@ -300,9 +316,8 @@
     """Replace the global error log by an etree.PyErrorLog that uses the
     standard Python logging package.
 
-    Note that this slows down processing and disables access to the global
-    error log from exceptions.  Parsers, XSLT etc. will continue to provide
-    their normal local error log.
+    Note that this disables access to the global error log from exceptions.
+    Parsers, XSLT etc. will continue to provide their normal local error log.
     """
     global __GLOBAL_ERROR_LOG
     __GLOBAL_ERROR_LOG = log
@@ -378,6 +393,11 @@
     c_error.domain = xmlerror.XML_FROM_XSLT
     c_error.code   = xmlerror.XML_ERR_OK    # what else?
     c_error.level  = xmlerror.XML_ERR_ERROR # what else?
+    c_error.str1   = NULL
+    c_error.str2   = NULL
+    c_error.str3   = NULL
+    c_error.int1   = 0
+    c_error.int2   = 0
 
     _forwardError(c_log_handler, &c_error)
 


More information about the lxml-checkins mailing list