CustomConstructor -> CustomClass, which calls specialClass

specialClass is an analog of functools.partial but for classes.
We can now use it instead of partial() in mn, so that Mininet
can introspect on the actual base class.

Fixes #488
This commit is contained in:
Bob Lantz
2015-03-13 21:17:43 -07:00
parent 5224884e5e
commit f6f6d9282b
2 changed files with 45 additions and 32 deletions
+7 -7
View File
@@ -33,7 +33,7 @@ from mininet.nodelib import LinuxBridge
from mininet.link import Link, TCLink, OVSLink from mininet.link import Link, TCLink, OVSLink
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
from mininet.topolib import TreeTopo, TorusTopo from mininet.topolib import TreeTopo, TorusTopo
from mininet.util import customConstructor, splitArgs from mininet.util import customClass, specialClass, splitArgs
from mininet.util import buildTopo from mininet.util import buildTopo
from functools import partial from functools import partial
@@ -69,8 +69,8 @@ SWITCHES = { 'user': UserSwitch,
HOSTDEF = 'proc' HOSTDEF = 'proc'
HOSTS = { 'proc': Host, HOSTS = { 'proc': Host,
'rt': partial( CPULimitedHost, sched='rt' ), 'rt': specialClass( CPULimitedHost, defaults=dict( sched='rt' ) ),
'cfs': partial( CPULimitedHost, sched='cfs' ) } 'cfs': specialClass( CPULimitedHost, defaults=dict( sched='cfs' ) ) }
CONTROLLERDEF = 'default' CONTROLLERDEF = 'default'
CONTROLLERS = { 'ref': Controller, CONTROLLERS = { 'ref': Controller,
@@ -311,10 +311,10 @@ class MininetRunner( object ):
self.options.switch ) self.options.switch )
topo = buildTopo( TOPOS, self.options.topo ) topo = buildTopo( TOPOS, self.options.topo )
switch = customConstructor( SWITCHES, self.options.switch ) switch = customClass( SWITCHES, self.options.switch )
host = customConstructor( HOSTS, self.options.host ) host = customClass( HOSTS, self.options.host )
controller = customConstructor( CONTROLLERS, self.options.controller ) controller = customClass( CONTROLLERS, self.options.controller )
link = customConstructor( LINKS, self.options.link ) link = customClass( LINKS, self.options.link )
if self.validate: if self.validate:
self.validate( self.options ) self.validate( self.options )
+38 -25
View File
@@ -523,43 +523,56 @@ def splitArgs( argstr ):
kwargs[ key ] = makeNumeric( val ) kwargs[ key ] = makeNumeric( val )
return fn, args, kwargs return fn, args, kwargs
def customConstructor( constructors, argStr ): def customClass( classes, argStr ):
"""Return custom constructor based on argStr """Return customized class based on argStr
The args and key/val pairs in argsStr will be automatically applied The args and key/val pairs in argStr will be automatically applied
when the generated constructor is later used. when the generated class is later used.
""" """
cname, newargs, kwargs = splitArgs( argStr ) cname, args, kwargs = splitArgs( argStr )
constructor = constructors.get( cname, None ) cls = classes.get( cname, None )
if not constructor: if not cname:
raise Exception( "error: %s is unknown - please specify one of %s" % raise Exception( "error: %s is unknown - please specify one of %s" %
( cname, constructors.keys() ) ) ( cname, constructors.keys() ) )
if not args and not kwargs:
return cls
if not newargs and not kwargs: return specialClass( cls, append=args, defaults=kwargs )
return constructor
if not isinstance( constructor, type ): def specialClass( cls, prepend=None, append=None,
raise Exception( "error: invalid arguments %s" % argStr ) defaults=None, override=None ):
"""Like functools.partial, but it returns a class
prepend: arguments to prepend to argument list
append: arguments to append to argument list
defaults: default values for keyword arguments
override: keyword arguments to override"""
# Return a customized subclass if prepend is None:
cls = constructor prepend = []
if append is None:
append = []
if defaults is None:
defaults = {}
if override is None:
override = {}
class CustomClass( cls ): class CustomClass( cls ):
"Customized subclass, useful for Node, Link, and other classes" "Customized subclass with preset args/params"
def __init__( self, name, *args, **params ): def __init__( self, *args, **params ):
params = params.copy() newparams = defaults.copy()
params.update( kwargs ) newparams.update( params )
if not newargs: newparams.update( override )
cls.__init__( self, name, *args, **params ) cls.__init__( self, *( list( prepend ) + list( args ) +
return list( append ) ),
if args: **newparams )
warn( 'warning: %s replacing %s with %s\n' %
( constructor, args, newargs ) )
cls.__init__( self, name, *newargs, **params )
CustomClass.__name__ = '%s%s' % ( cls.__name__, kwargs ) CustomClass.__name__ = '%s%s' % ( cls.__name__, defaults )
return CustomClass return CustomClass
def buildTopo( topos, topoStr ): def buildTopo( topos, topoStr ):
"""Create topology from string with format (object, arg1, arg2,...). """Create topology from string with format (object, arg1, arg2,...).
input topos is a dict of topo names to constructors, possibly w/args. input topos is a dict of topo names to constructors, possibly w/args.