mirror of
				https://github.com/Telecominfraproject/oopt-gnpy.git
				synced 2025-10-31 10:07:57 +00:00 
			
		
		
		
	 1a795639c7
			
		
	
	1a795639c7
	
	
	
		
			
			This commit introduces new functions for converting between YANG formatted files and legacy formats. The conversion processes adhere to RFC7951 for encoding YANG data. Key changes include: - Conversion of float and empty type representations. - Transformation of Span and SI lists xx_power_range into dictionaries. - Addition of necessary namespaces. - use of oopt-gnpy-libyang to enforce compliancy to yang models These utilities enable full compatibility with GNPy. Co-authored-by: Renato Ambrosone <renato.ambrosone@polito.it> Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com> Change-Id: Ia004113bca2b0631d1648564e5ccb60504fe80f8
		
			
				
	
	
		
			244 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python3
 | |
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| # SPDX-License-Identifier: BSD-3-Clause
 | |
| # JSON files format conversion legacy <-> YANG
 | |
| # Copyright (C) 2025 Telecom Infra Project and GNPy contributors
 | |
| # see AUTHORS.rst for a list of contributors
 | |
| 
 | |
| """
 | |
| YANG formatted to legacy format conversion
 | |
| ==========================================
 | |
| 
 | |
| """
 | |
| 
 | |
| from argparse import ArgumentParser
 | |
| from pathlib import Path
 | |
| from copy import deepcopy
 | |
| import json
 | |
| from typing import Dict
 | |
| 
 | |
| from gnpy.tools.yang_convert_utils import convert_degree, convert_back_degree, \
 | |
|     convert_delta_power_range, convert_back_delta_power_range, \
 | |
|     convert_dict, convert_back, \
 | |
|     remove_null_region_city, remove_union_that_fail, \
 | |
|     convert_design_band, convert_back_design_band, \
 | |
|     convert_none_to_empty, convert_empty_to_none, \
 | |
|     convert_loss_coeff_list, convert_back_loss_coeff_list, \
 | |
|     ELEMENTS_KEY, PATH_REQUEST_KEY, RESPONSE_KEY, SPECTRUM_KEY, EQPT_TYPES, EDFA_CONFIG_KEYS, SIM_PARAMS_KEYS, \
 | |
|     TOPO_NMSP, SERV_NMSP, EQPT_NMSP, SPECTRUM_NMSP, SIM_PARAMS_NMSP, EDFA_CONFIG_NMSP, RESP_NMSP, \
 | |
|     dump_data, add_missing_default_type_variety, \
 | |
|     remove_namespace_context, load_data, reorder_route_objects, reorder_lumped_losses_objects, \
 | |
|     reorder_raman_pumps, convert_raman_coef, convert_back_raman_coef, convert_raman_efficiency, \
 | |
|     convert_back_raman_efficiency, convert_nf_coef, convert_back_nf_coef, \
 | |
|     convert_nf_fit_coef, convert_back_nf_fit_coef
 | |
| 
 | |
| 
 | |
| def legacy_to_yang(json_data: Dict) -> Dict:
 | |
|     """Convert legacy format to GNPy YANG format.
 | |
| 
 | |
|     This function adds the required namespace if not present and processes the input JSON data
 | |
|     based on its structure to convert it to the appropriate YANG format. There is no validation
 | |
|     of yang formatted data.
 | |
| 
 | |
|     :param json_data: The input JSON data to convert.
 | |
|     :type json_data: Dict
 | |
|     :return: The converted JSON data in GNPy YANG format.
 | |
|     :rtype: Dict
 | |
|     """
 | |
|     json_data = convert_none_to_empty(deepcopy(json_data))
 | |
| 
 | |
|     # case of topology json
 | |
|     if ELEMENTS_KEY in json_data:
 | |
|         json_data = reorder_raman_pumps(json_data)
 | |
|         json_data = reorder_lumped_losses_objects(json_data)
 | |
|         json_data = remove_null_region_city(json_data)
 | |
|         json_data = convert_degree(json_data)
 | |
|         json_data = convert_design_band(json_data)
 | |
|         json_data = convert_loss_coeff_list(json_data)
 | |
|         json_data = convert_raman_coef(json_data)
 | |
|         json_data = {TOPO_NMSP: json_data}
 | |
|     elif TOPO_NMSP in json_data:
 | |
|         # then this is a new format topology json, ensure that there are no issues
 | |
|         json_data[TOPO_NMSP] = convert_degree(json_data[TOPO_NMSP])
 | |
|         json_data[TOPO_NMSP] = convert_design_band(json_data[TOPO_NMSP])
 | |
|         json_data[TOPO_NMSP] = convert_loss_coeff_list(json_data[TOPO_NMSP])
 | |
|         json_data[TOPO_NMSP] = remove_null_region_city(json_data[TOPO_NMSP])
 | |
| 
 | |
|     # case of equipment json
 | |
|     elif any(k in json_data for k in EQPT_TYPES):
 | |
