


import argparse
import glob
import inspect
import os
import re
import unittest

from get_test_info import get_test_classes

from tests.test_pipeline_mixin import pipeline_test_mapping


snake_case			:      Optional[Any] 							=   {}
for task, _ in pipeline_test_mapping.items():
							snake_case			:      Optional[int] 							=   {'pt': None, 'tf': None}


# DO **NOT** add item to this set (unless the reason is approved)
snake_case			:      Optional[int] 							=   {
    'tests/models/esm/test_modeling_esmfold.py',  # The pipeline test mapping is added to `test_modeling_esm.py`
}


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__							):

				"""simple docstring"""






				if "ModelTesterMixin" in [x.__name__ for x in test_class.__bases__]:
								return "pt"
				elif "TFModelTesterMixin" in [x.__name__ for x in test_class.__bases__]:
								return "tf"
				elif "FlaxModelTesterMixin" in [x.__name__ for x in test_class.__bases__]:
								return "flax"
				else:
								return None


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__   ,UpperCAmelCase__							):

				"""simple docstring"""






				if PIPELINE_TEST_MAPPING[task].get(UpperCAmelCase__   ,UpperCAmelCase__							) is not None:
								return PIPELINE_TEST_MAPPING[task][framework]

				_SCREAMING_SNAKE_CASE      = pipeline_test_mapping[task]['test']
				_SCREAMING_SNAKE_CASE      = None

				if framework == "pt":
								_SCREAMING_SNAKE_CASE      = getattr(UpperCAmelCase__   ,'model_mapping'   ,UpperCAmelCase__							)
				elif framework == "tf":
								_SCREAMING_SNAKE_CASE      = getattr(UpperCAmelCase__   ,'tf_model_mapping'   ,UpperCAmelCase__							)

				if mapping is not None:
								_SCREAMING_SNAKE_CASE      = dict(mapping.items()							)

				# cache the results
				_SCREAMING_SNAKE_CASE      = mapping
				return mapping


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__   ,UpperCAmelCase__							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = get_framework(UpperCAmelCase__							)
				if framework is None:
								return None
				_SCREAMING_SNAKE_CASE      = get_mapping_for_task(UpperCAmelCase__   ,UpperCAmelCase__							)
				if mapping is None:
								return None

				_SCREAMING_SNAKE_CASE      = list({model_class.config_class for model_class in test_class.all_model_classes}							)
				if len(UpperCAmelCase__							) != 1:
								raise ValueError('There should be exactly one configuration class from `test_class.all_model_classes`.'							)

				# This could be a list/tuple of model classes, but it's rare.
				_SCREAMING_SNAKE_CASE      = mapping.get(config_classes[0]   ,UpperCAmelCase__							)
				if isinstance(UpperCAmelCase__   ,(tuple, list)							):
								_SCREAMING_SNAKE_CASE      = sorted(UpperCAmelCase__   ,key=lambda UpperCAmelCase__							: x.__name__							)

				return model_class


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = [(task, get_model_for_pipeline_test(UpperCAmelCase__   ,UpperCAmelCase__							)) for task in pipeline_test_mapping]
				_SCREAMING_SNAKE_CASE      = sorted([(task, model) for task, model in mapping if model is not None]   ,key=lambda UpperCAmelCase__							: x[0]							)

				return dict(UpperCAmelCase__							)


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = get_framework(UpperCAmelCase__							)
				if framework == "pt":
								_SCREAMING_SNAKE_CASE      = 'torch'
				_SCREAMING_SNAKE_CASE      = '{}'

				_SCREAMING_SNAKE_CASE      = get_pipeline_model_mapping(UpperCAmelCase__							)
				if len(UpperCAmelCase__							) == 0:
								return ""

				_SCREAMING_SNAKE_CASE      = []
				for task, model_classes in mapping.items():
								if isinstance(UpperCAmelCase__   ,(tuple, list)							):
												# A list/tuple of model classes
												_SCREAMING_SNAKE_CASE      = '(' + ', '.join([x.__name__ for x in model_classes]							) + ')'
								else:
												# A single model class
												_SCREAMING_SNAKE_CASE      = model_classes.__name__
								texts.append(f'''"{task}": {value}'''							)
				_SCREAMING_SNAKE_CASE      = '{' + ', '.join(UpperCAmelCase__							) + '}'
				_SCREAMING_SNAKE_CASE      = f'''pipeline_model_mapping = {text} if is_{framework}_available() else {default_value}'''

				return text


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = {'ModelTesterMixin', 'TFModelTesterMixin', 'FlaxModelTesterMixin'}
				if not issubclass(UpperCAmelCase__   ,unittest.TestCase							):
								return False
				return len(base_class_names.intersection([x.__name__ for x in test_class.__bases__]							)							) > 0


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = [x for x in get_test_classes(UpperCAmelCase__							) if is_valid_test_class(UpperCAmelCase__							)]

				_SCREAMING_SNAKE_CASE      = None
				for test_class in test_classes:
								# If a test class has defined `pipeline_model_mapping`, let's take it
								if getattr(UpperCAmelCase__   ,'pipeline_model_mapping'   ,UpperCAmelCase__							) is not None:
												_SCREAMING_SNAKE_CASE      = test_class
												break
    # Take the test class with the shortest name (just a heuristic)
				if target_test_class is None and len(UpperCAmelCase__							) > 0:
								_SCREAMING_SNAKE_CASE      = sorted(UpperCAmelCase__   ,key=lambda UpperCAmelCase__							: (len(x.__name__							), x.__name__)							)[0]

				return target_test_class


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__   ,UpperCAmelCase__   ,UpperCAmelCase__							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = start_idx
				for idx, line in enumerate(lines[start_idx:]							):
								_SCREAMING_SNAKE_CASE      = len(UpperCAmelCase__							) - len(line.lstrip()							)
								if idx == 0 or indent > indent_level or (indent == indent_level and line.strip() == ")"):
												_SCREAMING_SNAKE_CASE      = start_idx + idx
								elif idx > 0 and indent <= indent_level:
												# Outside the definition block of `pipeline_model_mapping`
												break

				return end_idx


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__   ,UpperCAmelCase__=False							):

				"""simple docstring"""






				if getattr(UpperCAmelCase__   ,'pipeline_model_mapping'   ,UpperCAmelCase__							) is not None:
								if not overwrite:
												return "", -1

				_SCREAMING_SNAKE_CASE      = get_pipeline_model_mapping_string(UpperCAmelCase__							)
				if len(UpperCAmelCase__							) == 0:
								return "", -1
				_SCREAMING_SNAKE_CASE      = line_to_add + '\n'

				# The code defined the class `test_class`
				_SCREAMING_SNAKE_CASE      ,      _SCREAMING_SNAKE_CASE      = inspect.getsourcelines(UpperCAmelCase__							)
				# `inspect` gives the code for an object, including decorator(s) if any.
				# We (only) need the exact line of the class definition.
				for idx, line in enumerate(UpperCAmelCase__							):
								if line.lstrip().startswith('class '							):
												_SCREAMING_SNAKE_CASE      = class_lines[idx:]
												class_start_line_no += idx
												break
				_SCREAMING_SNAKE_CASE      = class_start_line_no + len(UpperCAmelCase__							) - 1

				# The index in `class_lines` that starts the definition of `all_model_classes`, `all_generative_model_classes` or
				# `pipeline_model_mapping`. This assumes they are defined in such order, and we take the start index of the last
				# block that appears in a `test_class`.
				_SCREAMING_SNAKE_CASE      = None
				# The indent level of the line at `class_lines[start_idx]` (if defined)
				_SCREAMING_SNAKE_CASE      = 0
				# To record if `pipeline_model_mapping` is found in `test_class`.
				_SCREAMING_SNAKE_CASE      = None
				for idx, line in enumerate(UpperCAmelCase__							):
								if line.strip().startswith('all_model_classes = '							):
												_SCREAMING_SNAKE_CASE      = len(UpperCAmelCase__							) - len(line.lstrip()							)
												_SCREAMING_SNAKE_CASE      = idx
								elif line.strip().startswith('all_generative_model_classes = '							):
												_SCREAMING_SNAKE_CASE      = len(UpperCAmelCase__							) - len(line.lstrip()							)
												_SCREAMING_SNAKE_CASE      = idx
								elif line.strip().startswith('pipeline_model_mapping = '							):
												_SCREAMING_SNAKE_CASE      = len(UpperCAmelCase__							) - len(line.lstrip()							)
												_SCREAMING_SNAKE_CASE      = idx
												_SCREAMING_SNAKE_CASE      = line
												break

				if start_idx is None:
								return "", -1
				# Find the ending index (inclusive) of the above found block.
				_SCREAMING_SNAKE_CASE      = find_block_ending(UpperCAmelCase__   ,UpperCAmelCase__   ,UpperCAmelCase__							)

				# Extract `is_xxx_available()` from existing blocks: some models require specific libraries like `timm` and use
				# `is_timm_available()` instead of `is_torch_available()`.
				# Keep leading and trailing whitespaces
				_SCREAMING_SNAKE_CASE      = re.compile(r'\s(is_\S+?_available\(\))\s'							)
				for line in class_lines[start_idx : end_idx + 1]:
								_SCREAMING_SNAKE_CASE      = r.search(UpperCAmelCase__							)
								if backend_condition is not None:
												# replace the leading and trailing whitespaces to the space character " ".
												_SCREAMING_SNAKE_CASE      = ' ' + backend_condition[0][1:-1] + ' '
												_SCREAMING_SNAKE_CASE      = r.sub(UpperCAmelCase__   ,UpperCAmelCase__							)
												break

				if def_line is None:
								# `pipeline_model_mapping` is not defined. The target index is set to the ending index (inclusive) of
								# `all_model_classes` or `all_generative_model_classes`.
								_SCREAMING_SNAKE_CASE      = end_idx
				else:
								# `pipeline_model_mapping` is defined. The target index is set to be one **BEFORE** its start index.
								_SCREAMING_SNAKE_CASE      = start_idx - 1
								# mark the lines of the currently existing `pipeline_model_mapping` to be removed.
								for idx in range(UpperCAmelCase__   ,end_idx + 1							):
												# These lines are going to be removed before writing to the test file.
												_SCREAMING_SNAKE_CASE      = None  # noqa

    # Make sure the test class is a subclass of `PipelineTesterMixin`.
				_SCREAMING_SNAKE_CASE      = [x.__name__ for x in test_class.__bases__]
				if "PipelineTesterMixin" not in parent_classes:
								# Put `PipelineTesterMixin` just before `unittest.TestCase`
								_SCREAMING_SNAKE_CASE      = [x for x in parent_classes if x != 'TestCase'] + ['PipelineTesterMixin']
								if "TestCase" in parent_classes:
												# Here we **assume** the original string is always with `unittest.TestCase`.
												_parent_classes.append('unittest.TestCase'							)
								_SCREAMING_SNAKE_CASE      = ', '.join(_parent_classes							)
								for idx, line in enumerate(UpperCAmelCase__							):
												# Find the ending of the declaration of `test_class`
												if line.strip().endswith('):'							):
																# mark the lines of the declaration of `test_class` to be removed
																for _idx in range(idx + 1							):
																				_SCREAMING_SNAKE_CASE      = None  # noqa
																break
        # Add the new, one-line, class declaration for `test_class`
								_SCREAMING_SNAKE_CASE      = f'''class {test_class.__name__}({parent_classes}):\n'''

				# Add indentation
				_SCREAMING_SNAKE_CASE      = ' ' * indent_level + line_to_add
				# Insert `pipeline_model_mapping` to `class_lines`.
				# (The line at `target_idx` should be kept by definition!)
				_SCREAMING_SNAKE_CASE      = class_lines[: target_idx + 1] + [line_to_add] + class_lines[target_idx + 1 :]
				# Remove the lines that are marked to be removed
				_SCREAMING_SNAKE_CASE      = [x for x in class_lines if x is not None]

				# Move from test class to module (in order to write to the test file)
				_SCREAMING_SNAKE_CASE      = inspect.getsourcelines(inspect.getmodule(UpperCAmelCase__							)							)[0]
				# Be careful with the 1-off between line numbers and array indices
				_SCREAMING_SNAKE_CASE      = module_lines[: class_start_line_no - 1] + class_lines + module_lines[class_end_line_no:]
				_SCREAMING_SNAKE_CASE      = ''.join(UpperCAmelCase__							)

				_SCREAMING_SNAKE_CASE      = inspect.getsourcefile(UpperCAmelCase__							)
				with open(UpperCAmelCase__   ,'w'   ,encoding='UTF-8'   ,newline='\n'							) as fp:
								fp.write(UpperCAmelCase__							)

				return line_to_add


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__   ,UpperCAmelCase__=False							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = find_test_class(UpperCAmelCase__							)
				if test_class:
								add_pipeline_model_mapping(UpperCAmelCase__   ,overwrite=UpperCAmelCase__							)


