From 13927591f2c8b5a57e35f08c392bd83c9c2616b1 Mon Sep 17 00:00:00 2001 From: James Garner Date: Fri, 18 Oct 2024 14:29:20 +1300 Subject: [PATCH] fix: don't use lexical sorting for version numbers in codegen Previously, python-libjuju iterated over schemas keyed by their version string (e.g. '3.1.9') using lexical sorting. For a given facade version, a definition in a higher versioned schema was intended to overwrite any prior definition saved (see generate_facades function in facade.py). With lexical sorting, '3.1.10' would be sorted in between '3.1.1' and '3.1.2', which would not lead to the desired behaviour. This commit fixes this problem by using a tuple of integers as the sorting key. A special case is requried for the version string 'latest', and we use (9000, 9000, 9000). --- juju/client/facade.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/juju/client/facade.py b/juju/client/facade.py index 011fcb2c..09c0b9d7 100644 --- a/juju/client/facade.py +++ b/juju/client/facade.py @@ -13,7 +13,7 @@ from collections import defaultdict from glob import glob from pathlib import Path -from typing import Any, Mapping, Sequence, TypeVar +from typing import Any, Dict, List, Mapping, Sequence, Tuple, TypeVar import typing_inspect @@ -926,11 +926,22 @@ def generate_definitions(schemas): return definitions -def generate_facades(schemas): +def sortable_schema_version(version_string: str) -> Tuple[int, int, int]: + """Return a sorting key in the form (major, minor, micro) from a version string.""" + # 'latest' is special cased in load_schemas and should come last + if version_string == 'latest': + return (9000, 9000, 9000) + # raise ValueError if string isn't in the format A.B.C + major, minor, micro = version_string.split('.') + # raise ValueError if major, minor, and micro aren't int strings + return (int(major), int(minor), int(micro)) + + +def generate_facades(schemas: Dict[str, List[Schema]]) -> Dict[str, Dict[int, codegen.Capture]]: captures = defaultdict(codegen.Capture) # Build the Facade classes - for juju_version in sorted(schemas.keys()): + for juju_version in sorted(schemas.keys(), key=sortable_schema_version): for schema in schemas[juju_version]: cls, source = buildFacade(schema) cls_name = "{}Facade".format(schema.name)