From c9068fa82457586ba5d7861b3e05fcd26175513a Mon Sep 17 00:00:00 2001 From: Miro <200482516+Mirochill@users.noreply.github.com> Date: Mon, 25 May 2026 12:08:00 +0200 Subject: [PATCH] Remove Python distutils imports --- mininet/util.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++-- util/vm/build.py | 10 ++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/mininet/util.py b/mininet/util.py index e776e9fd2..067d9ee67 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -56,11 +56,76 @@ def getincrementaldecoder(): return NullCodec try: - import packaging.version # replacement for distutils.version + import packaging.version StrictVersion = packaging.version.parse except ImportError: # python2.7 lacks ModuleNotFoundError - import distutils.version # pylint: disable=deprecated-module - StrictVersion = distutils.version.StrictVersion + class StrictVersion( object ): + "Small version comparator fallback for simple numeric versions." + + _regex = re.compile( r'^(\d+(?:\.\d+)*)(?:([a-zA-Z]+)(\d+)?)?$' ) + _preRank = { 'a': 0, 'alpha': 0, 'b': 1, 'beta': 1, + 'c': 2, 'pre': 2, 'preview': 2, 'rc': 2 } + + def __init__( self, version ): + match = self._regex.match( str( version ) ) + if not match: + raise ValueError( 'invalid version number %s' % version ) + release, label, number = match.groups() + self.release = tuple( int( part ) for part in release.split( '.' ) ) + if label: + self.prerelease = ( label.lower(), int( number or 0 ) ) + else: + self.prerelease = None + + @staticmethod + def _pad( left, right ): + "Pad release tuples to equal length." + length = max( len( left ), len( right ) ) + return ( left + ( 0, ) * ( length - len( left ) ), + right + ( 0, ) * ( length - len( right ) ) ) + + @classmethod + def _preKey( cls, prerelease ): + "Return a comparable prerelease key." + if prerelease is None: + return ( 3, 0 ) + label, number = prerelease + return ( cls._preRank.get( label, -1 ), number ) + + def _compare( self, other ): + "Compare two versions." + if not isinstance( other, StrictVersion ): + other = StrictVersion( other ) + left, right = self._pad( self.release, other.release ) + if left < right: + return -1 + if left > right: + return 1 + leftPre = self._preKey( self.prerelease ) + rightPre = self._preKey( other.prerelease ) + if leftPre < rightPre: + return -1 + if leftPre > rightPre: + return 1 + return 0 + + def __lt__( self, other ): + return self._compare( other ) < 0 + + def __le__( self, other ): + return self._compare( other ) <= 0 + + def __eq__( self, other ): + return self._compare( other ) == 0 + + def __ne__( self, other ): + return self._compare( other ) != 0 + + def __gt__( self, other ): + return self._compare( other ) > 0 + + def __ge__( self, other ): + return self._compare( other ) >= 0 try: oldpexpect = None diff --git a/util/vm/build.py b/util/vm/build.py index ea4df074c..fc1f7938a 100755 --- a/util/vm/build.py +++ b/util/vm/build.py @@ -38,7 +38,6 @@ from tempfile import mkdtemp, NamedTemporaryFile from time import time, strftime, localtime import argparse -from distutils.spawn import find_executable import inspect from traceback import print_exc @@ -64,6 +63,15 @@ Prompt = '\$ ' # Shell prompt that pexpect will wait for +def find_executable( executable ): + "Return executable path from PATH or None." + for dirname in os.environ.get( 'PATH', '' ).split( os.pathsep ): + filename = path.join( dirname, executable ) + if path.isfile( filename ) and os.access( filename, os.X_OK ): + return filename + return None + + # URLs for Ubuntu .iso images def serverURL( version, arch ):