




import os
import tempfile
import unittest

import numpy as np
import torch

from diffusers.models import ModelMixin, UNetaDConditionModel
from diffusers.models.attention_processor import AttnProcessor, LoRAAttnProcessor
from diffusers.utils import (
    floats_tensor,
    logging,
    skip_mps,
    torch_device,
)
from diffusers.utils.import_utils import is_xformers_available
from diffusers.utils.testing_utils import enable_full_determinism

from .test_modeling_common import ModelTesterMixin, UNetTesterMixin


enable_full_determinism()

lowerCamelCase_  						=   logging.get_logger(__name__)



def 	UpperCAmelCase_    (	__UpperCamelCase,				__UpperCamelCase = True	):
    SCREAMING_SNAKE_CASE__								={}
    for name in model.attn_processors.keys():
        SCREAMING_SNAKE_CASE__								=name.endswith("""attn2.processor"""	) and not (
            name.startswith("""transformer_in"""	) or """temp_attentions""" in name.split("""."""	)
        )
        SCREAMING_SNAKE_CASE__								=model.config.cross_attention_dim if has_cross_attention else None
        if name.startswith("""mid_block"""	):
            SCREAMING_SNAKE_CASE__								=model.config.block_out_channels[-1]
        elif name.startswith("""up_blocks"""	):
            SCREAMING_SNAKE_CASE__								=int(name[len("""up_blocks."""	)]	)
            SCREAMING_SNAKE_CASE__								=list(reversed(model.config.block_out_channels	)	)[block_id]
        elif name.startswith("""down_blocks"""	):
            SCREAMING_SNAKE_CASE__								=int(name[len("""down_blocks."""	)]	)
            SCREAMING_SNAKE_CASE__								=model.config.block_out_channels[block_id]
        elif name.startswith("""transformer_in"""	):
            # Note that the `8 * ...` comes from: https://github.com/huggingface/diffusers/blob/7139f0e874f10b2463caa8cbd585762a309d12d6/src/diffusers/models/unet_3d_condition.py#L148
            SCREAMING_SNAKE_CASE__								=8 * model.config.attention_head_dim

        SCREAMING_SNAKE_CASE__								=LoRAAttnProcessor(hidden_size=snake_case__,				cross_attention_dim=snake_case__	)
        SCREAMING_SNAKE_CASE__								=lora_attn_procs[name].to(model.device	)

        if mock_weights:
            # add 1 to weights to mock trained weights
            with torch.no_grad():
                lora_attn_procs[name].to_q_lora.up.weight += 1
                lora_attn_procs[name].to_k_lora.up.weight += 1
                lora_attn_procs[name].to_v_lora.up.weight += 1
                lora_attn_procs[name].to_out_lora.up.weight += 1

    return lora_attn_procs




