From fe066ce2d6f71603f525c6d887fddf632fedba8b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 7 Nov 2019 14:15:46 +0530 Subject: [PATCH] Conversion: CSS selectors with unknown pseudo-elements should not match any tags. See #1827700 (Private bug) --- src/css_selectors/select.py | 46 +++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/css_selectors/select.py b/src/css_selectors/select.py index 2626a8fe8c..ce6b2df178 100644 --- a/src/css_selectors/select.py +++ b/src/css_selectors/select.py @@ -13,7 +13,7 @@ from itertools import chain from lxml import etree from css_selectors.errors import ExpressionError -from css_selectors.parser import parse, ascii_lower, Element +from css_selectors.parser import parse, ascii_lower, Element, FunctionalPseudoElement from css_selectors.ordered_set import OrderedSet from polyglot.builtins import iteritems, itervalues @@ -182,8 +182,7 @@ class Select(object): seen = set() if root is not None: root = frozenset(self.itertag(root)) - for selector in get_parsed_selector(selector): - parsed_selector = selector.parsed_tree + for parsed_selector in get_parsed_selector(selector): for item in self.iterparsedselector(parsed_selector): if item not in seen and (root is None or item in root): yield item @@ -581,31 +580,54 @@ def allow_all(cache, item): return True -def select_pseudo(cache, pseudo): +def get_func_for_pseudo(cache, ident): try: - func = cache.dispatch_map[pseudo.ident.replace('-', '_')] + func = cache.dispatch_map[ident.replace('-', '_')] except KeyError: - if pseudo.ident == 'root': - yield cache.root - return - - if pseudo.ident in cache.ignore_inappropriate_pseudo_classes: + if ident in cache.ignore_inappropriate_pseudo_classes: func = allow_all else: raise ExpressionError( - "The pseudo-class :%s is not supported" % pseudo.ident) + "The pseudo-class :%s is not supported" % ident) try: func.is_pseudo except AttributeError: raise ExpressionError( - "The pseudo-class :%s is invalid" % pseudo.ident) + "The pseudo-class :%s is invalid" % ident) + return func + + +def select_selector(cache, selector): + if selector.pseudo_element is None: + for item in cache.iterparsedselector(selector.parsed_tree): + yield item + return + if isinstance(selector.pseudo_element, FunctionalPseudoElement): + raise ExpressionError( + "The pseudo-element ::%s is not supported" % selector.pseudo_element.name) + func = get_func_for_pseudo(cache, selector.pseudo_element) + for item in cache.iterparsedselector(selector.parsed_tree): + if func(cache, item): + yield item + + +def select_pseudo(cache, pseudo): + func = get_func_for_pseudo(cache, pseudo.ident) + if func is select_root: + yield cache.root + return for item in cache.iterparsedselector(pseudo.selector): if func(cache, item): yield item +@pseudo_func +def select_root(cache, elem): + return elem is cache.root + + @pseudo_func def select_first_child(cache, elem): try: