



"""simple docstring"""


import os
import pathlib
import tempfile
import uuid

import numpy as np

from ..utils import is_soundfile_availble, is_torch_available, is_vision_available, logging


snake_case_								=			logging.get_logger(__name__)

if is_vision_available():
				import PIL.Image
				from PIL import Image
				from PIL.Image import Image as ImageType
else:
				snake_case_								=			object

if is_torch_available():
				import torch

if is_soundfile_availble():
				import soundfile as sf







class  A_     :



						"""simple docstring"""






						def __init__(   self					:List[Any]  ,    lowercase_					:Optional[Any]   )							->     Any:
												UpperCAmelCase			 =					value






						def __str__(   self					:str   )							->     int:
												return self.to_string()






						def       UpperCAmelCase__	(   self					:Optional[int]   )							->     Dict:
												logger.error(
												    'This is a raw AgentType of unknown type. Display in notebooks and string conversion will be unreliable'   )
												return self._value






						def       UpperCAmelCase__	(   self					:Any   )							->     str:
												logger.error(
												    'This is a raw AgentType of unknown type. Display in notebooks and string conversion will be unreliable'   )
												return str(self._value   )







class  A_     (	SCREAMING_SNAKE_CASE_      ,  SCREAMING_SNAKE_CASE_							):



						"""simple docstring"""






						def       UpperCAmelCase__	(   self					:Optional[Any]   )							->     Optional[Any]:
												return self._value






						def       UpperCAmelCase__	(   self					:Union[str, Any]   )							->     Union[str, Any]:
												return self._value







class  A_     (	SCREAMING_SNAKE_CASE_      ,  SCREAMING_SNAKE_CASE_							):



						"""simple docstring"""






						def __init__(   self					:Optional[Any]  ,    lowercase_					:Optional[int]   )							->     str:
												super().__init__(lowercase_   )

												if not is_vision_available():
																		raise ImportError('PIL must be installed in order to handle images.'   )

												UpperCAmelCase			 =					None
												UpperCAmelCase			 =					None
												UpperCAmelCase			 =					None

												if isinstance(lowercase_  ,    lowercase_   ):
																		UpperCAmelCase			 =					value
												elif isinstance(lowercase_  ,    (str, pathlib.Path)   ):
																		UpperCAmelCase			 =					value
												elif isinstance(lowercase_  ,    torch.Tensor   ):
																		UpperCAmelCase			 =					value
												else:
																		raise ValueError(f"""Unsupported type for {self.__class__.__name__}: {type(lowercase_   )}"""   )






						def       UpperCAmelCase__	(   self					:Dict  ,    lowercase_					:Any=None  ,    lowercase_					:Any=None   )							->     Optional[int]:
												from IPython.display import Image, display

												display(Image(self.to_string()   )   )






						def       UpperCAmelCase__	(   self					:Union[str, Any]   )							->     str:
												if self._raw is not None:
																		return self._raw

												if self._path is not None:
																		UpperCAmelCase			 =					Image.open(self._path   )
																		return self._raw






						def       UpperCAmelCase__	(   self					:Optional[Any]   )							->     List[str]:
												if self._path is not None:
																		return self._path

												if self._raw is not None:
																		UpperCAmelCase			 =					tempfile.mkdtemp()
																		UpperCAmelCase			 =					os.path.join(lowercase_  ,    str(uuid.uuida()   ) + '.png'   )
																		self._raw.save(self._path   )

																		return self._path

												if self._tensor is not None:
																		UpperCAmelCase			 =					self._tensor.cpu().detach().numpy()

																		# There is likely simpler than load into image into save
																		UpperCAmelCase			 =					Image.fromarray((array * 2_55).astype(np.uinta   )   )

																		UpperCAmelCase			 =					tempfile.mkdtemp()
																		UpperCAmelCase			 =					os.path.join(lowercase_  ,    str(uuid.uuida()   ) + '.png'   )

																		img.save(self._path   )

																		return self._path







