[Lxml-checkins] r43301 - in lxml/trunk: . src/lxml src/lxml/tests
scoder at codespeak.net
scoder at codespeak.net
Sat May 12 17:34:00 CEST 2007
Author: scoder
Date: Sat May 12 17:34:00 2007
New Revision: 43301
Modified:
lxml/trunk/CHANGES.txt
lxml/trunk/src/lxml/tests/test_xpathevaluator.py
lxml/trunk/src/lxml/xmlerror.pxi
lxml/trunk/src/lxml/xpath.pxi
Log:
new XPathEvalError for evaluation errors (instead of always raising XPathSyntaxError)
Modified: lxml/trunk/CHANGES.txt
==============================================================================
--- lxml/trunk/CHANGES.txt (original)
+++ lxml/trunk/CHANGES.txt Sat May 12 17:34:00 2007
@@ -8,6 +8,10 @@
Features added
--------------
+* Error specific messages in XPath parsing and evaluation
+ NOTE: for evaluation errors, you will now get an XPathEvalError instead of
+ an XPathSyntaxError. To catch both, you can except on ``XPathError``
+
* The regular expression functions in XPath now support passing a node-set
instead of a string
Modified: lxml/trunk/src/lxml/tests/test_xpathevaluator.py
==============================================================================
--- lxml/trunk/src/lxml/tests/test_xpathevaluator.py (original)
+++ lxml/trunk/src/lxml/tests/test_xpathevaluator.py Sat May 12 17:34:00 2007
@@ -114,7 +114,20 @@
def test_xpath_error(self):
tree = self.parse('<a/>')
- self.assertRaises(SyntaxError, tree.xpath, '\\fad')
+ self.assertRaises(etree.XPathEvalError, tree.xpath, '\\fad')
+
+ def test_xpath_class_error(self):
+ self.assertRaises(SyntaxError, etree.XPath, '\\fad')
+ self.assertRaises(etree.XPathSyntaxError, etree.XPath, '\\fad')
+
+ def test_xpath_prefix_error(self):
+ tree = self.parse('<a/>')
+ self.assertRaises(etree.XPathEvalError, tree.xpath, '/fa:d')
+
+ def test_xpath_class_prefix_error(self):
+ tree = self.parse('<a/>')
+ xpath = etree.XPath("/fa:d")
+ self.assertRaises(etree.XPathEvalError, xpath, tree)
def test_elementtree_getpath(self):
a = etree.Element("a")
Modified: lxml/trunk/src/lxml/xmlerror.pxi
==============================================================================
--- lxml/trunk/src/lxml/xmlerror.pxi (original)
+++ lxml/trunk/src/lxml/xmlerror.pxi Sat May 12 17:34:00 2007
@@ -5,8 +5,9 @@
# module level API functions
def clearErrorLog():
- """Clear the global error log.
- Note that this log is already bounded to a fixed size."""
+ """Clear the global error log. Note that this log is already bound to a
+ fixed size.
+ """
__GLOBAL_ERROR_LOG.clear()
# dummy function: no debug output at all
@@ -145,6 +146,15 @@
def __len__(self):
return len(self._entries)
+ def __contains__(self, error_type):
+ for entry in self._entries:
+ if entry.type == error_type:
+ return True
+ return False
+
+ def __nonzero__(self):
+ return bool(self._entries)
+
def filter_domains(self, domains):
cdef _LogEntry entry
filtered = []
Modified: lxml/trunk/src/lxml/xpath.pxi
==============================================================================
--- lxml/trunk/src/lxml/xpath.pxi (original)
+++ lxml/trunk/src/lxml/xpath.pxi Sat May 12 17:34:00 2007
@@ -1,14 +1,36 @@
# XPath evaluation
-class XPathContextError(XPathError):
+class XPathSyntaxError(LxmlSyntaxError, XPathError):
pass
-class XPathSyntaxError(LxmlSyntaxError, XPathError):
+class XPathEvalError(XPathError):
pass
################################################################################
# XPath
+cdef object _XPATH_SYNTAX_ERRORS
+_XPATH_SYNTAX_ERRORS = (
+ xmlerror.XML_XPATH_NUMBER_ERROR,
+ xmlerror.XML_XPATH_UNFINISHED_LITERAL_ERROR,
+ xmlerror.XML_XPATH_VARIABLE_REF_ERROR,
+ xmlerror.XML_XPATH_INVALID_PREDICATE_ERROR,
+ xmlerror.XML_XPATH_UNCLOSED_ERROR,
+ xmlerror.XML_XPATH_INVALID_CHAR_ERROR
+)
+
+cdef object _XPATH_EVAL_ERRORS
+_XPATH_EVAL_ERRORS = (
+ xmlerror.XML_XPATH_UNDEF_VARIABLE_ERROR,
+ xmlerror.XML_XPATH_UNDEF_PREFIX_ERROR,
+ xmlerror.XML_XPATH_UNKNOWN_FUNC_ERROR,
+ xmlerror.XML_XPATH_INVALID_OPERAND,
+ xmlerror.XML_XPATH_INVALID_TYPE,
+ xmlerror.XML_XPATH_INVALID_ARITY,
+ xmlerror.XML_XPATH_INVALID_CTXT_SIZE,
+ xmlerror.XML_XPATH_INVALID_CTXT_POSITION
+)
+
cdef int _register_xpath_function(void* ctxt, name_utf, ns_utf):
if ns_utf is None:
return xpath.xmlXPathRegisterFunc(
@@ -76,11 +98,17 @@
cdef xpath.xmlXPathContext* _xpathCtxt
cdef _XPathContext _context
cdef python.PyThread_type_lock _eval_lock
+ cdef _ErrorLog _error_log
def __init__(self, namespaces, extensions, enable_regexp):
+ self._error_log = _ErrorLog()
self._context = _XPathContext(namespaces, extensions,
enable_regexp, None)
+ property error_log:
+ def __get__(self):
+ return self._error_log.copy()
+
def __dealloc__(self):
if self._xpathCtxt is not NULL:
xpath.xmlXPathFreeContext(self._xpathCtxt)
@@ -127,6 +155,12 @@
python.PyThread_release_lock(self._eval_lock)
cdef _raise_parse_error(self):
+ entries = self._error_log.filter_types(_XPATH_SYNTAX_ERRORS)
+ if entries:
+ entry = entries[0]
+ if entry is not None and entry.message:
+ raise XPathSyntaxError, entry.message
+
if self._xpathCtxt is not NULL and \
self._xpathCtxt.lastError.message is not NULL:
message = funicode(self._xpathCtxt.lastError.message)
@@ -134,6 +168,24 @@
message = "error in xpath expression"
raise XPathSyntaxError, message
+ cdef _raise_eval_error(self):
+ entries = self._error_log.filter_types(_XPATH_EVAL_ERRORS)
+ if entries:
+ entry = entries[0]
+ if entry is not None and entry.message:
+ raise XPathEvalError, entry.message
+ entries = self._error_log.filter_types(_XPATH_SYNTAX_ERRORS)
+ if entries:
+ entry = entries[0]
+ if entry is not None and entry.message:
+ raise XPathSyntaxError, entry.message
+ if self._xpathCtxt is not NULL and \
+ self._xpathCtxt.lastError.message is not NULL:
+ message = funicode(self._xpathCtxt.lastError.message)
+ else:
+ message = "error in xpath evaluation"
+ raise XPathEvalError, message
+
cdef object _handle_result(self, xpath.xmlXPathObject* xpathObj, _Document doc):
if self._context._exc._has_raised():
if xpathObj is not NULL:
@@ -144,7 +196,7 @@
if xpathObj is NULL:
self._context._release_temp_refs()
- self._raise_parse_error()
+ self._raise_eval_error()
try:
result = _unwrapXPathObject(xpathObj, doc)
@@ -176,7 +228,7 @@
_XPathEvaluatorBase.__init__(self, namespaces, extensions, regexp)
xpathCtxt = xpath.xmlXPathNewContext(doc._c_doc)
if xpathCtxt is NULL:
- raise XPathContextError, "Unable to create new XPath context"
+ python.PyErr_NoMemory()
self.set_context(xpathCtxt)
def registerNamespace(self, prefix, uri):
@@ -207,6 +259,7 @@
doc = self._element._doc
self._lock()
+ self._error_log.connect()
self._xpathCtxt.node = self._element._c_node
try:
self._context.register_context(doc)
@@ -217,6 +270,7 @@
python.PyEval_RestoreThread(state)
result = self._handle_result(xpathObj, doc)
finally:
+ self._error_log.disconnect()
self._context.unregister_context()
self._unlock()
@@ -249,6 +303,7 @@
doc = self._element._doc
self._lock()
+ self._error_log.connect()
try:
self._context.register_context(doc)
c_doc = _fakeRootDoc(doc._c_doc, self._element._c_node)
@@ -265,6 +320,7 @@
_destroyFakeDoc(doc._c_doc, c_doc)
self._context.unregister_context()
finally:
+ self._error_log.disconnect()
self._unlock()
return result
@@ -308,9 +364,11 @@
path = _utf8(path)
xpathCtxt = xpath.xmlXPathNewContext(NULL)
if xpathCtxt is NULL:
- raise XPathContextError, "Unable to create new XPath context"
+ python.PyErr_NoMemory()
self.set_context(xpathCtxt)
+ self._error_log.connect()
self._xpath = xpath.xmlXPathCtxtCompile(xpathCtxt, _cstr(path))
+ self._error_log.disconnect()
if self._xpath is NULL:
self._raise_parse_error()
@@ -325,6 +383,7 @@
element = _rootNodeOrRaise(_etree_or_element)
self._lock()
+ self._error_log.connect()
self._xpathCtxt.doc = document._c_doc
self._xpathCtxt.node = element._c_node
@@ -337,6 +396,7 @@
python.PyEval_RestoreThread(state)
result = self._handle_result(xpathObj, document)
finally:
+ self._error_log.disconnect()
self._context.unregister_context()
self._unlock()
return result
More information about the lxml-checkins
mailing list