[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