




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


__a  :		Tuple		     =   '''https://github.com/huggingface/datasets/tree/main/src/datasets/utils'''
__a  :		Tuple		     =   f'{BASE_REF_URL}/{__file__}'
__a  :		List[Any]		     =   logging.getLogger(__name__)
def  snake_case_					(		SCREAMING_SNAKE_CASE_    )      ->			Tuple[Any, str]:
							lowercase__  :	Union[str, Any]        =							pkg_resources.read_text(SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    )
							return yaml.safe_load(SCREAMING_SNAKE_CASE_    ), F"""{BASE_REF_URL}/resources/{resource}"""


__a     ,	__a  :		List[Any]		     =   load_yaml_resource('''readme_structure.yaml''')

__a  :		int		     =   [
    '''[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
__a  :		int		     =   Tuple[dict, List[str], List[str]]







class 				UpperCAmelCase:



	"""simple docstring"""






	def __init__(					self	,				lowerCamelCase	,				lowerCamelCase	,				lowerCamelCase = None	,				lowerCamelCase = False    ) ->      Optional[int]:





								"""simple docstring"""


								lowercase__  :	str        =							name
								lowercase__  :	str        =							level
								lowercase__  :	Optional[int]        =							lines
								lowercase__  :	Optional[int]        =							""
								lowercase__  :	List[Any]        =							True
								lowercase__  :	Union[str, Any]        =							{}
								lowercase__  :	List[Any]        =							[]
								lowercase__  :	Tuple        =							[]
								if self.lines is not None:
															self.parse(suppress_parsing_errors=lowerCamelCase    )

	def    __a     (					self	,				lowerCamelCase = False    ) ->      Union[str, Any]:





								"""simple docstring"""


								lowercase__  :	str        =							""
								lowercase__  :	Optional[int]        =							[]
								lowercase__  :	Tuple        =							False
								for line in self.lines:
															if line.strip(" \n"    ) == "":
																						continue
															elif line.strip(" \n"    )[:3] == "```":
																						lowercase__  :	Union[str, Any]        =							not code_start
															elif line.split()[0] == self.level + "#" and not code_start:
																						if current_sub_level != "":
																													lowercase__  :	Optional[int]        =							Section(lowerCamelCase	,				self.level + "#"	,				lowerCamelCase    )
																													lowercase__  :	Tuple        =							[]
																						else:
																													if current_lines != []:
																																				self.text += "".join(lowerCamelCase    ).strip()
																																				if self.text != "" and self.text not in FILLER_TEXT:
																																											lowercase__  :	int        =							False
																																				lowercase__  :	List[str]        =							[]

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

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

	def    __a     (					self	,				lowerCamelCase    ) ->      ReadmeValidatorOutput:





								"""simple docstring"""


								lowercase__  :	Any        =							[]
								lowercase__  :	List[str]        =							[]
								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__  :	Any        =							[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__  :	Optional[int]        =							[subsection["name"] for subsection in structure["subsections"]]
																						lowercase__  :	int        =							False
																						for idx, name in enumerate(lowerCamelCase    ):
																													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__  :	Optional[Any]        =							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__  :	Optional[int]        =							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    __a     (					self    ) ->      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 				UpperCAmelCase(					snake_case_					):  # Level 0



	"""simple docstring"""






	def __init__(					self	,				lowerCamelCase	,				lowerCamelCase	,				lowerCamelCase = None	,				lowerCamelCase = False    ) ->      Union[str, Any]:





								"""simple docstring"""


								super().__init__(name=lowerCamelCase	,				level=""    )  # Not using lines here as we need to use a child class parse
								lowercase__  :	Union[str, Any]        =							structure
								lowercase__  :	Optional[Any]        =							-2
								lowercase__  :	Dict        =							0
								lowercase__  :	List[Any]        =							lines
								if self.lines is not None:
															self.parse(suppress_parsing_errors=lowerCamelCase    )

	def    __a     (					self    ) ->      Optional[int]:





								"""simple docstring"""


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

	@classmethod
	def    __a     (					cls	,				lowerCamelCase	,				lowerCamelCase = None	,				lowerCamelCase = False    ) ->      Union[str, Any]:





								"""simple docstring"""


								with open(lowerCamelCase	,				encoding="utf-8"    ) as f:
															lowercase__  :	Optional[Any]        =							f.readlines()
								return cls(lowerCamelCase	,				lowerCamelCase	,				lowerCamelCase	,				suppress_parsing_errors=lowerCamelCase    )

	@classmethod
	def    __a     (					cls	,				lowerCamelCase	,				lowerCamelCase = None	,				lowerCamelCase = "root"	,				lowerCamelCase = False    ) ->      List[Any]:





								"""simple docstring"""


								lowercase__  :	List[str]        =							string.split("\n"    )
								return cls(lowerCamelCase	,				lowerCamelCase	,				lowerCamelCase	,				suppress_parsing_errors=lowerCamelCase    )

	def    __a     (					self	,				lowerCamelCase = False    ) ->      Optional[Any]:





								"""simple docstring"""


								lowercase__  :	Union[str, Any]        =							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__  :	str        =							self.lines[line_count + 1 :]  # Get the last + 1 th item.
								else:
															lowercase__  :	List[Any]        =							self.lines[self.tag_count :]
								super().parse(suppress_parsing_errors=lowerCamelCase    )

	def __str__(					self    ) ->      str:





								"""simple docstring"""


								return str(self.to_dict()    )







	def    __a     (					self	,				lowerCamelCase    ) ->      Optional[int]:





								"""simple docstring"""


								lowercase__  :	Optional[int]        =							[]
								lowercase__  :	Dict        =							[]
								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__  :	Optional[int]        =							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__  :	Optional[Any]        =							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__  :	Optional[int]        =							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

						__a  :		str		     =   ArgumentParser(usage='''Validate the content (excluding YAML tags) of a README.md file.''')
						ap.add_argument('''readme_filepath''')
						__a  :		str		     =   ap.parse_args()
						__a  :		Optional[Any]		     =   Path(args.readme_filepath)
						__a  :		Optional[Any]		     =   ReadMe.from_readme(readme_filepath)





def  snake_case_					(		SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    )      ->			list[int]:
							if hue < 0 or hue > 3_60:
														raise Exception("hue should be between 0 and 360"    )

							if saturation < 0 or saturation > 1:
														raise Exception("saturation should be between 0 and 1"    )

							if value < 0 or value > 1:
														raise Exception("value should be between 0 and 1"    )

							lowercase__  :	List[Any]        =							value * saturation
							lowercase__  :	Optional[int]        =							hue / 60
							lowercase__  :	int        =							chroma * (1 - abs(hue_section % 2 - 1    ))
							lowercase__  :	Any        =							value - chroma

							if hue_section >= 0 and hue_section <= 1:
														lowercase__  :	int        =							round(2_55 * (chroma + match_value)    )
														lowercase__  :	Tuple        =							round(2_55 * (second_largest_component + match_value)    )
														lowercase__  :	Optional[int]        =							round(2_55 * (match_value)    )
							elif hue_section > 1 and hue_section <= 2:
														lowercase__  :	List[str]        =							round(2_55 * (second_largest_component + match_value)    )
														lowercase__  :	List[str]        =							round(2_55 * (chroma + match_value)    )
														lowercase__  :	List[str]        =							round(2_55 * (match_value)    )
							elif hue_section > 2 and hue_section <= 3:
														lowercase__  :	Any        =							round(2_55 * (match_value)    )
														lowercase__  :	List[str]        =							round(2_55 * (chroma + match_value)    )
														lowercase__  :	List[str]        =							round(2_55 * (second_largest_component + match_value)    )
							elif hue_section > 3 and hue_section <= 4:
														lowercase__  :	str        =							round(2_55 * (match_value)    )
														lowercase__  :	Any        =							round(2_55 * (second_largest_component + match_value)    )
														lowercase__  :	Dict        =							round(2_55 * (chroma + match_value)    )
							elif hue_section > 4 and hue_section <= 5:
														lowercase__  :	Tuple        =							round(2_55 * (second_largest_component + match_value)    )
														lowercase__  :	List[str]        =							round(2_55 * (match_value)    )
														lowercase__  :	Dict        =							round(2_55 * (chroma + match_value)    )
							else:
														lowercase__  :	List[Any]        =							round(2_55 * (chroma + match_value)    )
														lowercase__  :	Dict        =							round(2_55 * (match_value)    )
														lowercase__  :	Optional[int]        =							round(2_55 * (second_largest_component + match_value)    )

							return [red, green, blue]
def  snake_case_					(		SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    )      ->			list[float]:
							if red < 0 or red > 2_55:
														raise Exception("red should be between 0 and 255"    )

							if green < 0 or green > 2_55:
														raise Exception("green should be between 0 and 255"    )

							if blue < 0 or blue > 2_55:
														raise Exception("blue should be between 0 and 255"    )

							lowercase__  :	List[str]        =							red / 2_55
							lowercase__  :	str        =							green / 2_55
							lowercase__  :	Any        =							blue / 2_55
							lowercase__  :	Optional[int]        =							max(SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    )
							lowercase__  :	List[str]        =							value - min(SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    )
							lowercase__  :	Optional[Any]        =							0 if value == 0 else chroma / value

							if chroma == 0:
														lowercase__  :	Dict        =							0.0
							elif value == float_red:
														lowercase__  :	Union[str, Any]        =							60 * (0 + (float_green - float_blue) / chroma)
							elif value == float_green:
														lowercase__  :	Any        =							60 * (2 + (float_blue - float_red) / chroma)
							else:
														lowercase__  :	Any        =							60 * (4 + (float_red - float_green) / chroma)

							lowercase__  :	Tuple        =							(hue + 3_60) % 3_60

							return [hue, saturation, value]




def  snake_case_					(		SCREAMING_SNAKE_CASE_    ,SCREAMING_SNAKE_CASE_    )      ->			bool:
							lowercase__  :	Optional[Any]        =							abs(hsv_a[0] - hsv_a[0]    ) < 0.2
							lowercase__  :	Optional[int]        =							abs(hsv_a[1] - hsv_a[1]    ) < 0.002
							lowercase__  :	int        =							abs(hsv_a[2] - hsv_a[2]    ) < 0.002

							return check_hue and check_saturation and check_value