

"""simple docstring"""






import logging
from pathlib import Path
from typing import Any, List, Tuple

import yaml


# loading package files: https://stackoverflow.com/a/20885799
try:
							import importlib.resources as pkg_resources
except ImportError:
							# Try backported to PY<37 `importlib_resources`.
							import importlib_resources as pkg_resources

from . import resources


__lowerCAmelCase				      =   '''https://github.com/huggingface/datasets/tree/main/src/datasets/utils'''
__lowerCAmelCase				      =   f'''{BASE_REF_URL}/{__file__}'''
__lowerCAmelCase				      =   logging.getLogger(__name__)
def 		A_	(   __UpperCamelCase     :				str				):
		lowercase										=							pkg_resources.read_text(__UpperCamelCase       ,	__UpperCamelCase				)
		return yaml.safe_load(__UpperCamelCase				), f"""{BASE_REF_URL}/resources/{resource}"""


__lowerCAmelCase      ,		__lowerCAmelCase				      =   load_yaml_resource('''readme_structure.yaml''')

__lowerCAmelCase				      =   [
    '''[Needs More Information]''',
    '''[More Information Needed]''',
    '''(https://github.com/huggingface/datasets/blob/main/CONTRIBUTING.md#how-to-contribute-to-the-dataset-cards)''',
]

# Dictionary representation of section/readme, error_list, warning_list
__lowerCAmelCase				      =   Tuple[dict, List[str], List[str]]
class 	_lowerCAmelCase    :

							def __init__( self       :    List[str] ,		a       :    str ,		a       :    str ,		a       :    List[str] = None ,		a       :    bool = False    )   ->    int:

									"""simple docstring"""
									lowercase										=							name
									lowercase										=							level
									lowercase										=							lines
									lowercase										=							''''''
									lowercase										=							True
									lowercase										=							{}
									lowercase										=							[]
									lowercase										=							[]
									if self.lines is not None:
											self.parse(suppress_parsing_errors=a    )

							def 					_lowerCAmelCase  ( self       :    List[str] ,		a       :    bool = False    )   ->    Optional[int]:

									"""simple docstring"""
									lowercase										=							''''''
									lowercase										=							[]
									lowercase										=							False
									for line in self.lines:
											if line.strip(''' \n'''    ) == "":
													continue
											elif line.strip(''' \n'''    )[:3] == "```":
													lowercase										=							not code_start
											elif line.split()[0] == self.level + "#" and not code_start:
													if current_sub_level != "":
															lowercase										=							Section(a ,		self.level + '''#''' ,		a    )
															lowercase										=							[]
													else:
															if current_lines != []:
																	self.text += "".join(a    ).strip()
																	if self.text != "" and self.text not in FILLER_TEXT:
																			lowercase										=							False
																	lowercase										=							[]

													lowercase										=							''' '''.join(line.split()[1:]    ).strip(''' \n'''    )
											else:
													current_lines.append(a    )
									else:
											if current_sub_level != "":
													if current_sub_level in self.content:
															self.parsing_error_list.append(
															    f"""Multiple sections with the same heading `{current_sub_level}` have been found. Please keep only one of these sections."""    )
													lowercase										=							Section(a ,		self.level + '''#''' ,		a    )
											else:
													if current_lines != []:
															self.text += "".join(a    ).strip()
															if self.text != "" and self.text not in FILLER_TEXT:
																	lowercase										=							False

									if self.level == "" and not suppress_parsing_errors:
											if self.parsing_error_list != [] or self.parsing_warning_list != []:
													lowercase										=							lowercase										=							'''\n'''.join('''-\t''' + x for x in self.parsing_error_list + self.parsing_warning_list    )
													lowercase										=							f"""The following issues were found while parsing the README at `{self.name}`:\n""" + errors
													raise ValueError(a    )

							def 					_lowerCAmelCase  ( self       :    Optional[int] ,		a       :    dict    )   ->    ReadmeValidatorOutput:

									"""simple docstring"""
									lowercase										=							[]
									lowercase										=							[]
									if structure["allow_empty"] is False:
											# If content is expected
											if self.is_empty_text and self.content == {}:
													# If no content is found, mention it in the error_list
													error_list.append(f"""Expected some content in section `{self.name}` but it is empty."""    )

									if structure["allow_empty_text"] is False:
											# If some text is expected
											if self.is_empty_text:
													# If no text is found, mention it in the error_list
													error_list.append(
													    f"""Expected some text in section `{self.name}` but it is empty (text in subsections are ignored)."""    )
        # Subsections Validation
									if structure["subsections"] is not None:
											# If subsections are expected
											if self.content == {}:
													# If no subsections are present
													lowercase										=							[subsection['''name'''] for subsection in structure['''subsections''']]
													# Mention the expected values in the error_list
													error_list.append(
													    f"""Section `{self.name}` expected the following subsections: {", ".join(["`"+x+"`" for x in values]    )}. Found 'None'."""    )
											else:
													# If some subsections are present
													lowercase										=							[subsection['''name'''] for subsection in structure['''subsections''']]
													lowercase										=							False
													for idx, name in enumerate(a    ):
															if name not in self.content:
																	# If the expected subsection is not present
																	error_list.append(f"""Section `{self.name}` is missing subsection: `{name}`."""    )
																	lowercase										=							True
															else:
																	# If the subsection is present, validate subsection, return the result
																	# and concat the errors from subsection to section error_list

																	# Skip sublevel validation if current level is `###`
																	if self.level == "###":
																			continue
																	else:
																			lowercase					,  lowercase					,  lowercase										=							self.content[name].validate(
																			    structure['''subsections'''][idx]    )
																	error_list += subsec_error_list
																	warning_list += subsec_warning_list

													if has_missing_subsections:  # we only allow to have extra subsections if all the other ones are here
															for name in self.content:
																	if name not in structure_names:
																			# If an extra subsection is present
																			warning_list.append(
																			    f"""`{self.name}` has an extra subsection: `{name}`. Skipping further validation checks for this subsection as expected structure is unknown."""    )
									if error_list:
											# If there are errors, do not return the dictionary as it is invalid
											return {}, error_list, warning_list
									else:
											return self.to_dict(), error_list, warning_list

							def 					_lowerCAmelCase  ( self       :    Tuple    )   ->    dict:

									"""simple docstring"""
									return {
									    "name": self.name,
									    "text": self.text,
									    "is_empty_text": self.is_empty_text,
									    "subsections": [value.to_dict() for value in self.content.values()],
									}