if __name__ == "__main__":
							snake_case			:      Union[str, Any] 							=   argparse.ArgumentParser()
							parser.add_argument(
							    '--test_file', type=str, help='A path to the test file, starting with the repository\'s `tests` directory.'
							)
							parser.add_argument(
							    '--all',
							    action='store_true',
							    help='If to check and modify all test files.',
							)
							parser.add_argument(
							    '--overwrite',
							    action='store_true',
							    help='If to overwrite a test class if it has already defined `pipeline_model_mapping`.',
							)
							snake_case			:      List[Any] 							=   parser.parse_args()

							if not args.all and not args.test_file:
														raise ValueError('Please specify either `test_file` or pass `--all` to check/modify all test files.')
							elif args.all and args.test_file:
														raise ValueError('Only one of `--test_file` and `--all` could be specified.')

							snake_case			:      Optional[int] 							=   []
							if args.test_file:
														snake_case			:      Tuple 							=   [args.test_file]
							else:
														snake_case			:      List[Any] 							=   os.path.join('tests', 'models', '**', 'test_modeling_*.py')
														for test_file in glob.glob(pattern):
																					# `Flax` is not concerned at this moment
																					if not test_file.startswith('test_modeling_flax_'):
																												test_files.append(test_file)

							for test_file in test_files:
														if test_file in TEST_FILE_TO_IGNORE:
																					print(f"""[SKIPPED] {test_file} is skipped as it is in `TEST_FILE_TO_IGNORE` in the file {__file__}.""")
																					continue
														add_pipeline_model_mapping_to_test_file(test_file, overwrite=args.overwrite)