|         json_data = convert_raman_efficiency(json_data)
 | |
|         json_data = convert_delta_power_range(json_data)
 | |
|         json_data = convert_nf_coef(json_data)
 | |
|         json_data = add_missing_default_type_variety(json_data)
 | |
|         json_data = {EQPT_NMSP: json_data}
 | |
|     elif EQPT_NMSP in json_data:
 | |
|         # then this is already a new format topology json, ensure that there are no issues
 | |
|         json_data[EQPT_NMSP] = convert_raman_efficiency(json_data[EQPT_NMSP])
 | |
|         json_data[EQPT_NMSP] = convert_delta_power_range(json_data[EQPT_NMSP])
 | |
|         json_data[EQPT_NMSP] = convert_nf_coef(json_data[EQPT_NMSP])
 | |
|         json_data[EQPT_NMSP] = add_missing_default_type_variety(json_data[EQPT_NMSP])
 | |
| 
 | |
|     # case of service json
 | |
|     elif PATH_REQUEST_KEY in json_data:
 | |
|         json_data = reorder_route_objects(json_data)
 | |
|         json_data = remove_union_that_fail(json_data)
 | |
|         json_data = {SERV_NMSP: json_data}
 | |
| 
 | |
|     elif SERV_NMSP in json_data:
 | |
|         json_data[SERV_NMSP] = reorder_route_objects(json_data[SERV_NMSP])
 | |
|         json_data[SERV_NMSP] = remove_union_that_fail(json_data[SERV_NMSP])
 | |
| 
 | |
|     # case of edfa_config json
 | |
|     elif any(k in json_data for k in EDFA_CONFIG_KEYS):
 | |
|         json_data = convert_nf_fit_coef(json_data)
 | |
|         json_data = {EDFA_CONFIG_NMSP: json_data}
 | |
| 
 | |
|     elif EDFA_CONFIG_NMSP in json_data:
 | |
|         json_data[EDFA_CONFIG_NMSP] = convert_nf_fit_coef(json_data[EDFA_CONFIG_NMSP])
 | |
| 
 | |
|     # case of spectrum json
 | |
|     elif SPECTRUM_KEY in json_data:
 | |
|         json_data = {SPECTRUM_NMSP: json_data[SPECTRUM_KEY]}
 | |
| 
 | |
|     # case of sim_params json
 | |
|     elif any(k in json_data for k in SIM_PARAMS_KEYS):
 | |
|         json_data = {SIM_PARAMS_NMSP: json_data}
 | |
| 
 | |
|     # case of response json
 | |
|     elif RESPONSE_KEY in json_data:
 | |
|         json_data = {RESP_NMSP: json_data}
 | |
| 
 | |
|     elif any(k in json_data for k in [SPECTRUM_NMSP, SIM_PARAMS_NMSP, RESP_NMSP]):
 | |
|         # then this is a new format json, nothing to convert
 | |
|         pass
 | |
| 
 | |
|     else:
 | |
|         raise ValueError('Unrecognized type of content (not topology, service or equipment)')
 | |
| 
 | |
|     json_data = convert_dict(json_data)
 | |
|     return json_data
 | |
| 
 | |
| 
 | |
| def yang_to_legacy(json_data: Dict) -> Dict:
 | |
|     """Convert GNPy YANG format to legacy format.
 | |
| 
 | |
|     This function processes the input JSON data to convert it from the new GNPy YANG format
 | |
|     back to the legacy format. It handles various types of content, including topology,
 | |
|     equipment, and service jsons, ensuring that the necessary conversions are applied.
 | |
|     The input data is validated with oopt-gnpy-libyang.
 | |
| 
 | |
|     :param json_data: The input JSON data in GNPy YANG format to convert.
 | |
|     :type json_data: Dict
 | |
|     :return: The converted JSON data in legacy format.
 | |
|     :rtype: Dict
 | |
| 
 | |
|     :raises ValueError: If the input JSON data does not match any recognized content type
 | |
|                         (not topology, service, or equipment).
 | |
|     """
 | |
|     # validate data compliance: make sure that this is yang formated data before validation.
 | |
|     load_data(json.dumps(legacy_to_yang(json_data)))
 | |
|     json_data = convert_empty_to_none(json_data)
 | |
|     json_data = convert_back(json_data)
 | |
| 
 | |
|     # case of topology json
 | |
|     if ELEMENTS_KEY in json_data:
 | |
|         json_data = convert_back_degree(json_data)
 | |
|         json_data = convert_back_design_band(json_data)
 | |
|         json_data = convert_back_loss_coeff_list(json_data)
 | |
|         json_data = convert_back_raman_coef(json_data)
 | |
|     elif TOPO_NMSP in json_data:
 | |
|         json_data = convert_back_degree(json_data[TOPO_NMSP])
 | |
|         json_data = convert_back_design_band(json_data)
 | |
|         json_data = convert_back_loss_coeff_list(json_data)
 | |
|         json_data = convert_back_raman_coef(json_data)
 | |
| 
 | |
|     # case of equipment json
 | |
