




import html

from ...feature_extraction_utils import BatchFeature, FeatureExtractionMixin
from ...utils import is_bsa_available, logging, requires_backends


if is_bsa_available():
   import bsa
   from bsa import BeautifulSoup


lowerCamelCase__ :   Any					=							logging.get_logger(__name__)





class        lowerCamelCase_							(      SCREAMING_SNAKE_CASE__					):


 '''simple docstring'''







 def __init__(							self  :		Tuple				,				**_lowerCAmelCase  :		Optional[int]						):
       requires_backends(self				,				['bs4']						)
       super().__init__(**_lowerCAmelCase						)



 def       lowerCAmelCase_  (							self  :		Optional[Any]				,				_lowerCAmelCase  :		int						):
       SCREAMING_SNAKE_CASE_							=			[]
       SCREAMING_SNAKE_CASE_							=			[]
       SCREAMING_SNAKE_CASE_							=			element if element.name else element.parent
       for parent in child.parents:  # type: bs4.element.Tag
             SCREAMING_SNAKE_CASE_							=			parent.find_all(child.name				,				recursive=_lowerCAmelCase						)
             xpath_tags.append(child.name						)
             xpath_subscripts.append(
                 0 if 1 == len(_lowerCAmelCase						) else next(i for i, s in enumerate(_lowerCAmelCase				,				1						) if s is child						)						)
             SCREAMING_SNAKE_CASE_							=			parent
       xpath_tags.reverse()
       xpath_subscripts.reverse()
       return xpath_tags, xpath_subscripts



 def       lowerCAmelCase_  (							self  :		Optional[Any]				,				_lowerCAmelCase  :		Union[str, Any]						):
       SCREAMING_SNAKE_CASE_							=			BeautifulSoup(_lowerCAmelCase				,				'html.parser'						)

       SCREAMING_SNAKE_CASE_							=			[]
       SCREAMING_SNAKE_CASE_							=			[]
       SCREAMING_SNAKE_CASE_							=			[]

       for element in html_code.descendants:
             if type(_lowerCAmelCase						) == bsa.element.NavigableString:
                   if type(element.parent						) != bsa.element.Tag:
                         continue

                   SCREAMING_SNAKE_CASE_							=			html.unescape(_lowerCAmelCase						).strip()
                   if not text_in_this_tag:
                         continue

                   all_doc_strings.append(_lowerCAmelCase						)

                   SCREAMING_SNAKE_CASE_						, SCREAMING_SNAKE_CASE_							=			self.xpath_soup(_lowerCAmelCase						)
                   stringaxtag_seq.append(_lowerCAmelCase						)
                   stringaxsubs_seq.append(_lowerCAmelCase						)

       if len(_lowerCAmelCase						) != len(_lowerCAmelCase						):
             raise ValueError('Number of doc strings and xtags does not correspond'						)
       if len(_lowerCAmelCase						) != len(_lowerCAmelCase						):
             raise ValueError('Number of doc strings and xsubs does not correspond'						)

       return all_doc_strings, stringaxtag_seq, stringaxsubs_seq



 def       lowerCAmelCase_  (							self  :		Any				,				_lowerCAmelCase  :		Optional[int]				,				_lowerCAmelCase  :		Tuple						):
       SCREAMING_SNAKE_CASE_							=			''
       for tagname, subs in zip(_lowerCAmelCase				,				_lowerCAmelCase						):
             xpath += F"/{tagname}"
             if subs != 0:
                   xpath += F"[{subs}]"
       return xpath




 def __call__(							self  :		Union[str, Any]				,				_lowerCAmelCase  :		Union[str, Any]						):
       SCREAMING_SNAKE_CASE_							=			False

       # Check that strings has a valid type
       if isinstance(_lowerCAmelCase				,				_lowerCAmelCase						):
             SCREAMING_SNAKE_CASE_							=			True
       elif isinstance(_lowerCAmelCase				,				(list, tuple)						):
             if len(_lowerCAmelCase						) == 0 or isinstance(html_strings[0]				,				_lowerCAmelCase						):
                   SCREAMING_SNAKE_CASE_							=			True

       if not valid_strings:
             raise ValueError(
                 'HTML strings must of type `str`, `List[str]` (batch of examples), '
                 F"but is of type {type(_lowerCAmelCase						)}."						)

       SCREAMING_SNAKE_CASE_							=			bool(isinstance(_lowerCAmelCase				,				(list, tuple)						) and (isinstance(html_strings[0]				,				_lowerCAmelCase						))						)

       if not is_batched:
             SCREAMING_SNAKE_CASE_							=			[html_strings]

       # Get nodes + xpaths
       SCREAMING_SNAKE_CASE_							=			[]
       SCREAMING_SNAKE_CASE_							=			[]
       for html_string in html_strings:
             SCREAMING_SNAKE_CASE_						, SCREAMING_SNAKE_CASE_						, SCREAMING_SNAKE_CASE_							=			self.get_three_from_single(_lowerCAmelCase						)
             nodes.append(_lowerCAmelCase						)
             SCREAMING_SNAKE_CASE_							=			[]
             for node, tag_list, sub_list in zip(_lowerCAmelCase				,				_lowerCAmelCase				,				_lowerCAmelCase						):
                   SCREAMING_SNAKE_CASE_							=			self.construct_xpath(_lowerCAmelCase				,				_lowerCAmelCase						)
                   xpath_strings.append(_lowerCAmelCase						)
             xpaths.append(_lowerCAmelCase						)

       # return as Dict
       SCREAMING_SNAKE_CASE_							=			{'nodes': nodes, 'xpaths': xpaths}
       SCREAMING_SNAKE_CASE_							=			BatchFeature(data=_lowerCAmelCase				,				tensor_type=_lowerCAmelCase						)

       return encoded_inputs
from functools import lru_cache


@lru_cache
def    a__       (						__UpperCamelCase ):
      if num < 0:
            raise ValueError("Number should not be negative." )

      return 1 if num in (0, 1) else num * factorial(num - 1 )


if __name__ == "__main__":
      import doctest

      doctest.testmod()