from __future__ import annotations

from collections import Counter


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = [True] * n
				_SCREAMING_SNAKE_CASE      = False
				_SCREAMING_SNAKE_CASE      = False
				_SCREAMING_SNAKE_CASE      = True

				for i in range(3   ,int(n**0.5 + 1							)   ,2							):
								_SCREAMING_SNAKE_CASE      = i * 2
								while index < n:
												_SCREAMING_SNAKE_CASE      = False
												_SCREAMING_SNAKE_CASE      = index + i

				_SCREAMING_SNAKE_CASE      = [2]

				for i in range(3   ,UpperCAmelCase__   ,2							):
								if is_prime[i]:
												primes.append(UpperCAmelCase__							)

				return primes


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = str(UpperCAmelCase__							)
				_SCREAMING_SNAKE_CASE      = []
				_SCREAMING_SNAKE_CASE      = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

				for duplicate in Counter(UpperCAmelCase__							) - Counter(set(UpperCAmelCase__							)							):
								_SCREAMING_SNAKE_CASE      = [int(number_str.replace(UpperCAmelCase__   ,UpperCAmelCase__							)							) for digit in digits]
								replacements.append(UpperCAmelCase__							)

				return replacements


def 				SCREAMING_SNAKE_CASE (     UpperCAmelCase__ = 8							):

				"""simple docstring"""






				_SCREAMING_SNAKE_CASE      = set()

				# Filter primes with less than 3 replaceable digits
				_SCREAMING_SNAKE_CASE      = {
				    x for x in set(prime_sieve(100_0000							)							) if len(str(UpperCAmelCase__							)							) - len(set(str(UpperCAmelCase__							)							)							) >= 3
				}

				for prime in primes:
								if prime in numbers_checked:
												continue

								_SCREAMING_SNAKE_CASE      = digit_replacements(UpperCAmelCase__							)

								for family in replacements:
												numbers_checked.update(UpperCAmelCase__							)
												_SCREAMING_SNAKE_CASE      = primes.intersection(UpperCAmelCase__							)

												if len(UpperCAmelCase__							) != family_length:
																continue

												return min(UpperCAmelCase__							)

				return -1


if __name__ == "__main__":
							print(solution())