|     elif any(k in json_data for k in EQPT_TYPES):
 | |
|         json_data = convert_back_delta_power_range(json_data)
 | |
|         json_data = convert_back_raman_efficiency(json_data)
 | |
|         json_data = convert_back_nf_coef(json_data)
 | |
|         json_data = remove_namespace_context(json_data, "gnpy-eqpt-config:")
 | |
|     elif EQPT_NMSP in json_data:
 | |
|         json_data[EQPT_NMSP] = convert_back_delta_power_range(json_data[EQPT_NMSP])
 | |
|         json_data[EQPT_NMSP] = convert_back_raman_efficiency(json_data[EQPT_NMSP])
 | |
|         json_data[EQPT_NMSP] = convert_back_nf_coef(json_data[EQPT_NMSP])
 | |
|         json_data = remove_namespace_context(json_data[EQPT_NMSP], "gnpy-eqpt-config:")
 | |
| 
 | |
|     # case of EDFA config json
 | |
|     elif any(k in json_data for k in EDFA_CONFIG_KEYS):
 | |
|         json_data = convert_back_nf_fit_coef(json_data)
 | |
|     elif EDFA_CONFIG_NMSP in json_data:
 | |
|         json_data[EDFA_CONFIG_NMSP] = convert_back_nf_fit_coef(json_data[EDFA_CONFIG_NMSP])
 | |
| 
 | |
|     # case of service json
 | |
|     elif SERV_NMSP in json_data:
 | |
|         json_data = json_data[SERV_NMSP]
 | |
| 
 | |
|     # case of sim_params json
 | |
|     elif SIM_PARAMS_NMSP in json_data:
 | |
|         json_data = json_data[SIM_PARAMS_NMSP]
 | |
| 
 | |
|     # case of spectrum json
 | |
|     elif SPECTRUM_NMSP in json_data:
 | |
|         json_data = {SPECTRUM_KEY: json_data[SPECTRUM_NMSP]}
 | |
| 
 | |
|     # case of planning response json
 | |
|     elif RESP_NMSP in json_data:
 | |
|         json_data = json_data[RESP_NMSP]
 | |
|     elif any(k in json_data for k in SIM_PARAMS_KEYS + [SPECTRUM_KEY, RESPONSE_KEY, PATH_REQUEST_KEY]):
 | |
|         # then this is a legacy format json, nothing to convert
 | |
|         pass
 | |
|     else:
 | |
|         raise ValueError('Unrecognized type of content (not topology, service or equipment)')
 | |
|     return json_data
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     """Conversion function
 | |
|     """
 | |
|     parser = ArgumentParser()
 | |
|     parser.add_argument('--legacy-to-yang', nargs='?', type=Path,
 | |
|                         help='convert file with this name into yangconformedname.json')
 | |
|     parser.add_argument('--yang-to-legacy', nargs='?', type=Path,
 | |
|                         help='convert file with this name into gnpy'
 | |
|                              + ' using decimal instead of strings and null instead of [null]')
 | |
|     parser.add_argument('--validate', nargs='?', type=Path,
 | |
|                         help='validate yang conformity')
 | |
|     parser.add_argument('-o', '--output', type=Path,
 | |
|                         help='Stores into file with this name; default = GNPy_legacy_formatted-<file_name>.json or'
 | |
|                         + 'GNPy_yang_formatted-<file_name>.json')
 | |
|     args = parser.parse_args()
 | |
| 
 | |
|     if not (args.legacy_to_yang or args.yang_to_legacy or args.validate):
 | |
|         parser.error("You must specify at least one of --legacy-to-yang, --yang-to-legacy, or --validate ")
 | |
| 
 | |
|     output = None
 | |
|     converted = None
 | |
|     if args.validate:
 | |
|         with open(args.validate, 'r', encoding='utf-8') as f:
 | |
|             json_data = json.load(f)
 | |
|             load_data(json.dumps(json_data))
 | |
|         return 0
 | |
|     elif args.legacy_to_yang:
 | |
|         prefix = 'GNPy_yang_formatted-'
 | |
|         with open(args.legacy_to_yang, 'r', encoding='utf-8') as f:
 | |
|             json_data = json.load(f)
 | |
|             # note that dump_data automatically validate date against yang models
 | |
|             converted = dump_data(legacy_to_yang(json_data))
 | |
|         output = prefix + str(args.legacy_to_yang.name)
 | |
|     elif args.yang_to_legacy:
 | |
|         prefix = 'GNPy_legacy_formatted-'
 | |
|         with open(args.yang_to_legacy, 'r', encoding='utf-8') as f:
 | |
|             json_data = json.load(f)
 | |
|             converted = json.dumps(yang_to_legacy(json_data), indent=2, ensure_ascii=False)
 | |
|         output = prefix + str(args.yang_to_legacy.name)
 | |
|     if args.output:
 | |
|         output = args.output
 | |
|     with open(output, 'w', encoding='utf-8') as f:
 | |
|         f.write(converted)
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     main()
 |