Adding new class type TextHandlers

This commit is contained in:
Karim shoair
2024-11-06 21:03:19 +02:00
parent 7a84511b7a
commit 5e848ef046
2 changed files with 50 additions and 3 deletions
+47 -2
View File
@@ -3,7 +3,7 @@ from types import MappingProxyType
from collections.abc import Mapping from collections.abc import Mapping
from scrapling.core.utils import _is_iterable, flatten from scrapling.core.utils import _is_iterable, flatten
from scrapling.core._types import Dict, List, Union, Pattern from scrapling.core._types import Dict, List, Union, Pattern, SupportsIndex
from orjson import loads, dumps from orjson import loads, dumps
from w3lib.html import replace_entities as _replace_entities from w3lib.html import replace_entities as _replace_entities
@@ -69,7 +69,7 @@ class TextHandler(str):
return [TextHandler(_replace_entities(s)) for s in results] return [TextHandler(_replace_entities(s)) for s in results]
def re_first(self, regex: Union[str, Pattern[str]], default=None, replace_entities: bool = True, def re_first(self, regex: Union[str, Pattern[str]], default=None, replace_entities: bool = True,
clean_match: bool = False, case_sensitive: bool = False,): clean_match: bool = False, case_sensitive: bool = False) -> Union[str, None]:
"""Apply the given regex to text and return the first match if found, otherwise return the default value. """Apply the given regex to text and return the first match if found, otherwise return the default value.
:param regex: Can be either a compiled regular expression or a string. :param regex: Can be either a compiled regular expression or a string.
@@ -83,6 +83,51 @@ class TextHandler(str):
return result[0] if result else default return result[0] if result else default
class TextHandlers(List[TextHandler]):
"""
The :class:`TextHandlers` class is a subclass of the builtin ``List`` class, which provides a few additional methods.
"""
__slots__ = ()
def __getitem__(self, pos: Union[SupportsIndex, slice]) -> Union[TextHandler, "TextHandlers[TextHandler]"]:
lst = super().__getitem__(pos)
if isinstance(pos, slice):
return self.__class__(lst)
else:
return lst
def re(self, regex: Union[str, Pattern[str]], replace_entities: bool = True, clean_match: bool = False,
case_sensitive: bool = False) -> 'List[str]':
"""Call the ``.re()`` method for each element in this list and return
their results flattened as TextHandlers.
:param regex: Can be either a compiled regular expression or a string.
:param replace_entities: if enabled character entity references are replaced by their corresponding character
:param clean_match: if enabled, this will ignore all whitespaces and consecutive spaces while matching
:param case_sensitive: if enabled, function will set the regex to ignore letters case while compiling it
"""
results = [
n.re(regex, replace_entities, clean_match, case_sensitive) for n in self
]
return flatten(results)
def re_first(self, regex: Union[str, Pattern[str]], default=None, replace_entities: bool = True,
clean_match: bool = False, case_sensitive: bool = False) -> Union[str, None]:
"""Call the ``.re_first()`` method for each element in this list and return
the first result or the default value otherwise.
:param regex: Can be either a compiled regular expression or a string.
:param default: The default value to be returned if there is no match
:param replace_entities: if enabled character entity references are replaced by their corresponding character
:param clean_match: if enabled, this will ignore all whitespaces and consecutive spaces while matching
:param case_sensitive: if enabled, function will set the regex to ignore letters case while compiling it
"""
for n in self:
for result in n.re(regex, replace_entities, clean_match, case_sensitive):
return result
return default
class AttributesHandler(Mapping): class AttributesHandler(Mapping):
"""A read-only mapping to use instead of the standard dictionary for the speed boost but """A read-only mapping to use instead of the standard dictionary for the speed boost but
at the same time I use it to add more functionalities. at the same time I use it to add more functionalities.
+3 -1
View File
@@ -3,7 +3,7 @@ from difflib import SequenceMatcher
from scrapling.core.translator import HTMLTranslator from scrapling.core.translator import HTMLTranslator
from scrapling.core.mixins import SelectorsGeneration from scrapling.core.mixins import SelectorsGeneration
from scrapling.core.custom_types import TextHandler, AttributesHandler from scrapling.core.custom_types import TextHandler, TextHandlers, AttributesHandler
from scrapling.core.storage_adaptors import SQLiteStorageSystem, StorageSystemMixin, _StorageTools from scrapling.core.storage_adaptors import SQLiteStorageSystem, StorageSystemMixin, _StorageTools
from scrapling.core.utils import setup_basic_logging, logging, clean_spaces, flatten, html_forbidden from scrapling.core.utils import setup_basic_logging, logging, clean_spaces, flatten, html_forbidden
from scrapling.core._types import Any, Dict, List, Tuple, Optional, Pattern, Union, Callable, Generator, SupportsIndex from scrapling.core._types import Any, Dict, List, Tuple, Optional, Pattern, Union, Callable, Generator, SupportsIndex
@@ -158,6 +158,8 @@ class Adaptor(SelectorsGeneration):
results = [self.__get_correct_result(n) for n in result] results = [self.__get_correct_result(n) for n in result]
if all(isinstance(res, self.__class__) for res in results): if all(isinstance(res, self.__class__) for res in results):
return Adaptors(results) return Adaptors(results)
elif all(isinstance(res, TextHandler) for res in results):
return TextHandlers(results)
return results return results
return self.__get_correct_result(result) return self.__get_correct_result(result)