




import inspect
import os
from argparse import ArgumentParser, Namespace
from importlib import import_module

import huggingface_hub
import numpy as np
from packaging import version

from .. import (
    FEATURE_EXTRACTOR_MAPPING,
    IMAGE_PROCESSOR_MAPPING,
    PROCESSOR_MAPPING,
    TOKENIZER_MAPPING,
    AutoConfig,
    AutoFeatureExtractor,
    AutoImageProcessor,
    AutoProcessor,
    AutoTokenizer,
    is_datasets_available,
    is_tf_available,
    is_torch_available,
)
from ..utils import TF2_WEIGHTS_INDEX_NAME, TF2_WEIGHTS_NAME, logging
from . import BaseTransformersCLICommand


if is_tf_available():
		import tensorflow as tf

		tf.config.experimental.enable_tensor_float_aa_execution(False)

if is_torch_available():
		import torch

if is_datasets_available():
		from datasets import load_dataset


__a  :					List[Any]          =  5e-5  # larger error tolerance than in our internal tests, to avoid flaky user-facing errors





def     UpperCAmelCase						(   lowercase							):







				"""simple docstring"""



				return PTtoTFCommand(
				    args.model_name							,      args.local_dir							,      args.max_error							,      args.new_weights							,      args.no_pr							,      args.push							,      args.extra_commit_description							,      args.override_model_class							,      )




