

'''simple docstring'''







import argparse
import json
import os

from tensorflow.core.protobuf.saved_model_pba import SavedModel


# All paths are set with the intent you should run this script from the root of the repo with the command
# python utils/check_copies.py
__lowerCamelCase						    =      '''.'''

# Internal TensorFlow ops that can be safely ignored (mostly specific to a saved model)
__lowerCamelCase						    =      [
    '''Assert''',
    '''AssignVariableOp''',
    '''EmptyTensorList''',
    '''MergeV2Checkpoints''',
    '''ReadVariableOp''',
    '''ResourceGather''',
    '''RestoreV2''',
    '''SaveV2''',
    '''ShardedFilename''',
    '''StatefulPartitionedCall''',
    '''StaticRegexFullMatch''',
    '''VarHandleOp''',
]
def  UpperCAmelCase__      ( UpperCAmelCase__,    UpperCAmelCase__,    UpperCAmelCase__			)     ->     List[str]:
       A_		   = SavedModel()
       A_		   = []

       with open(os.path.join(UpperCAmelCase__,    """utils""",    """tf_ops""",    """onnx.json"""			)			) as f:
              A_		   = json.load(UpperCAmelCase__			)["""opsets"""]

       for i in range(1,    opset + 1			):
              onnx_ops.extend(onnx_opsets[str(UpperCAmelCase__			)]			)

       with open(UpperCAmelCase__,    """rb"""			) as f:
              saved_model.ParseFromString(f.read()			)

       A_		   = set()

       # Iterate over every metagraph in case there is more than one (a saved model can contain multiple graphs)
       for meta_graph in saved_model.meta_graphs:
              # Add operations in the graph definition
              model_op_names.update(node.op for node in meta_graph.graph_def.node			)

              # Go through the functions in the graph definition
              for func in meta_graph.graph_def.library.function:
                     # Add operations in each function
                     model_op_names.update(node.op for node in func.node_def			)

    # Convert to list, sorted if you want
       A_		   = sorted(UpperCAmelCase__			)
       A_		   = []

       for op in model_op_names:
              if op not in onnx_ops and op not in INTERNAL_OPS:
                     incompatible_ops.append(UpperCAmelCase__			)

       if strict and len(UpperCAmelCase__			) > 0:
              raise Exception(F'''Found the following incompatible ops for the opset {opset}:\n''' + incompatible_ops			)
       elif len(UpperCAmelCase__			) > 0:
              print(F'''Found the following incompatible ops for the opset {opset}:'''			)
              print(*UpperCAmelCase__,    sep="""\n"""			)
       else:
              print(F'''The saved model {saved_model_path} can properly be converted with ONNX.'''			)


if __name__ == "__main__":
      __lowerCamelCase						    =      argparse.ArgumentParser()
      parser.add_argument('''--saved_model_path''', help='''Path of the saved model to check (the .pb file).''')
      parser.add_argument(
          '''--opset''', default=12, type=int, help='''The ONNX opset against which the model has to be tested.'''
      )
      parser.add_argument(
          '''--framework''', choices=['''onnx'''], default='''onnx''', help='''Frameworks against which to test the saved model.'''
      )
      parser.add_argument(
          '''--strict''', action='''store_true''', help='''Whether make the checking strict (raise errors) or not (raise warnings)'''
      )
      __lowerCamelCase						    =      parser.parse_args()

      if args.framework == "onnx":
            onnx_compliancy(args.saved_model_path, args.strict, args.opset)



'''simple docstring'''







from functools import lru_cache
@lru_cache
def  UpperCAmelCase__      ( UpperCAmelCase__			)     ->     int:
       if num < 0:
              raise ValueError("""Number should not be negative."""			)

       return 1 if num in (0, 1) else num * factorial(num - 1			)


if __name__ == "__main__":
      import doctest

      doctest.testmod()
