Kinder, gentler Python 3 compatibility
Looking at trying to minimize code changes for Python 3. For now we are keeping byte str() in py2 and unicode str() in py3. It's a pain to rewrite all string code to usee u'' for py2 compatibility. However we may need to revisit this for pexpect(). Created compatibility wrappers in util.py: BaseString (replacement for basestring) decode() (optionally decode utf-8 for py3) encode() (optionally encode utf-8 for py3) Also we've switched from the .iter*() flavors to their static alternatives for py2 (note they are iterators in py3!) Changed util.errRun and clean.sh to call decode()
This commit is contained in:
@@ -256,7 +256,7 @@ class MininetRunner( object ):
|
|||||||
opts.add_option( '--arp', action='store_true',
|
opts.add_option( '--arp', action='store_true',
|
||||||
default=False, help='set all-pairs ARP entries' )
|
default=False, help='set all-pairs ARP entries' )
|
||||||
opts.add_option( '--verbosity', '-v', type='choice',
|
opts.add_option( '--verbosity', '-v', type='choice',
|
||||||
choices=LEVELS.keys(), default = 'info',
|
choices=list( LEVELS.keys() ), default = 'info',
|
||||||
help = '|'.join( LEVELS.keys() ) )
|
help = '|'.join( LEVELS.keys() ) )
|
||||||
opts.add_option( '--innamespace', action='store_true',
|
opts.add_option( '--innamespace', action='store_true',
|
||||||
default=False, help='sw and ctrl in namespace?' )
|
default=False, help='sw and ctrl in namespace?' )
|
||||||
@@ -286,7 +286,7 @@ class MininetRunner( object ):
|
|||||||
metavar='server1,server2...',
|
metavar='server1,server2...',
|
||||||
help=( 'run on multiple servers (experimental!)' ) )
|
help=( 'run on multiple servers (experimental!)' ) )
|
||||||
opts.add_option( '--placement', type='choice',
|
opts.add_option( '--placement', type='choice',
|
||||||
choices=PLACEMENT.keys(), default='block',
|
choices=list( PLACEMENT.keys() ), default='block',
|
||||||
metavar='block|random',
|
metavar='block|random',
|
||||||
help=( 'node placement for --cluster '
|
help=( 'node placement for --cluster '
|
||||||
'(experimental!) ' ) )
|
'(experimental!) ' ) )
|
||||||
|
|||||||
+3
-3
@@ -16,12 +16,13 @@ import time
|
|||||||
|
|
||||||
from mininet.log import info
|
from mininet.log import info
|
||||||
from mininet.term import cleanUpScreens
|
from mininet.term import cleanUpScreens
|
||||||
|
from mininet.util import decode
|
||||||
|
|
||||||
def sh( cmd ):
|
def sh( cmd ):
|
||||||
"Print a command and send it to the shell"
|
"Print a command and send it to the shell"
|
||||||
info( cmd + '\n' )
|
info( cmd + '\n' )
|
||||||
return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
|
result = Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
|
||||||
|
return decode( result )
|
||||||
|
|
||||||
def killprocs( pattern ):
|
def killprocs( pattern ):
|
||||||
"Reliably terminate processes matching a pattern (including args)"
|
"Reliably terminate processes matching a pattern (including args)"
|
||||||
@@ -76,7 +77,6 @@ class Cleanup( object ):
|
|||||||
for dp in dps:
|
for dp in dps:
|
||||||
if dp:
|
if dp:
|
||||||
sh( 'dpctl deldp ' + dp )
|
sh( 'dpctl deldp ' + dp )
|
||||||
|
|
||||||
info( "*** Removing OVS datapaths\n" )
|
info( "*** Removing OVS datapaths\n" )
|
||||||
dps = sh("ovs-vsctl --timeout=1 list-br").strip().splitlines()
|
dps = sh("ovs-vsctl --timeout=1 list-br").strip().splitlines()
|
||||||
if dps:
|
if dps:
|
||||||
|
|||||||
+1
-1
@@ -164,7 +164,7 @@ class Intf( object ):
|
|||||||
method: config method name
|
method: config method name
|
||||||
param: arg=value (ignore if value=None)
|
param: arg=value (ignore if value=None)
|
||||||
value may also be list or dict"""
|
value may also be list or dict"""
|
||||||
name, value = param.items()[ 0 ]
|
name, value = list( param.items() )[ 0 ]
|
||||||
f = getattr( self, method, None )
|
f = getattr( self, method, None )
|
||||||
if not f or value is None:
|
if not f or value is None:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"Module dependency utility functions for Mininet."
|
"Module dependency utility functions for Mininet."
|
||||||
|
|
||||||
from mininet.util import quietRun
|
from mininet.util import quietRun, BaseString
|
||||||
from mininet.log import info, error, debug
|
from mininet.log import info, error, debug
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
@@ -28,9 +28,9 @@ def moduleDeps( subtract=None, add=None ):
|
|||||||
add: string or list of module names to add, if not already loaded"""
|
add: string or list of module names to add, if not already loaded"""
|
||||||
subtract = subtract if subtract is not None else []
|
subtract = subtract if subtract is not None else []
|
||||||
add = add if add is not None else []
|
add = add if add is not None else []
|
||||||
if isinstance( subtract, basestring ):
|
if isinstance( subtract, BaseString ):
|
||||||
subtract = [ subtract ]
|
subtract = [ subtract ]
|
||||||
if isinstance( add, basestring ):
|
if isinstance( add, BaseString ):
|
||||||
add = [ add ]
|
add = [ add ]
|
||||||
for mod in subtract:
|
for mod in subtract:
|
||||||
if mod in lsmod():
|
if mod in lsmod():
|
||||||
|
|||||||
+3
-3
@@ -104,7 +104,7 @@ from mininet.nodelib import NAT
|
|||||||
from mininet.link import Link, Intf
|
from mininet.link import Link, Intf
|
||||||
from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
|
from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
|
||||||
macColonHex, ipStr, ipParse, netParse, ipAdd,
|
macColonHex, ipStr, ipParse, netParse, ipAdd,
|
||||||
waitListening )
|
waitListening, BaseString )
|
||||||
from mininet.term import cleanUpScreens, makeTerms
|
from mininet.term import cleanUpScreens, makeTerms
|
||||||
|
|
||||||
# Mininet version: should be consistent with README and LICENSE
|
# Mininet version: should be consistent with README and LICENSE
|
||||||
@@ -383,8 +383,8 @@ class Mininet( object ):
|
|||||||
params: additional link params (optional)
|
params: additional link params (optional)
|
||||||
returns: link object"""
|
returns: link object"""
|
||||||
# Accept node objects or names
|
# Accept node objects or names
|
||||||
node1 = node1 if not isinstance( node1, basestring ) else self[ node1 ]
|
node1 = node1 if not isinstance( node1, BaseString ) else self[ node1 ]
|
||||||
node2 = node2 if not isinstance( node2, basestring ) else self[ node2 ]
|
node2 = node2 if not isinstance( node2, BaseString ) else self[ node2 ]
|
||||||
options = dict( params )
|
options = dict( params )
|
||||||
# Port is optional
|
# Port is optional
|
||||||
if port1 is not None:
|
if port1 is not None:
|
||||||
|
|||||||
+14
-11
@@ -62,7 +62,8 @@ from time import sleep
|
|||||||
|
|
||||||
from mininet.log import info, error, warn, debug
|
from mininet.log import info, error, warn, debug
|
||||||
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||||
numCores, retry, mountCgroups )
|
numCores, retry, mountCgroups, BaseString, decode,
|
||||||
|
encode )
|
||||||
from mininet.moduledeps import moduleDeps, pathCheck, TUN
|
from mininet.moduledeps import moduleDeps, pathCheck, TUN
|
||||||
from mininet.link import Link, Intf, TCIntf, OVSIntf
|
from mininet.link import Link, Intf, TCIntf, OVSIntf
|
||||||
from re import findall
|
from re import findall
|
||||||
@@ -144,7 +145,9 @@ class Node( object ):
|
|||||||
master, slave = pty.openpty()
|
master, slave = pty.openpty()
|
||||||
self.shell = self._popen( cmd, stdin=slave, stdout=slave, stderr=slave,
|
self.shell = self._popen( cmd, stdin=slave, stdout=slave, stderr=slave,
|
||||||
close_fds=False )
|
close_fds=False )
|
||||||
self.stdin = os.fdopen( master, 'rw' )
|
# XXX BL: This doesn't seem right, and we should also probably
|
||||||
|
# close our files when we exit...
|
||||||
|
self.stdin = os.fdopen( master, 'r' )
|
||||||
self.stdout = self.stdin
|
self.stdout = self.stdin
|
||||||
self.pid = self.shell.pid
|
self.pid = self.shell.pid
|
||||||
self.pollOut = select.poll()
|
self.pollOut = select.poll()
|
||||||
@@ -171,7 +174,7 @@ class Node( object ):
|
|||||||
def mountPrivateDirs( self ):
|
def mountPrivateDirs( self ):
|
||||||
"mount private directories"
|
"mount private directories"
|
||||||
# Avoid expanding a string into a list of chars
|
# Avoid expanding a string into a list of chars
|
||||||
assert not isinstance( self.privateDirs, basestring )
|
assert not isinstance( self.privateDirs, BaseString )
|
||||||
for directory in self.privateDirs:
|
for directory in self.privateDirs:
|
||||||
if isinstance( directory, tuple ):
|
if isinstance( directory, tuple ):
|
||||||
# mount given private directory
|
# mount given private directory
|
||||||
@@ -218,7 +221,7 @@ class Node( object ):
|
|||||||
maxbytes: maximum number of bytes to return"""
|
maxbytes: maximum number of bytes to return"""
|
||||||
count = len( self.readbuf )
|
count = len( self.readbuf )
|
||||||
if count < maxbytes:
|
if count < maxbytes:
|
||||||
data = os.read( self.stdout.fileno(), maxbytes - count )
|
data = decode( os.read( self.stdout.fileno(), maxbytes - count ) )
|
||||||
self.readbuf += data
|
self.readbuf += data
|
||||||
if maxbytes >= len( self.readbuf ):
|
if maxbytes >= len( self.readbuf ):
|
||||||
result = self.readbuf
|
result = self.readbuf
|
||||||
@@ -242,7 +245,7 @@ class Node( object ):
|
|||||||
def write( self, data ):
|
def write( self, data ):
|
||||||
"""Write data to node.
|
"""Write data to node.
|
||||||
data: string"""
|
data: string"""
|
||||||
os.write( self.stdin.fileno(), data )
|
os.write( self.stdin.fileno(), encode( data ) )
|
||||||
|
|
||||||
def terminate( self ):
|
def terminate( self ):
|
||||||
"Send kill signal to Node and clean up after it."
|
"Send kill signal to Node and clean up after it."
|
||||||
@@ -376,7 +379,7 @@ class Node( object ):
|
|||||||
if isinstance( args[ 0 ], list ):
|
if isinstance( args[ 0 ], list ):
|
||||||
# popen([cmd, arg1, arg2...])
|
# popen([cmd, arg1, arg2...])
|
||||||
cmd = args[ 0 ]
|
cmd = args[ 0 ]
|
||||||
elif isinstance( args[ 0 ], basestring ):
|
elif isinstance( args[ 0 ], BaseString ):
|
||||||
# popen("cmd arg1 arg2...")
|
# popen("cmd arg1 arg2...")
|
||||||
cmd = args[ 0 ].split()
|
cmd = args[ 0 ].split()
|
||||||
else:
|
else:
|
||||||
@@ -462,7 +465,7 @@ class Node( object ):
|
|||||||
"""
|
"""
|
||||||
if not intf:
|
if not intf:
|
||||||
return self.defaultIntf()
|
return self.defaultIntf()
|
||||||
elif isinstance( intf, basestring):
|
elif isinstance( intf, BaseString):
|
||||||
return self.nameToIntf[ intf ]
|
return self.nameToIntf[ intf ]
|
||||||
else:
|
else:
|
||||||
return intf
|
return intf
|
||||||
@@ -514,7 +517,7 @@ class Node( object ):
|
|||||||
"""Set the default route to go through intf.
|
"""Set the default route to go through intf.
|
||||||
intf: Intf or {dev <intfname> via <gw-ip> ...}"""
|
intf: Intf or {dev <intfname> via <gw-ip> ...}"""
|
||||||
# Note setParam won't call us if intf is none
|
# Note setParam won't call us if intf is none
|
||||||
if isinstance( intf, basestring ) and ' ' in intf:
|
if isinstance( intf, BaseString ) and ' ' in intf:
|
||||||
params = intf
|
params = intf
|
||||||
else:
|
else:
|
||||||
params = 'dev %s' % intf
|
params = 'dev %s' % intf
|
||||||
@@ -561,7 +564,7 @@ class Node( object ):
|
|||||||
method: config method name
|
method: config method name
|
||||||
param: arg=value (ignore if value=None)
|
param: arg=value (ignore if value=None)
|
||||||
value may also be list or dict"""
|
value may also be list or dict"""
|
||||||
name, value = param.items()[ 0 ]
|
name, value = list( param.items() )[ 0 ]
|
||||||
if value is None:
|
if value is None:
|
||||||
return
|
return
|
||||||
f = getattr( self, method, None )
|
f = getattr( self, method, None )
|
||||||
@@ -610,7 +613,7 @@ class Node( object ):
|
|||||||
|
|
||||||
def intfList( self ):
|
def intfList( self ):
|
||||||
"List of our interfaces sorted by port number"
|
"List of our interfaces sorted by port number"
|
||||||
return [ self.intfs[ p ] for p in sorted( self.intfs.iterkeys() ) ]
|
return [ self.intfs[ p ] for p in sorted( self.intfs.keys() ) ]
|
||||||
|
|
||||||
def intfNames( self ):
|
def intfNames( self ):
|
||||||
"The names of our interfaces sorted by port number"
|
"The names of our interfaces sorted by port number"
|
||||||
@@ -1232,7 +1235,7 @@ class OVSSwitch( Switch ):
|
|||||||
run( cmds, shell=True )
|
run( cmds, shell=True )
|
||||||
# Reapply link config if necessary...
|
# Reapply link config if necessary...
|
||||||
for switch in switches:
|
for switch in switches:
|
||||||
for intf in switch.intfs.itervalues():
|
for intf in switch.intfs.values():
|
||||||
if isinstance( intf, TCIntf ):
|
if isinstance( intf, TCIntf ):
|
||||||
intf.config( **intf.params )
|
intf.config( **intf.params )
|
||||||
return switches
|
return switches
|
||||||
|
|||||||
+3
-3
@@ -57,12 +57,12 @@ class MultiGraph( object ):
|
|||||||
|
|
||||||
def edges_iter( self, data=False, keys=False ):
|
def edges_iter( self, data=False, keys=False ):
|
||||||
"Iterator: return graph edges, optionally with data and keys"
|
"Iterator: return graph edges, optionally with data and keys"
|
||||||
for src, entry in self.edge.iteritems():
|
for src, entry in self.edge.items():
|
||||||
for dst, entrykeys in entry.iteritems():
|
for dst, entrykeys in entry.items():
|
||||||
if src > dst:
|
if src > dst:
|
||||||
# Skip duplicate edges
|
# Skip duplicate edges
|
||||||
continue
|
continue
|
||||||
for k, attrs in entrykeys.iteritems():
|
for k, attrs in entrykeys.items():
|
||||||
if data:
|
if data:
|
||||||
if keys:
|
if keys:
|
||||||
yield( src, dst, k, attrs )
|
yield( src, dst, k, attrs )
|
||||||
|
|||||||
+15
-1
@@ -12,6 +12,18 @@ from fcntl import fcntl, F_GETFL, F_SETFL
|
|||||||
from os import O_NONBLOCK
|
from os import O_NONBLOCK
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Python 2/3 compatibility
|
||||||
|
Python3 = sys.version_info[0] == 3
|
||||||
|
BaseString = str if Python3 else basestring
|
||||||
|
Encoding = 'utf-8' if Python3 else None
|
||||||
|
def decode( s ):
|
||||||
|
"Decode a byte string if needed for Python 3"
|
||||||
|
return s.decode( Encoding ) if Python3 else s
|
||||||
|
def encode( s ):
|
||||||
|
"Encode a byte string if needed for Python 3"
|
||||||
|
return s.encode( Encoding ) if Python3 else s
|
||||||
|
|
||||||
# Command execution support
|
# Command execution support
|
||||||
|
|
||||||
@@ -98,6 +110,8 @@ def errRun( *cmd, **kwargs ):
|
|||||||
f = fdtofile[ fd ]
|
f = fdtofile[ fd ]
|
||||||
if event & POLLIN:
|
if event & POLLIN:
|
||||||
data = f.read( 1024 )
|
data = f.read( 1024 )
|
||||||
|
if Python3:
|
||||||
|
data = data.decode( Encoding )
|
||||||
if echo:
|
if echo:
|
||||||
output( data )
|
output( data )
|
||||||
if f == popen.stdout:
|
if f == popen.stdout:
|
||||||
@@ -374,7 +388,7 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
|||||||
terminates: when all EOFs received"""
|
terminates: when all EOFs received"""
|
||||||
poller = poll()
|
poller = poll()
|
||||||
fdToHost = {}
|
fdToHost = {}
|
||||||
for host, popen in popens.iteritems():
|
for host, popen in popens.items():
|
||||||
fd = popen.stdout.fileno()
|
fd = popen.stdout.fileno()
|
||||||
fdToHost[ fd ] = host
|
fdToHost[ fd ] = host
|
||||||
poller.register( fd, POLLIN )
|
poller.register( fd, POLLIN )
|
||||||
|
|||||||
Reference in New Issue
Block a user