From cf5675876c163f39706b1fb0d0e4ab706260af1b Mon Sep 17 00:00:00 2001 From: lantz Date: Fri, 21 Apr 2023 17:37:09 -0700 Subject: [PATCH] update CI workflows: update/fix codecheck; remove Ubuntu 18.04 (#1167) 1. update/fix codecheck Run workflow with pylint 2.15.7 Add a bunch of fiddly and mostly cosmetic changes to make pylint (and make codecheck) happy. Also try to run pyflakes3 vs. pyflakes 2. remove Ubuntu 18.04 Ubuntu 18.04 has been removed from github actions, so we remove it from our workflow as well --- .github/workflows/code-check.yaml | 2 +- .github/workflows/run-tests.yaml | 2 +- .pylint | 27 ++++---- Makefile | 4 +- bin/mn | 5 +- examples/baresshd.py | 5 +- examples/cluster.py | 12 ++-- examples/consoles.py | 15 +++-- examples/linearbandwidth.py | 3 +- examples/miniedit.py | 108 ++++++++++++++---------------- examples/multiping.py | 4 +- examples/multipoll.py | 7 +- examples/treeping64.py | 3 +- mininet/clean.py | 4 +- mininet/cli.py | 18 ++--- mininet/link.py | 11 ++- mininet/net.py | 2 +- mininet/node.py | 6 +- mininet/test/test_walkthrough.py | 3 +- mininet/topo.py | 6 +- mininet/topolib.py | 6 +- mininet/util.py | 18 +++-- 22 files changed, 142 insertions(+), 129 deletions(-) diff --git a/.github/workflows/code-check.yaml b/.github/workflows/code-check.yaml index fd35ce4..824e335 100644 --- a/.github/workflows/code-check.yaml +++ b/.github/workflows/code-check.yaml @@ -17,6 +17,6 @@ jobs: - name: Install Mininet code check dependencies run: | PYTHON=`which python` util/install.sh -n - python -m pip install pylint==2.4.4 + python -m pip install pylint==2.15.7 - name: Run code check run: make codecheck diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 4b33f67..e45f531 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, ubuntu-18.04] + os: [ubuntu-20.04] python-version: [3.x, 2.x] steps: - name: Check out Mininet source diff --git a/.pylint b/.pylint index a61fce1..016b1d4 100644 --- a/.pylint +++ b/.pylint @@ -16,7 +16,7 @@ #init-hook= # Profiled execution. -profile=no +#profile=no # Add to the black list. It should be a base name, not a # path. You may set this option multiple times. @@ -45,12 +45,13 @@ load-plugins= # Note: we may want to re-enable some of these at some point, but many of them # are just style issues rather than errors. # -disable=pointless-except, invalid-name, super-init-not-called, fixme, star-args, +disable=invalid-name, super-init-not-called, fixme, too-many-instance-attributes, too-few-public-methods, - too-many-locals, too-many-public-methods, duplicate-code, bad-whitespace, - locally-disabled, locally-enabled, bad-continuation, + too-many-locals, too-many-public-methods, duplicate-code, + locally-disabled, useless-object-inheritance, unnecessary-pass, no-else-return, - no-else-raise, no-else-continue, super-with-arguments + no-else-raise, no-else-continue, super-with-arguments, + consider-using-f-string, unspecified-encoding # bad-continuation, wrong-import-order @@ -62,12 +63,12 @@ output-format=colorized msg-template='{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}' # Include message's id in output -include-ids=yes +# include-ids=yes # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". -files-output=no +# files-output=no # Tells whether to display a full report or only the messages reports=no @@ -81,7 +82,7 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme # Add a comment according to your evaluation note. This is used by the global # evaluation report (R0004). -comment=no +#comment=no # Enable the report(s) with the given id(s). #enable-report= @@ -103,7 +104,7 @@ comment=no [BASIC] # Required attributes for module, separated by a comma -required-attributes= +#required-attributes= # Regular expression which should only match functions or classes name which do # not require a docstring @@ -144,7 +145,7 @@ good-names=i,j,k,ex,Run,_ bad-names=foo,bar,baz,toto,tutu,tata # List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,apply,inpu +#bad-functions=map,filter,apply,inpu # try to find bugs in the code using type inference @@ -161,7 +162,7 @@ ignored-classes=SQLObjec # When zope mode is activated, add a predefined set of Zope acquired attributes # to generated-members. -zope=no +#zope=no # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. @@ -199,7 +200,7 @@ additional-builtins= # List of interface methods to ignore, separated by a comma. This is used for # instance to not check methods defines in Zope's Interface base class. -ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by +#ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp,build @@ -221,7 +222,7 @@ max-locals=15 max-returns=6 # Maximum number of branch for function / method body -max-branchs=12 +#max-branchs=12 # Maximum number of statements in function / method body max-statements=50 diff --git a/Makefile b/Makefile index bffc9bb..0fb1f84 100644 --- a/Makefile +++ b/Makefile @@ -26,14 +26,14 @@ clean: codecheck: $(PYSRC) -echo "Running code check" util/versioncheck.py - pyflakes $(PYSRC) + pyflakes3 $(PYSRC) || pyflakes $(PYSRC) pylint --rcfile=.pylint $(PYSRC) # Exclude miniedit from pep8 checking for now pep8 --repeat --ignore=$(P8IGN) `ls $(PYSRC) | grep -v miniedit.py` errcheck: $(PYSRC) -echo "Running check for errors only" - pyflakes $(PYSRC) + pyflakes3 $(PYSRC) || pyflakes $(PYSRC) pylint -E --rcfile=.pylint $(PYSRC) test: $(MININET) $(TEST) diff --git a/bin/mn b/bin/mn index ffbcb74..0893182 100755 --- a/bin/mn +++ b/bin/mn @@ -189,8 +189,9 @@ class MininetRunner( object ): customs = {} if os.path.isfile( fileName ): # pylint: disable=exec-used - exec( compile( open( fileName ).read(), fileName, 'exec' ), - customs, customs ) + with open( fileName ) as f: + exec( compile( f.read(), fileName, 'exec' ), + customs, customs ) for name, val in customs.items(): self.setCustom( name, val ) else: diff --git a/examples/baresshd.py b/examples/baresshd.py index c04db0e..2249ff7 100755 --- a/examples/baresshd.py +++ b/examples/baresshd.py @@ -27,9 +27,8 @@ h1.setIP( '10.0.0.1', 8 ) root.setIP( '10.0.0.2', 8 ) info( "*** Creating banner file\n" ) -f = open( '/tmp/%s.banner' % h1.name, 'w' ) -f.write( 'Welcome to %s at %s\n' % ( h1.name, h1.IP() ) ) -f.close() +with open( '/tmp/%s.banner' % h1.name, 'w' ) as f: + f.write( 'Welcome to %s at %s\n' % ( h1.name, h1.IP() ) ) info( "*** Running sshd\n" ) cmd = '/usr/sbin/sshd -o UseDNS=no -u0 -o "Banner /tmp/%s.banner"' % h1.name diff --git a/examples/cluster.py b/examples/cluster.py index 10bccc3..fce27bb 100755 --- a/examples/cluster.py +++ b/examples/cluster.py @@ -82,14 +82,13 @@ import sys import re from itertools import groupby from operator import attrgetter -from distutils.version import StrictVersion from mininet.node import Node, Host, OVSSwitch, Controller from mininet.link import Link, Intf from mininet.net import Mininet from mininet.topo import LinearTopo from mininet.topolib import TreeTopo -from mininet.util import quietRun, errRun, decode +from mininet.util import quietRun, errRun, decode, StrictVersion from mininet.examples.clustercli import CLI from mininet.log import setLogLevel, debug, info, error from mininet.clean import addCleanupCallback @@ -314,7 +313,7 @@ class RemoteOVSSwitch( RemoteMixin, OVSSwitch ): kwargs.update( batch=True ) super( RemoteOVSSwitch, self ).__init__( *args, **kwargs ) - def isOldOVS( self ): + def isOldOVS( self ): # pylint: disable=arguments-differ "Is remote switch using an old OVS version?" cls = type( self ) if self.server not in cls.OVSVersions: @@ -376,8 +375,9 @@ class RemoteLink( Link ): Link.stop( self ) self.tunnel = None - def makeIntfPair( self, intfname1, intfname2, addr1=None, addr2=None, - node1=None, node2=None, deleteIntfs=True ): + def makeIntfPair( self, # pylint: disable=arguments-renamed + intfname1, intfname2, addr1=None, addr2=None, + node1=None, node2=None, deleteIntfs=True ): """Create pair of interfaces intfname1: name of interface 1 intfname2: name of interface 2 @@ -781,7 +781,9 @@ class MininetCluster( Mininet ): "Popen() for server connections" assert self # please pylint old = signal( SIGINT, SIG_IGN ) + # pylint: disable=consider-using-with conn = Popen( cmd, stdin=PIPE, stdout=PIPE, close_fds=True ) + # pylint: enable=consider-using-with signal( SIGINT, old ) return conn diff --git a/examples/consoles.py b/examples/consoles.py index a9af8fb..b7ede10 100755 --- a/examples/consoles.py +++ b/examples/consoles.py @@ -69,7 +69,10 @@ class Console( Frame ): self.bindEvents() self.sendCmd( 'export TERM=dumb' ) - self.outputHook = None + def outputHook( _obj, _text): + return True + + self.outputHook = outputHook def makeWidgets( self ): "Make a label, a text area, and a scroll bar." @@ -111,10 +114,8 @@ class Console( Frame ): self.text.insert( 'end', text ) self.text.mark_set( 'insert', 'end' ) self.text.see( 'insert' ) - outputHook = lambda x, y: True # make pylint happier - if self.outputHook: - outputHook = self.outputHook - outputHook( self, text ) + if callable( self.outputHook ): + self.outputHook( self, text ) def handleKey( self, event ): "If it's an interactive command, send it to the node." @@ -294,10 +295,10 @@ class ConsoleApp( Frame ): 'switches': 'Switch', 'controllers': 'Controller' } - for name in titles: + for name, title in titles.items(): nodes = getattr( net, name ) frame, consoles = self.createConsoles( - cframe, nodes, width, titles[ name ] ) + cframe, nodes, width, title ) self.consoles[ name ] = Object( frame=frame, consoles=consoles ) self.selected = None self.select( 'hosts' ) diff --git a/examples/linearbandwidth.py b/examples/linearbandwidth.py index 6802e7e..437f0d1 100755 --- a/examples/linearbandwidth.py +++ b/examples/linearbandwidth.py @@ -83,9 +83,8 @@ def linearBandwidthTest( lengths ): output = quietRun( 'sysctl -w net.ipv4.tcp_congestion_control=reno' ) assert 'reno' in output - for datapath in switches: + for datapath, Switch in switches.items(): info( "*** testing", datapath, "datapath\n" ) - Switch = switches[ datapath ] results[ datapath ] = [] link = partial( TCLink, delay='30ms', bw=100 ) net = Mininet( topo=topo, switch=Switch, diff --git a/examples/miniedit.py b/examples/miniedit.py index 1dd00b2..082d4d4 100755 --- a/examples/miniedit.py +++ b/examples/miniedit.py @@ -18,16 +18,15 @@ import os import re import sys -from distutils.version import StrictVersion from functools import partial -from optparse import OptionParser +from optparse import OptionParser # pylint: disable=deprecated-module from subprocess import call from sys import exit # pylint: disable=redefined-builtin from mininet.log import info, debug, warn, setLogLevel from mininet.net import Mininet, VERSION from mininet.util import (netParse, ipAdd, quietRun, - buildTopo, custom, customClass ) + buildTopo, custom, customClass, StrictVersion ) from mininet.term import makeTerm, cleanUpScreens from mininet.node import (Controller, RemoteController, NOX, OVSController, CPULimitedHost, Host, Node, @@ -1363,7 +1362,7 @@ class MiniEdit( Frame ): # Tools for tool in self.tools: - cmd = ( lambda t=tool: self.activate( t ) ) + cmd = partial( self.activate, tool ) b = Button( toolbar, text=tool, font=self.smallFont, command=cmd) if tool in self.images: b.config( height=35, image=self.images[ tool ] ) @@ -1421,10 +1420,7 @@ class MiniEdit( Frame ): def convertJsonUnicode(self, text): "Some part of Mininet don't like Unicode" - try: - unicode - except NameError: - return text + unicode = globals.get( 'unicode', str ) if isinstance(text, dict): return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.items()} if isinstance(text, list): @@ -1635,10 +1631,10 @@ class MiniEdit( Frame ): hostsToSave = [] switchesToSave = [] controllersToSave = [] - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) - x1, y1 = self.canvas.coords( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) + x1, y1 = self.canvas.coords( item ) if 'Switch' in tags or 'LegacySwitch' in tags or 'LegacyRouter' in tags: nodeNum = self.switchOpts[name]['nodeNum'] nodeToSave = {'number':str(nodeNum), @@ -1683,14 +1679,13 @@ class MiniEdit( Frame ): savingDictionary['application'] = self.appPrefs try: - f = open(fileName, 'w') - f.write(json.dumps(savingDictionary, sort_keys=True, indent=4, separators=(',', ': '))) - # pylint: disable=broad-except - except Exception as er: + with open(fileName, 'w') as f: + f.write( + json.dumps(savingDictionary, + sort_keys=True, + indent=4, separators=(',', ': '))) + except Exception as er: # pylint: disable=broad-except warn( er, '\n' ) - # pylint: enable=broad-except - finally: - f.close() def exportScript( self ): "Export command." @@ -1702,7 +1697,7 @@ class MiniEdit( Frame ): fileName = tkFileDialog.asksaveasfilename(filetypes=myFormats ,title="Export the topology as...") if len(fileName ) > 0: # debug( "Now saving under %s\n" % fileName ) - f = open(fileName, 'w') + f = open(fileName, 'w') # pylint: disable=consider-using-with f.write("#!/usr/bin/env python\n") f.write("\n") @@ -1718,9 +1713,9 @@ class MiniEdit( Frame ): f.write("from subprocess import call\n") inBandCtrl = False - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Controller' in tags: opts = self.controllers[name] @@ -1746,9 +1741,9 @@ class MiniEdit( Frame ): f.write(" ipBase='"+self.appPrefs['ipBase']+"')\n") f.write("\n") f.write(" info( '*** Adding controller\\n' )\n") - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Controller' in tags: opts = self.controllers[name] @@ -1780,9 +1775,9 @@ class MiniEdit( Frame ): # Save Switches and Hosts f.write(" info( '*** Add switches\\n')\n") - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'LegacyRouter' in tags: f.write(" "+name+" = net.addHost('"+name+"', cls=Node, ip='0.0.0.0')\n") f.write(" "+name+".cmd('sysctl -w net.ipv4.ip_forward=1')\n") @@ -1820,9 +1815,9 @@ class MiniEdit( Frame ): f.write("\n") f.write(" info( '*** Add hosts\\n')\n") - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Host' in tags: opts = self.hostOpts[name] ip = None @@ -1915,9 +1910,9 @@ class MiniEdit( Frame ): f.write("\n") f.write(" info( '*** Starting switches\\n')\n") - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Switch' in tags or 'LegacySwitch' in tags: opts = self.switchOpts[name] ctrlList = ",".join(opts['controllers']) @@ -1926,9 +1921,9 @@ class MiniEdit( Frame ): f.write("\n") f.write(" info( '*** Post configure switches and hosts\\n')\n") - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Switch' in tags: opts = self.switchOpts[name] if opts['switchType'] == 'default': @@ -1956,9 +1951,9 @@ class MiniEdit( Frame ): if 'switchIP' in opts: if len(opts['switchIP']) > 0: f.write(" "+name+".cmd('ifconfig "+name+" "+opts['switchIP']+"')\n") - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Host' in tags: opts = self.hostOpts[name] # Attach vlan interfaces @@ -1980,9 +1975,9 @@ class MiniEdit( Frame ): if len(nflowValues['nflowTarget']) > 0: nflowEnabled = False nflowSwitches = '' - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Switch' in tags: opts = self.switchOpts[name] @@ -2004,9 +1999,9 @@ class MiniEdit( Frame ): if len(sflowValues['sflowTarget']) > 0: sflowEnabled = False sflowSwitches = '' - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Switch' in tags: opts = self.switchOpts[name] @@ -2021,9 +2016,9 @@ class MiniEdit( Frame ): f.write("\n") f.write(" CLI(net)\n") - for widget in self.widgetToItem: + for widget, item in self.widgetToItem: name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Host' in tags: opts = self.hostOpts[name] # Run User Defined Stop Command @@ -2445,7 +2440,8 @@ class MiniEdit( Frame ): line3.pack(pady=10 ) line4.pack(pady=10 ) line5.pack(pady=10 ) - hide = ( lambda about=about: about.withdraw() ) + def hide(): + about.withdraw() self.aboutBox = about # Hide on close rather than destroying window Wm.wm_protocol( about, name='WM_DELETE_WINDOW', func=hide ) @@ -2620,9 +2616,9 @@ class MiniEdit( Frame ): info( 'New controller details for ' + name + ' = ' + str(self.controllers[name]), '\n' ) # Find references to controller and change name if oldName != name: - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): switchName = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Switch' in tags: switch = self.switchOpts[switchName] if oldName in switch['controllers']: @@ -2703,9 +2699,9 @@ class MiniEdit( Frame ): tags = self.canvas.gettags(item) if 'Controller' in tags: # remove from switch controller lists - for searchwidget in self.widgetToItem: + for searchwidget, searchitem in self.widgetToItem.items(): name = searchwidget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ searchwidget ] ) + tags = self.canvas.gettags( searchitem ) if 'Switch' in tags: if widget['text'] in self.switchOpts[name]['controllers']: self.switchOpts[name]['controllers'].remove(widget['text']) @@ -2718,9 +2714,9 @@ class MiniEdit( Frame ): def buildNodes( self, net): # Make nodes info( "Getting Hosts and Switches.\n" ) - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) # debug( name+' has '+str(tags), '\n' ) if 'Switch' in tags: @@ -2934,9 +2930,9 @@ class MiniEdit( Frame ): def postStartSetup( self ): # Setup host details - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Host' in tags: newHost = self.net.get(name) opts = self.hostOpts[name] @@ -2961,9 +2957,9 @@ class MiniEdit( Frame ): if len(nflowValues['nflowTarget']) > 0: nflowEnabled = False nflowSwitches = '' - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Switch' in tags: opts = self.switchOpts[name] @@ -2991,9 +2987,9 @@ class MiniEdit( Frame ): if len(sflowValues['sflowTarget']) > 0: sflowEnabled = False sflowSwitches = '' - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Switch' in tags: opts = self.switchOpts[name] @@ -3036,9 +3032,9 @@ class MiniEdit( Frame ): #for switch in self.net.switches: # info( switch.name + ' ') # switch.start( self.net.controllers ) - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Switch' in tags: opts = self.switchOpts[name] switchControllers = [] @@ -3058,9 +3054,9 @@ class MiniEdit( Frame ): "Stop network." if self.net is not None: # Stop host details - for widget in self.widgetToItem: + for widget, item in self.widgetToItem.items(): name = widget[ 'text' ] - tags = self.canvas.gettags( self.widgetToItem[ widget ] ) + tags = self.canvas.gettags( item ) if 'Host' in tags: newHost = self.net.get(name) opts = self.hostOpts[name] diff --git a/examples/multiping.py b/examples/multiping.py index 3700f9e..3196206 100755 --- a/examples/multiping.py +++ b/examples/multiping.py @@ -17,9 +17,9 @@ from mininet.topo import SingleSwitchTopo from mininet.log import info, setLogLevel -def chunks( l, n ): +def chunks( items, n ): "Divide list l into chunks of size n - thanks Stackoverflow" - return [ l[ i: i + n ] for i in range( 0, len( l ), n ) ] + return [ items[ i: i + n ] for i in range( 0, len( items ), n ) ] def startpings( host, targetips ): "Tell host to repeatedly ping targets" diff --git a/examples/multipoll.py b/examples/multipoll.py index fcf63ed..76ff0a0 100755 --- a/examples/multipoll.py +++ b/examples/multipoll.py @@ -18,11 +18,12 @@ from mininet.util import decode def monitorFiles( outfiles, seconds, timeoutms ): "Monitor set of files and return [(host, line)...]" - devnull = open( '/dev/null', 'w' ) + devnull = open( '/dev/null', 'w' ) # pylint: disable=consider-using-with tails, fdToFile, fdToHost = {}, {}, {} for h, outfile in outfiles.items(): - tail = Popen( [ 'tail', '-f', outfile ], - stdout=PIPE, stderr=devnull ) + tail = Popen( # pylint: disable=consider-using-with + [ 'tail', '-f', outfile ], + stdout=PIPE, stderr=devnull ) fd = tail.stdout.fileno() tails[ h ] = tail fdToFile[ fd ] = tail.stdout diff --git a/examples/treeping64.py b/examples/treeping64.py index 3f86679..770e389 100755 --- a/examples/treeping64.py +++ b/examples/treeping64.py @@ -25,9 +25,8 @@ def treePing64(): switches = { 'reference user': UserSwitch, 'Open vSwitch kernel': OVSKernelSwitch } - for name in switches: + for name, switch in switches.items(): info( "*** Testing", name, "datapath\n" ) - switch = switches[ name ] network = TreeNet( depth=2, fanout=8, switch=switch, waitConnected=True ) result = network.run( network.pingAll ) diff --git a/mininet/clean.py b/mininet/clean.py index f66d633..ea9d81c 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -21,7 +21,9 @@ from mininet.util import decode def sh( cmd ): "Print a command and send it to the shell" info( cmd + '\n' ) - result = Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ] + p = Popen( # pylint: disable=consider-using-with + [ '/bin/sh', '-c', cmd ], stdout=PIPE ) + result = p.communicate()[ 0 ] return decode( result ) def killprocs( pattern ): diff --git a/mininet/cli.py b/mininet/cli.py index 2356b4a..e39965c 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -150,7 +150,7 @@ class CLI( Cmd ): ' mininet> xterm h2\n\n' ) - def do_help( self, line ): # pylint: disable=arguments-differ + def do_help( self, line ): # pylint: disable=arguments-renamed "Describe available CLI commands." Cmd.do_help( self, line ) if line == '': @@ -352,13 +352,13 @@ class CLI( Cmd ): error( 'usage: source \n' ) return try: - self.inputFile = open( args[ 0 ] ) - while True: - line = self.inputFile.readline() - if len( line ) > 0: - self.onecmd( line ) - else: - break + with open( args[ 0 ] ) as self.inputFile: + while True: + line = self.inputFile.readline() + if len( line ) > 0: + self.onecmd( line ) + else: + break except IOError: error( 'error reading file %s\n' % args[ 0 ] ) self.inputFile.close() @@ -456,12 +456,14 @@ class CLI( Cmd ): try: bothPoller.poll() # XXX BL: this doesn't quite do what we want. + # pylint: disable=condition-evals-to-constant if False and self.inputFile: key = self.inputFile.read( 1 ) if key != '': node.write( key ) else: self.inputFile = None + # pylint: enable=condition-evals-to-constant if isReadable( self.inPoller ): key = self.stdin.read( 1 ) node.write( key ) diff --git a/mininet/link.py b/mininet/link.py index 56912f7..3b0e13a 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -316,8 +316,9 @@ class TCIntf( Intf ): debug(" *** executing command: %s\n" % c) return self.cmd( c ) - # pylint: disable=arguments-differ - def config( self, bw=None, delay=None, jitter=None, loss=None, + def config( # pylint: disable=arguments-renamed,arguments-differ + self, + bw=None, delay=None, jitter=None, loss=None, gro=False, txo=True, rxo=True, speedup=0, use_hfsc=False, use_tbf=False, latency_ms=None, enable_ecn=False, enable_red=False, @@ -539,9 +540,7 @@ class OVSLink( Link ): def __init__( self, node1, node2, **kwargs ): "See Link.__init__() for options" - try: - OVSSwitch - except NameError: + if 'OVSSwitch' not in globals(): # pylint: disable=import-outside-toplevel,cyclic-import from mininet.node import OVSSwitch self.isPatchLink = False @@ -551,7 +550,7 @@ class OVSLink( Link ): kwargs.update( cls1=OVSIntf, cls2=OVSIntf ) Link.__init__( self, node1, node2, **kwargs ) - # pylint: disable=arguments-differ, signature-differs + # pylint: disable=arguments-renamed, arguments-differ, signature-differs def makeIntfPair( self, *args, **kwargs ): "Usually delegated to OVSSwitch" if self.isPatchLink: diff --git a/mininet/net.py b/mininet/net.py index b4e0be9..eccd32f 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -201,7 +201,7 @@ class Mininet( object ): sleep( delay ) time += delay warn( 'Timed out after %d seconds\n' % time ) - for switch in remaining: + for switch in remaining.copy(): if not switch.connected(): warn( 'Warning: %s is not connected to a controller\n' % switch.name ) diff --git a/mininet/node.py b/mininet/node.py index 4ae0edc..2c37b5b 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -57,7 +57,6 @@ import pty import re import signal import select -from distutils.version import StrictVersion from re import findall from subprocess import Popen, PIPE from sys import exit # pylint: disable=redefined-builtin @@ -66,7 +65,8 @@ from time import sleep from mininet.log import info, error, warn, debug from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin, numCores, retry, mountCgroups, BaseString, decode, - encode, getincrementaldecoder, Python3, which ) + encode, getincrementaldecoder, Python3, which, + StrictVersion ) from mininet.moduledeps import moduleDeps, pathCheck, TUN from mininet.link import Link, Intf, TCIntf, OVSIntf @@ -219,7 +219,7 @@ class Node( object ): params: parameters to Popen()""" # Leave this is as an instance method for now assert self - popen = Popen( cmd, **params ) + popen = Popen( cmd, **params ) # pylint: disable=consider-using-with debug( '_popen', cmd, popen.pid ) return popen diff --git a/mininet/test/test_walkthrough.py b/mininet/test/test_walkthrough.py index 7ed67fe..77e77f7 100755 --- a/mininet/test/test_walkthrough.py +++ b/mininet/test/test_walkthrough.py @@ -10,10 +10,9 @@ import os import re import unittest -from distutils.version import StrictVersion from sys import stdout -from mininet.util import quietRun, pexpect +from mininet.util import quietRun, pexpect, StrictVersion from mininet.clean import cleanup diff --git a/mininet/topo.py b/mininet/topo.py index 21f1dcf..f79fe23 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -336,9 +336,11 @@ class LinearTopo( Topo ): self.n = n if n == 1: - genHostName = lambda i, j: 'h%s' % i + def genHostName( i, _j ): + return 'h%s' % i else: - genHostName = lambda i, j: 'h%ss%d' % ( j, i ) + def genHostName( i, j ): + return 'h%ss%d' % ( j, i ) lastSwitch = None for i in irange( 1, k ): diff --git a/mininet/topolib.py b/mininet/topolib.py index 9a05617..d60e59a 100644 --- a/mininet/topolib.py +++ b/mininet/topolib.py @@ -53,9 +53,11 @@ class TorusTopo( Topo ): raise Exception( 'Please use 3x3 or greater for compatibility ' 'with 2.1' ) if n == 1: - genHostName = lambda loc, k: 'h%s' % ( loc ) + def genHostName( loc, _k ): + return 'h%s' % ( loc ) else: - genHostName = lambda loc, k: 'h%sx%d' % ( loc, k ) + def genHostName( loc, k ): + return 'h%sx%d' % ( loc, k ) hosts, switches, dpid = {}, {}, 0 # Create and wire interior diff --git a/mininet/util.py b/mininet/util.py index 36b5d24..feffc48 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -46,6 +46,7 @@ if Python3: "Encode buffer for Python 3" return buf.encode( Encoding ) getincrementaldecoder = codecs.getincrementaldecoder( Encoding ) + else: decode, encode = NullCodec.decode, NullCodec.encode @@ -54,11 +55,16 @@ else: return NullCodec try: - # pylint: disable=import-error + import packaging.version # replacement for distutils.version + StrictVersion = packaging.version.parse +except ImportError: # python2.7 lacks ModuleNotFoundError + import distutils.version # pylint: disable=deprecated-module + StrictVersion = distutils.version.StrictVersion + +try: oldpexpect = None - import pexpect as oldpexpect + import pexpect as oldpexpect # pylint: disable=import-error - # pylint: enable=import-error class Pexpect( object ): "Custom pexpect that is compatible with str" @staticmethod @@ -97,11 +103,12 @@ def oldQuietRun( *cmd ): cmd = cmd[ 0 ] if isinstance( cmd, BaseString ): cmd = cmd.split( ' ' ) - popen = Popen( cmd, stdout=PIPE, stderr=STDOUT ) + out = '' + popen = Popen( # pylint: disable=consider-using-with + cmd, stdout=PIPE, stderr=STDOUT ) # We can't use Popen.communicate() because it uses # select(), which can't handle # high file descriptor numbers! poll() can, however. - out = '' readable = poll() readable.register( popen.stdout ) while True: @@ -142,6 +149,7 @@ def errRun( *cmd, **kwargs ): elif isinstance( cmd, list ) and shell: cmd = " ".join( arg for arg in cmd ) debug( '*** errRun:', cmd, '\n' ) + # pylint: disable=consider-using-with popen = Popen( cmd, stdout=PIPE, stderr=stderr, shell=shell ) # We use poll() because select() doesn't work with large fd numbers, # and thus communicate() doesn't work either