diff --git a/area_reader/__init__.py b/area_reader/__init__.py index 10a0685..4b2f3c3 100644 --- a/area_reader/__init__.py +++ b/area_reader/__init__.py @@ -3901,7 +3901,25 @@ def __init__(self, *args, **kwargs): ) def _unstructure_enum(self, obj): - name = obj.name if obj.name is not None else str(obj.value) + # Composite Flag values have no .name before Python 3.11; decompose + # into single-bit member names in ascending bit order, matching the + # names 3.11+ produces, so JSON output is identical on every version. + name = obj.name + if name is None and isinstance(obj, enum.Flag): + bits = { + member.value: member.name + for member in type(obj).__members__.values() + if member.value and not member.value & (member.value - 1) + } + names = [bits[bit] for bit in sorted(bits) if obj.value & bit] + covered = 0 + for bit in bits: + if obj.value & bit: + covered |= bit + if names and covered == obj.value: + name = "|".join(names) + if name is None: + name = str(obj.value) return obj.__class__.__name__ + "." + name diff --git a/test_jsonification.py b/test_jsonification.py index 974bdb2..b41fcbc 100644 --- a/test_jsonification.py +++ b/test_jsonification.py @@ -101,14 +101,21 @@ def test_every_int_flag_type_jsonifies_zero(flag_type): ids=lambda flag_type: flag_type.__name__, ) def test_every_int_flag_type_jsonifies_named_combinations(flag_type): - members = list(flag_type) - if len(members) < 2: - pytest.skip("flag type has fewer than two iterable members") - value = members[0] | members[1] + bits = sorted( + { + member.value: member + for member in flag_type.__members__.values() + if member.value and not member.value & (member.value - 1) + }.values(), + key=lambda member: member.value, + ) + if len(bits) < 2: + pytest.skip("flag type has fewer than two single-bit members") + value = bits[0] | bits[1] result = area_reader.EnumNameConverter().unstructure(value) - assert result == f"{flag_type.__name__}.{value.name}" + assert result == f"{flag_type.__name__}.{bits[0].name}|{bits[1].name}" assert json.loads(json.dumps(result)) == result diff --git a/test_swr_writer.py b/test_swr_writer.py index 28c3ef4..253b0e4 100644 --- a/test_swr_writer.py +++ b/test_swr_writer.py @@ -96,6 +96,8 @@ def test_swr_write_uses_the_canonical_rendering(tmp_path: Path) -> None: def test_fuss_fields_are_editable_declaratively(tmp_path: Path) -> None: + if not swr_paths(): + pytest.skip("upstream SWR/FUSS corpus is unavailable") source = load_swr(UPSTREAM_SWR / "area" / "kashyyyk") mob = next(iter(source.area.mobs.values())) room = next(iter(source.area.rooms.values()))