From 518541eb81cb70432363d2ac1baf75e4c6ec6580 Mon Sep 17 00:00:00 2001 From: JustAnotherArchivist Date: Sun, 23 Jul 2023 18:40:10 +0000 Subject: [PATCH] Fix metadata fields list caching for subclasses Because the _allFieldsCache attribute gets inherited, when it gets set for a class, all subclasses will also see that list rather than their own, potentially different list. To fix this, use a global dict indexing on the metadata class instead. --- codearchiver/core.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/codearchiver/core.py b/codearchiver/core.py index 242c4b6..41f8c8e 100644 --- a/codearchiver/core.py +++ b/codearchiver/core.py @@ -104,7 +104,9 @@ class Metadata(list[tuple[str, str]]): version: int = 0 '''Version, incremented on every backward-incompatible change''' - _allFieldsCache: typing.Optional[tuple[MetadataField]] = None + # This cache needs to be different for each subclass. + # The easiest way to achieve that is by mapping class objects to the corresponding cache. + _allFieldsCache: dict[typing.Type['Metadata'], tuple[MetadataField]] = {} def append(self, *args): if len(args) == 1: @@ -116,12 +118,13 @@ class Metadata(list[tuple[str, str]]): def _allFields(self): '''All fields known by this metadata collection, own ones and all from superclasses''' - if type(self)._allFieldsCache is None: + cls = type(self) + if cls not in cls._allFieldsCache: fields = [] - for cls in reversed(type(self).mro()): - fields.extend(getattr(cls, 'fields', [])) - type(self)._allFieldsCache = tuple(fields) - return type(self)._allFieldsCache + for cls_ in reversed(cls.mro()): + fields.extend(getattr(cls_, 'fields', [])) + cls._allFieldsCache[cls] = tuple(fields) + return cls._allFieldsCache[cls] def validate(self): '''Check that all keys and values conform to the specification'''