





'''simple docstring'''



import argparse
import collections
import os
import re

from transformers.utils import direct_transformers_import


# All paths are set with the intent you should run this script from the root of the repo with the command
# python utils/check_table.py
_SCREAMING_SNAKE_CASE					=    '''src/transformers'''
_SCREAMING_SNAKE_CASE					=    '''docs/source/en'''
_SCREAMING_SNAKE_CASE					=    '''.'''




def    _lowerCAmelCase						(				lowerCamelCase_			:  List[str]		,       lowerCamelCase_			:  Optional[int]		,       lowerCamelCase_			:  int				):
			with open(lowerCamelCase_		,       '''r'''		,       encoding='''utf-8'''		,       newline='''\n'''				) as f:
						__lowercase										=							f.readlines()
			# Find the start prompt.
			__lowercase										=							0
			while not lines[start_index].startswith(lowerCamelCase_				):
						start_index += 1
			start_index += 1

			__lowercase										=							start_index
			while not lines[end_index].startswith(lowerCamelCase_				):
						end_index += 1
			end_index -= 1

			while len(lines[start_index]				) <= 1:
						start_index += 1
			while len(lines[end_index]				) <= 1:
						end_index -= 1
			end_index += 1
			return "".join(lines[start_index:end_index]				), start_index, end_index, lines


# Add here suffixes that are used to identify models, separated by |
_SCREAMING_SNAKE_CASE					=    '''Model|Encoder|Decoder|ForConditionalGeneration'''
# Regexes that match TF/Flax/PT model names.
_SCREAMING_SNAKE_CASE					=    re.compile(R'''TF(.*)(?:Model|Encoder|Decoder|ForConditionalGeneration)''')
_SCREAMING_SNAKE_CASE					=    re.compile(R'''Flax(.*)(?:Model|Encoder|Decoder|ForConditionalGeneration)''')
# Will match any TF or Flax model too so need to be in an else branch afterthe two previous regexes.
_SCREAMING_SNAKE_CASE					=    re.compile(R'''(.*)(?:Model|Encoder|Decoder|ForConditionalGeneration)''')


# This is to make sure the transformers module imported is the one in the repo.
_SCREAMING_SNAKE_CASE					=    direct_transformers_import(TRANSFORMERS_PATH)




def    _lowerCAmelCase						(				lowerCamelCase_			:  Optional[int]				):
			__lowercase										=							re.finditer('''.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)'''		,       lowerCamelCase_				)
			return [m.group(0				) for m in matches]




def    _lowerCAmelCase						(				lowerCamelCase_			:  Optional[Any]		,       lowerCamelCase_			:  int				):
			__lowercase										=							2 if text == '''✅''' or text == '''❌''' else len(lowerCamelCase_				)
			__lowercase										=							(width - text_length) // 2
			__lowercase										=							width - text_length - left_indent
			return " " * left_indent + text + " " * right_indent




