

import argparse
import json
from pathlib import Path

import requests
import torch
from huggingface_hub import cached_download, hf_hub_download, hf_hub_url
from PIL import Image

from transformers import DetaConfig, DetaForObjectDetection, DetaImageProcessor, SwinConfig
from transformers.utils import logging


logging.set_verbosity_info()
_UpperCAmelCase		:       Any						    =	logging.get_logger(__name__)





def  __lowerCamelCase     (			UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   SwinConfig(
							    embed_dim=192       ,							depths=(2, 2, 18, 2)       ,							num_heads=(6, 12, 24, 48)       ,							window_size=12       ,							out_features=['stage2', 'stage3', 'stage4']       ,							)

							snake_case_          =   DetaConfig(
							    backbone_config=UpperCamelCase__       ,							num_queries=900       ,							encoder_ffn_dim=2048       ,							decoder_ffn_dim=2048       ,							num_feature_levels=5       ,							assign_first_stage=UpperCamelCase__       ,							with_box_refine=UpperCamelCase__       ,							two_stage=UpperCamelCase__       ,							)

							# set labels
							snake_case_          =   'huggingface/label-files'
							if "o365" in model_name:
														snake_case_          =   366
														snake_case_          =   'object365-id2label.json'
							else:
														snake_case_          =   91
														snake_case_          =   'coco-detection-id2label.json'

							snake_case_          =   num_labels
							snake_case_          =   json.load(open(cached_download(hf_hub_url(UpperCamelCase__       ,							UpperCamelCase__       ,							repo_type='dataset'				)				)       ,							'r'				)				)
							snake_case_          =   {int(UpperCamelCase__				): v for k, v in idalabel.items()}
							snake_case_          =   idalabel
							snake_case_          =   {v: k for k, v in idalabel.items()}

							return config





def  __lowerCamelCase     (			UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   []

							# stem
							# fmt: off
							rename_keys.append(('backbone.0.body.patch_embed.proj.weight', 'model.backbone.model.embeddings.patch_embeddings.projection.weight')				)
							rename_keys.append(('backbone.0.body.patch_embed.proj.bias', 'model.backbone.model.embeddings.patch_embeddings.projection.bias')				)
							rename_keys.append(('backbone.0.body.patch_embed.norm.weight', 'model.backbone.model.embeddings.norm.weight')				)
							rename_keys.append(('backbone.0.body.patch_embed.norm.bias', 'model.backbone.model.embeddings.norm.bias')				)
							# stages
							for i in range(len(config.backbone_config.depths				)				):
														for j in range(config.backbone_config.depths[i]				):
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.norm1.weight''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.layernorm_before.weight''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.norm1.bias''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.layernorm_before.bias''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.attn.relative_position_bias_table''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.attention.self.relative_position_bias_table''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.attn.relative_position_index''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.attention.self.relative_position_index''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.attn.proj.weight''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.attention.output.dense.weight''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.attn.proj.bias''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.attention.output.dense.bias''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.norm2.weight''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.layernorm_after.weight''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.norm2.bias''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.layernorm_after.bias''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.mlp.fc1.weight''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.intermediate.dense.weight''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.mlp.fc1.bias''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.intermediate.dense.bias''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.mlp.fc2.weight''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.output.dense.weight''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.blocks.{j}.mlp.fc2.bias''', F'''model.backbone.model.encoder.layers.{i}.blocks.{j}.output.dense.bias''')				)

														if i < 3:
																					rename_keys.append((F'''backbone.0.body.layers.{i}.downsample.reduction.weight''', F'''model.backbone.model.encoder.layers.{i}.downsample.reduction.weight''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.downsample.norm.weight''', F'''model.backbone.model.encoder.layers.{i}.downsample.norm.weight''')				)
																					rename_keys.append((F'''backbone.0.body.layers.{i}.downsample.norm.bias''', F'''model.backbone.model.encoder.layers.{i}.downsample.norm.bias''')				)

							rename_keys.append(('backbone.0.body.norm1.weight', 'model.backbone.model.hidden_states_norms.stage2.weight')				)
							rename_keys.append(('backbone.0.body.norm1.bias', 'model.backbone.model.hidden_states_norms.stage2.bias')				)
							rename_keys.append(('backbone.0.body.norm2.weight', 'model.backbone.model.hidden_states_norms.stage3.weight')				)
							rename_keys.append(('backbone.0.body.norm2.bias', 'model.backbone.model.hidden_states_norms.stage3.bias')				)
							rename_keys.append(('backbone.0.body.norm3.weight', 'model.backbone.model.hidden_states_norms.stage4.weight')				)
							rename_keys.append(('backbone.0.body.norm3.bias', 'model.backbone.model.hidden_states_norms.stage4.bias')				)

							# transformer encoder
							for i in range(config.encoder_layers				):
														rename_keys.append((F'''transformer.encoder.layers.{i}.self_attn.sampling_offsets.weight''', F'''model.encoder.layers.{i}.self_attn.sampling_offsets.weight''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.self_attn.sampling_offsets.bias''', F'''model.encoder.layers.{i}.self_attn.sampling_offsets.bias''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.self_attn.attention_weights.weight''', F'''model.encoder.layers.{i}.self_attn.attention_weights.weight''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.self_attn.attention_weights.bias''', F'''model.encoder.layers.{i}.self_attn.attention_weights.bias''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.self_attn.value_proj.weight''', F'''model.encoder.layers.{i}.self_attn.value_proj.weight''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.self_attn.value_proj.bias''', F'''model.encoder.layers.{i}.self_attn.value_proj.bias''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.self_attn.output_proj.weight''', F'''model.encoder.layers.{i}.self_attn.output_proj.weight''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.self_attn.output_proj.bias''', F'''model.encoder.layers.{i}.self_attn.output_proj.bias''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.norm1.weight''', F'''model.encoder.layers.{i}.self_attn_layer_norm.weight''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.norm1.bias''', F'''model.encoder.layers.{i}.self_attn_layer_norm.bias''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.linear1.weight''', F'''model.encoder.layers.{i}.fc1.weight''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.linear1.bias''', F'''model.encoder.layers.{i}.fc1.bias''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.linear2.weight''', F'''model.encoder.layers.{i}.fc2.weight''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.linear2.bias''', F'''model.encoder.layers.{i}.fc2.bias''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.norm2.weight''', F'''model.encoder.layers.{i}.final_layer_norm.weight''')				)
														rename_keys.append((F'''transformer.encoder.layers.{i}.norm2.bias''', F'''model.encoder.layers.{i}.final_layer_norm.bias''')				)

							# transformer decoder
							for i in range(config.decoder_layers				):
														rename_keys.append((F'''transformer.decoder.layers.{i}.cross_attn.sampling_offsets.weight''', F'''model.decoder.layers.{i}.encoder_attn.sampling_offsets.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.cross_attn.sampling_offsets.bias''', F'''model.decoder.layers.{i}.encoder_attn.sampling_offsets.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.cross_attn.attention_weights.weight''', F'''model.decoder.layers.{i}.encoder_attn.attention_weights.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.cross_attn.attention_weights.bias''', F'''model.decoder.layers.{i}.encoder_attn.attention_weights.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.cross_attn.value_proj.weight''', F'''model.decoder.layers.{i}.encoder_attn.value_proj.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.cross_attn.value_proj.bias''', F'''model.decoder.layers.{i}.encoder_attn.value_proj.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.cross_attn.output_proj.weight''', F'''model.decoder.layers.{i}.encoder_attn.output_proj.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.cross_attn.output_proj.bias''', F'''model.decoder.layers.{i}.encoder_attn.output_proj.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.norm1.weight''', F'''model.decoder.layers.{i}.encoder_attn_layer_norm.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.norm1.bias''', F'''model.decoder.layers.{i}.encoder_attn_layer_norm.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.self_attn.out_proj.weight''', F'''model.decoder.layers.{i}.self_attn.out_proj.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.self_attn.out_proj.bias''', F'''model.decoder.layers.{i}.self_attn.out_proj.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.norm2.weight''', F'''model.decoder.layers.{i}.self_attn_layer_norm.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.norm2.bias''', F'''model.decoder.layers.{i}.self_attn_layer_norm.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.linear1.weight''', F'''model.decoder.layers.{i}.fc1.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.linear1.bias''', F'''model.decoder.layers.{i}.fc1.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.linear2.weight''', F'''model.decoder.layers.{i}.fc2.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.linear2.bias''', F'''model.decoder.layers.{i}.fc2.bias''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.norm3.weight''', F'''model.decoder.layers.{i}.final_layer_norm.weight''')				)
														rename_keys.append((F'''transformer.decoder.layers.{i}.norm3.bias''', F'''model.decoder.layers.{i}.final_layer_norm.bias''')				)

							# fmt: on

							return rename_keys





def  __lowerCamelCase     (			UpperCamelCase__       ,							UpperCamelCase__       ,							UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   dct.pop(UpperCamelCase__				)
							snake_case_          =   val





def  __lowerCamelCase     (			UpperCamelCase__       ,							UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   [int(backbone_config.embed_dim * 2**i				) for i in range(len(backbone_config.depths				)				)]
							for i in range(len(backbone_config.depths				)				):
														snake_case_          =   num_features[i]
														for j in range(backbone_config.depths[i]				):
																					# fmt: off
																					# read in weights + bias of input projection layer (in original implementation, this is a single matrix + bias)
																					snake_case_          =   state_dict.pop(F'''backbone.0.body.layers.{i}.blocks.{j}.attn.qkv.weight'''				)
																					snake_case_          =   state_dict.pop(F'''backbone.0.body.layers.{i}.blocks.{j}.attn.qkv.bias'''				)
																					# next, add query, keys and values (in that order) to the state dict
																					snake_case_          =   in_proj_weight[:dim, :]
																					snake_case_          =   in_proj_bias[: dim]
																					snake_case_          =   in_proj_weight[
																					    dim : dim * 2, :
																					]
																					snake_case_          =   in_proj_bias[
																					    dim : dim * 2
																					]
																					snake_case_          =   in_proj_weight[
																					    -dim :, :
																					]
																					snake_case_          =   in_proj_bias[-dim :]
																					# fmt: on





def  __lowerCamelCase     (			UpperCamelCase__       ,							UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   config.d_model
							for i in range(config.decoder_layers				):
														# read in weights + bias of input projection layer of self-attention
														snake_case_          =   state_dict.pop(F'''transformer.decoder.layers.{i}.self_attn.in_proj_weight'''				)
														snake_case_          =   state_dict.pop(F'''transformer.decoder.layers.{i}.self_attn.in_proj_bias'''				)
														# next, add query, keys and values (in that order) to the state dict
														snake_case_          =   in_proj_weight[:hidden_size, :]
														snake_case_          =   in_proj_bias[:hidden_size]
														snake_case_          =   in_proj_weight[
														    hidden_size : hidden_size * 2, :
														]
														snake_case_          =   in_proj_bias[hidden_size : hidden_size * 2]
														snake_case_          =   in_proj_weight[-hidden_size:, :]
														snake_case_          =   in_proj_bias[-hidden_size:]





def  __lowerCamelCase     (			):







							'''simple docstring'''






							snake_case_          =   'http://images.cocodataset.org/val2017/000000039769.jpg'
							snake_case_          =   Image.open(requests.get(UpperCamelCase__       ,							stream=UpperCamelCase__				).raw				)

							return im





@torch.no_grad()
def  __lowerCamelCase     (			UpperCamelCase__       ,							UpperCamelCase__       ,							UpperCamelCase__				):







							'''simple docstring'''






							snake_case_          =   get_deta_config(UpperCamelCase__				)

							# load original state dict
							if model_name == "deta-swin-large":
														snake_case_          =   hf_hub_download(repo_id='nielsr/deta-checkpoints'       ,							filename='adet_swin_ft.pth'				)
							elif model_name == "deta-swin-large-o365":
														snake_case_          =   hf_hub_download(repo_id='jozhang97/deta-swin-l-o365'       ,							filename='deta_swin_pt_o365.pth'				)
							else:
														raise ValueError(F'''Model name {model_name} not supported'''				)

							snake_case_          =   torch.load(UpperCamelCase__       ,							map_location='cpu'				)['model']

							# original state dict
							for name, param in state_dict.items():
														print(UpperCamelCase__       ,							param.shape				)

							# rename keys
							snake_case_          =   create_rename_keys(UpperCamelCase__				)
							for src, dest in rename_keys:
														rename_key(UpperCamelCase__       ,							UpperCamelCase__       ,							UpperCamelCase__				)
							read_in_swin_q_k_v(UpperCamelCase__       ,							config.backbone_config				)
							read_in_decoder_q_k_v(UpperCamelCase__       ,							UpperCamelCase__				)

							# fix some prefixes
							for key in state_dict.copy().keys():
														if "transformer.decoder.class_embed" in key or "transformer.decoder.bbox_embed" in key:
																					snake_case_          =   state_dict.pop(UpperCamelCase__				)
																					snake_case_          =   val
														if "input_proj" in key:
																					snake_case_          =   state_dict.pop(UpperCamelCase__				)
																					snake_case_          =   val
														if "level_embed" in key or "pos_trans" in key or "pix_trans" in key or "enc_output" in key:
																					snake_case_          =   state_dict.pop(UpperCamelCase__				)
																					snake_case_          =   val

    # finally, create HuggingFace model and load state dict
							snake_case_          =   DetaForObjectDetection(UpperCamelCase__				)
							model.load_state_dict(UpperCamelCase__				)
							model.eval()

							snake_case_          =   'cuda' if torch.cuda.is_available() else 'cpu'
							model.to(UpperCamelCase__				)

							# load image processor
							snake_case_          =   DetaImageProcessor(format='coco_detection'				)

							# verify our conversion on image
							snake_case_          =   prepare_img()
							snake_case_          =   processor(images=UpperCamelCase__       ,							return_tensors='pt'				)
							snake_case_          =   encoding['pixel_values']
							snake_case_          =   model(pixel_values.to(UpperCamelCase__				)				)

							# verify logits
							print('Logits:'       ,							outputs.logits[0, :3, :3]				)
							print('Boxes:'       ,							outputs.pred_boxes[0, :3, :3]				)
							if model_name == "deta-swin-large":
														snake_case_          =   torch.tensor(
														    [[-7.63_08, -2.84_85, -5.37_37], [-7.20_37, -4.55_05, -4.80_27], [-7.29_43, -4.26_11, -4.66_17]]				)
														snake_case_          =   torch.tensor([[0.49_87, 0.49_69, 0.99_99], [0.25_49, 0.54_98, 0.48_05], [0.54_98, 0.27_57, 0.05_69]]				)
							elif model_name == "deta-swin-large-o365":
														snake_case_          =   torch.tensor(
														    [[-8.01_22, -3.57_20, -4.97_17], [-8.15_47, -3.68_86, -4.63_89], [-7.66_10, -3.61_94, -5.01_34]]				)
														snake_case_          =   torch.tensor([[0.25_23, 0.55_49, 0.48_81], [0.77_15, 0.41_49, 0.46_01], [0.55_03, 0.27_53, 0.05_75]]				)
							assert torch.allclose(outputs.logits[0, :3, :3]       ,							expected_logits.to(UpperCamelCase__				)       ,							atol=1E-4				)
							assert torch.allclose(outputs.pred_boxes[0, :3, :3]       ,							expected_boxes.to(UpperCamelCase__				)       ,							atol=1E-4				)
							print('Everything ok!'				)

							if pytorch_dump_folder_path:
														# Save model and processor
														logger.info(F'''Saving PyTorch model and processor to {pytorch_dump_folder_path}...'''				)
														Path(UpperCamelCase__				).mkdir(exist_ok=UpperCamelCase__				)
														model.save_pretrained(UpperCamelCase__				)
														processor.save_pretrained(UpperCamelCase__				)

							# Push to hub
							if push_to_hub:
														print('Pushing model and processor to hub...'				)
														model.push_to_hub(F'''jozhang97/{model_name}'''				)
														processor.push_to_hub(F'''jozhang97/{model_name}'''				)


if __name__ == "__main__":
					_UpperCAmelCase		:       Dict						    =	argparse.ArgumentParser()

					parser.add_argument(
					    """--model_name""",
					    type=str,
					    default="""deta-swin-large""",
					    choices=["""deta-swin-large""", """deta-swin-large-o365"""],
					    help="""Name of the model you'd like to convert.""",
					)
					parser.add_argument(
					    """--pytorch_dump_folder_path""",
					    default=None,
					    type=str,
					    help="""Path to the folder to output PyTorch model.""",
					)
					parser.add_argument(
					    """--push_to_hub""", action="""store_true""", help="""Whether or not to push the converted model to the 🤗 hub."""
					)
					_UpperCAmelCase		:       int						    =	parser.parse_args()
					convert_deta_checkpoint(args.model_name, args.pytorch_dump_folder_path, args.push_to_hub)







from typing import TYPE_CHECKING

from ...utils import (
    OptionalDependencyNotAvailable,
    _LazyModule,
    is_tf_available,
    is_torch_available,
    is_vision_available,
)


_UpperCAmelCase		:       Dict						    =	{
    """configuration_blip""": [
        """BLIP_PRETRAINED_CONFIG_ARCHIVE_MAP""",
        """BlipConfig""",
        """BlipTextConfig""",
        """BlipVisionConfig""",
    ],
    """processing_blip""": ["""BlipProcessor"""],
}

try:
					if not is_vision_available():
										raise OptionalDependencyNotAvailable()
except OptionalDependencyNotAvailable:
					pass
else:
					_UpperCAmelCase		:       Optional[int]						    =	["""BlipImageProcessor"""]


try:
					if not is_torch_available():
										raise OptionalDependencyNotAvailable()
except OptionalDependencyNotAvailable:
					pass
else:
					_UpperCAmelCase		:       Any						    =	[
					    """BLIP_PRETRAINED_MODEL_ARCHIVE_LIST""",
					    """BlipModel""",
					    """BlipPreTrainedModel""",
					    """BlipForConditionalGeneration""",
					    """BlipForQuestionAnswering""",
					    """BlipVisionModel""",
					    """BlipTextModel""",
					    """BlipForImageTextRetrieval""",
					]

try:
					if not is_tf_available():
										raise OptionalDependencyNotAvailable()
except OptionalDependencyNotAvailable:
					pass
else:
					_UpperCAmelCase		:       Any						    =	[
					    """TF_BLIP_PRETRAINED_MODEL_ARCHIVE_LIST""",
					    """TFBlipModel""",
					    """TFBlipPreTrainedModel""",
					    """TFBlipForConditionalGeneration""",
					    """TFBlipForQuestionAnswering""",
					    """TFBlipVisionModel""",
					    """TFBlipTextModel""",
					    """TFBlipForImageTextRetrieval""",
					]

if TYPE_CHECKING:
					from .configuration_blip import BLIP_PRETRAINED_CONFIG_ARCHIVE_MAP, BlipConfig, BlipTextConfig, BlipVisionConfig
					from .processing_blip import BlipProcessor

					try:
										if not is_vision_available():
															raise OptionalDependencyNotAvailable()
					except OptionalDependencyNotAvailable:
										pass
					else:
										from .image_processing_blip import BlipImageProcessor

					try:
										if not is_torch_available():
															raise OptionalDependencyNotAvailable()
					except OptionalDependencyNotAvailable:
										pass
					else:
										from .modeling_blip import (
										    BLIP_PRETRAINED_MODEL_ARCHIVE_LIST,
										    BlipForConditionalGeneration,
										    BlipForImageTextRetrieval,
										    BlipForQuestionAnswering,
										    BlipModel,
										    BlipPreTrainedModel,
										    BlipTextModel,
										    BlipVisionModel,
										)

					try:
										if not is_tf_available():
															raise OptionalDependencyNotAvailable()
					except OptionalDependencyNotAvailable:
										pass
					else:
										from .modeling_tf_blip import (
										    TF_BLIP_PRETRAINED_MODEL_ARCHIVE_LIST,
										    TFBlipForConditionalGeneration,
										    TFBlipForImageTextRetrieval,
										    TFBlipForQuestionAnswering,
										    TFBlipModel,
										    TFBlipPreTrainedModel,
										    TFBlipTextModel,
										    TFBlipVisionModel,
										)

else:
					import sys

					_UpperCAmelCase		:       Optional[int]						    =	_LazyModule(__name__, globals()["""__file__"""], _import_structure, module_spec=__spec__)




