



"""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


snake_case_								=			"""https://github.com/huggingface/datasets/tree/main/src/datasets/utils"""
snake_case_								=			f'''{BASE_REF_URL}/{__file__}'''
snake_case_								=			logging.getLogger(__name__)

def 					_lowerCAmelCase (  lowercase_		):
						UpperCAmelCase			 =					pkg_resources.read_text(lowercase_						,      lowercase_		)
						return yaml.safe_load(lowercase_		), F"""{BASE_REF_URL}/resources/{resource}"""


snake_case_	,  snake_case_								=			load_yaml_resource("""readme_structure.yaml""")

snake_case_								=			[
    """[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
snake_case_								=			Tuple[dict, List[str], List[str]]







class  A_     :



						"""simple docstring"""






						def __init__(   self					:int  ,    lowercase_					:str  ,    lowercase_					:str  ,    lowercase_					:List[str] = None  ,    lowercase_					:bool = False   )							->     Union[str, Any]:
												UpperCAmelCase			 =					name
												UpperCAmelCase			 =					level
												UpperCAmelCase			 =					lines
												UpperCAmelCase			 =					''
												UpperCAmelCase			 =					True
												UpperCAmelCase			 =					{}
												UpperCAmelCase			 =					[]
												UpperCAmelCase			 =					[]
												if self.lines is not None:
																		self.parse(suppress_parsing_errors=lowercase_   )






						def       UpperCAmelCase__	(   self					:Dict  ,    lowercase_					:bool = False   )							->     Optional[int]:
												UpperCAmelCase			 =					''
												UpperCAmelCase			 =					[]
												UpperCAmelCase			 =					False
												for line in self.lines:
																		if line.strip(' \n'   ) == "":
																								continue
																		elif line.strip(' \n'   )[:3] == "```":
																								UpperCAmelCase			 =					not code_start
																		elif line.split()[0] == self.level + "#" and not code_start:
																								if current_sub_level != "":
																														UpperCAmelCase			 =					Section(lowercase_  ,    self.level + '#'  ,    lowercase_   )
																														UpperCAmelCase			 =					[]
																								else:
																														if current_lines != []:
																																				self.text += "".join(lowercase_   ).strip()
																																				if self.text != "" and self.text not in FILLER_TEXT:
																																										UpperCAmelCase			 =					False
																																				UpperCAmelCase			 =					[]

																								UpperCAmelCase			 =					' '.join(line.split()[1:]   ).strip(' \n'   )
																		else:
																								current_lines.append(lowercase_   )
												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."""   )
																								UpperCAmelCase			 =					Section(lowercase_  ,    self.level + '#'  ,    lowercase_   )
																		else:
																								if current_lines != []:
																														self.text += "".join(lowercase_   ).strip()
																														if self.text != "" and self.text not in FILLER_TEXT:
																																				UpperCAmelCase			 =					False

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






						def       UpperCAmelCase__	(   self					:Union[str, Any]  ,    lowercase_					:dict   )							->     ReadmeValidatorOutput:
												UpperCAmelCase			 =					[]
												UpperCAmelCase			 =					[]
												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
																								UpperCAmelCase			 =					[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
																								UpperCAmelCase			 =					[subsection['name'] for subsection in structure['subsections']]
																								UpperCAmelCase			 =					False
																								for idx, name in enumerate(lowercase_   ):
																														if name not in self.content:
																																				# If the expected subsection is not present
																																				error_list.append(f"""Section `{self.name}` is missing subsection: `{name}`."""   )
																																				UpperCAmelCase			 =					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:
																																										UpperCAmelCase ,       UpperCAmelCase ,       UpperCAmelCase			 =					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       UpperCAmelCase__	(   self					:int   )							->     dict:
												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  A_     (	SCREAMING_SNAKE_CASE_							):  # Level 0



						"""simple docstring"""






						def __init__(   self					:List[str]  ,    lowercase_					:str  ,    lowercase_					:List[str]  ,    lowercase_					:dict = None  ,    lowercase_					:bool = False   )							->     Optional[int]:
												super().__init__(name=lowercase_  ,    level=''   )  # Not using lines here as we need to use a child class parse
												UpperCAmelCase			 =					structure
												UpperCAmelCase			 =					-2
												UpperCAmelCase			 =					0
												UpperCAmelCase			 =					lines
												if self.lines is not None:
																		self.parse(suppress_parsing_errors=lowercase_   )






						def       UpperCAmelCase__	(   self					:Union[str, Any]   )							->     Optional[Any]:
												if self.structure is None:
																		UpperCAmelCase ,       UpperCAmelCase ,       UpperCAmelCase			 =					self._validate(lowercase_   )
												else:
																		UpperCAmelCase ,       UpperCAmelCase ,       UpperCAmelCase			 =					self._validate(self.structure   )
												if error_list != [] or warning_list != []:
																		UpperCAmelCase			 =					'\n'.join(['-\t' + x for x in error_list + warning_list]   )
																		UpperCAmelCase			 =					f"""The following issues were found for the README at `{self.name}`:\n""" + errors
																		raise ValueError(lowercase_   )






						@classmethod
						def       UpperCAmelCase__	(   cls					:List[Any]  ,    lowercase_					:Path  ,    lowercase_					:dict = None  ,    lowercase_					:bool = False   )							->     Tuple:
												with open(lowercase_  ,    encoding='utf-8'   ) as f:
																		UpperCAmelCase			 =					f.readlines()
												return cls(lowercase_  ,    lowercase_  ,    lowercase_  ,    suppress_parsing_errors=lowercase_   )






						@classmethod
						def       UpperCAmelCase__	(   cls					:str  ,    lowercase_					:str  ,    lowercase_					:dict = None  ,    lowercase_					:str = "root"  ,    lowercase_					:bool = False   )							->     Any:
												UpperCAmelCase			 =					string.split('\n'   )
												return cls(lowercase_  ,    lowercase_  ,    lowercase_  ,    suppress_parsing_errors=lowercase_   )






						def       UpperCAmelCase__	(   self					:int  ,    lowercase_					:bool = False   )							->     Dict:
												# Skip Tags
												UpperCAmelCase			 =					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:
																		UpperCAmelCase			 =					self.lines[line_count + 1 :]  # Get the last + 1 th item.
												else:
																		UpperCAmelCase			 =					self.lines[self.tag_count :]
												super().parse(suppress_parsing_errors=lowercase_   )






						def __str__(   self					:Optional[Any]   )							->     Union[str, Any]:
												return str(self.to_dict()   )






						def       UpperCAmelCase__	(   self					:str  ,    lowercase_					:Union[str, Any]   )							->     List[Any]:
												UpperCAmelCase			 =					[]
												UpperCAmelCase			 =					[]
												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.
												UpperCAmelCase			 =					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
																		UpperCAmelCase			 =					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
																								UpperCAmelCase ,       UpperCAmelCase ,       UpperCAmelCase			 =					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

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







_SCREAMING_SNAKE_CASE     :   dict[str, float]							 =      {
    "kilogram": 1,
    "gram": pow(1_0, 3),
    "milligram": pow(1_0, 6),
    "metric-ton": pow(1_0, -3),
    "long-ton": 0.00_0984_2073,
    "short-ton": 0.00_1102_3122,
    "pound": 2.20_4624_4202,
    "stone": 0.15_7473_1728,
    "ounce": 35.2_7399_0723,
    "carrat": 5_0_0_0,
    "atomic-mass-unit": 6.022136652E26,
}

_SCREAMING_SNAKE_CASE     :   dict[str, float]							 =      {
    "kilogram": 1,
    "gram": pow(1_0, -3),
    "milligram": pow(1_0, -6),
    "metric-ton": pow(1_0, 3),
    "long-ton": 1016.0_4608,
    "short-ton": 907.184,
    "pound": 0.45_3592,
    "stone": 6.3_5029,
    "ounce": 0.028_3495,
    "carrat": 0.0002,
    "atomic-mass-unit": 1.660540199E-27,
}

def 					SCREAMING_SNAKE_CASE  (   __UpperCamelCase			:    str				,    __UpperCamelCase			:    str				,    __UpperCamelCase			:    float							)			->							float:

				"""simple docstring"""







				if to_type not in KILOGRAM_CHART or from_type not in WEIGHT_TYPE_CHART:
								A__	:						int								=				(
								    F"Invalid 'from_type' or 'to_type' value: {from_type!r}, {to_type!r}\n"
								    F"Supported values are: {', '.join(__UpperCamelCase							)}"
								)
								raise ValueError(__UpperCamelCase							)
				return value * KILOGRAM_CHART[to_type] * WEIGHT_TYPE_CHART[from_type]


if __name__ == "__main__":
					import doctest

					doctest.testmod()