


from __future__ import annotations

from collections.abc import Callable
from typing import Generic, TypeVar

__UpperCAmelCase : Tuple 			=				TypeVar("T")
__UpperCAmelCase : Dict 			=				TypeVar("U")



class    UpperCAmelCase_	(							Generic[T, U]):
       '''simple docstring'''






       def __init__(     self ,					__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              UpperCamelCase    :	Any   	=		key
              UpperCamelCase    :	Dict   	=		val
              UpperCamelCase    :	DoubleLinkedListNode[T, U] | None   	=		None
              UpperCamelCase    :	DoubleLinkedListNode[T, U] | None   	=		None






       def __repr__(     self						):




              """simple docstring"""




              return (
                  f"""Node: key: {self.key}, val: {self.val}, """
                  f"""has next: {bool(self.next						)}, has prev: {bool(self.prev						)}"""
              )




class    UpperCAmelCase_	(							Generic[T, U]):
       '''simple docstring'''






       def __init__(     self						):




              """simple docstring"""




              UpperCamelCase    :	DoubleLinkedListNode[T, U]   	=		DoubleLinkedListNode(__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						)
              UpperCamelCase    :	DoubleLinkedListNode[T, U]   	=		DoubleLinkedListNode(__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						)
              UpperCamelCase	, UpperCamelCase    :	Optional[Any]   	=		self.rear, self.head






       def __repr__(     self						):




              """simple docstring"""




              UpperCamelCase    :	Optional[Any]   	=		['''DoubleLinkedList''']
              UpperCamelCase    :	Any   	=		self.head
              while node.next is not None:
                     rep.append(str(__SCREAMING_SNAKE_CASE						)						)
                     UpperCamelCase    :	Union[str, Any]   	=		node.next
              rep.append(str(self.rear						)						)
              return ",\n    ".join(__SCREAMING_SNAKE_CASE						)






       def  _lowercase   (     self ,					__SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              UpperCamelCase    :	str   	=		self.rear.prev

              # All nodes other than self.head are guaranteed to have non-None previous
              assert previous is not None

              UpperCamelCase    :	int   	=		node
              UpperCamelCase    :	Any   	=		previous
              UpperCamelCase    :	int   	=		node
              UpperCamelCase    :	Tuple   	=		self.rear






       def  _lowercase   (     self ,					__SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              if node.prev is None or node.next is None:
                     return None

              UpperCamelCase    :	Any   	=		node.next
              UpperCamelCase    :	int   	=		node.prev
              UpperCamelCase    :	int   	=		None
              UpperCamelCase    :	str   	=		None
              return node




class    UpperCAmelCase_	(							Generic[T, U]):
       '''simple docstring'''
       __UpperCamelCase      :     dict[Callable[[T], U], LRUCache[T, U]]							=					{}






       def __init__(     self ,					__SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              UpperCamelCase    :	DoubleLinkedList[T, U]   	=		DoubleLinkedList()
              UpperCamelCase    :	Any   	=		capacity
              UpperCamelCase    :	Dict   	=		0
              UpperCamelCase    :	List[str]   	=		0
              UpperCamelCase    :	Union[str, Any]   	=		0
              UpperCamelCase    :	dict[T, DoubleLinkedListNode[T, U]]   	=		{}






       def __repr__(     self						):




              """simple docstring"""




              return (
                  f"""CacheInfo(hits={self.hits}, misses={self.miss}, """
                  f"""capacity={self.capacity}, current size={self.num_keys})"""
              )






       def __contains__(     self ,					__SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              return key in self.cache






       def  _lowercase   (     self ,					__SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              if key in self.cache:
                     self.hits += 1
                     UpperCamelCase    :	DoubleLinkedListNode[T, U]   	=		self.cache[key]
                     UpperCamelCase    :	Dict   	=		self.list.remove(self.cache[key]						)
                     assert node == value_node

                     # node is guaranteed not None because it is in self.cache
                     assert node is not None
                     self.list.add(__SCREAMING_SNAKE_CASE						)
                     return node.val
              self.miss += 1
              return None






       def  _lowercase   (     self ,					__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              if key not in self.cache:
                     if self.num_keys >= self.capacity:
                            # delete first node (oldest) when over capacity
                            UpperCamelCase    :	Dict   	=		self.list.head.next

                            # guaranteed to have a non-None first node when num_keys > 0
                            # explain to type checker via assertions
                            assert first_node is not None
                            assert first_node.key is not None
                            assert (
                                self.list.remove(__SCREAMING_SNAKE_CASE						) is not None
                            )  # node guaranteed to be in list assert node.key is not None

                            del self.cache[first_node.key]
                            self.num_keys -= 1
                     UpperCamelCase    :	Union[str, Any]   	=		DoubleLinkedListNode(__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						)
                     self.list.add(self.cache[key]						)
                     self.num_keys += 1

              else:
                     # bump node to the end of the list, update value
                     UpperCamelCase    :	Optional[int]   	=		self.list.remove(self.cache[key]						)
                     assert node is not None  # node guaranteed to be in list
                     UpperCamelCase    :	Optional[int]   	=		value
                     self.list.add(__SCREAMING_SNAKE_CASE						)






       @classmethod
       def  _lowercase   (     cls ,					__SCREAMING_SNAKE_CASE = 128						):




              """simple docstring"""




              def cache_decorator_inner(__SCREAMING_SNAKE_CASE						) -> Callable[..., U]:
                     def cache_decorator_wrapper(*__SCREAMING_SNAKE_CASE						) -> U:
                            if func not in cls.decorator_function_to_instance_map:
                                   UpperCamelCase    :	Any   	=		LRUCache(__SCREAMING_SNAKE_CASE						)

                            UpperCamelCase    :	str   	=		cls.decorator_function_to_instance_map[func].get(args[0]						)
                            if result is None:
                                   UpperCamelCase    :	Optional[Any]   	=		func(*__SCREAMING_SNAKE_CASE						)
                                   cls.decorator_function_to_instance_map[func].put(args[0] ,					__SCREAMING_SNAKE_CASE						)
                            return result

                     def cache_info() -> LRUCache[T, U]:
                            return cls.decorator_function_to_instance_map[func]

                     setattr(__SCREAMING_SNAKE_CASE ,					'''cache_info''' ,					__SCREAMING_SNAKE_CASE						)  # noqa: B010

                     return cache_decorator_wrapper

              return cache_decorator_inner


if __name__ == "__main__":
  import doctest

  doctest.testmod()





import json
import os
import shutil
import warnings
from argparse import ArgumentParser, Namespace
from pathlib import Path
from typing import List

from ..utils import logging
from . import BaseTransformersCLICommand


try:
  from cookiecutter.main import cookiecutter

  __UpperCAmelCase : List[Any] 			=				True
except ImportError:
  __UpperCAmelCase : List[str] 			=				False

__UpperCAmelCase : Any 			=				logging.get_logger(__name__)  # pylint: disable=invalid-name


def      a	(							SCREAMING_SNAKE_CASE_      :		Namespace       ):






       """simple docstring"""





       return AddNewModelCommand(args.testing							,			args.testing_file							,			path=args.path       )



class    UpperCAmelCase_	(							_a):
       '''simple docstring'''






       @staticmethod
       def  _lowercase   (     __SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              UpperCamelCase    :	List[Any]   	=		parser.add_parser('''add-new-model'''						)
              add_new_model_parser.add_argument('''--testing''' ,					action='''store_true''' ,					help='''If in testing mode.'''						)
              add_new_model_parser.add_argument('''--testing_file''' ,					type=__SCREAMING_SNAKE_CASE ,					help='''Configuration file on which to run.'''						)
              add_new_model_parser.add_argument(
                  '''--path''' ,					type=__SCREAMING_SNAKE_CASE ,					help='''Path to cookiecutter. Should only be used for testing purposes.'''						)
              add_new_model_parser.set_defaults(func=__SCREAMING_SNAKE_CASE						)






       def __init__(     self ,					__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE=None ,					*__SCREAMING_SNAKE_CASE						):




              """simple docstring"""




              UpperCamelCase    :	Tuple   	=		testing
              UpperCamelCase    :	Any   	=		testing_file
              UpperCamelCase    :	Dict   	=		path






       def  _lowercase   (     self						):




              """simple docstring"""




              warnings.warn(
                  '''The command `transformers-cli add-new-model` is deprecated and will be removed in v5 of Transformers. '''
                  '''It is not actively maintained anymore, so might give a result that won\'t pass all tests and quality '''
                  '''checks, you should use `transformers-cli add-new-model-like` instead.'''						)
              if not _has_cookiecutter:
                     raise ImportError(
                         '''Model creation dependencies are required to use the `add_new_model` command. Install them by running '''
                         '''the following at the root of your `transformers` clone:\n\n\t$ pip install -e .[modelcreation]\n'''						)
              # Ensure that there is no other `cookiecutter-template-xxx` directory in the current working directory
              UpperCamelCase    :	List[str]   	=		[directory for directory in os.listdir() if '''cookiecutter-template-''' == directory[:22]]
              if len(__SCREAMING_SNAKE_CASE						) > 0:
                     raise ValueError(
                         '''Several directories starting with `cookiecutter-template-` in current working directory. '''
                         '''Please clean your directory by removing all folders starting with `cookiecutter-template-` or '''
                         '''change your working directory.'''						)

              UpperCamelCase    :	Dict   	=		(
                  Path(__SCREAMING_SNAKE_CASE						).parent.parent.parent.parent if self._path is None else Path(self._path						).parent.parent
              )
              UpperCamelCase    :	List[Any]   	=		path_to_transformer_root / '''templates''' / '''adding_a_new_model'''

              # Execute cookiecutter
              if not self._testing:
                     cookiecutter(str(__SCREAMING_SNAKE_CASE						)						)
              else:
                     with open(self._testing_file ,					'''r'''						) as configuration_file:
                            UpperCamelCase    :	Tuple   	=		json.load(__SCREAMING_SNAKE_CASE						)

                     cookiecutter(
                         str(path_to_cookiecutter if self._path is None else self._path						) ,					no_input=__SCREAMING_SNAKE_CASE ,					extra_context=__SCREAMING_SNAKE_CASE ,					)

              UpperCamelCase    :	Dict   	=		[directory for directory in os.listdir() if '''cookiecutter-template-''' in directory[:22]][0]

              # Retrieve configuration
              with open(directory + '''/configuration.json''' ,					'''r'''						) as configuration_file:
                     UpperCamelCase    :	Tuple   	=		json.load(__SCREAMING_SNAKE_CASE						)

              UpperCamelCase    :	Dict   	=		configuration['''lowercase_modelname''']
              UpperCamelCase    :	int   	=		configuration['''generate_tensorflow_pytorch_and_flax''']
              os.remove(f"""{directory}/configuration.json"""						)

              UpperCamelCase    :	str   	=		'''PyTorch''' in generate_tensorflow_pytorch_and_flax
              UpperCamelCase    :	Any   	=		'''TensorFlow''' in generate_tensorflow_pytorch_and_flax
              UpperCamelCase    :	Union[str, Any]   	=		'''Flax''' in generate_tensorflow_pytorch_and_flax

              UpperCamelCase    :	Optional[Any]   	=		f"""{path_to_transformer_root}/src/transformers/models/{lowercase_model_name}"""
              os.makedirs(__SCREAMING_SNAKE_CASE ,					exist_ok=__SCREAMING_SNAKE_CASE						)
              os.makedirs(f"""{path_to_transformer_root}/tests/models/{lowercase_model_name}""" ,					exist_ok=__SCREAMING_SNAKE_CASE						)

              # Tests require submodules as they have parent imports
              with open(f"""{path_to_transformer_root}/tests/models/{lowercase_model_name}/__init__.py""" ,					'''w'''						):
                     pass

              shutil.move(
                  f"""{directory}/__init__.py""" ,					f"""{model_dir}/__init__.py""" ,					)
              shutil.move(
                  f"""{directory}/configuration_{lowercase_model_name}.py""" ,					f"""{model_dir}/configuration_{lowercase_model_name}.py""" ,					)

              def remove_copy_lines(__SCREAMING_SNAKE_CASE						):
                     with open(__SCREAMING_SNAKE_CASE ,					'''r'''						) as f:
                            UpperCamelCase    :	Any   	=		f.readlines()
                     with open(__SCREAMING_SNAKE_CASE ,					'''w'''						) as f:
                            for line in lines:
                                   if "# Copied from transformers." not in line:
                                          f.write(__SCREAMING_SNAKE_CASE						)

              if output_pytorch:
                     if not self._testing:
                            remove_copy_lines(f"""{directory}/modeling_{lowercase_model_name}.py"""						)

                     shutil.move(
                         f"""{directory}/modeling_{lowercase_model_name}.py""" ,					f"""{model_dir}/modeling_{lowercase_model_name}.py""" ,					)

                     shutil.move(
                         f"""{directory}/test_modeling_{lowercase_model_name}.py""" ,					f"""{path_to_transformer_root}/tests/models/{lowercase_model_name}/test_modeling_{lowercase_model_name}.py""" ,					)
              else:
                     os.remove(f"""{directory}/modeling_{lowercase_model_name}.py"""						)
                     os.remove(f"""{directory}/test_modeling_{lowercase_model_name}.py"""						)

              if output_tensorflow:
                     if not self._testing:
                            remove_copy_lines(f"""{directory}/modeling_tf_{lowercase_model_name}.py"""						)

                     shutil.move(
                         f"""{directory}/modeling_tf_{lowercase_model_name}.py""" ,					f"""{model_dir}/modeling_tf_{lowercase_model_name}.py""" ,					)

                     shutil.move(
                         f"""{directory}/test_modeling_tf_{lowercase_model_name}.py""" ,					f"""{path_to_transformer_root}/tests/models/{lowercase_model_name}/test_modeling_tf_{lowercase_model_name}.py""" ,					)
              else:
                     os.remove(f"""{directory}/modeling_tf_{lowercase_model_name}.py"""						)
                     os.remove(f"""{directory}/test_modeling_tf_{lowercase_model_name}.py"""						)

              if output_flax:
                     if not self._testing:
                            remove_copy_lines(f"""{directory}/modeling_flax_{lowercase_model_name}.py"""						)

                     shutil.move(
                         f"""{directory}/modeling_flax_{lowercase_model_name}.py""" ,					f"""{model_dir}/modeling_flax_{lowercase_model_name}.py""" ,					)

                     shutil.move(
                         f"""{directory}/test_modeling_flax_{lowercase_model_name}.py""" ,					f"""{path_to_transformer_root}/tests/models/{lowercase_model_name}/test_modeling_flax_{lowercase_model_name}.py""" ,					)
              else:
                     os.remove(f"""{directory}/modeling_flax_{lowercase_model_name}.py"""						)
                     os.remove(f"""{directory}/test_modeling_flax_{lowercase_model_name}.py"""						)

              shutil.move(
                  f"""{directory}/{lowercase_model_name}.md""" ,					f"""{path_to_transformer_root}/docs/source/en/model_doc/{lowercase_model_name}.md""" ,					)

              shutil.move(
                  f"""{directory}/tokenization_{lowercase_model_name}.py""" ,					f"""{model_dir}/tokenization_{lowercase_model_name}.py""" ,					)

              shutil.move(
                  f"""{directory}/tokenization_fast_{lowercase_model_name}.py""" ,					f"""{model_dir}/tokenization_{lowercase_model_name}_fast.py""" ,					)

              from os import fdopen, remove
              from shutil import copymode, move
              from tempfile import mkstemp

              def replace(__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						):
                     # Create temp file
                     UpperCamelCase	, UpperCamelCase    :	Optional[Any]   	=		mkstemp()
                     UpperCamelCase    :	Tuple   	=		False
                     with fdopen(__SCREAMING_SNAKE_CASE ,					'''w'''						) as new_file:
                            with open(__SCREAMING_SNAKE_CASE						) as old_file:
                                   for line in old_file:
                                          new_file.write(__SCREAMING_SNAKE_CASE						)
                                          if line_to_copy_below in line:
                                                 UpperCamelCase    :	Optional[int]   	=		True
                                                 for line_to_copy in lines_to_copy:
                                                        new_file.write(__SCREAMING_SNAKE_CASE						)

                     if not line_found:
                            raise ValueError(f"""Line {line_to_copy_below} was not found in file."""						)

                     # Copy the file permissions from the old file to the new file
                     copymode(__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						)
                     # Remove original file
                     remove(__SCREAMING_SNAKE_CASE						)
                     # Move new file
                     move(__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						)

              def skip_units(__SCREAMING_SNAKE_CASE						):
                     return (
                         ("generating PyTorch" in line and not output_pytorch)
                         or ("generating TensorFlow" in line and not output_tensorflow)
                         or ("generating Flax" in line and not output_flax)
                     )

              def replace_in_files(__SCREAMING_SNAKE_CASE						):
                     with open(__SCREAMING_SNAKE_CASE						) as datafile:
                            UpperCamelCase    :	int   	=		[]
                            UpperCamelCase    :	Dict   	=		False
                            UpperCamelCase    :	List[Any]   	=		False
                            for line in datafile:
                                   if "# To replace in: " in line and "##" not in line:
                                          UpperCamelCase    :	Dict   	=		line.split('''"'''						)[1]
                                          UpperCamelCase    :	int   	=		skip_units(__SCREAMING_SNAKE_CASE						)
                                   elif "# Below: " in line and "##" not in line:
                                          UpperCamelCase    :	Dict   	=		line.split('''"'''						)[1]
                                          UpperCamelCase    :	List[str]   	=		skip_units(__SCREAMING_SNAKE_CASE						)
                                   elif "# End." in line and "##" not in line:
                                          if not skip_file and not skip_snippet:
                                                 replace(__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE ,					__SCREAMING_SNAKE_CASE						)

                                          UpperCamelCase    :	Dict   	=		[]
                                   elif "# Replace with" in line and "##" not in line:
                                          UpperCamelCase    :	Tuple   	=		[]
                                   elif "##" not in line:
                                          lines_to_copy.append(__SCREAMING_SNAKE_CASE						)

                     remove(__SCREAMING_SNAKE_CASE						)

              replace_in_files(f"""{directory}/to_replace_{lowercase_model_name}.py"""						)
              os.rmdir(__SCREAMING_SNAKE_CASE						)

