diff --git a/gnpy/core/convert.py b/gnpy/core/convert.py index 3124a710..a8ec0884 100755 --- a/gnpy/core/convert.py +++ b/gnpy/core/convert.py @@ -7,11 +7,11 @@ xls to json parser, that can be called directly from the transmission_main_examp xls examples are meshTopologyExampleV2.xls and CORONET_Global_Topology.xls Require Nodes and Links sheets, Eqpt sheet is optional *in Nodes sheet, only the 'City' column is mandatory. The column 'Type' is discovered based -on the topology: degree 2 = ILA, other degrees = ROADM. The value is also corrected if the user +on the topology: degree 2 = ILA, other degrees = ROADM. The value is also corrected if the user specifies an ILA of degree != 2. -*In Links sheet only the 3 first columns (Node A, Node Z and east Distance (km)) are mandatory. +*In Links sheet only the 3 first columns (Node A, Node Z and east Distance (km)) are mandatory. Missing west information are copied from east information so it is possible to input undir data -*in Eqpt sheet +*in Eqpt sheet """ from sys import exit @@ -39,19 +39,19 @@ class Link(namedtuple('Link', 'from_city to_city \ west_distance west_fiber west_lineic west_con_in west_con_out west_pmd west_cable \ distance_units')): def __new__(cls, from_city, to_city, - east_distance, east_fiber='SSMF', east_lineic=0.2, - east_con_in=None, east_con_out=None, east_pmd=0.1, east_cable='', - west_distance='', west_fiber='', west_lineic='', + east_distance, east_fiber='SSMF', east_lineic=0.2, + east_con_in=None, east_con_out=None, east_pmd=0.1, east_cable='', + west_distance='', west_fiber='', west_lineic='', west_con_in='', west_con_out='', west_pmd='', west_cable='', distance_units='km'): - east_values = [east_distance, east_fiber, east_lineic, east_con_in, east_con_out, + east_values = [east_distance, east_fiber, east_lineic, east_con_in, east_con_out, east_pmd, east_cable] - west_values = [west_distance, west_fiber, west_lineic, west_con_in, west_con_out, + west_values = [west_distance, west_fiber, west_lineic, west_con_in, west_con_out, west_pmd, west_cable] default_values = [80,'SSMF',0.2,None,None,0.1,''] east_values = [x[0] if x[0] != '' else x[1] for x in zip(east_values,default_values)] west_values = [x[0] if x[0] != '' else x[1] for x in zip(west_values,east_values)] - return super().__new__(cls, from_city, to_city, *east_values, *west_values, distance_units) + return super().__new__(cls, from_city, to_city, *east_values, *west_values, distance_units) class Eqpt(namedtuple('Eqpt', 'from_city to_city \ egress_amp_type egress_att_in egress_amp_gain egress_amp_tilt egress_amp_att_out\ @@ -64,7 +64,7 @@ class Eqpt(namedtuple('Eqpt', 'from_city to_city \ ingress_amp_type, ingress_att_in, ingress_amp_gain, ingress_amp_tilt, ingress_amp_att_out] default_values = ['','','',0,0,0,0,'',0,0,0,0] values = [x[0] if x[0] != '' else x[1] for x in zip(values,default_values)] - return super().__new__(cls, *values) + return super().__new__(cls, *values) def sanity_check(nodes, nodes_by_city, links_by_city, eqpts_by_city): try : @@ -83,7 +83,7 @@ def sanity_check(nodes, nodes_by_city, links_by_city, eqpts_by_city): for city,link in links_by_city.items(): if nodes_by_city[city].node_type.lower()=='ila' and len(link) != 2: - #wrong input: ILA sites can only be Degree 2 + #wrong input: ILA sites can only be Degree 2 # => correct to make it a ROADM and remove entry in links_by_city #TODO : put in log rather than print print(f'invalid node type ({nodes_by_city[city].node_type})\ @@ -115,7 +115,7 @@ def convert_file(input_filename, filter_region=[]): global eqpts_by_city eqpts_by_city = defaultdict(list) for eqpt in eqpts: - eqpts_by_city[eqpt.from_city].append(eqpt) + eqpts_by_city[eqpt.from_city].append(eqpt) nodes = sanity_check(nodes, nodes_by_city, links_by_city, eqpts_by_city) @@ -148,7 +148,7 @@ def convert_file(input_filename, filter_region=[]): 'latitude': x.latitude, 'longitude': x.longitude}}, 'type': 'Fused'} - for x in nodes_by_city.values() if x.node_type.lower() == 'fused'] + + for x in nodes_by_city.values() if x.node_type.lower() == 'fused'] + [{'uid': f'fiber ({x.from_city} → {x.to_city})-{x.east_cable}', 'metadata': {'location': midpoint(nodes_by_city[x.from_city], nodes_by_city[x.to_city])}, @@ -171,7 +171,7 @@ def convert_file(input_filename, filter_region=[]): 'loss_coef': x.west_lineic, 'con_in':x.west_con_in, 'con_out':x.west_con_out} - } # missing ILA construction + } # missing ILA construction for x in links] + [{'uid': f'egress edfa in {e.from_city} to {e.to_city}', 'metadata': {'location': {'city': nodes_by_city[e.from_city].city, @@ -193,7 +193,7 @@ def convert_file(input_filename, filter_region=[]): 'type_variety': e.ingress_amp_type, 'operational': {'gain_target': e.ingress_amp_gain, 'tilt_target': e.ingress_amp_tilt} - } + } for e in eqpts if e.ingress_amp_type.lower() != ''], 'connections': list(chain.from_iterable([eqpt_connection_by_city(n.city) @@ -205,7 +205,7 @@ def convert_file(input_filename, filter_region=[]): for x in nodes_by_city.values() if x.node_type.lower()=='roadm'], [{'from_node': f'roadm {x.city}', 'to_node': f'trx {x.city}'} - for x in nodes_by_city.values() if x.node_type.lower()=='roadm']))) + for x in nodes_by_city.values() if x.node_type.lower()=='roadm']))) } #print(dumps(data, indent=2)) @@ -235,20 +235,20 @@ def parse_excel(input_filename): expected = ['City', 'State', 'Country', 'Region', 'Latitude', 'Longitude'] if header != expected: raise ValueError(f'Malformed header on Nodes sheet: {header} != {expected}') - """ + """ nodes = [] for row in all_rows(nodes_sheet, start=5): nodes.append(Node(*(x.value for x in row[0:NODES_COLUMN]))) #check input expected_node_types = ('ROADM', 'ILA', 'FUSED') - nodes = [n._replace(node_type='ILA') + nodes = [n._replace(node_type='ILA') if not (n.node_type in expected_node_types) else n for n in nodes] # sanity check """ header = [x.value.strip() for x in links_sheet.row(4)] - expected = ['Node A', 'Node Z', + expected = ['Node A', 'Node Z', 'Distance (km)', 'Fiber type', 'lineic att', 'Con_in', 'Con_out', 'PMD', 'Cable id', 'Distance (km)', 'Fiber type', 'lineic att', 'Con_in', 'Con_out', 'PMD', 'Cable id'] if header != expected: @@ -280,7 +280,7 @@ def eqpt_connection_by_city(city_name): if nodes_by_city[city_name].node_type.lower() in ('ila', 'fused'): # Then len(other_cities) == 2 direction = ['ingress', 'egress'] - for i in range(2): + for i in range(2): from_ = fiber_link(other_cities[i], city_name) in_ = eqpt_in_city_to_city(city_name, other_cities[0],direction[i]) to_ = fiber_link(city_name, other_cities[1-i]) @@ -334,7 +334,7 @@ def fiber_dest_from_source(city_name): destinations = [] links_from_city = links_by_city[city_name] for l in links_from_city: - if l.from_city == city_name: + if l.from_city == city_name: destinations.append(l.to_city) else: destinations.append(l.from_city) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index 465b91eb..23dd3e62 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -109,7 +109,7 @@ class Roadm(Node): 'metadata' : { 'location': self.metadata['location']._asdict() } - } + } def __repr__(self): return f'{type(self).__name__}(uid={self.uid!r}, loss={self.loss!r})' @@ -174,7 +174,7 @@ class Fused(Node): nonlinear_interference=pwr.nli/attenuation, amplified_spontaneous_emission=pwr.ase/attenuation) yield carrier._replace(power=pwr) - + def update_pref(self, pref): return pref._replace(p_span0=pref.p0, p_spani=pref.pi - self.loss) @@ -192,7 +192,7 @@ class Fiber(Node): params = {} if 'con_in' not in params: # if not defined in the network json connector loss in/out - # the None value will be updated in network.py[build_network] + # the None value will be updated in network.py[build_network] # with default values from eqpt_config.json[Spans] params['con_in'] = None params['con_out'] = None @@ -209,8 +209,8 @@ class Fiber(Node): self.con_in = self.params.con_in self.con_out = self.params.con_out self.dispersion = self.params.dispersion # s/m/m - self.gamma = self.params.gamma # 1/W/m - self.pch_out = None + self.gamma = self.params.gamma # 1/W/m + self.pch_out = None # TODO|jla: discuss factor 2 in the linear lineic attenuation @property @@ -249,15 +249,15 @@ class Fiber(Node): def fiber_loss(self): # dB fiber loss, not including padding attenuator return self.loss_coef * self.length + self.con_in + self.con_out - + @property def loss(self): #total loss incluiding padding att_in: useful for polymorphism with roadm loss return self.loss_coef * self.length + self.con_in + self.con_out + self.att_in - + @property def passive(self): - return True + return True @property def lin_attenuation(self): @@ -459,7 +459,7 @@ class Edfa(Node): if self.pin_db is None or self.pout_db is None: return f'{type(self).__name__} {self.uid}' nf = mean(self.nf) - return '\n'.join([f'{type(self).__name__} {self.uid}', + return '\n'.join([f'{type(self).__name__} {self.uid}', f' type_variety: {self.params.type_variety}', f' effective gain(dB): {self.effective_gain:.2f}', f' (before att_in and before output VOA)', @@ -519,13 +519,13 @@ class Edfa(Node): g1a = gain_target - self.params.nf_model.delta_p - dg nf_avg = lin2db(db2lin(self.params.nf_model.nf1) + db2lin(self.params.nf_model.nf2)/db2lin(g1a)) elif self.params.type_def == 'fixed_gain': - nf_avg = self.params.nf_model.nf0 + nf_avg = self.params.nf_model.nf0 else: nf_avg = polyval(self.params.nf_fit_coeff, -dg) if avg: return nf_avg + pad else: - return self.interpol_nf_ripple + nf_avg + pad # input VOA = 1 for 1 NF degradation + return self.interpol_nf_ripple + nf_avg + pad # input VOA = 1 for 1 NF degradation def noise_profile(self, df): """ noise_profile(bw) computes amplifier ase (W) in signal bw (Hz) @@ -704,7 +704,7 @@ class Edfa(Node): yield carrier._replace(power=pwr) def update_pref(self, pref): - return pref._replace(p_span0=pref.p0, + return pref._replace(p_span0=pref.p0, p_spani=pref.pi + self.effective_gain - self.operational.out_voa) def __call__(self, spectral_info): diff --git a/gnpy/core/equipment.py b/gnpy/core/equipment.py index 5b8c58a6..f2758922 100644 --- a/gnpy/core/equipment.py +++ b/gnpy/core/equipment.py @@ -4,7 +4,7 @@ ''' nf model parameters calculation calculate nf1, nf2 and Delta_P of a 2 coils edfa with internal VOA -from nf_min and nf_max inputs +from nf_min and nf_max inputs ''' from numpy import clip, polyval from sys import exit @@ -31,12 +31,12 @@ AmpBase = namedtuple( ' nf_model nf_fit_coeff nf_ripple dgt gain_ripple out_voa_auto allowed_for_design') class Amp(AmpBase): def __new__(cls, - type_variety, type_def, gain_flatmax, gain_min, p_max, nf_model=None, - nf_fit_coeff=None, nf_ripple=None, dgt=None, gain_ripple=None, + type_variety, type_def, gain_flatmax, gain_min, p_max, nf_model=None, + nf_fit_coeff=None, nf_ripple=None, dgt=None, gain_ripple=None, out_voa_auto=False, allowed_for_design=True): return super().__new__(cls, - type_variety, type_def, gain_flatmax, gain_min, p_max, - nf_model, nf_fit_coeff, nf_ripple, dgt, gain_ripple, + type_variety, type_def, gain_flatmax, gain_min, p_max, + nf_model, nf_fit_coeff, nf_ripple, dgt, gain_ripple, out_voa_auto, allowed_for_design) @classmethod @@ -162,7 +162,7 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F print('Computation stopped.') exit() else: - # default transponder charcteristics + # default transponder charcteristics trx_params['frequency'] = {'min': default_si_data.f_min, 'max': default_si_data.f_max} trx_params['baud_rate'] = default_si_data.baud_rate trx_params['spacing'] = default_si_data.spacing @@ -178,10 +178,10 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F def automatic_spacing(baud_rate): """return the min possible channel spacing for a given baud rate""" - spacing_list = [(38e9,50e9), (67e9,75e9), (92e9,100e9)] #list of possible tuples + spacing_list = [(38e9,50e9), (67e9,75e9), (92e9,100e9)] #list of possible tuples #[(max_baud_rate, spacing_for_this_baud_rate)] acceptable_spacing_list = list(filter(lambda x : x[0]>baud_rate, spacing_list)) - if len(acceptable_spacing_list) < 1: + if len(acceptable_spacing_list) < 1: #can't find an adequate spacing from the list, so default to: return baud_rate*1.2 else: diff --git a/gnpy/core/info.py b/gnpy/core/info.py index 9000677e..eff0faad 100644 --- a/gnpy/core/info.py +++ b/gnpy/core/info.py @@ -25,7 +25,7 @@ class ConvenienceAccess: if abbrev in kwargs: kwargs[field] = kwargs.pop(abbrev) return self._replace(**kwargs) - + #def ptot_dbm(self): # p = array([c.power.signal+c.power.nli+c.power.ase for c in self.carriers]) # return lin2db(sum(p*1e3)) @@ -64,7 +64,7 @@ def create_input_spectral_information(f_min, roll_off, baud_rate, power, spacing pref = lin2db(power * 1e3) si = SpectralInformation(pref=Pref(pref, pref)) si = si.update(carriers=[ - Channel(f, (f_min+spacing*f), + Channel(f, (f_min+spacing*f), baud_rate, roll_off, Power(power, 0, 0)) for f in range(1,nb_channel+1) ]) return si diff --git a/gnpy/core/network.py b/gnpy/core/network.py index eed0e140..118837a8 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -26,7 +26,7 @@ logger = getLogger(__name__) def load_network(filename, equipment): json_filename = '' if filename.suffix.lower() == '.xls': - logger.info('Automatically generating topology JSON file') + logger.info('Automatically generating topology JSON file') json_filename = convert_file(filename) elif filename.suffix.lower() == '.json': json_filename = filename @@ -95,7 +95,7 @@ def select_edfa(gain_target, power_target, equipment): power=min( pin +edfa.gain_flatmax - +TARGET_EXTENDED_GAIN, + +TARGET_EXTENDED_GAIN, edfa.p_max ) -power_target, @@ -106,7 +106,7 @@ def select_edfa(gain_target, power_target, equipment): acceptable_gain_list = \ list(filter(lambda x : x.gain>-TARGET_EXTENDED_GAIN, edfa_list)) - if len(acceptable_gain_list) < 1: + if len(acceptable_gain_list) < 1: #no amplifier satisfies the required gain, so pick the highest gain: gain_max = max(edfa_list, key=itemgetter(2)).gain #pick up all amplifiers that share this max gain: @@ -127,10 +127,10 @@ def select_edfa(gain_target, power_target, equipment): def set_roadm_loss(network, equipment, pref_ch_db): roadms = [roadm for roadm in network if isinstance(roadm, Roadm)] - power_mode = equipment['Spans']['default'].power_mode + power_mode = equipment['Spans']['default'].power_mode default_roadm_loss = equipment['Roadms']['default'].gain_mode_default_loss pref_roadm_db = equipment['Roadms']['default'].power_mode_pref - roadm_loss = pref_ch_db - pref_roadm_db + roadm_loss = pref_ch_db - pref_roadm_db for roadm in roadms: if power_mode: @@ -165,7 +165,7 @@ def target_power(dp_from_gain, network, node, equipment): #get_fiber_dp #print(f'{repr(node)} delta power in:\n{dp}dB') return dp - + def prev_node_generator(network, node): """fused spans interest: @@ -187,7 +187,7 @@ def next_node_generator(network, node): yield next_node yield from next_node_generator(network, next_node) else: - StopIteration + StopIteration def span_loss(network, node): """Fused span interest: @@ -197,10 +197,10 @@ def span_loss(network, node): prev_node = next(n for n in network.predecessors(node)) if isinstance(prev_node, Fused): loss += sum(n.loss for n in prev_node_generator(network, node)) - except StopIteration: + except StopIteration: pass try: - next_node = next(n for n in network.successors(node)) + next_node = next(n for n in network.successors(node)) if isinstance(next_node, Fused): loss += sum(n.loss for n in next_node_generator(network, node)) except StopIteration: @@ -209,7 +209,7 @@ def span_loss(network, node): def find_first_node(network, node): """Fused node interest: - returns the 1st node at the origin of a succession of fused nodes + returns the 1st node at the origin of a succession of fused nodes (aka no amp in between)""" this_node = node for this_node in prev_node_generator(network, node): @@ -218,7 +218,7 @@ def find_first_node(network, node): def find_last_node(network, node): """Fused node interest: - returns the last node in a succession of fused nodes + returns the last node in a succession of fused nodes (aka no amp in between)""" this_node = node for this_node in next_node_generator(network, node): @@ -231,7 +231,7 @@ def set_amplifier_voa(amp, pref_total_db, power_mode): if power_mode: gain_target = amp.operational.gain_target pout = pref_total_db + amp.dp_db - voa = min(amp.params.p_max-pout, + voa = min(amp.params.p_max-pout, amp.params.gain_flatmax-amp.operational.gain_target) voa = round2float(max(voa, 0), 0.5) - VOA_MARGIN if amp.params.out_voa_auto else 0 amp.dp_db = amp.dp_db + voa @@ -283,7 +283,7 @@ def set_egress_amplifier(network, roadm, equipment, pref_total_db): def add_egress_amplifier(network, node): - next_nodes = [n for n in network.successors(node) + next_nodes = [n for n in network.successors(node) if not (isinstance(n, Transceiver) or isinstance(n, Fused) or isinstance(n, Edfa))] #no amplification for fused spans or TRX for i, next_node in enumerate(next_nodes): @@ -393,16 +393,16 @@ def build_network(network, equipment, pref_ch_db, pref_total_db): padding = default_span_data.padding #set raodm loss for gain_mode before to build network - set_roadm_loss(network, equipment, pref_ch_db) + set_roadm_loss(network, equipment, pref_ch_db) fibers = [f for f in network.nodes() if isinstance(f, Fiber)] add_connector_loss(fibers, con_in, con_out, default_span_data.EOL) add_fiber_padding(network, fibers, padding) - # don't group split fiber and add amp in the same loop + # don't group split fiber and add amp in the same loop # =>for code clarity (at the expense of speed): for fiber in fibers: split_fiber(network, fiber, bounds, target_length, equipment) - amplified_nodes = [n for n in network.nodes() + amplified_nodes = [n for n in network.nodes() if isinstance(n, Fiber) or isinstance(n, Roadm)] for node in amplified_nodes: add_egress_amplifier(network, node) @@ -411,9 +411,9 @@ def build_network(network, equipment, pref_ch_db, pref_total_db): for roadm in roadms: set_egress_amplifier(network, roadm, equipment, pref_total_db) - #support older json input topology wo Roadms: - if len(roadms) == 0: + #support older json input topology wo Roadms: + if len(roadms) == 0: trx = [t for t in network.nodes() if isinstance(t, Transceiver)] for t in trx: - set_egress_amplifier(network, t, equipment, pref_total_db) + set_egress_amplifier(network, t, equipment, pref_total_db) diff --git a/gnpy/core/request.py b/gnpy/core/request.py index a1bcc0d9..714d93e2 100644 --- a/gnpy/core/request.py +++ b/gnpy/core/request.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # TelecomInfraProject/gnpy/examples # Module name : path_requests_run.py -# Version : +# Version : # License : BSD 3-Clause Licence # Copyright (c) 2018, Telecom Infra Project @@ -10,7 +10,7 @@ @author: jeanluc-auge read json request file in accordance with: Yang model for requesting Path Computation - draft-ietf-teas-yang-path-computation-01.txt. + draft-ietf-teas-yang-path-computation-01.txt. and returns path results in terms of path and feasibility """ @@ -76,8 +76,8 @@ class Result_element(Element): self.computed_path = computed_path hop_type = [] for e in computed_path : - if isinstance(e, Transceiver) : - hop_type.append(' - '.join([path_request.tsp,path_request.tsp_mode])) + if isinstance(e, Transceiver) : + hop_type.append(' - '.join([path_request.tsp,path_request.tsp_mode])) else: hop_type.append('not recorded') self.hop_type = hop_type @@ -203,10 +203,10 @@ class Result_element(Element): ] } } - + @property def json(self): - return self.pathresult + return self.pathresult def compute_constrained_path(network, req): trx = [n for n in network.nodes() if isinstance(n, Transceiver)] @@ -226,7 +226,7 @@ def compute_constrained_path(network, req): node = next(el for el in roadm if el.uid == f'roadm {n}') except StopIteration: try: - node = next(el for el in edfa + node = next(el for el in edfa if el.uid.startswith(f'egress edfa in {n}')) except StopIteration: msg = f'could not find node : {n} in network topology: \ @@ -257,7 +257,7 @@ def compute_constrained_path(network, req): # target=next(el for el in trx if el.uid == req.destination)): # print([e.uid for e in p if isinstance(e,Roadm)]) - return total_path + return total_path def propagate(path, req, equipment, show=False): #update roadm loss in case of power sweep (power mode only) @@ -269,13 +269,13 @@ def propagate(path, req, equipment, show=False): si = el(si) if show : print(el) - return path + return path def jsontocsv(json_data,equipment,fileout): # read json path result file in accordance with: # Yang model for requesting Path Computation - # draft-ietf-teas-yang-path-computation-01.txt. + # draft-ietf-teas-yang-path-computation-01.txt. # and write results in an CSV file mywriter = writer(fileout) @@ -290,32 +290,32 @@ def jsontocsv(json_data,equipment,fileout): ['path-route-object']['unnumbered-hop']['node-id'] destination = p['path-properties']['path-route-objects'][-1]\ ['path-route-object']['unnumbered-hop']['node-id'] - pth = ' | '.join([ e['path-route-object']['unnumbered-hop']['node-id'] + pth = ' | '.join([ e['path-route-object']['unnumbered-hop']['node-id'] for e in p['path-properties']['path-route-objects']]) [tsp,mode] = p['path-properties']['path-route-objects'][0]\ ['path-route-object']['unnumbered-hop']['hop-type'].split(' - ') - + # find the min acceptable OSNR, baud rate from the eqpt library based on tsp (tupe) and mode (format) try: - [minosnr, baud_rate] = next([m['OSNR'] , m['baud_rate']] + [minosnr, baud_rate] = next([m['OSNR'] , m['baud_rate']] for m in equipment['Transceiver'][tsp].mode if m['format']==mode) # for debug # print(f'coucou {baud_rate}') except IndexError: msg = f'could not find tsp : {self.tsp} with mode: {self.tsp_mode} in eqpt library' - + raise ValueError(msg) - output_snr = next(e['accumulative-value'] + output_snr = next(e['accumulative-value'] for e in p['path-properties']['path-metric'] if e['metric-type'] == 'SNR@0.1nm') - output_snrbandwidth = next(e['accumulative-value'] + output_snrbandwidth = next(e['accumulative-value'] for e in p['path-properties']['path-metric'] if e['metric-type'] == 'SNR@bandwidth') - output_osnr = next(e['accumulative-value'] + output_osnr = next(e['accumulative-value'] for e in p['path-properties']['path-metric'] if e['metric-type'] == 'OSNR@0.1nm') - output_osnrbandwidth = next(e['accumulative-value'] + output_osnrbandwidth = next(e['accumulative-value'] for e in p['path-properties']['path-metric'] if e['metric-type'] == 'OSNR@bandwidth') - power = next(e['accumulative-value'] + power = next(e['accumulative-value'] for e in p['path-properties']['path-metric'] if e['metric-type'] == 'reference_power') if isinstance(output_snr, str): isok = '' @@ -333,5 +333,5 @@ def jsontocsv(json_data,equipment,fileout): output_osnr, output_snrbandwidth, output_snr, - isok - )) \ No newline at end of file + isok + )) diff --git a/gnpy/core/utils.py b/gnpy/core/utils.py index c1e1e439..96d1716f 100644 --- a/gnpy/core/utils.py +++ b/gnpy/core/utils.py @@ -61,10 +61,10 @@ def write_csv(obj, filename): #main header w.writerow([data_key]) #sub headers: - headers = [_ for _ in data_list[0].keys()] + headers = [_ for _ in data_list[0].keys()] w.writerow(headers) for data_dict in data_list: - w.writerow([_ for _ in data_dict.values()]) + w.writerow([_ for _ in data_dict.values()]) def c(): """