From 02140ba2bcabdcc720b190acc7c3bc07384668b6 Mon Sep 17 00:00:00 2001 From: Alex Jinks Date: Fri, 8 May 2026 16:11:52 -0400 Subject: [PATCH] fix: replace distutils.version.LooseVersion for Python 3.12+ compatibility distutils was deprecated in Python 3.10 and removed entirely in Python 3.12, causing an immediate ModuleNotFoundError on any import of panos. Fixes #580. Co-Authored-By: Claude Sonnet 4.6 --- panos/__init__.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/panos/__init__.py b/panos/__init__.py index 1651acd7..b1fb520f 100755 --- a/panos/__init__.py +++ b/panos/__init__.py @@ -32,7 +32,7 @@ import logging import sys import xml.etree.ElementTree as ET -from distutils.version import LooseVersion # Used by PanOSVersion class +import re # Warn if running on end-of-life python if sys.version_info < (3, 6): @@ -127,7 +127,28 @@ def isstring(arg): pan.DEBUG3 = pan.DEBUG2 - 1 -class PanOSVersion(LooseVersion): +class _LooseVersion: + """Minimal LooseVersion replacement; distutils was removed in Python 3.12.""" + + _component_re = re.compile(r"(\d+|[a-z]+|\.)") + + def __init__(self, vstring=None): + if vstring: + self.parse(vstring) + + def parse(self, vstring): + self.vstring = vstring + parts = [x for x in self._component_re.split(vstring) if x and x != "."] + self.version = [int(x) if x.isdigit() else x for x in parts] + + def __str__(self): + return self.vstring + + def __repr__(self): + return "LooseVersion ('%s')" % str(self) + + +class PanOSVersion(_LooseVersion): """LooseVersion with convenience properties to access version components""" @property