def    _lowerCAmelCase						(				):
			__lowercase										=							transformers_module.models.auto.configuration_auto.CONFIG_MAPPING_NAMES
			__lowercase										=							{
			    name: config_maping_names[code]
			    for code, name in transformers_module.MODEL_NAMES_MAPPING.items()
			    if code in config_maping_names
			}
			__lowercase										=							{name: config.replace('''Config'''		,       ''''''				) for name, config in model_name_to_config.items()}

			# Dictionaries flagging if each model prefix has a slow/fast tokenizer, backend in PT/TF/Flax.
			__lowercase										=							collections.defaultdict(lowerCamelCase_				)
			__lowercase										=							collections.defaultdict(lowerCamelCase_				)
			__lowercase										=							collections.defaultdict(lowerCamelCase_				)
			__lowercase										=							collections.defaultdict(lowerCamelCase_				)
			__lowercase										=							collections.defaultdict(lowerCamelCase_				)

			# Let's lookup through all transformers object (once).
			for attr_name in dir(lowerCamelCase_				):
						__lowercase										=							None
						if attr_name.endswith('''Tokenizer'''				):
									__lowercase										=							slow_tokenizers
									__lowercase										=							attr_name[:-9]
						elif attr_name.endswith('''TokenizerFast'''				):
									__lowercase										=							fast_tokenizers
									__lowercase										=							attr_name[:-1_3]
						elif _re_tf_models.match(lowerCamelCase_				) is not None:
									__lowercase										=							tf_models
									__lowercase										=							_re_tf_models.match(lowerCamelCase_				).groups()[0]
						elif _re_flax_models.match(lowerCamelCase_				) is not None:
									__lowercase										=							flax_models
									__lowercase										=							_re_flax_models.match(lowerCamelCase_				).groups()[0]
						elif _re_pt_models.match(lowerCamelCase_				) is not None:
									__lowercase										=							pt_models
									__lowercase										=							_re_pt_models.match(lowerCamelCase_				).groups()[0]

						if lookup_dict is not None:
									while len(lowerCamelCase_				) > 0:
												if attr_name in model_name_to_prefix.values():
															__lowercase										=							True
															break
												# Try again after removing the last word in the name
												__lowercase										=							''''''.join(camel_case_split(lowerCamelCase_				)[:-1]				)

    # Let's build that table!
			__lowercase										=							list(model_name_to_config.keys()				)
			model_names.sort(key=str.lower				)
			__lowercase										=							['''Model''', '''Tokenizer slow''', '''Tokenizer fast''', '''PyTorch support''', '''TensorFlow support''', '''Flax Support''']
			# We'll need widths to properly display everything in the center (+2 is to leave one extra space on each side).
			__lowercase										=							[len(lowerCamelCase_				) + 2 for c in columns]
			__lowercase										=							max([len(lowerCamelCase_				) for name in model_names]				) + 2

			# Build the table per se
			__lowercase										=							'''|''' + '''|'''.join([_center_text(lowerCamelCase_		,       lowerCamelCase_				) for c, w in zip(lowerCamelCase_		,       lowerCamelCase_				)]				) + '''|\n'''
			# Use ":-----:" format to center-aligned table cell texts
			table += "|" + "|".join([''':''' + '''-''' * (w - 2) + ''':''' for w in widths]				) + "|\n"

			__lowercase										=							{True: '''✅''', False: '''❌'''}
			for name in model_names:
						__lowercase										=							model_name_to_prefix[name]
						__lowercase										=							[
						    name,
						    check[slow_tokenizers[prefix]],
						    check[fast_tokenizers[prefix]],
						    check[pt_models[prefix]],
						    check[tf_models[prefix]],
						    check[flax_models[prefix]],
						]
						table += "|" + "|".join([_center_text(lowerCamelCase_		,       lowerCamelCase_				) for l, w in zip(lowerCamelCase_		,       lowerCamelCase_				)]				) + "|\n"
			return table




def    _lowerCAmelCase						(				lowerCamelCase_			:  Union[str, Any]=False				):
			__lowercase						,		__lowercase						,		__lowercase						,		__lowercase										=							_find_text_in_file(
			    filename=os.path.join(lowerCamelCase_		,       '''index.md'''				)		,       start_prompt='''<!--This table is updated automatically from the auto modules'''		,       end_prompt='''<!-- End table-->'''		,       )
			__lowercase										=							get_model_table_from_auto_modules()

			if current_table != new_table:
						if overwrite:
									with open(os.path.join(lowerCamelCase_		,       '''index.md'''				)		,       '''w'''		,       encoding='''utf-8'''		,       newline='''\n'''				) as f:
												f.writelines(lines[:start_index] + [new_table] + lines[end_index:]				)
						else:
									raise ValueError(
									    '''The model table in the `index.md` has not been updated. Run `make fix-copies` to fix this.'''				)


if __name__ == "__main__":
	_SCREAMING_SNAKE_CASE					=    argparse.ArgumentParser()
	parser.add_argument('''--fix_and_overwrite''', action='''store_true''', help='''Whether to fix inconsistencies.''')
	_SCREAMING_SNAKE_CASE					=    parser.parse_args()

	check_model_table(args.fix_and_overwrite)












'''simple docstring'''



import collections
import json
import math
import os
import re
import time
from fnmatch import fnmatch
from typing import Dict

import requests
from slack_sdk import WebClient


_SCREAMING_SNAKE_CASE					=    WebClient(token=os.environ['''CI_SLACK_BOT_TOKEN'''])




def    _lowerCAmelCase						(				lowerCamelCase_			:  Any				):
			__lowercase										=							test_results.split(''' '''				)

			__lowercase										=							0
			__lowercase										=							0

			# When the output is short enough, the output is surrounded by = signs: "== OUTPUT =="
			# When it is too long, those signs are not present.
			__lowercase										=							expressions[-2] if '''=''' in expressions[-1] else expressions[-1]

			for i, expression in enumerate(lowerCamelCase_				):
						if "failed" in expression:
									failed += int(expressions[i - 1]				)
						if "passed" in expression:
									success += int(expressions[i - 1]				)

			return failed, success, time_spent




