diff options
author | S. Solomon Darnell | 2025-03-28 21:52:21 -0500 |
---|---|---|
committer | S. Solomon Darnell | 2025-03-28 21:52:21 -0500 |
commit | 4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch) | |
tree | ee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/soupsieve/util.py | |
parent | cc961e04ba734dd72309fb548a2f97d67d578813 (diff) | |
download | gn-ai-master.tar.gz |
Diffstat (limited to '.venv/lib/python3.12/site-packages/soupsieve/util.py')
-rw-r--r-- | .venv/lib/python3.12/site-packages/soupsieve/util.py | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/soupsieve/util.py b/.venv/lib/python3.12/site-packages/soupsieve/util.py new file mode 100644 index 00000000..9b2e64df --- /dev/null +++ b/.venv/lib/python3.12/site-packages/soupsieve/util.py @@ -0,0 +1,117 @@ +"""Utility.""" +from __future__ import annotations +from functools import wraps, lru_cache +import warnings +import re +from typing import Callable, Any + +DEBUG = 0x00001 + +RE_PATTERN_LINE_SPLIT = re.compile(r'(?:\r\n|(?!\r\n)[\n\r])|$') + +UC_A = ord('A') +UC_Z = ord('Z') + + +@lru_cache(maxsize=512) +def lower(string: str) -> str: + """Lower.""" + + new_string = [] + for c in string: + o = ord(c) + new_string.append(chr(o + 32) if UC_A <= o <= UC_Z else c) + return ''.join(new_string) + + +class SelectorSyntaxError(Exception): + """Syntax error in a CSS selector.""" + + def __init__(self, msg: str, pattern: str | None = None, index: int | None = None) -> None: + """Initialize.""" + + self.line = None + self.col = None + self.context = None + + if pattern is not None and index is not None: + # Format pattern to show line and column position + self.context, self.line, self.col = get_pattern_context(pattern, index) + msg = f'{msg}\n line {self.line}:\n{self.context}' + + super().__init__(msg) + + +def deprecated(message: str, stacklevel: int = 2) -> Callable[..., Any]: # pragma: no cover + """ + Raise a `DeprecationWarning` when wrapped function/method is called. + + Usage: + + @deprecated("This method will be removed in version X; use Y instead.") + def some_method()" + pass + """ + + def _wrapper(func: Callable[..., Any]) -> Callable[..., Any]: + @wraps(func) + def _deprecated_func(*args: Any, **kwargs: Any) -> Any: + warnings.warn( + f"'{func.__name__}' is deprecated. {message}", + category=DeprecationWarning, + stacklevel=stacklevel + ) + return func(*args, **kwargs) + return _deprecated_func + return _wrapper + + +def warn_deprecated(message: str, stacklevel: int = 2) -> None: # pragma: no cover + """Warn deprecated.""" + + warnings.warn( + message, + category=DeprecationWarning, + stacklevel=stacklevel + ) + + +def get_pattern_context(pattern: str, index: int) -> tuple[str, int, int]: + """Get the pattern context.""" + + last = 0 + current_line = 1 + col = 1 + text = [] # type: list[str] + line = 1 + offset = None # type: int | None + + # Split pattern by newline and handle the text before the newline + for m in RE_PATTERN_LINE_SPLIT.finditer(pattern): + linetext = pattern[last:m.start(0)] + if not len(m.group(0)) and not len(text): + indent = '' + offset = -1 + col = index - last + 1 + elif last <= index < m.end(0): + indent = '--> ' + offset = (-1 if index > m.start(0) else 0) + 3 + col = index - last + 1 + else: + indent = ' ' + offset = None + if len(text): + # Regardless of whether we are presented with `\r\n`, `\r`, or `\n`, + # we will render the output with just `\n`. We will still log the column + # correctly though. + text.append('\n') + text.append(f'{indent}{linetext}') + if offset is not None: + text.append('\n') + text.append(' ' * (col + offset) + '^') + line = current_line + + current_line += 1 + last = m.end(0) + + return ''.join(text), line, col |