class  A_     (	SCREAMING_SNAKE_CASE_							):



						"""simple docstring"""






						def __init__(   self					:Optional[int]  ,    lowercase_					:Optional[Any]  ,    lowercase_					:Dict=1_60_00   )							->     Optional[Any]:
												super().__init__(lowercase_   )

												if not is_soundfile_availble():
																		raise ImportError('soundfile must be installed in order to handle audio.'   )

												UpperCAmelCase			 =					None
												UpperCAmelCase			 =					None

												UpperCAmelCase			 =					samplerate

												if isinstance(lowercase_  ,    (str, pathlib.Path)   ):
																		UpperCAmelCase			 =					value
												elif isinstance(lowercase_  ,    torch.Tensor   ):
																		UpperCAmelCase			 =					value
												else:
																		raise ValueError(f"""Unsupported audio type: {type(lowercase_   )}"""   )






						def       UpperCAmelCase__	(   self					:Union[str, Any]  ,    lowercase_					:Union[str, Any]=None  ,    lowercase_					:str=None   )							->     Optional[Any]:
												from IPython.display import Audio, display

												display(Audio(self.to_string()  ,    rate=self.samplerate   )   )






						def       UpperCAmelCase__	(   self					:str   )							->     List[Any]:
												if self._tensor is not None:
																		return self._tensor

												if self._path is not None:
																		UpperCAmelCase ,       UpperCAmelCase			 =					sf.read(self._path   )
																		UpperCAmelCase			 =					torch.tensor(lowercase_   )
																		return self._tensor






						def       UpperCAmelCase__	(   self					:List[str]   )							->     Any:
												if self._path is not None:
																		return self._path

												if self._tensor is not None:
																		UpperCAmelCase			 =					tempfile.mkdtemp()
																		UpperCAmelCase			 =					os.path.join(lowercase_  ,    str(uuid.uuida()   ) + '.wav'   )
																		sf.write(self._path  ,    self._tensor  ,    samplerate=self.samplerate   )
																		return self._path


snake_case_								=			{"""text""": AgentText, """image""": AgentImage, """audio""": AgentAudio}
snake_case_								=			{str: AgentText}

if is_vision_available():
				snake_case_								=			AgentImage

def 					_lowerCAmelCase (  *lowercase_						,      **lowercase_		):
						UpperCAmelCase			 =					[(arg.to_raw() if isinstance(lowercase_						,      lowercase_		) else arg) for arg in args]
						UpperCAmelCase			 =					{k: (v.to_raw() if isinstance(lowercase_						,      lowercase_		) else v) for k, v in kwargs.items()}
						return args, kwargs






def 					_lowerCAmelCase (  lowercase_						,      lowercase_=None		):
						if isinstance(lowercase_						,      lowercase_		):
												UpperCAmelCase			 =					{}
												for i, (k, v) in enumerate(outputs.items()		):
																		if output_types is not None:
																								# If the class has defined outputs, we can map directly according to the class definition
																								if output_types[i] in AGENT_TYPE_MAPPING:
																														UpperCAmelCase			 =					AGENT_TYPE_MAPPING[output_types[i]](lowercase_		)
																								else:
																														UpperCAmelCase			 =					AgentType(lowercase_		)

																		else:
																								# If the class does not have defined output, then we map according to the type
																								for _k, _v in INSTANCE_TYPE_MAPPING.items():
																														if isinstance(lowercase_						,      _k		):
																																				UpperCAmelCase			 =					_v(lowercase_		)
																								if k not in decoded_outputs:
																														UpperCAmelCase			 =					AgentType[v]

						elif isinstance(lowercase_						,      (list, tuple)		):
												UpperCAmelCase			 =					type(lowercase_		)()
												for i, v in enumerate(lowercase_		):
																		if output_types is not None:
																								# If the class has defined outputs, we can map directly according to the class definition
																								if output_types[i] in AGENT_TYPE_MAPPING:
																														decoded_outputs.append(AGENT_TYPE_MAPPING[output_types[i]](lowercase_		)		)
																								else:
																														decoded_outputs.append(AgentType(lowercase_		)		)
																		else:
																								# If the class does not have defined output, then we map according to the type
																								UpperCAmelCase			 =					False
																								for _k, _v in INSTANCE_TYPE_MAPPING.items():
																														if isinstance(lowercase_						,      _k		):
																																				decoded_outputs.append(_v(lowercase_		)		)
																																				UpperCAmelCase			 =					True

																								if not found:
																														decoded_outputs.append(AgentType(lowercase_		)		)

						else:
												if output_types[0] in AGENT_TYPE_MAPPING:
																		# If the class has defined outputs, we can map directly according to the class definition
																		UpperCAmelCase			 =					AGENT_TYPE_MAPPING[output_types[0]](lowercase_		)

												else:
																		# If the class does not have defined output, then we map according to the type
																		for _k, _v in INSTANCE_TYPE_MAPPING.items():
																								if isinstance(lowercase_						,      _k		):
																														return _v(lowercase_		)
																		return AgentType(lowercase_		)

						return decoded_outputs










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


