Permalink
Browse files

Let extended translators override what XPathExpr class is used

GenericTranslator offers an excelent way to support custom selectors
trough method hooks and allowing to return a *new* XPathExpr from this
hooks.

The main problem is that returning extended `XPathExpr` instances fail
for combiners because `XPathExpr.join()` assume a fixed XPathExpr
instance attributes (element, path and condition) to copy from `other` to `self`

`XPathExpr.join()` can be extended in subclass but needs that `left`
xpath instance to be of the extended class too, and right now we can
only control `right` xpath type.

The problem can be mitigated by recasting all xpath returned from
`GenericTranslator.xpath_element()` that only works because it is the
only hook that cast `XPathExpr` instances.

The proposed change allow projects extending GenericTranslator to also
safely extend `XPathExpr` to correctly support combiners in extended
features.
  • Loading branch information...
1 parent 653a5a5 commit 91e752d4994f3d95b89b850b96672f47418623d8 @dangra dangra committed Jan 10, 2013
Showing with 5 additions and 2 deletions.
  1. +5 −2 cssselect/xpath.py
View
@@ -146,6 +146,9 @@ class GenericTranslator(object):
lower_case_attribute_names = False
lower_case_attribute_values = False
+ # class used to represent and xpath expression
+ xpathexpr_cls = XPathExpr
+
def css_to_xpath(self, css, prefix='descendant-or-self::'):
"""Translate a *group of selectors* to XPath.
@@ -190,7 +193,7 @@ def selector_to_xpath(self, selector, prefix='descendant-or-self::'):
if not tree:
raise TypeError('Expected a parsed selector, got %r' % (selector,))
xpath = self.xpath(tree)
- assert isinstance(xpath, XPathExpr) # help debug a missing 'return'
+ assert isinstance(xpath, self.xpathexpr_cls) # help debug a missing 'return'
return (prefix or '') + _unicode(xpath)
@staticmethod
@@ -305,7 +308,7 @@ def xpath_element(self, selector):
# http://www.w3.org/TR/css3-namespace/#prefixes
element = '%s:%s' % (selector.namespace, element)
safe = safe and is_safe_name(selector.namespace)
- xpath = XPathExpr(element=element)
+ xpath = self.xpathexpr_cls(element=element)
if not safe:
xpath.add_name_test()
return xpath

0 comments on commit 91e752d

Please sign in to comment.