aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/bs4/css.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/bs4/css.py')
-rw-r--r--.venv/lib/python3.12/site-packages/bs4/css.py338
1 files changed, 338 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/bs4/css.py b/.venv/lib/python3.12/site-packages/bs4/css.py
new file mode 100644
index 00000000..c20850fc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/bs4/css.py
@@ -0,0 +1,338 @@
+"""Integration code for CSS selectors using `Soup Sieve <https://facelessuser.github.io/soupsieve/>`_ (pypi: ``soupsieve``).
+
+Acquire a `CSS` object through the `element.Tag.css` attribute of
+the starting point of your CSS selector, or (if you want to run a
+selector against the entire document) of the `BeautifulSoup` object
+itself.
+
+The main advantage of doing this instead of using ``soupsieve``
+functions is that you don't need to keep passing the `element.Tag` to be
+selected against, since the `CSS` object is permanently scoped to that
+`element.Tag`.
+
+"""
+
+from __future__ import annotations
+
+from types import ModuleType
+from typing import (
+ Any,
+ cast,
+ Iterable,
+ Iterator,
+ Optional,
+ TYPE_CHECKING,
+)
+import warnings
+from bs4._typing import _NamespaceMapping
+
+if TYPE_CHECKING:
+ from soupsieve import SoupSieve
+ from bs4 import element
+ from bs4.element import ResultSet, Tag
+
+soupsieve: Optional[ModuleType]
+try:
+ import soupsieve
+except ImportError:
+ soupsieve = None
+ warnings.warn(
+ "The soupsieve package is not installed. CSS selectors cannot be used."
+ )
+
+
+class CSS(object):
+ """A proxy object against the ``soupsieve`` library, to simplify its
+ CSS selector API.
+
+ You don't need to instantiate this class yourself; instead, use
+ `element.Tag.css`.
+
+ :param tag: All CSS selectors run by this object will use this as
+ their starting point.
+
+ :param api: An optional drop-in replacement for the ``soupsieve`` module,
+ intended for use in unit tests.
+ """
+
+ def __init__(self, tag: element.Tag, api: Optional[ModuleType] = None):
+ if api is None:
+ api = soupsieve
+ if api is None:
+ raise NotImplementedError(
+ "Cannot execute CSS selectors because the soupsieve package is not installed."
+ )
+ self.api = api
+ self.tag = tag
+
+ def escape(self, ident: str) -> str:
+ """Escape a CSS identifier.
+
+ This is a simple wrapper around `soupsieve.escape() <https://facelessuser.github.io/soupsieve/api/#soupsieveescape>`_. See the
+ documentation for that function for more information.
+ """
+ if soupsieve is None:
+ raise NotImplementedError(
+ "Cannot escape CSS identifiers because the soupsieve package is not installed."
+ )
+ return cast(str, self.api.escape(ident))
+
+ def _ns(
+ self, ns: Optional[_NamespaceMapping], select: str
+ ) -> Optional[_NamespaceMapping]:
+ """Normalize a dictionary of namespaces."""
+ if not isinstance(select, self.api.SoupSieve) and ns is None:
+ # If the selector is a precompiled pattern, it already has
+ # a namespace context compiled in, which cannot be
+ # replaced.
+ ns = self.tag._namespaces
+ return ns
+
+ def _rs(self, results: Iterable[Tag]) -> ResultSet[Tag]:
+ """Normalize a list of results to a py:class:`ResultSet`.
+
+ A py:class:`ResultSet` is more consistent with the rest of
+ Beautiful Soup's API, and :py:meth:`ResultSet.__getattr__` has
+ a helpful error message if you try to treat a list of results
+ as a single result (a common mistake).
+ """
+ # Import here to avoid circular import
+ from bs4 import ResultSet
+
+ return ResultSet(None, results)
+
+ def compile(
+ self,
+ select: str,
+ namespaces: Optional[_NamespaceMapping] = None,
+ flags: int = 0,
+ **kwargs: Any,
+ ) -> SoupSieve:
+ """Pre-compile a selector and return the compiled object.
+
+ :param selector: A CSS selector.
+
+ :param namespaces: A dictionary mapping namespace prefixes
+ used in the CSS selector to namespace URIs. By default,
+ Beautiful Soup will use the prefixes it encountered while
+ parsing the document.
+
+ :param flags: Flags to be passed into Soup Sieve's
+ `soupsieve.compile() <https://facelessuser.github.io/soupsieve/api/#soupsievecompile>`_ method.
+
+ :param kwargs: Keyword arguments to be passed into Soup Sieve's
+ `soupsieve.compile() <https://facelessuser.github.io/soupsieve/api/#soupsievecompile>`_ method.
+
+ :return: A precompiled selector object.
+ :rtype: soupsieve.SoupSieve
+ """
+ return self.api.compile(select, self._ns(namespaces, select), flags, **kwargs)
+
+ def select_one(
+ self,
+ select: str,
+ namespaces: Optional[_NamespaceMapping] = None,
+ flags: int = 0,
+ **kwargs: Any,
+ ) -> element.Tag | None:
+ """Perform a CSS selection operation on the current Tag and return the
+ first result, if any.
+
+ This uses the Soup Sieve library. For more information, see
+ that library's documentation for the `soupsieve.select_one() <https://facelessuser.github.io/soupsieve/api/#soupsieveselect_one>`_ method.
+
+ :param selector: A CSS selector.
+
+ :param namespaces: A dictionary mapping namespace prefixes
+ used in the CSS selector to namespace URIs. By default,
+ Beautiful Soup will use the prefixes it encountered while
+ parsing the document.
+
+ :param flags: Flags to be passed into Soup Sieve's
+ `soupsieve.select_one() <https://facelessuser.github.io/soupsieve/api/#soupsieveselect_one>`_ method.
+
+ :param kwargs: Keyword arguments to be passed into Soup Sieve's
+ `soupsieve.select_one() <https://facelessuser.github.io/soupsieve/api/#soupsieveselect_one>`_ method.
+ """
+ return self.api.select_one(
+ select, self.tag, self._ns(namespaces, select), flags, **kwargs
+ )
+
+ def select(
+ self,
+ select: str,
+ namespaces: Optional[_NamespaceMapping] = None,
+ limit: int = 0,
+ flags: int = 0,
+ **kwargs: Any,
+ ) -> ResultSet[element.Tag]:
+ """Perform a CSS selection operation on the current `element.Tag`.
+
+ This uses the Soup Sieve library. For more information, see
+ that library's documentation for the `soupsieve.select() <https://facelessuser.github.io/soupsieve/api/#soupsieveselect>`_ method.
+
+ :param selector: A CSS selector.
+
+ :param namespaces: A dictionary mapping namespace prefixes
+ used in the CSS selector to namespace URIs. By default,
+ Beautiful Soup will pass in the prefixes it encountered while
+ parsing the document.
+
+ :param limit: After finding this number of results, stop looking.
+
+ :param flags: Flags to be passed into Soup Sieve's
+ `soupsieve.select() <https://facelessuser.github.io/soupsieve/api/#soupsieveselect>`_ method.
+
+ :param kwargs: Keyword arguments to be passed into Soup Sieve's
+ `soupsieve.select() <https://facelessuser.github.io/soupsieve/api/#soupsieveselect>`_ method.
+ """
+ if limit is None:
+ limit = 0
+
+ return self._rs(
+ self.api.select(
+ select, self.tag, self._ns(namespaces, select), limit, flags, **kwargs
+ )
+ )
+
+ def iselect(
+ self,
+ select: str,
+ namespaces: Optional[_NamespaceMapping] = None,
+ limit: int = 0,
+ flags: int = 0,
+ **kwargs: Any,
+ ) -> Iterator[element.Tag]:
+ """Perform a CSS selection operation on the current `element.Tag`.
+
+ This uses the Soup Sieve library. For more information, see
+ that library's documentation for the `soupsieve.iselect()
+ <https://facelessuser.github.io/soupsieve/api/#soupsieveiselect>`_
+ method. It is the same as select(), but it returns a generator
+ instead of a list.
+
+ :param selector: A string containing a CSS selector.
+
+ :param namespaces: A dictionary mapping namespace prefixes
+ used in the CSS selector to namespace URIs. By default,
+ Beautiful Soup will pass in the prefixes it encountered while
+ parsing the document.
+
+ :param limit: After finding this number of results, stop looking.
+
+ :param flags: Flags to be passed into Soup Sieve's
+ `soupsieve.iselect() <https://facelessuser.github.io/soupsieve/api/#soupsieveiselect>`_ method.
+
+ :param kwargs: Keyword arguments to be passed into Soup Sieve's
+ `soupsieve.iselect() <https://facelessuser.github.io/soupsieve/api/#soupsieveiselect>`_ method.
+ """
+ return self.api.iselect(
+ select, self.tag, self._ns(namespaces, select), limit, flags, **kwargs
+ )
+
+ def closest(
+ self,
+ select: str,
+ namespaces: Optional[_NamespaceMapping] = None,
+ flags: int = 0,
+ **kwargs: Any,
+ ) -> Optional[element.Tag]:
+ """Find the `element.Tag` closest to this one that matches the given selector.
+
+ This uses the Soup Sieve library. For more information, see
+ that library's documentation for the `soupsieve.closest()
+ <https://facelessuser.github.io/soupsieve/api/#soupsieveclosest>`_
+ method.
+
+ :param selector: A string containing a CSS selector.
+
+ :param namespaces: A dictionary mapping namespace prefixes
+ used in the CSS selector to namespace URIs. By default,
+ Beautiful Soup will pass in the prefixes it encountered while
+ parsing the document.
+
+ :param flags: Flags to be passed into Soup Sieve's
+ `soupsieve.closest() <https://facelessuser.github.io/soupsieve/api/#soupsieveclosest>`_ method.
+
+ :param kwargs: Keyword arguments to be passed into Soup Sieve's
+ `soupsieve.closest() <https://facelessuser.github.io/soupsieve/api/#soupsieveclosest>`_ method.
+
+ """
+ return self.api.closest(
+ select, self.tag, self._ns(namespaces, select), flags, **kwargs
+ )
+
+ def match(
+ self,
+ select: str,
+ namespaces: Optional[_NamespaceMapping] = None,
+ flags: int = 0,
+ **kwargs: Any,
+ ) -> bool:
+ """Check whether or not this `element.Tag` matches the given CSS selector.
+
+ This uses the Soup Sieve library. For more information, see
+ that library's documentation for the `soupsieve.match()
+ <https://facelessuser.github.io/soupsieve/api/#soupsievematch>`_
+ method.
+
+ :param: a CSS selector.
+
+ :param namespaces: A dictionary mapping namespace prefixes
+ used in the CSS selector to namespace URIs. By default,
+ Beautiful Soup will pass in the prefixes it encountered while
+ parsing the document.
+
+ :param flags: Flags to be passed into Soup Sieve's
+ `soupsieve.match()
+ <https://facelessuser.github.io/soupsieve/api/#soupsievematch>`_
+ method.
+
+ :param kwargs: Keyword arguments to be passed into SoupSieve's
+ `soupsieve.match()
+ <https://facelessuser.github.io/soupsieve/api/#soupsievematch>`_
+ method.
+ """
+ return cast(
+ bool,
+ self.api.match(
+ select, self.tag, self._ns(namespaces, select), flags, **kwargs
+ ),
+ )
+
+ def filter(
+ self,
+ select: str,
+ namespaces: Optional[_NamespaceMapping] = None,
+ flags: int = 0,
+ **kwargs: Any,
+ ) -> ResultSet[element.Tag]:
+ """Filter this `element.Tag`'s direct children based on the given CSS selector.
+
+ This uses the Soup Sieve library. It works the same way as
+ passing a `element.Tag` into that library's `soupsieve.filter()
+ <https://facelessuser.github.io/soupsieve/api/#soupsievefilter>`_
+ method. For more information, see the documentation for
+ `soupsieve.filter()
+ <https://facelessuser.github.io/soupsieve/api/#soupsievefilter>`_.
+
+ :param namespaces: A dictionary mapping namespace prefixes
+ used in the CSS selector to namespace URIs. By default,
+ Beautiful Soup will pass in the prefixes it encountered while
+ parsing the document.
+
+ :param flags: Flags to be passed into Soup Sieve's
+ `soupsieve.filter()
+ <https://facelessuser.github.io/soupsieve/api/#soupsievefilter>`_
+ method.
+
+ :param kwargs: Keyword arguments to be passed into SoupSieve's
+ `soupsieve.filter()
+ <https://facelessuser.github.io/soupsieve/api/#soupsievefilter>`_
+ method.
+ """
+ return self._rs(
+ self.api.filter(
+ select, self.tag, self._ns(namespaces, select), flags, **kwargs
+ )
+ )