From f6f6d9282bbca0650c587fdc71cf43ebea1f7ee9 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Fri, 13 Mar 2015 21:15:25 -0700 Subject: [PATCH] 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 --- bin/mn | 14 +++++------ mininet/util.py | 63 +++++++++++++++++++++++++++++-------------------- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/bin/mn b/bin/mn index d69b6b1..082a437 100755 --- a/bin/mn +++ b/bin/mn @@ -33,7 +33,7 @@ from mininet.nodelib import LinuxBridge from mininet.link import Link, TCLink, OVSLink from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo 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 functools import partial @@ -69,8 +69,8 @@ SWITCHES = { 'user': UserSwitch, HOSTDEF = 'proc' HOSTS = { 'proc': Host, - 'rt': partial( CPULimitedHost, sched='rt' ), - 'cfs': partial( CPULimitedHost, sched='cfs' ) } + 'rt': specialClass( CPULimitedHost, defaults=dict( sched='rt' ) ), + 'cfs': specialClass( CPULimitedHost, defaults=dict( sched='cfs' ) ) } CONTROLLERDEF = 'default' CONTROLLERS = { 'ref': Controller, @@ -311,10 +311,10 @@ class MininetRunner( object ): self.options.switch ) topo = buildTopo( TOPOS, self.options.topo ) - switch = customConstructor( SWITCHES, self.options.switch ) - host = customConstructor( HOSTS, self.options.host ) - controller = customConstructor( CONTROLLERS, self.options.controller ) - link = customConstructor( LINKS, self.options.link ) + switch = customClass( SWITCHES, self.options.switch ) + host = customClass( HOSTS, self.options.host ) + controller = customClass( CONTROLLERS, self.options.controller ) + link = customClass( LINKS, self.options.link ) if self.validate: self.validate( self.options ) diff --git a/mininet/util.py b/mininet/util.py index 517e0db..6755c6d 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -523,43 +523,56 @@ def splitArgs( argstr ): kwargs[ key ] = makeNumeric( val ) return fn, args, kwargs -def customConstructor( constructors, argStr ): - """Return custom constructor based on argStr - The args and key/val pairs in argsStr will be automatically applied - when the generated constructor is later used. +def customClass( classes, argStr ): + """Return customized class based on argStr + The args and key/val pairs in argStr will be automatically applied + when the generated class is later used. """ - cname, newargs, kwargs = splitArgs( argStr ) - constructor = constructors.get( cname, None ) + cname, args, kwargs = splitArgs( argStr ) + cls = classes.get( cname, None ) - if not constructor: + if not cname: raise Exception( "error: %s is unknown - please specify one of %s" % ( cname, constructors.keys() ) ) + if not args and not kwargs: + return cls - if not newargs and not kwargs: - return constructor + return specialClass( cls, append=args, defaults=kwargs ) - if not isinstance( constructor, type ): - raise Exception( "error: invalid arguments %s" % argStr ) +def specialClass( cls, prepend=None, append=None, + 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 - cls = constructor + if prepend is None: + prepend = [] + + if append is None: + append = [] + + if defaults is None: + defaults = {} + + if override is None: + override = {} class CustomClass( cls ): - "Customized subclass, useful for Node, Link, and other classes" - def __init__( self, name, *args, **params ): - params = params.copy() - params.update( kwargs ) - if not newargs: - cls.__init__( self, name, *args, **params ) - return - if args: - warn( 'warning: %s replacing %s with %s\n' % - ( constructor, args, newargs ) ) - cls.__init__( self, name, *newargs, **params ) + "Customized subclass with preset args/params" + def __init__( self, *args, **params ): + newparams = defaults.copy() + newparams.update( params ) + newparams.update( override ) + cls.__init__( self, *( list( prepend ) + list( args ) + + list( append ) ), + **newparams ) - CustomClass.__name__ = '%s%s' % ( cls.__name__, kwargs ) + CustomClass.__name__ = '%s%s' % ( cls.__name__, defaults ) return CustomClass + def buildTopo( topos, topoStr ): """Create topology from string with format (object, arg1, arg2,...). input topos is a dict of topo names to constructors, possibly w/args.