@skip_mps
class       __a					( _UpperCamelCase							,     _UpperCamelCase							,     unittest.TestCase     ):


     """simple docstring"""


     _A				:    Any									=  UNetaDConditionModel
     _A				:    int									=  "sample"




     @property
     def   __A				(	self			: Any						)		->   Any:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__								=4
         SCREAMING_SNAKE_CASE__								=4
         SCREAMING_SNAKE_CASE__								=4
         SCREAMING_SNAKE_CASE__								=(3_2, 3_2)

         SCREAMING_SNAKE_CASE__								=floats_tensor((batch_size, num_channels, num_frames) + sizes						).to(__a						)
         SCREAMING_SNAKE_CASE__								=torch.tensor([1_0]						).to(__a						)
         SCREAMING_SNAKE_CASE__								=floats_tensor((batch_size, 4, 3_2)						).to(__a						)

         return {"sample": noise, "timestep": time_step, "encoder_hidden_states": encoder_hidden_states}




     @property
     def   __A				(	self			: str						)		->   List[str]:


         '''simple docstring'''





         return (4, 4, 3_2, 3_2)




     @property
     def   __A				(	self			: Any						)		->   Dict:


         '''simple docstring'''





         return (4, 4, 3_2, 3_2)




     def   __A				(	self			: Any						)		->   Optional[int]:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__								={
             """block_out_channels""": (3_2, 6_4),
             """down_block_types""": (
                 """CrossAttnDownBlock3D""",
                 """DownBlock3D""",
             ),
             """up_block_types""": ("""UpBlock3D""", """CrossAttnUpBlock3D"""),
             """cross_attention_dim""": 3_2,
             """attention_head_dim""": 8,
             """out_channels""": 4,
             """in_channels""": 4,
             """layers_per_block""": 1,
             """sample_size""": 3_2,
         }
         SCREAMING_SNAKE_CASE__								=self.dummy_input
         return init_dict, inputs_dict




     @unittest.skipIf(
         torch_device != """cuda""" or not is_xformers_available()				,reason="""XFormers attention is only available with CUDA and `xformers` installed"""				,)
     def   __A				(	self			: Dict						)		->   int:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()
         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)

         model.enable_xformers_memory_efficient_attention()

         assert (
             model.mid_block.attentions[0].transformer_blocks[0].attna.processor.__class__.__name__
             == "XFormersAttnProcessor"
         ), "xformers is not enabled"




     def   __A				(	self			: Tuple						)		->   Optional[int]:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=3_2

         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)
         model.eval()

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						)

             if isinstance(__a				,__a						):
                 SCREAMING_SNAKE_CASE__								=output.sample

         self.assertIsNotNone(__a						)
         SCREAMING_SNAKE_CASE__								=inputs_dict["""sample"""].shape
         self.assertEqual(output.shape				,__a				,"""Input and output shapes do not match"""						)




     def   __A				(	self			: Tuple						)		->   List[Any]:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()
         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)
         model.eval()

         with torch.no_grad():
             # Warmup pass when using mps (see #372)
             if torch_device == "mps" and isinstance(__a				,__a						):
                 model(**self.dummy_input						)

             SCREAMING_SNAKE_CASE__								=model(**__a						)
             if isinstance(__a				,__a						):
                 SCREAMING_SNAKE_CASE__								=first.sample

             SCREAMING_SNAKE_CASE__								=model(**__a						)
             if isinstance(__a				,__a						):
                 SCREAMING_SNAKE_CASE__								=second.sample

         SCREAMING_SNAKE_CASE__								=first.cpu().numpy()
         SCREAMING_SNAKE_CASE__								=second.cpu().numpy()
         SCREAMING_SNAKE_CASE__								=out_a[~np.isnan(__a						)]
         SCREAMING_SNAKE_CASE__								=out_a[~np.isnan(__a						)]
         SCREAMING_SNAKE_CASE__								=np.amax(np.abs(out_a - out_a						)						)
         self.assertLessEqual(__a				,1e-5						)




     def   __A				(	self			: int						)		->   Any:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=8

         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)
         model.eval()

         model.set_attention_slice("""auto"""						)
         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						)
         assert output is not None

         model.set_attention_slice("""max"""						)
         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						)
         assert output is not None

         model.set_attention_slice(2						)
         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						)
         assert output is not None




     def   __A				(	self			: List[Any]						)		->   Dict:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=8

         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						).sample

         SCREAMING_SNAKE_CASE__								=create_lora_layers(__a						)

         # make sure we can set a list of attention processors
         model.set_attn_processor(__a						)
         model.to(__a						)

         # test that attn processors can be set to itself
         model.set_attn_processor(model.attn_processors						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a				,cross_attention_kwargs={"""scale""": 0.0}						).sample
             SCREAMING_SNAKE_CASE__								=model(**__a				,cross_attention_kwargs={"""scale""": 0.5}						).sample
             SCREAMING_SNAKE_CASE__								=model(**__a				,cross_attention_kwargs={"""scale""": 0.5}						).sample

         assert (samplea - samplea).abs().max() < 3e-3
         assert (samplea - samplea).abs().max() < 3e-3

         # sample 2 and sample 3 should be different
         assert (samplea - samplea).abs().max() > 3e-3




     def   __A				(	self			: List[Any]						)		->   List[Any]:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=8

         torch.manual_seed(0						)
         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						).sample

         SCREAMING_SNAKE_CASE__								=create_lora_layers(__a						)
         model.set_attn_processor(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a				,cross_attention_kwargs={"""scale""": 0.5}						).sample

         with tempfile.TemporaryDirectory() as tmpdirname:
             model.save_attn_procs(__a						)
             self.assertTrue(os.path.isfile(os.path.join(__a				,"""pytorch_lora_weights.bin"""						)						)						)
             torch.manual_seed(0						)
             SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
             new_model.to(__a						)
             new_model.load_attn_procs(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=new_model(**__a				,cross_attention_kwargs={"""scale""": 0.5}						).sample

         assert (sample - new_sample).abs().max() < 1e-3

         # LoRA and no LoRA should NOT be the same
         assert (sample - old_sample).abs().max() > 1e-4




     def   __A				(	self			: Union[str, Any]						)		->   int:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=8

         torch.manual_seed(0						)
         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						).sample

         SCREAMING_SNAKE_CASE__								=create_lora_layers(__a						)
         model.set_attn_processor(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a				,cross_attention_kwargs={"""scale""": 0.5}						).sample

         with tempfile.TemporaryDirectory() as tmpdirname:
             model.save_attn_procs(__a				,safe_serialization=__a						)
             self.assertTrue(os.path.isfile(os.path.join(__a				,"""pytorch_lora_weights.safetensors"""						)						)						)
             torch.manual_seed(0						)
             SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
             new_model.to(__a						)
             new_model.load_attn_procs(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=new_model(**__a				,cross_attention_kwargs={"""scale""": 0.5}						).sample

         assert (sample - new_sample).abs().max() < 3e-3

         # LoRA and no LoRA should NOT be the same
         assert (sample - old_sample).abs().max() > 1e-4




     def   __A				(	self			: Optional[Any]						)		->   Union[str, Any]:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=8

         torch.manual_seed(0						)
         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)

         SCREAMING_SNAKE_CASE__								=create_lora_layers(__a				,mock_weights=__a						)
         model.set_attn_processor(__a						)
         # Saving as torch, properly reloads with directly filename
         with tempfile.TemporaryDirectory() as tmpdirname:
             model.save_attn_procs(__a						)
             self.assertTrue(os.path.isfile(os.path.join(__a				,"""pytorch_lora_weights.bin"""						)						)						)
             torch.manual_seed(0						)
             SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
             new_model.to(__a						)
             new_model.load_attn_procs(__a				,weight_name="""pytorch_lora_weights.bin"""						)




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


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=8

         torch.manual_seed(0						)
         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)

         SCREAMING_SNAKE_CASE__								=create_lora_layers(__a				,mock_weights=__a						)
         model.set_attn_processor(__a						)
         # Saving as torch, properly reloads with directly filename
         with tempfile.TemporaryDirectory() as tmpdirname:
             model.save_attn_procs(__a						)
             self.assertTrue(os.path.isfile(os.path.join(__a				,"""pytorch_lora_weights.bin"""						)						)						)
             torch.manual_seed(0						)
             SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
             new_model.to(__a						)
             with self.assertRaises(__a						) as e:
                 new_model.load_attn_procs(__a				,use_safetensors=__a						)
             self.assertIn("""Error no file named pytorch_lora_weights.safetensors"""				,str(e.exception						)						)




     def   __A				(	self			: str						)		->   Any:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=8

         torch.manual_seed(0						)
         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						).sample

         SCREAMING_SNAKE_CASE__								=create_lora_layers(__a						)
         model.set_attn_processor(__a						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a				,cross_attention_kwargs={"""scale""": 0.0}						).sample

         model.set_attn_processor(AttnProcessor()						)

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						).sample

         assert (sample - new_sample).abs().max() < 1e-4
         assert (sample - old_sample).abs().max() < 3e-3




     @unittest.skipIf(
         torch_device != """cuda""" or not is_xformers_available()				,reason="""XFormers attention is only available with CUDA and `xformers` installed"""				,)
     def   __A				(	self			: int						)		->   int:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()

         SCREAMING_SNAKE_CASE__								=4

         torch.manual_seed(0						)
         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)
         SCREAMING_SNAKE_CASE__								=create_lora_layers(__a						)
         model.set_attn_processor(__a						)

         # default
         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						).sample

             model.enable_xformers_memory_efficient_attention()
             SCREAMING_SNAKE_CASE__								=model(**__a						).sample

             model.disable_xformers_memory_efficient_attention()
             SCREAMING_SNAKE_CASE__								=model(**__a						).sample

         assert (sample - on_sample).abs().max() < 1e-4
         assert (sample - off_sample).abs().max() < 1e-4




     def   __A				(	self			: int						)		->   Optional[Any]:


         '''simple docstring'''





         SCREAMING_SNAKE_CASE__			,		SCREAMING_SNAKE_CASE__								=self.prepare_init_args_and_inputs_for_common()
         SCREAMING_SNAKE_CASE__								=3_2

         SCREAMING_SNAKE_CASE__								=self.model_class(**__a						)
         model.to(__a						)
         model.eval()

         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						)[0]

         model.enable_forward_chunking()
         with torch.no_grad():
             SCREAMING_SNAKE_CASE__								=model(**__a						)[0]

         self.assertEqual(output.shape				,output_a.shape				,"""Shape doesn\'t match"""						)
         assert np.abs(output.cpu() - output_a.cpu()						).max() < 1e-2