class        _UpperCamelCase				(						_UpperCAmelCase			):


			"""simple docstring"""






			@staticmethod
			def 	_SCREAMING_SNAKE_CASE      (       lowerCAmelCase__						)					-> Dict:

							'''simple docstring'''


							__lowercase			      =							parser.add_parser(
							    '''pt-to-tf'''				,       help=(
							        '''CLI tool to run convert a transformers model from a PyTorch checkpoint to a TensorFlow checkpoint.'''
							        ''' Can also be used to validate existing weights without opening PRs, with --no-pr.'''
							    )				,       )
							train_parser.add_argument(
							    '''--model-name'''				,       type=lowerCAmelCase__				,       required=lowerCAmelCase__				,       help='''The model name, including owner/organization, as seen on the hub.'''				,       )
							train_parser.add_argument(
							    '''--local-dir'''				,       type=lowerCAmelCase__				,       default=''''''				,       help='''Optional local directory of the model repository. Defaults to /tmp/{model_name}'''				,       )
							train_parser.add_argument(
							    '''--max-error'''				,       type=lowerCAmelCase__				,       default=lowerCAmelCase__				,       help=(
							        F"Maximum error tolerance. Defaults to {MAX_ERROR}. This flag should be avoided, use at your own risk."
							    )				,       )
							train_parser.add_argument(
							    '''--new-weights'''				,       action='''store_true'''				,       help='''Optional flag to create new TensorFlow weights, even if they already exist.'''				,       )
							train_parser.add_argument(
							    '''--no-pr'''				,       action='''store_true'''				,       help='''Optional flag to NOT open a PR with converted weights.'''						)
							train_parser.add_argument(
							    '''--push'''				,       action='''store_true'''				,       help='''Optional flag to push the weights directly to `main` (requires permissions)'''				,       )
							train_parser.add_argument(
							    '''--extra-commit-description'''				,       type=lowerCAmelCase__				,       default=''''''				,       help='''Optional additional commit description to use when opening a PR (e.g. to tag the owner).'''				,       )
							train_parser.add_argument(
							    '''--override-model-class'''				,       type=lowerCAmelCase__				,       default=lowerCAmelCase__				,       help='''If you think you know better than the auto-detector, you can specify the model class here. '''
							    '''Can be either an AutoModel class or a specific model class like BertForSequenceClassification.'''				,       )
							train_parser.set_defaults(func=lowerCAmelCase__						)





			@staticmethod
			def 	_SCREAMING_SNAKE_CASE      (       lowerCAmelCase__				,       lowerCAmelCase__						)					-> Any:

							'''simple docstring'''


							__lowercase			      =							set(pt_outputs.keys()						)
							__lowercase			      =							set(tf_outputs.keys()						)
							if pt_out_attrs != tf_out_attrs:
											raise ValueError(
											    F"The model outputs have different attributes, aborting. (Pytorch: {pt_out_attrs}, TensorFlow:"
											    F" {tf_out_attrs})"						)

							# 2. For each output attribute, computes the difference
							def _find_pt_tf_differences(lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__=""						):
											# If the current attribute is a tensor, it is a leaf and we make the comparison. Otherwise, we will dig in
											# recursivelly, keeping the name of the attribute.
											if isinstance(lowerCAmelCase__				,       torch.Tensor						):
															__lowercase			      =							np.max(np.abs(pt_out.numpy() - tf_out.numpy()						)						)
															__lowercase			      =							tensor_difference
											else:
															__lowercase			      =							attr_name
															for i, pt_item in enumerate(lowerCAmelCase__						):
																			# If it is a named attribute, we keep the name. Otherwise, just its index.
																			if isinstance(lowerCAmelCase__				,       lowerCAmelCase__						):
																							__lowercase			      =							root_name + pt_item
																							__lowercase			      =							tf_out[pt_item]
																							__lowercase			      =							pt_out[pt_item]
																			else:
																							__lowercase			      =							root_name + F"[{i}]"
																							__lowercase			      =							tf_out[i]
																			__lowercase			      =							_find_pt_tf_differences(lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__						)

											return differences

							return _find_pt_tf_differences(lowerCAmelCase__				,       lowerCAmelCase__				,       {}						)





			def __init__(       self				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__				,       *lowerCAmelCase__				,       )					-> str:

							'''simple docstring'''


							__lowercase			      =							logging.get_logger('''transformers-cli/pt_to_tf'''						)
							__lowercase			      =							model_name
							__lowercase			      =							local_dir if local_dir else os.path.join('''/tmp'''				,       lowerCAmelCase__						)
							__lowercase			      =							max_error
							__lowercase			      =							new_weights
							__lowercase			      =							no_pr
							__lowercase			      =							push
							__lowercase			      =							extra_commit_description
							__lowercase			      =							override_model_class





			def 	_SCREAMING_SNAKE_CASE      (       self				,       lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__						)					-> int:

							'''simple docstring'''


							def _get_audio_input():
											__lowercase			      =							load_dataset('''hf-internal-testing/librispeech_asr_dummy'''				,       '''clean'''				,       split='''validation'''						)
											__lowercase			      =							ds.sort('''id'''						).select(range(2						)						)[:2]['''audio''']
											__lowercase			      =							[x['''array'''] for x in speech_samples]
											return raw_samples

							__lowercase			      =							type(pt_model.config						)
							if model_config_class in PROCESSOR_MAPPING:
											__lowercase			      =							AutoProcessor.from_pretrained(self._local_dir						)
											if model_config_class in TOKENIZER_MAPPING and processor.tokenizer.pad_token is None:
															__lowercase			      =							processor.tokenizer.eos_token
							elif model_config_class in IMAGE_PROCESSOR_MAPPING:
											__lowercase			      =							AutoImageProcessor.from_pretrained(self._local_dir						)
							elif model_config_class in FEATURE_EXTRACTOR_MAPPING:
											__lowercase			      =							AutoFeatureExtractor.from_pretrained(self._local_dir						)
							elif model_config_class in TOKENIZER_MAPPING:
											__lowercase			      =							AutoTokenizer.from_pretrained(self._local_dir						)
											if processor.pad_token is None:
															__lowercase			      =							processor.eos_token
							else:
											raise ValueError(F"Unknown data processing type (model config type: {model_config_class})"						)

							__lowercase			      =							set(inspect.signature(pt_model.forward						).parameters.keys()						)
							__lowercase			      =							{}
							if "input_ids" in model_forward_signature:
											processor_inputs.update(
											    {
											        '''text''': ['''Hi there!''', '''I am a batch with more than one row and different input lengths.'''],
											        '''padding''': True,
											        '''truncation''': True,
											    }						)
							if "pixel_values" in model_forward_signature:
											__lowercase			      =							load_dataset('''cifar10'''				,       '''plain_text'''				,       split='''test'''						)[:2]['''img''']
											processor_inputs.update({'''images''': sample_images}						)
							if "input_features" in model_forward_signature:
											__lowercase			      =							inspect.signature(processor.feature_extractor						).parameters
											# Pad to the largest input length by default but take feature extractor default
											# padding value if it exists e.g. "max_length" and is not False or None
											if "padding" in feature_extractor_signature:
															__lowercase			      =							feature_extractor_signature['''padding'''].default
															if default_strategy is not False and default_strategy is not None:
																			__lowercase			      =							default_strategy
															else:
																			__lowercase			      =							True
											else:
															__lowercase			      =							True
											processor_inputs.update({'''audio''': _get_audio_input(), '''padding''': padding_strategy}						)
							if "input_values" in model_forward_signature:  # Wav2Vec2 audio input
											processor_inputs.update({'''audio''': _get_audio_input(), '''padding''': True}						)
							__lowercase			      =							processor(**lowerCAmelCase__				,       return_tensors='''pt'''						)
							__lowercase			      =							processor(**lowerCAmelCase__				,       return_tensors='''tf'''						)

							# Extra input requirements, in addition to the input modality
							if (
							    config.is_encoder_decoder
							    or (hasattr(lowerCAmelCase__				,       '''encoder'''						) and hasattr(lowerCAmelCase__				,       '''decoder'''						))
							    or "decoder_input_ids" in tf_dummy_inputs
							):
											__lowercase			      =							np.asarray([[1], [1]]				,       dtype=lowerCAmelCase__						) * (pt_model.config.decoder_start_token_id or 0)
											pt_input.update({'''decoder_input_ids''': torch.tensor(lowerCAmelCase__						)}						)
											tf_input.update({'''decoder_input_ids''': tf.convert_to_tensor(lowerCAmelCase__						)}						)

							return pt_input, tf_input





			def 	_SCREAMING_SNAKE_CASE      (       self						)					-> Dict:

							'''simple docstring'''


							if version.parse(huggingface_hub.__version__						) < version.parse('''0.9.0'''						):
											raise ImportError(
											    '''The huggingface_hub version must be >= 0.9.0 to use this command. Please update your huggingface_hub'''
											    ''' installation.'''						)
							else:
											from huggingface_hub import Repository, create_commit
											from huggingface_hub._commit_api import CommitOperationAdd

							# Fetch remote data
							__lowercase			      =							Repository(local_dir=self._local_dir				,       clone_from=self._model_name						)

							# Load config and get the appropriate architecture -- the latter is needed to convert the head's weights
							__lowercase			      =							AutoConfig.from_pretrained(self._local_dir						)
							__lowercase			      =							config.architectures
							if self._override_model_class is not None:
											if self._override_model_class.startswith('''TF'''						):
															__lowercase			      =							[self._override_model_class[2:]]
											else:
															__lowercase			      =							[self._override_model_class]
											try:
															__lowercase			      =							getattr(import_module('''transformers'''						)				,       architectures[0]						)
											except AttributeError:
															raise ValueError(F"Model class {self._override_model_class} not found in transformers."						)
											try:
															__lowercase			      =							getattr(import_module('''transformers'''						)				,       '''TF''' + architectures[0]						)
											except AttributeError:
															raise ValueError(F"TF model class TF{self._override_model_class} not found in transformers."						)
							elif architectures is None:  # No architecture defined -- use auto classes
											__lowercase			      =							getattr(import_module('''transformers'''						)				,       '''AutoModel'''						)
											__lowercase			      =							getattr(import_module('''transformers'''						)				,       '''TFAutoModel'''						)
											self._logger.warning('''No detected architecture, using AutoModel/TFAutoModel'''						)
							else:  # Architecture defined -- use it
											if len(lowerCAmelCase__						) > 1:
															raise ValueError(F"More than one architecture was found, aborting. (architectures = {architectures})"						)
											self._logger.warning(F"Detected architecture: {architectures[0]}"						)
											__lowercase			      =							getattr(import_module('''transformers'''						)				,       architectures[0]						)
											try:
															__lowercase			      =							getattr(import_module('''transformers'''						)				,       '''TF''' + architectures[0]						)
											except AttributeError:
															raise AttributeError(F"The TensorFlow equivalent of {architectures[0]} doesn't exist in transformers."						)

        # Check the TF dummy inputs to see what keys we need in the forward pass
							__lowercase			      =							tf_class.from_config(lowerCAmelCase__						)
							__lowercase			      =							tf_from_pt_model.dummy_inputs

							del tf_from_pt_model  # Try to keep only one model in memory at a time

							# Load the model and get some basic inputs
							__lowercase			      =							pt_class.from_pretrained(self._local_dir						)
							pt_model.eval()

							__lowercase      ,					__lowercase			      =							self.get_inputs(lowerCAmelCase__				,       lowerCAmelCase__				,       lowerCAmelCase__						)

							with torch.no_grad():
											__lowercase			      =							pt_model(**lowerCAmelCase__				,       output_hidden_states=lowerCAmelCase__						)
							del pt_model  # will no longer be used, and may have a large memory footprint

							__lowercase			      =							tf_class.from_pretrained(self._local_dir				,       from_pt=lowerCAmelCase__						)
							__lowercase			      =							tf_from_pt_model(**lowerCAmelCase__				,       output_hidden_states=lowerCAmelCase__				,       training=lowerCAmelCase__						)

							# Confirms that cross loading PT weights into TF worked.
							__lowercase			      =							self.find_pt_tf_differences(lowerCAmelCase__				,       lowerCAmelCase__						)
							__lowercase			      =							{k: v for k, v in crossload_differences.items() if '''hidden''' not in k}
							__lowercase			      =							{k: v for k, v in crossload_differences.items() if '''hidden''' in k}
							if len(lowerCAmelCase__						) == 0 and architectures is not None:
											raise ValueError(
											    F"Something went wrong -- the config file has architectures ({architectures}), but no model head"
											    ''' output was found. All outputs start with \'hidden\''''						)
							__lowercase			      =							max(output_differences.values()						) if output_differences else 0.0
							__lowercase			      =							max(hidden_differences.values()						)
							if max_crossload_output_diff > self._max_error or max_crossload_hidden_diff > self._max_error:
											raise ValueError(
											    '''The cross-loaded TensorFlow model has different outputs, something went wrong!\n'''
											    + F"\nList of maximum output differences above the threshold ({self._max_error}):\n"
											    + '''\n'''.join([F"{k}: {v:.3e}" for k, v in output_differences.items() if v > self._max_error]						)
											    + F"\n\nList of maximum hidden layer differences above the threshold ({self._max_error}):\n"
											    + '''\n'''.join([F"{k}: {v:.3e}" for k, v in hidden_differences.items() if v > self._max_error]						)						)

							# Save the weights in a TF format (if needed) and confirms that the results are still good
							__lowercase			      =							os.path.join(self._local_dir				,       lowerCAmelCase__						)
							__lowercase			      =							os.path.join(self._local_dir				,       lowerCAmelCase__						)
							if (not os.path.exists(lowerCAmelCase__						) and not os.path.exists(lowerCAmelCase__						)) or self._new_weights:
											tf_from_pt_model.save_pretrained(self._local_dir						)
							del tf_from_pt_model  # will no longer be used, and may have a large memory footprint

							__lowercase			      =							tf_class.from_pretrained(self._local_dir						)
							__lowercase			      =							tf_model(**lowerCAmelCase__				,       output_hidden_states=lowerCAmelCase__						)

							__lowercase			      =							self.find_pt_tf_differences(lowerCAmelCase__				,       lowerCAmelCase__						)
							__lowercase			      =							{k: v for k, v in conversion_differences.items() if '''hidden''' not in k}
							__lowercase			      =							{k: v for k, v in conversion_differences.items() if '''hidden''' in k}
							if len(lowerCAmelCase__						) == 0 and architectures is not None:
											raise ValueError(
											    F"Something went wrong -- the config file has architectures ({architectures}), but no model head"
											    ''' output was found. All outputs start with \'hidden\''''						)
							__lowercase			      =							max(output_differences.values()						) if output_differences else 0.0
							__lowercase			      =							max(hidden_differences.values()						)
							if max_conversion_output_diff > self._max_error or max_conversion_hidden_diff > self._max_error:
											raise ValueError(
											    '''The converted TensorFlow model has different outputs, something went wrong!\n'''
											    + F"\nList of maximum output differences above the threshold ({self._max_error}):\n"
											    + '''\n'''.join([F"{k}: {v:.3e}" for k, v in output_differences.items() if v > self._max_error]						)
											    + F"\n\nList of maximum hidden layer differences above the threshold ({self._max_error}):\n"
											    + '''\n'''.join([F"{k}: {v:.3e}" for k, v in hidden_differences.items() if v > self._max_error]						)						)

							__lowercase			      =							'''Update TF weights''' if self._new_weights else '''Add TF weights'''
							if self._push:
											repo.git_add(auto_lfs_track=lowerCAmelCase__						)
											repo.git_commit(lowerCAmelCase__						)
											repo.git_push(blocking=lowerCAmelCase__						)  # this prints a progress bar with the upload
											self._logger.warning(F"TF weights pushed into {self._model_name}"						)
							elif not self._no_pr:
											self._logger.warning('''Uploading the weights into a new PR...'''						)
											__lowercase			      =							(
											    '''Model converted by the [`transformers`\' `pt_to_tf`'''
											    ''' CLI](https://github.com/huggingface/transformers/blob/main/src/transformers/commands/pt_to_tf.py). '''
											    '''All converted model outputs and hidden layers were validated against its PyTorch counterpart.\n\n'''
											    F"Maximum crossload output difference={max_crossload_output_diff:.3e}; "
											    F"Maximum crossload hidden layer difference={max_crossload_hidden_diff:.3e};\n"
											    F"Maximum conversion output difference={max_conversion_output_diff:.3e}; "
											    F"Maximum conversion hidden layer difference={max_conversion_hidden_diff:.3e};\n"
											)
											if self._max_error > MAX_ERROR:
															commit_descrition += (
															    F"\n\nCAUTION: The maximum admissible error was manually increased to {self._max_error}!"
															)
											if self._extra_commit_description:
															commit_descrition += "\n\n" + self._extra_commit_description

											# sharded model -> adds all related files (index and .h5 shards)
											if os.path.exists(lowerCAmelCase__						):
															__lowercase			      =							[
															    CommitOperationAdd(path_in_repo=lowerCAmelCase__				,       path_or_fileobj=lowerCAmelCase__						)
															]
															for shard_path in tf.io.gfile.glob(self._local_dir + '''/tf_model-*.h5'''						):
																			operations += [
																			    CommitOperationAdd(path_in_repo=os.path.basename(lowerCAmelCase__						)				,       path_or_fileobj=lowerCAmelCase__						)
																			]
											else:
															__lowercase			      =							[CommitOperationAdd(path_in_repo=lowerCAmelCase__				,       path_or_fileobj=lowerCAmelCase__						)]

											__lowercase			      =							create_commit(
											    repo_id=self._model_name				,       operations=lowerCAmelCase__				,       commit_message=lowerCAmelCase__				,       commit_description=lowerCAmelCase__				,       repo_type='''model'''				,       create_pr=lowerCAmelCase__				,       ).pr_url
											self._logger.warning(F"PR open in {hub_pr_url}"						)
