From: Giacomo Travaglini Date: Mon, 2 Mar 2020 14:30:25 +0000 (+0000) Subject: misc: Views and Iterators instead of Lists in python3 X-Git-Tag: v20.0.0.0~348 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=10b484240733131fea4f10d4605285106e0ab890;p=gem5.git misc: Views and Iterators instead of Lists in python3 * dict methods dict.keys(), dict.items() and dict.values() return "views" instead of lists * The dict.iterkeys(), dict.iteritems() and dict.itervalues() methods are no longer supported. * map() and filter() return iterators. * range() now behaves like xrange() used to behave, except it works with values of arbitrary size. The latter no longer exists. * zip() now returns an iterator. Change-Id: Id480018239db88d7f5d60588c93719056de4a0c0 Signed-off-by: Giacomo Travaglini Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/26248 Reviewed-by: Gabe Black Maintainer: Gabe Black Tested-by: kokoro --- diff --git a/SConstruct b/SConstruct index eb6b08984..110f9c896 100755 --- a/SConstruct +++ b/SConstruct @@ -677,10 +677,12 @@ if main['USE_PYTHON']: print("Info: Using Python config: %s" % (python_config, )) py_includes = readCommand([python_config, '--includes'], exception='').split() - py_includes = filter(lambda s: match(r'.*\/include\/.*',s), py_includes) + py_includes = list(filter( + lambda s: match(r'.*\/include\/.*',s), py_includes)) # Strip the -I from the include folders before adding them to the # CPPPATH - py_includes = map(lambda s: s[2:] if s.startswith('-I') else s, py_includes) + py_includes = list(map( + lambda s: s[2:] if s.startswith('-I') else s, py_includes)) main.Append(CPPPATH=py_includes) # Read the linker flags and split them into libraries and other link @@ -966,7 +968,7 @@ sticky_vars.AddVariables( EnumVariable('TARGET_ISA', 'Target ISA', 'alpha', all_isa_list), EnumVariable('TARGET_GPU_ISA', 'Target GPU ISA', 'hsail', all_gpu_isa_list), ListVariable('CPU_MODELS', 'CPU models', - sorted(n for n,m in CpuModel.dict.iteritems() if m.default), + sorted(n for n,m in CpuModel.dict.items() if m.default), sorted(CpuModel.dict.keys())), BoolVariable('EFENCE', 'Link with Electric Fence malloc debugger', False), @@ -1187,7 +1189,7 @@ for variant_path in variant_paths: joinpath(opts_dir, default)] else: default_vars_files = [joinpath(opts_dir, variant_dir)] - existing_files = filter(isfile, default_vars_files) + existing_files = list(filter(isfile, default_vars_files)) if existing_files: default_vars_file = existing_files[0] sticky_vars.files.append(default_vars_file) diff --git a/site_scons/gem5_scons/__init__.py b/site_scons/gem5_scons/__init__.py index 86494cf6a..16bb753af 100644 --- a/site_scons/gem5_scons/__init__.py +++ b/site_scons/gem5_scons/__init__.py @@ -83,10 +83,10 @@ class Transform(object): def strip(f): return strip_build_path(str(f), env) if len(source) > 0: - srcs = map(strip, source) + srcs = list(map(strip, source)) else: srcs = [''] - tgts = map(strip, target) + tgts = list(map(strip, target)) # surprisingly, os.path.commonprefix is a dumb char-by-char string # operation that has nothing to do with paths. com_pfx = os.path.commonprefix(srcs + tgts) @@ -123,7 +123,7 @@ class Transform(object): # recalculate length in case com_pfx was modified com_pfx_len = len(com_pfx) def fmt(files): - f = map(lambda s: s[com_pfx_len:], files) + f = list(map(lambda s: s[com_pfx_len:], files)) return ', '.join(f) return self.format % (com_pfx, fmt(srcs), fmt(tgts)) diff --git a/src/SConscript b/src/SConscript index 0797dba0d..d377ff5e0 100644 --- a/src/SConscript +++ b/src/SConscript @@ -265,7 +265,7 @@ def blobToCpp(data, symbol, cpp_code, hpp_code=None, namespace=None): cpp_code(symbol_declaration + ' = {') cpp_code.indent() step = 16 - for i in xrange(0, len(data), step): + for i in six.moves.range(0, len(data), step): x = array.array('B', data[i:i+step]) cpp_code(''.join('%d,' % d for d in x)) cpp_code.dedent() @@ -661,7 +661,7 @@ def makeTheISA(source, target, env): code.write(str(target[0])) -env.Command('config/the_isa.hh', map(Value, all_isa_list), +env.Command('config/the_isa.hh', list(map(Value, all_isa_list)), MakeAction(makeTheISA, Transform("CFG ISA", 0))) def makeTheGPUISA(source, target, env): @@ -706,7 +706,7 @@ def makeTheGPUISA(source, target, env): code.write(str(target[0])) -env.Command('config/the_gpu_isa.hh', map(Value, all_gpu_isa_list), +env.Command('config/the_gpu_isa.hh', list(map(Value, all_gpu_isa_list)), MakeAction(makeTheGPUISA, Transform("CFG ISA", 0))) ######################################################################## @@ -797,7 +797,7 @@ sys.meta_path.remove(importer) sim_objects = m5.SimObject.allClasses all_enums = m5.params.allEnums -for name,obj in sorted(sim_objects.iteritems()): +for name,obj in sorted(sim_objects.items()): for param in obj._params.local.values(): # load the ptype attribute now because it depends on the # current version of SimObject.allClasses, but when scons @@ -920,7 +920,7 @@ def createSimObjectPyBindWrapper(target, source, env): # Generate all of the SimObject param C++ struct header files params_hh_files = [] -for name,simobj in sorted(sim_objects.iteritems()): +for name,simobj in sorted(sim_objects.items()): py_source = PySource.modules[simobj.__module__] extra_deps = [ py_source.tnode ] @@ -932,7 +932,7 @@ for name,simobj in sorted(sim_objects.iteritems()): # C++ parameter description files if GetOption('with_cxx_config'): - for name,simobj in sorted(sim_objects.iteritems()): + for name,simobj in sorted(sim_objects.items()): py_source = PySource.modules[simobj.__module__] extra_deps = [ py_source.tnode ] @@ -957,14 +957,14 @@ if GetOption('with_cxx_config'): code = code_formatter() - for name,simobj in sorted(sim_objects.iteritems()): + for name,simobj in sorted(sim_objects.items()): if not hasattr(simobj, 'abstract') or not simobj.abstract: code('#include "cxx_config/${name}.hh"') code() code('void cxxConfigInit()') code('{') code.indent() - for name,simobj in sorted(sim_objects.iteritems()): + for name,simobj in sorted(sim_objects.items()): not_abstract = not hasattr(simobj, 'abstract') or \ not simobj.abstract if not_abstract and 'type' in simobj.__dict__: @@ -979,14 +979,14 @@ if GetOption('with_cxx_config'): env.Command(cxx_config_init_cc_file, Value(name), MakeAction(createCxxConfigInitCC, Transform("CXXCINIT"))) cxx_param_hh_files = ["cxx_config/%s.hh" % simobj - for name,simobj in sorted(sim_objects.iteritems()) + for name,simobj in sorted(sim_objects.items()) if not hasattr(simobj, 'abstract') or not simobj.abstract] Depends(cxx_config_init_cc_file, cxx_param_hh_files + [File('sim/cxx_config.hh')]) Source(cxx_config_init_cc_file) # Generate all enum header files -for name,enum in sorted(all_enums.iteritems()): +for name,enum in sorted(all_enums.items()): py_source = PySource.modules[enum.__module__] extra_deps = [ py_source.tnode ] @@ -1003,7 +1003,7 @@ for name,enum in sorted(all_enums.iteritems()): # Generate SimObject Python bindings wrapper files if env['USE_PYTHON']: - for name,simobj in sorted(sim_objects.iteritems()): + for name,simobj in sorted(sim_objects.items()): py_source = PySource.modules[simobj.__module__] extra_deps = [ py_source.tnode ] cc_file = File('python/_m5/param_%s.cc' % name) @@ -1055,7 +1055,7 @@ namespace Debug { ''') - for name, flag in sorted(source[0].read().iteritems()): + for name, flag in sorted(source[0].read().items()): n, compound, desc = flag assert n == name @@ -1117,7 +1117,7 @@ namespace Debug { code.write(str(target[0])) -for name,flag in sorted(debug_flags.iteritems()): +for name,flag in sorted(debug_flags.items()): n, compound, desc = flag assert n == name diff --git a/src/arch/arm/fastmodel/SConscript b/src/arch/arm/fastmodel/SConscript index f5c039d08..2fd4ba0c2 100644 --- a/src/arch/arm/fastmodel/SConscript +++ b/src/arch/arm/fastmodel/SConscript @@ -270,8 +270,8 @@ class ArmFastModelComponent(object): '%s-%s' % (tlc, config_name), ] - static_lib_nodes = map(simgen_static, static_libs) - shared_lib_nodes = map(simgen_shared, shared_libs) + static_lib_nodes = list(map(simgen_static, static_libs)) + shared_lib_nodes = list(map(simgen_shared, shared_libs)) # We need to use the static libraries as files so that the linker # doesn't use the shared versions of them instead. We need to use # the shared libraries by name so that the linker will apply RPATH diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa index 23b234a67..7aaca04f5 100644 --- a/src/arch/arm/isa/formats/aarch64.isa +++ b/src/arch/arm/isa/formats/aarch64.isa @@ -3005,7 +3005,7 @@ let {{ decoder_output =''' namespace Aarch64 {''' - for decoderFlavor, type_dict in decoders.iteritems(): + for decoderFlavor, type_dict in decoders.items(): decoder_output +=''' template StaticInstPtr decodeFpAdvSIMD<%(df)sDecoder>(ExtMachInst machInst); ''' % { "df" : decoderFlavor } diff --git a/src/arch/arm/isa/insts/neon64.isa b/src/arch/arm/isa/insts/neon64.isa index e1b0f441e..6db9e38dc 100644 --- a/src/arch/arm/isa/insts/neon64.isa +++ b/src/arch/arm/isa/insts/neon64.isa @@ -3385,12 +3385,12 @@ let {{ threeRegScrambleInstX("zip2", "Zip2QX", "SimdAluOp", unsignedTypes, 4, zipCode % "eCount / 2") - for decoderFlavor, type_dict in decoders.iteritems(): + for decoderFlavor, type_dict in decoders.items(): header_output += ''' class %(decoder_flavor)sDecoder { public: ''' % { "decoder_flavor" : decoderFlavor } - for type,name in type_dict.iteritems(): + for type,name in type_dict.items(): header_output += ''' template using %(type)s = %(new_name)s;''' % { "type" : type, "new_name" : name diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py index 49b3b0729..ef655d3cc 100755 --- a/src/arch/isa_parser.py +++ b/src/arch/isa_parser.py @@ -146,7 +146,7 @@ class Template(object): myDict.update(snippets) - compositeCode = ' '.join(map(str, snippets.values())) + compositeCode = ' '.join(list(map(str, snippets.values()))) # Add in template itself in case it references any # operands explicitly (like Mem) @@ -253,7 +253,7 @@ class Format(object): if debug: raise error(lineno, 'error defining "%s": %s.' % (name, exc)) - for k in vars.keys(): + for k in list(vars.keys()): if k not in ('header_output', 'decoder_output', 'exec_output', 'decode_block'): del vars[k] @@ -1415,7 +1415,7 @@ class InstObjParams(object): self.base_class = base_class if not isinstance(snippets, dict): snippets = {'code' : snippets} - compositeCode = ' '.join(map(str, snippets.values())) + compositeCode = ' '.join(list(map(str, snippets.values()))) self.snippets = snippets self.operands = OperandList(parser, compositeCode) @@ -1916,10 +1916,10 @@ class ISAParser(Grammar): def p_specification(self, t): 'specification : opt_defs_and_outputs top_level_decode_block' - for f in self.splits.iterkeys(): + for f in self.splits.keys(): f.write('\n#endif\n') - for f in self.files.itervalues(): # close ALL the files; + for f in self.files.values(): # close ALL the files; f.close() # not doing so can cause compilation to fail self.write_top_level_files() @@ -2368,7 +2368,7 @@ StaticInstPtr # Pass the ID and arg list to the current format class to deal with. currentFormat = self.formatStack.top() codeObj = currentFormat.defineInst(self, t[1], t[3], t.lexer.lineno) - args = ','.join(map(str, t[3])) + args = ','.join(list(map(str, t[3]))) args = re.sub('(?m)^', '//', args) args = re.sub('^//', '', args) comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args) @@ -2507,7 +2507,7 @@ StaticInstPtr def buildOperandNameMap(self, user_dict, lineno): operand_name = {} - for op_name, val in user_dict.iteritems(): + for op_name, val in user_dict.items(): # Check if extra attributes have been specified. if len(val) > 9: @@ -2580,7 +2580,7 @@ StaticInstPtr self.operandNameMap = operand_name # Define operand variables. - operands = user_dict.keys() + operands = list(user_dict.keys()) # Add the elems defined in the vector operands and # build a map elem -> vector (used in OperandList) elem_to_vec = {} diff --git a/src/arch/x86/isa/formats/multi.isa b/src/arch/x86/isa/formats/multi.isa index edc3326db..94859e628 100644 --- a/src/arch/x86/isa/formats/multi.isa +++ b/src/arch/x86/isa/formats/multi.isa @@ -49,7 +49,7 @@ def format Inst(*opTypeSet) {{ def format MultiInst(switchVal, *opTypeSets) {{ switcher = {} - for (count, opTypeSet) in zip(xrange(len(opTypeSets)), opTypeSets): + for (count, opTypeSet) in zip(range(len(opTypeSets)), opTypeSets): switcher[count] = (specializeInst, Name, opTypeSet, EmulEnv()) blocks = doSplitDecode(switchVal, switcher) (header_output, decoder_output, diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py index a92e078e2..65a906243 100644 --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -111,7 +111,7 @@ class StateMachine(Symbol): assert self.table is None # Check for duplicate action - for other in self.actions.itervalues(): + for other in self.actions.values(): if action.ident == other.ident: action.warning("Duplicate action definition: %s" % action.ident) action.error("Duplicate action definition: %s" % action.ident) @@ -186,7 +186,7 @@ class StateMachine(Symbol): table[index] = trans # Look at all actions to make sure we used them all - for action in self.actions.itervalues(): + for action in self.actions.values(): if not action.used: error_msg = "Unused action: %s" % action.ident if "desc" in action: @@ -402,23 +402,23 @@ void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); // Actions ''') if self.TBEType != None and self.EntryType != None: - for action in self.actions.itervalues(): + for action in self.actions.values(): code('/** \\brief ${{action.desc}} */') code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 'm_cache_entry_ptr, Addr addr);') elif self.TBEType != None: - for action in self.actions.itervalues(): + for action in self.actions.values(): code('/** \\brief ${{action.desc}} */') code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 'm_tbe_ptr, Addr addr);') elif self.EntryType != None: - for action in self.actions.itervalues(): + for action in self.actions.values(): code('/** \\brief ${{action.desc}} */') code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 'm_cache_entry_ptr, Addr addr);') else: - for action in self.actions.itervalues(): + for action in self.actions.values(): code('/** \\brief ${{action.desc}} */') code('void ${{action.ident}}(Addr addr);') @@ -937,7 +937,7 @@ $c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) // Actions ''') if self.TBEType != None and self.EntryType != None: - for action in self.actions.itervalues(): + for action in self.actions.values(): if "c_code" not in action: continue @@ -958,7 +958,7 @@ $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.Entry ''') elif self.TBEType != None: - for action in self.actions.itervalues(): + for action in self.actions.values(): if "c_code" not in action: continue @@ -973,7 +973,7 @@ $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr) ''') elif self.EntryType != None: - for action in self.actions.itervalues(): + for action in self.actions.values(): if "c_code" not in action: continue @@ -988,7 +988,7 @@ $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Add ''') else: - for action in self.actions.itervalues(): + for action in self.actions.values(): if "c_code" not in action: continue @@ -1330,7 +1330,7 @@ ${ident}_Controller::doTransitionWorker(${ident}_Event event, # Check for resources case_sorter = [] res = trans.resources - for key,val in res.iteritems(): + for key,val in res.items(): val = ''' if (!%s.areNSlotsAvailable(%s, clockEdge())) return TransitionResult_ResourceStall; @@ -1390,7 +1390,7 @@ if (!checkResourceAvailable(%s_RequestType_%s, addr)) { # Walk through all of the unique code blocks and spit out the # corresponding case statement elements - for case,transitions in cases.iteritems(): + for case,transitions in cases.items(): # Iterative over all the multiple transitions that share # the same code for trans in transitions: @@ -1428,23 +1428,23 @@ if (!checkResourceAvailable(%s_RequestType_%s, addr)) { self.printHTMLTransitions(path, None) # Generate transition tables - for state in self.states.itervalues(): + for state in self.states.values(): self.printHTMLTransitions(path, state) # Generate action descriptions - for action in self.actions.itervalues(): + for action in self.actions.values(): name = "%s_action_%s.html" % (self.ident, action.ident) code = html.createSymbol(action, "Action") code.write(path, name) # Generate state descriptions - for state in self.states.itervalues(): + for state in self.states.values(): name = "%s_State_%s.html" % (self.ident, state.ident) code = html.createSymbol(state, "State") code.write(path, name) # Generate event descriptions - for event in self.events.itervalues(): + for event in self.events.values(): name = "%s_Event_%s.html" % (self.ident, event.ident) code = html.createSymbol(event, "Event") code.write(path, name) @@ -1479,14 +1479,14 @@ if (!checkResourceAvailable(%s_RequestType_%s, addr)) { """) - for event in self.events.itervalues(): + for event in self.events.values(): href = "%s_Event_%s.html" % (self.ident, event.ident) ref = self.frameRef(href, "Status", href, "1", event.short) code('$ref') code('') # -- Body of table - for state in self.states.itervalues(): + for state in self.states.values(): # -- Each row if state == active_state: color = "yellow" @@ -1503,7 +1503,7 @@ if (!checkResourceAvailable(%s_RequestType_%s, addr)) { ''') # -- One column for each event - for event in self.events.itervalues(): + for event in self.events.values(): trans = self.table.get((state,event), None) if trans is None: # This is the no transition case @@ -1572,7 +1572,7 @@ if (!checkResourceAvailable(%s_RequestType_%s, addr)) { ''') - for event in self.events.itervalues(): + for event in self.events.values(): href = "%s_Event_%s.html" % (self.ident, event.ident) ref = self.frameRef(href, "Status", href, "1", event.short) code('$ref') diff --git a/src/mem/slicc/symbols/Transition.py b/src/mem/slicc/symbols/Transition.py index 3fd5a4401..8c0209454 100644 --- a/src/mem/slicc/symbols/Transition.py +++ b/src/mem/slicc/symbols/Transition.py @@ -54,7 +54,7 @@ class Transition(Symbol): self.resources = {} for action in self.actions: - for var,value in action.resources.iteritems(): + for var,value in action.resources.items(): num = int(value) if var in self.resources: num += int(value) diff --git a/src/mem/slicc/symbols/Type.py b/src/mem/slicc/symbols/Type.py index 8464544e9..fa5e79a74 100644 --- a/src/mem/slicc/symbols/Type.py +++ b/src/mem/slicc/symbols/Type.py @@ -269,7 +269,7 @@ $klass ${{self.c_ident}}$parent # ******** Full init constructor ******** if not self.isGlobal: params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \ - for dm in self.data_members.itervalues() ] + for dm in self.data_members.values() ] params = ', '.join(params) if self.isMessage: @@ -485,7 +485,7 @@ enum ${{self.c_ident}} { code.indent() # For each field - for i,(ident,enum) in enumerate(self.enums.iteritems()): + for i,(ident,enum) in enumerate(self.enums.items()): desc = enum.get("desc", "No description avaliable") if i == 0: init = ' = %s_FIRST' % self.c_ident @@ -530,7 +530,7 @@ int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); ''') - for enum in self.enums.itervalues(): + for enum in self.enums.values(): code(''' MachineID get${{enum.ident}}MachineID(NodeID RubyNode); @@ -594,7 +594,7 @@ AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj) ''') if self.isMachineType: - for enum in self.enums.itervalues(): + for enum in self.enums.values(): if enum.primary: code('#include "mem/ruby/protocol/${{enum.ident}}' '_Controller.hh"') @@ -619,7 +619,7 @@ ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) # For each field code.indent() - for enum in self.enums.itervalues(): + for enum in self.enums.values(): code(' case ${{self.c_ident}}_${{enum.ident}}:') code(' return "${{enum.ident}}";') code.dedent() @@ -640,7 +640,7 @@ string_to_${{self.c_ident}}(const string& str) # For each field start = "" code.indent() - for enum in self.enums.itervalues(): + for enum in self.enums.values(): code('${start}if (str == "${{enum.ident}}") {') code(' return ${{self.c_ident}}_${{enum.ident}};') start = "} else " @@ -679,7 +679,7 @@ ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) # For each field code.indent() - for i,enum in enumerate(self.enums.itervalues()): + for i,enum in enumerate(self.enums.values()): code(' case ${{self.c_ident}}_${{enum.ident}}:') code(' return $i;') code.dedent() @@ -706,7 +706,7 @@ ${{self.c_ident}}_from_base_level(int type) # For each field code.indent() - for i,enum in enumerate(self.enums.itervalues()): + for i,enum in enumerate(self.enums.values()): code(' case $i:') code(' return ${{self.c_ident}}_${{enum.ident}};') code.dedent() @@ -762,7 +762,7 @@ ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) ''') # For each field - for enum in self.enums.itervalues(): + for enum in self.enums.values(): code('case ${{self.c_ident}}_${{enum.ident}}:') if enum.primary: code('return ${{enum.ident}}_Controller::getNumControllers();') @@ -778,7 +778,7 @@ ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) } ''') - for enum in self.enums.itervalues(): + for enum in self.enums.values(): code(''' MachineID diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index 32ac7d1dd..a045fb7b0 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -686,7 +686,7 @@ class MetaSimObject(type): # the object itself, not including inherited params (which # will also be inherited from the base class's param struct # here). Sort the params based on their key - params = map(lambda k_v: k_v[1], sorted(cls._params.local.items())) + params = list(map(lambda k_v: k_v[1], sorted(cls._params.local.items()))) ports = cls._ports.local code('''#include "pybind11/pybind11.h" @@ -783,7 +783,7 @@ module_init(py::module &m_internal) # the object itself, not including inherited params (which # will also be inherited from the base class's param struct # here). Sort the params based on their key - params = map(lambda k_v: k_v[1], sorted(cls._params.local.items())) + params = list(map(lambda k_v: k_v[1], sorted(cls._params.local.items()))) ports = cls._ports.local try: ptypes = [p.ptype for p in params]