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