# (todo: sayakpaul) implement SLOW tests.









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_(			snake_case__:  str   )       -> Tuple[Any, str]:
 UpperCAmelCase__							=				pkg_resources.read_text(snake_case__  ,    snake_case__   )
 return yaml.safe_load(snake_case__   ), 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     lowercase						:



 '''simple docstring'''


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






  """simple docstring"""





  UpperCAmelCase__							=				name
  UpperCAmelCase__							=				level
  UpperCAmelCase__							=				lines
  UpperCAmelCase__							=				''
  UpperCAmelCase__							=				True
  UpperCAmelCase__							=				{}
  UpperCAmelCase__							=				[]
  UpperCAmelCase__							=				[]
  if self.lines is not None:
   self.parse(suppress_parsing_errors=__a )




 def   UpperCamelCase__							(self       ,       __a = False ) ->					Tuple:






  """simple docstring"""





  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(__a       ,       self.level + '#'       ,       __a )
     UpperCAmelCase__							=				[]
    else:
     if current_lines != []:
      self.text += "".join(__a ).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(__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." )
    UpperCAmelCase__							=				Section(__a       ,       self.level + '#'       ,       __a )
   else:
    if current_lines != []:
     self.text += "".join(__a ).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(__a )




 def   UpperCamelCase__							(self       ,       __a ) ->					ReadmeValidatorOutput:






  """simple docstring"""





  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(__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}`." )
      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 ) ->					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     lowercase						(       _UpperCamelCase					):  # Level 0



 '''simple docstring'''


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






  """simple docstring"""





  super().__init__(name=__a       ,       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=__a )




 def   UpperCamelCase__							(self ) ->					int:






  """simple docstring"""





  if self.structure is None:
   UpperCAmelCase__				,    UpperCAmelCase__				,    UpperCAmelCase__							=				self._validate(__a )
  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(__a )




 @classmethod
 def   UpperCamelCase__							(cls       ,       __a       ,       __a = None       ,       __a = False ) ->					List[str]:






  """simple docstring"""





  with open(__a       ,       encoding='utf-8' ) as f:
   UpperCAmelCase__							=				f.readlines()
  return cls(__a       ,       __a       ,       __a       ,       suppress_parsing_errors=__a )




 @classmethod
 def   UpperCamelCase__							(cls       ,       __a       ,       __a = None       ,       __a = "root"       ,       __a = False ) ->					Dict:






  """simple docstring"""





  UpperCAmelCase__							=				string.split('\n' )
  return cls(__a       ,       __a       ,       __a       ,       suppress_parsing_errors=__a )




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






  """simple docstring"""





  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=__a )




 def __str__(self ) ->					List[str]:






  """simple docstring"""





  return str(self.to_dict() )




 def   UpperCamelCase__							(self       ,       __a ) ->					Tuple:






  """simple docstring"""





  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

 _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)



