Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/turbohtml/query/_xpath.py: 96%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

28 statements  

1""" 

2Smart-string xpath results, mirroring lxml's ``_ElementUnicodeResult``. 

3 

4When :meth:`turbohtml.Node.xpath` is called with ``smart_strings=True``, an 

5attribute or ``text()`` value comes back as an :class:`XPathString`: a ``str`` 

6that also remembers the element it was selected from, so ``result.getparent()`` 

7walks back into the tree and ``result.is_attribute`` / ``result.attrname`` 

8identify where it came from. The C core constructs these; importing this module 

9registers the type with it. 

10""" 

11 

12from __future__ import annotations 

13 

14from typing import TYPE_CHECKING 

15 

16from turbohtml._html import Element, _register_xpath_string # Element stays importable so autodoc resolves it 

17 

18if TYPE_CHECKING: 

19 from typing import Self 

20 

21 

22# isinstance(result, str) must hold for callers, and the C core builds the value 

23# through str.__new__, so this stays a real str subclass (FURB189 suppressed). 

24class XPathString(str): # ruff:ignore[subclass-builtin] 

25 """ 

26 A string xpath result that remembers the element it came from. 

27 

28 :param value: the string value itself, the attribute or ``text()`` result. 

29 :param parent: the element the value was selected from, returned by :meth:`getparent`. 

30 :param is_attribute: whether the value came from an attribute rather than element text. 

31 :param attrname: the attribute name the value came from, or ``None`` for a text value. 

32 """ 

33 

34 __slots__ = ("_parent", "attrname", "is_attribute", "is_tail", "is_text") 

35 

36 _parent: Element 

37 is_attribute: bool 

38 """Whether the value was selected from an attribute.""" 

39 is_text: bool 

40 """Whether the value was selected from element text.""" 

41 is_tail: bool 

42 """Whether the value is tail text; always False, kept for lxml compatibility.""" 

43 attrname: str | None 

44 """The attribute name the value came from, or None for a text value.""" 

45 

46 def __new__(cls, value: str, parent: Element, is_attribute: bool, attrname: str | None) -> Self: # ruff:ignore[boolean-type-hint-positional-argument] 

47 self = str.__new__(cls, value) 

48 self._parent = parent 

49 self.is_attribute = is_attribute 

50 self.is_text = not is_attribute 

51 self.is_tail = False 

52 self.attrname = attrname 

53 return self 

54 

55 def getparent(self) -> Element: 

56 """Return the element this attribute or text value was selected from.""" 

57 return self._parent 

58 

59 

60_register_xpath_string(XPathString)