Skip to content

Commit 91e752d

Browse files
committed
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.
1 parent 653a5a5 commit 91e752d

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

cssselect/xpath.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ class GenericTranslator(object):
146146
lower_case_attribute_names = False
147147
lower_case_attribute_values = False
148148

149+
# class used to represent and xpath expression
150+
xpathexpr_cls = XPathExpr
151+
149152
def css_to_xpath(self, css, prefix='descendant-or-self::'):
150153
"""Translate a *group of selectors* to XPath.
151154
@@ -190,7 +193,7 @@ def selector_to_xpath(self, selector, prefix='descendant-or-self::'):
190193
if not tree:
191194
raise TypeError('Expected a parsed selector, got %r' % (selector,))
192195
xpath = self.xpath(tree)
193-
assert isinstance(xpath, XPathExpr) # help debug a missing 'return'
196+
assert isinstance(xpath, self.xpathexpr_cls) # help debug a missing 'return'
194197
return (prefix or '') + _unicode(xpath)
195198

196199
@staticmethod
@@ -305,7 +308,7 @@ def xpath_element(self, selector):
305308
# http://www.w3.org/TR/css3-namespace/#prefixes
306309
element = '%s:%s' % (selector.namespace, element)
307310
safe = safe and is_safe_name(selector.namespace)
308-
xpath = XPathExpr(element=element)
311+
xpath = self.xpathexpr_cls(element=element)
309312
if not safe:
310313
xpath.add_name_test()
311314
return xpath

0 commit comments

Comments
 (0)