class 	_lowerCAmelCase    (      __snake_case       ):  # Level 0

							def __init__( self       :    Optional[Any] ,		a       :    str ,		a       :    List[str] ,		a       :    dict = None ,		a       :    bool = False    )   ->    Union[str, Any]:

									"""simple docstring"""
									super().__init__(name=a ,		level=''''''    )  # Not using lines here as we need to use a child class parse
									lowercase										=							structure
									lowercase										=							-2
									lowercase										=							0
									lowercase										=							lines
									if self.lines is not None:
											self.parse(suppress_parsing_errors=a    )

							def 					_lowerCAmelCase  ( self       :    Optional[Any]    )   ->    List[str]:

									"""simple docstring"""
									if self.structure is None:
											lowercase					,  lowercase					,  lowercase										=							self._validate(a    )
									else:
											lowercase					,  lowercase					,  lowercase										=							self._validate(self.structure    )
									if error_list != [] or warning_list != []:
											lowercase										=							'''\n'''.join(['''-\t''' + x for x in error_list + warning_list]    )
											lowercase										=							f"""The following issues were found for the README at `{self.name}`:\n""" + errors
											raise ValueError(a    )

							@classmethod
							def 					_lowerCAmelCase  ( cls       :    Union[str, Any] ,		a       :    Path ,		a       :    dict = None ,		a       :    bool = False    )   ->    Dict:

									"""simple docstring"""
									with open(a ,		encoding='''utf-8'''    ) as f:
											lowercase										=							f.readlines()
									return cls(a ,		a ,		a ,		suppress_parsing_errors=a    )

							@classmethod
							def 					_lowerCAmelCase  ( cls       :    Tuple ,		a       :    str ,		a       :    dict = None ,		a       :    str = "root" ,		a       :    bool = False    )   ->    int:

									"""simple docstring"""
									lowercase										=							string.split('''\n'''    )
									return cls(a ,		a ,		a ,		suppress_parsing_errors=a    )

							def 					_lowerCAmelCase  ( self       :    Dict ,		a       :    bool = False    )   ->    Tuple:

									"""simple docstring"""
									# Skip Tags
									lowercase										=							0

									for line in self.lines:
											self.yaml_tags_line_count += 1
											if line.strip(''' \n'''    ) == "---":
													self.tag_count += 1
													if self.tag_count == 2:
															break
											line_count += 1
									if self.tag_count == 2:
											lowercase										=							self.lines[line_count + 1 :]  # Get the last + 1 th item.
									else:
											lowercase										=							self.lines[self.tag_count :]
									super().parse(suppress_parsing_errors=a    )

							def __str__( self       :    str    )   ->    str:

									"""simple docstring"""
									return str(self.to_dict()    )

							def 					_lowerCAmelCase  ( self       :    List[str] ,		a       :    Optional[int]    )   ->    str:

									"""simple docstring"""
									lowercase										=							[]
									lowercase										=							[]
									if self.yaml_tags_line_count == 0:
											warning_list.append('''Empty YAML markers are present in the README.'''    )
									elif self.tag_count == 0:
											warning_list.append('''No YAML markers are present in the README.'''    )
									elif self.tag_count == 1:
											warning_list.append('''Only the start of YAML tags present in the README.'''    )
									# Check how many first level sections are present.
									lowercase										=							len(self.content.keys()    )
									if num_first_level_keys > 1:
											# If more than one, add to the error list, continue
											error_list.append(
											    f"""The README has several first-level headings: {", ".join(["`"+x+"`" for x in list(self.content.keys()    )]    )}. Only one heading is expected. Skipping further validation for this README."""    )
									elif num_first_level_keys < 1:
											# If less than one, append error.
											error_list.append(
											    '''The README has no first-level headings. One heading is expected. Skipping further validation for this README.'''    )

									else:
											# If one exactly
											lowercase										=							list(self.content.keys()    )[0]  # Get the key
											if start_key.startswith('''Dataset Card for'''    ):  # Check correct start
													# If the starting is correct, validate all the sections
													lowercase					,  lowercase					,  lowercase										=							self.content[start_key].validate(
													    readme_structure['''subsections'''][0]    )
													error_list += sec_error_list
													warning_list += sec_warning_list
											else:
													# If not found, append error
													error_list.append(
													    '''No first-level heading starting with `Dataset Card for` found in README. Skipping further validation for this README.'''    )
									if error_list:
											# If there are errors, do not return the dictionary as it is invalid
											return {}, error_list, warning_list
									else:
											return self.to_dict(), error_list, warning_list


if __name__ == "__main__":
							from argparse import ArgumentParser

							__lowerCAmelCase				      =   ArgumentParser(usage='''Validate the content (excluding YAML tags) of a README.md file.''')
							ap.add_argument('''readme_filepath''')
							__lowerCAmelCase				      =   ap.parse_args()
							__lowerCAmelCase				      =   Path(args.readme_filepath)
							__lowerCAmelCase				      =   ReadMe.from_readme(readme_filepath)


"""simple docstring"""






from ..utils import DummyObject, requires_backends
class 	_lowerCAmelCase    (      metaclass=__snake_case       ):
							__lowerCAmelCase					:    Optional[Any]     =  ['''tensorflow_text''']

							def __init__( self       :    Optional[int] ,		*a       :    int ,		**a       :    str    )   ->    str:

									"""simple docstring"""
									requires_backends(self ,		['''tensorflow_text''']    )