def    _lowerCAmelCase						(				lowerCamelCase_			:  Union[str, Any]				):
			__lowercase										=							{}
			__lowercase										=							None
			__lowercase										=							False
			for line in failures_short_lines.split('''\n'''				):
						if re.search(r'''_ \[doctest\]'''		,       lowerCamelCase_				):
									__lowercase										=							True
									__lowercase										=							line.split(''' '''				)[2]
						elif in_error and not line.split(''' '''				)[0].isdigit():
									__lowercase										=							line
									__lowercase										=							False

			return failures






class 							__lowercase       :







	'''simple docstring'''

	def __init__(self     ,_lowerCamelCase     ,_lowerCamelCase )							->							Any:







				'''simple docstring'''





				__lowercase										=							title

				__lowercase										=							doc_test_results['''time_spent'''].split(''',''' )[0]
				__lowercase										=							doc_test_results['''success''']
				__lowercase										=							doc_test_results['''failures''']
				__lowercase										=							self.n_success + self.n_failures

				# Failures and success of the modeling tests
				__lowercase										=							doc_test_results


	@property
	def 						_UpperCAmelCase     (self )							->							str:







				'''simple docstring'''





				__lowercase										=							[self._time_spent]
				__lowercase										=							0

				for time in time_spent:
							__lowercase										=							time.split(''':''' )

							# Time can be formatted as xx:xx:xx, as .xx, or as x.xx if the time spent was less than a minute.
							if len(_lowerCamelCase ) == 1:
										__lowercase										=							[0, 0, time_parts[0]]

							__lowercase						,		__lowercase						,		__lowercase										=							int(time_parts[0] ), int(time_parts[1] ), float(time_parts[2] )
							total_secs += hours * 3600 + minutes * 60 + seconds

				__lowercase						,		__lowercase						,		__lowercase										=							total_secs // 3600, (total_secs % 3600) // 60, total_secs % 60
				return f"{int(_lowerCamelCase )}h{int(_lowerCamelCase )}m{int(_lowerCamelCase )}s"


	@property
	def 						_UpperCAmelCase     (self )							->							Dict:







				'''simple docstring'''





				return {"type": "header", "text": {"type": "plain_text", "text": self.title}}


	@property
	def 						_UpperCAmelCase     (self )							->							Dict:







				'''simple docstring'''





				return {
				    "type": "section",
				    "text": {
				        "type": "plain_text",
				        "text": f"🌞 There were no failures: all {self.n_tests} tests passed. The suite ran in {self.time}.",
				        "emoji": True,
				    },
				    "accessory": {
				        "type": "button",
				        "text": {"type": "plain_text", "text": "Check Action results", "emoji": True},
				        "url": f"https://github.com/huggingface/transformers/actions/runs/{os.environ['GITHUB_RUN_ID']}",
				    },
				}


	@property
	def 						_UpperCAmelCase     (self )							->							Dict:







				'''simple docstring'''





				return {
				    "type": "section",
				    "text": {
				        "type": "plain_text",
				        "text": (
				            f"There were {self.n_failures} failures, out of {self.n_tests} tests.\nThe suite ran in"
				            f" {self.time}."
				        ),
				        "emoji": True,
				    },
				    "accessory": {
				        "type": "button",
				        "text": {"type": "plain_text", "text": "Check Action results", "emoji": True},
				        "url": f"https://github.com/huggingface/transformers/actions/runs/{os.environ['GITHUB_RUN_ID']}",
				    },
				}


	@property
	def 						_UpperCAmelCase     (self )							->							Dict:







				'''simple docstring'''





				__lowercase										=							40
				__lowercase										=							{k: v['''failed'''] for k, v in doc_test_results.items() if isinstance(_lowerCamelCase     ,_lowerCamelCase )}

				__lowercase										=							''''''
				for category, failures in category_failures.items():
							if len(_lowerCamelCase ) == 0:
										continue

							if report != "":
										report += "\n\n"

							report += f"*{category} failures*:".ljust(line_length // 2 ).rjust(line_length // 2 ) + "\n"
							report += "`"
							report += "`\n`".join(_lowerCamelCase )
							report += "`"

				return {
				    "type": "section",
				    "text": {
				        "type": "mrkdwn",
				        "text": f"The following examples had failures:\n\n\n{report}\n",
				    },
				}


	@property
	def 						_UpperCAmelCase     (self )							->							str:







				'''simple docstring'''





				__lowercase										=							[self.header]

				if self.n_failures > 0:
							blocks.append(self.failures )

				if self.n_failures > 0:
							blocks.extend([self.category_failures] )

				if self.n_failures == 0:
							blocks.append(self.no_failures )

				return json.dumps(_lowerCamelCase )


	@staticmethod
	def 						_UpperCAmelCase     ()							->							List[str]:







				'''simple docstring'''





				__lowercase										=							[
				    {
				        '''type''': '''section''',
				        '''text''': {
				            '''type''': '''plain_text''',
				            '''text''': '''There was an issue running the tests.''',
				        },
				        '''accessory''': {
				            '''type''': '''button''',
				            '''text''': {'''type''': '''plain_text''', '''text''': '''Check Action results''', '''emoji''': True},
				            '''url''': f"https://github.com/huggingface/transformers/actions/runs/{os.environ['GITHUB_RUN_ID']}",
				        },
				    }
				]

				print('''Sending the following payload''' )
				print(json.dumps({'''blocks''': json.loads(_lowerCamelCase )} ) )

				client.chat_postMessage(
				    channel=os.environ['''CI_SLACK_CHANNEL_ID_DAILY''']     ,text='''There was an issue running the tests.'''     ,blocks=_lowerCamelCase     ,)


	def 						_UpperCAmelCase     (self )							->							Tuple:







				'''simple docstring'''





				print('''Sending the following payload''' )
				print(json.dumps({'''blocks''': json.loads(self.payload )} ) )

				__lowercase										=							f"{self.n_failures} failures out of {self.n_tests} tests," if self.n_failures else '''All tests passed.'''

				__lowercase										=							client.chat_postMessage(
				    channel=os.environ['''CI_SLACK_CHANNEL_ID_DAILY''']     ,blocks=self.payload     ,text=_lowerCamelCase     ,)


	def 						_UpperCAmelCase     (self     ,_lowerCamelCase     ,_lowerCamelCase     ,_lowerCamelCase     ,_lowerCamelCase )							->							Union[str, Any]:







				'''simple docstring'''





				__lowercase										=							''''''
				for key, value in failures.items():
							__lowercase										=							value[:200] + ''' [Truncated]''' if len(_lowerCamelCase ) > 250 else value
							failures_text += f"*{key}*\n_{value}_\n\n"

				__lowercase										=							job_name
				__lowercase										=							{'''type''': '''section''', '''text''': {'''type''': '''mrkdwn''', '''text''': text}}

				if job_link is not None:
							__lowercase										=							{
							    '''type''': '''button''',
							    '''text''': {'''type''': '''plain_text''', '''text''': '''GitHub Action job''', '''emoji''': True},
							    '''url''': job_link,
							}

				return [
				    {"type": "header", "text": {"type": "plain_text", "text": title.upper(), "emoji": True}},
				    content,
				    {"type": "section", "text": {"type": "mrkdwn", "text": failures_text}},
				]


	def 						_UpperCAmelCase     (self )							->							Any:







				'''simple docstring'''





				if self.thread_ts is None:
							raise ValueError('''Can only post reply if a post has been made.''' )

				__lowercase										=							self.doc_test_results.pop('''job_link''' )
				self.doc_test_results.pop('''failures''' )
				self.doc_test_results.pop('''success''' )
				self.doc_test_results.pop('''time_spent''' )

				__lowercase										=							sorted(self.doc_test_results.items()     ,key=lambda _lowerCamelCase : t[0] )
				for job, job_result in sorted_dict:
							if len(job_result['''failures'''] ):
										__lowercase										=							f"*Num failures* :{len(job_result['failed'] )} \n"
										__lowercase										=							job_result['''failures''']
										__lowercase										=							self.get_reply_blocks(_lowerCamelCase     ,_lowerCamelCase     ,_lowerCamelCase     ,text=_lowerCamelCase )

										print('''Sending the following reply''' )
										print(json.dumps({'''blocks''': blocks} ) )

										client.chat_postMessage(
										    channel=os.environ['''CI_SLACK_CHANNEL_ID_DAILY''']     ,text=f"Results for {job}"     ,blocks=_lowerCamelCase     ,thread_ts=self.thread_ts['''ts''']     ,)

										time.sleep(1 )





def    _lowerCAmelCase						(				):
			__lowercase										=							os.environ['''GITHUB_RUN_ID''']
			__lowercase										=							f"https://api.github.com/repos/huggingface/transformers/actions/runs/{run_id}/jobs?per_page=100"
			__lowercase										=							requests.get(lowerCamelCase_				).json()
			__lowercase										=							{}

			try:
						jobs.update({job['''name''']: job['''html_url'''] for job in result['''jobs''']}				)
						__lowercase										=							math.ceil((result['''total_count'''] - 1_0_0) / 1_0_0				)

						for i in range(lowerCamelCase_				):
									__lowercase										=							requests.get(url + f"&page={i + 2}"				).json()
									jobs.update({job['''name''']: job['''html_url'''] for job in result['''jobs''']}				)

						return jobs
			except Exception as e:
						print('''Unknown error, could not fetch links.'''		,       lowerCamelCase_				)

			return {}




def    _lowerCAmelCase						(				lowerCamelCase_			:  str				):
			__lowercase										=							{}

			if os.path.exists(lowerCamelCase_				):
						__lowercase										=							os.listdir(lowerCamelCase_				)
						for file in files:
									try:
												with open(os.path.join(lowerCamelCase_		,       lowerCamelCase_				)		,       encoding='''utf-8'''				) as f:
															__lowercase										=							f.read()
									except UnicodeDecodeError as e:
												raise ValueError(f"Could not open {os.path.join(lowerCamelCase_		,       lowerCamelCase_				)}."				) from e

			return _artifact




def    _lowerCAmelCase						(				):






			class 							__lowercase       :







				'''simple docstring'''

				def __init__(self     ,_lowerCamelCase )							->							Dict:







							'''simple docstring'''





							__lowercase										=							name
							__lowercase										=							[]


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







							'''simple docstring'''





							return self.name


				def 						_UpperCAmelCase     (self     ,_lowerCamelCase )							->							Dict:







							'''simple docstring'''





							self.paths.append({'''name''': self.name, '''path''': path} )





			__lowercase										=							{}

			__lowercase										=							filter(os.path.isdir		,       os.listdir()				)
			for directory in directories:
						__lowercase										=							directory
						if artifact_name not in _available_artifacts:
									__lowercase										=							Artifact(lowerCamelCase_				)

									_available_artifacts[artifact_name].add_path(lowerCamelCase_				)

			return _available_artifacts


if __name__ == "__main__":
	_SCREAMING_SNAKE_CASE					=    get_job_links()
	_SCREAMING_SNAKE_CASE					=    retrieve_available_artifacts()

	_SCREAMING_SNAKE_CASE					=    collections.OrderedDict(
	    [
	        ('''*.py''', '''API Examples'''),
	        ('''*.md''', '''MD Examples'''),
	    ]
	)

	# This dict will contain all the information relative to each doc test category:
	# - failed: list of failed tests
	# - failures: dict in the format 'test': 'error_message'
	_SCREAMING_SNAKE_CASE					=    {
	    v: {
	        '''failed''': [],
	        '''failures''': {},
	    }
	    for v in docs.values()
	}

	# Link to the GitHub Action job
	_SCREAMING_SNAKE_CASE					=    github_actions_job_links.get('''run_doctests''')

	_SCREAMING_SNAKE_CASE					=    available_artifacts['''doc_tests_gpu_test_reports'''].paths[0]
	_SCREAMING_SNAKE_CASE					=    retrieve_artifact(artifact_path['''name'''])
	if "stats" in artifact:
		_SCREAMING_SNAKE_CASE					,	_SCREAMING_SNAKE_CASE					,	_SCREAMING_SNAKE_CASE					=    handle_test_results(artifact['''stats'''])
		_SCREAMING_SNAKE_CASE					=    failed
		_SCREAMING_SNAKE_CASE					=    success
		_SCREAMING_SNAKE_CASE					=    time_spent[1:-1] + ''', '''

		_SCREAMING_SNAKE_CASE					=    extract_first_line_failure(artifact['''failures_short'''])
		for line in artifact["summary_short"].split('''\n'''):
			if re.search('''FAILED''', line):
				_SCREAMING_SNAKE_CASE					=    line.replace('''FAILED ''', '''''')
				_SCREAMING_SNAKE_CASE					=    line.split()[0].replace('''\n''', '''''')

				if "::" in line:
					_SCREAMING_SNAKE_CASE					,	_SCREAMING_SNAKE_CASE					=    line.split('''::''')
				else:
					_SCREAMING_SNAKE_CASE					,	_SCREAMING_SNAKE_CASE					=    line, line

				for file_regex in docs.keys():
					if fnmatch(file_path, file_regex):
						_SCREAMING_SNAKE_CASE					=    docs[file_regex]
						doc_test_results[category]["failed"].append(test)

						_SCREAMING_SNAKE_CASE					=    all_failures[test] if test in all_failures else '''N/A'''
						_SCREAMING_SNAKE_CASE					=    failure
						break

	_SCREAMING_SNAKE_CASE					=    Message('''🤗 Results of the doc tests.''', doc_test_results)
	message.post()
	message.post_reply()