import os
import sys

from . import rsa_key_generator as rkg

__a  :					Union[str, Any]          =  1_2_8
__a  :					List[str]          =  2_5_6





def     UpperCAmelCase						(   lowercase							,      lowercase = DEFAULT_BLOCK_SIZE							):







				"""simple docstring"""



				__lowercase			      =							message.encode('''ascii'''							)

				__lowercase			      =							[]
				for block_start in range(0							,      len(lowercase							)							,      lowercase							):
								__lowercase			      =							0
								for i in range(lowercase							,      min(block_start + block_size							,      len(lowercase							)							)							):
												block_int += message_bytes[i] * (BYTE_SIZE ** (i % block_size))
								block_ints.append(lowercase							)
				return block_ints





def     UpperCAmelCase						(   lowercase							,      lowercase							,      lowercase = DEFAULT_BLOCK_SIZE							):







				"""simple docstring"""



				__lowercase			      =							[]
				for block_int in block_ints:
								__lowercase			      =							[]
								for i in range(block_size - 1							,      -1							,      -1							):
												if len(lowercase							) + i < message_length:
																__lowercase			      =							block_int // (BYTE_SIZE**i)
																__lowercase			      =							block_int % (BYTE_SIZE**i)
																block_message.insert(0							,      chr(lowercase							)							)
								message.extend(lowercase							)
				return "".join(lowercase							)