UpperCAmelCase_			      =  '''https://github.com/huggingface/datasets/tree/main/src/datasets/utils'''
UpperCAmelCase_			      =  f"""{BASE_REF_URL}/{__file__}"""
UpperCAmelCase_			      =  logging.getLogger(__name__)
def   UpperCAmelCase							(		A__     )							->					Tuple[Any, str]:
	_snake_case					:							Optional[int]					     =   pkg_resources.read_text(A__				,  A__     )
	return yaml.safe_load(A__     ), f'''{BASE_REF_URL}/resources/{resource}'''


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

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





class 		__SCREAMING_SNAKE_CASE      :






				"""simple docstring"""

				def __init__(				self						,	SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__ = None						,	SCREAMING_SNAKE_CASE__ = False      ):






					"""simple docstring"""

					_snake_case					:							Optional[Any]					     =   name
					_snake_case					:							str					     =   level
					_snake_case					:							Optional[Any]					     =   lines
					_snake_case					:							Any					     =   """"""
					_snake_case					:							int					     =   True
					_snake_case					:							Dict					     =   {}
					_snake_case					:							List[str]					     =   []
					_snake_case					:							Optional[Any]					     =   []
					if self.lines is not None:
						self.parse(suppress_parsing_errors=SCREAMING_SNAKE_CASE__      )







				def 		__lowerCamelCase(				self						,	SCREAMING_SNAKE_CASE__ = False      ):






					"""simple docstring"""

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

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

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







				def 		__lowerCamelCase(				self						,	SCREAMING_SNAKE_CASE__      ):






					"""simple docstring"""

					_snake_case					:							Union[str, Any]					     =   []
					_snake_case					:							Tuple					     =   []
					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
							_snake_case					:							Optional[int]					     =   [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
							_snake_case					:							Tuple					     =   [subsection["""name"""] for subsection in structure["""subsections"""]]
							_snake_case					:							Dict					     =   False
							for idx, name in enumerate(SCREAMING_SNAKE_CASE__      ):
								if name not in self.content:
									# If the expected subsection is not present
									error_list.append(f'''Section `{self.name}` is missing subsection: `{name}`.'''      )
									_snake_case					:							int					     =   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:
										_snake_case     , _snake_case     , _snake_case					:							Tuple					     =   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      ):






					"""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 		__SCREAMING_SNAKE_CASE      (				lowercase__      ):  # Level 0






				"""simple docstring"""

				def __init__(				self						,	SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__ = None						,	SCREAMING_SNAKE_CASE__ = False      ):






					"""simple docstring"""

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







				def 		__lowerCamelCase(				self      ):






					"""simple docstring"""

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







				@classmethod
				def 		__lowerCamelCase(				cls						,	SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__ = None						,	SCREAMING_SNAKE_CASE__ = False      ):






					"""simple docstring"""

					with open(SCREAMING_SNAKE_CASE__						,	encoding="""utf-8"""      ) as f:
						_snake_case					:							List[str]					     =   f.readlines()
					return cls(SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__						,	suppress_parsing_errors=SCREAMING_SNAKE_CASE__      )







				@classmethod
				def 		__lowerCamelCase(				cls						,	SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__ = None						,	SCREAMING_SNAKE_CASE__ = "root"						,	SCREAMING_SNAKE_CASE__ = False      ):






					"""simple docstring"""

					_snake_case					:							Tuple					     =   string.split("""\n"""      )
					return cls(SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__						,	SCREAMING_SNAKE_CASE__						,	suppress_parsing_errors=SCREAMING_SNAKE_CASE__      )







				def 		__lowerCamelCase(				self						,	SCREAMING_SNAKE_CASE__ = False      ):






					"""simple docstring"""

					_snake_case					:							Optional[int]					     =   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:
						_snake_case					:							Optional[int]					     =   self.lines[line_count + 1 :]  # Get the last + 1 th item.
					else:
						_snake_case					:							List[str]					     =   self.lines[self.tag_count :]
					super().parse(suppress_parsing_errors=SCREAMING_SNAKE_CASE__      )







				def __str__(				self      ):






					"""simple docstring"""

					return str(self.to_dict()      )







				def 		__lowerCamelCase(				self						,	SCREAMING_SNAKE_CASE__      ):






					"""simple docstring"""

					_snake_case					:							str					     =   []
					_snake_case					:							str					     =   []
					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.
					_snake_case					:							List[str]					     =   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
						_snake_case					:							List[str]					     =   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
							_snake_case     , _snake_case     , _snake_case					:							List[Any]					     =   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

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