def     UpperCAmelCase						(   lowercase							,      lowercase							,      lowercase = DEFAULT_BLOCK_SIZE							):







				"""simple docstring"""



				__lowercase			      =							[]
				__lowercase      ,					__lowercase			      =							key

				for block in get_blocks_from_text(lowercase							,      lowercase							):
								encrypted_blocks.append(pow(lowercase							,      lowercase							,      lowercase							)							)
				return encrypted_blocks





def     UpperCAmelCase						(   lowercase							,      lowercase							,      lowercase							,      lowercase = DEFAULT_BLOCK_SIZE							,      ):







				"""simple docstring"""



				__lowercase			      =							[]
				__lowercase      ,					__lowercase			      =							key
				for block in encrypted_blocks:
								decrypted_blocks.append(pow(lowercase							,      lowercase							,      lowercase							)							)
				return get_text_from_blocks(lowercase							,      lowercase							,      lowercase							)





def     UpperCAmelCase						(   lowercase							):







				"""simple docstring"""



				with open(lowercase							) as fo:
								__lowercase			      =							fo.read()
				__lowercase      ,					__lowercase      ,					__lowercase			      =							content.split(''','''							)
				return (int(lowercase							), int(lowercase							), int(lowercase							))





def     UpperCAmelCase						(   lowercase							,      lowercase							,      lowercase							,      lowercase = DEFAULT_BLOCK_SIZE							,      ):







				"""simple docstring"""



				__lowercase      ,					__lowercase      ,					__lowercase			      =							read_key_file(lowercase							)
				if key_size < block_size * 8:
								sys.exit(
								    '''ERROR: Block size is {} bits and key size is {} bits. The RSA cipher '''
								    '''requires the block size to be equal to or greater than the key size. '''
								    '''Either decrease the block size or use different keys.'''.format(
								        block_size * 8							,      lowercase							)							)

				__lowercase			      =							[str(lowercase							) for i in encrypt_message(lowercase							,      (n, e)							,      lowercase							)]

				__lowercase			      =							''','''.join(lowercase							)
				__lowercase			      =							F"{len(lowercase							)}_{block_size}_{encrypted_content}"
				with open(lowercase							,      '''w'''							) as fo:
								fo.write(lowercase							)
				return encrypted_content





def     UpperCAmelCase						(   lowercase							,      lowercase							):







				"""simple docstring"""



				__lowercase      ,					__lowercase      ,					__lowercase			      =							read_key_file(lowercase							)
				with open(lowercase							) as fo:
								__lowercase			      =							fo.read()
				__lowercase      ,					__lowercase      ,					__lowercase			      =							content.split('''_'''							)
				__lowercase			      =							int(lowercase							)
				__lowercase			      =							int(lowercase							)

				if key_size < block_size * 8:
								sys.exit(
								    '''ERROR: Block size is {} bits and key size is {} bits. The RSA cipher '''
								    '''requires the block size to be equal to or greater than the key size. '''
								    '''Did you specify the correct key file and encrypted file?'''.format(
								        block_size * 8							,      lowercase							)							)

				__lowercase			      =							[]
				for block in encrypted_message.split(''','''							):
								encrypted_blocks.append(int(lowercase							)							)

				return decrypt_message(lowercase							,      lowercase							,      (n, d)							,      lowercase							)





def     UpperCAmelCase						(   ):







				"""simple docstring"""



				__lowercase			      =							'''encrypted_file.txt'''
				__lowercase			      =							input(r'''Encrypt\Decrypt [e\d]: '''							)

				if response.lower().startswith('''e'''							):
								__lowercase			      =							'''encrypt'''
				elif response.lower().startswith('''d'''							):
								__lowercase			      =							'''decrypt'''

				if mode == "encrypt":
								if not os.path.exists('''rsa_pubkey.txt'''							):
												rkg.make_key_files('''rsa'''							,      1024							)

								__lowercase			      =							input('''\nEnter message: '''							)
								__lowercase			      =							'''rsa_pubkey.txt'''
								print(F"Encrypting and writing to {filename}..."							)
								__lowercase			      =							encrypt_and_write_to_file(lowercase							,      lowercase							,      lowercase							)

								print('''\nEncrypted text:'''							)
								print(lowercase							)

				elif mode == "decrypt":
								__lowercase			      =							'''rsa_privkey.txt'''
								print(F"Reading from {filename} and decrypting..."							)
								__lowercase			      =							read_from_file_and_decrypt(lowercase							,      lowercase							)
								print('''writing decryption to rsa_decryption.txt...'''							)
								with open('''rsa_decryption.txt'''							,      '''w'''							) as dec:
												dec.write(lowercase							)

								print('''\nDecryption:'''							)
								print(lowercase							)


if __name__ == "__main__":
		main()