Preserve de-duplicated tag order in documentation

The 'set' datatype in Python does not provide iteration-order
guarantees related to insertion-order.  That means that its
usage in the 'split_csv' helper function during documentation
build can produce nondeterministic results.

That is non-desirable for two reasons: it means that the
documentation output may appear to vary unnecessarily between
builds, and secondly there could be loss-of-information in cases
where tag order in the source documentation is significant.

This patch implements order-preserving de-duplication of tags,
allowing authors to specify tags using intentional priority
ordering, while also removing tags that appear more than once.

(cherry picked from commit 5a79b36f56)
This commit is contained in:
James Addison 2024-02-25 21:10:36 +00:00 committed by Petr Špaček
parent 2443a31350
commit 3ecef74b9a

View file

@ -41,12 +41,18 @@ logger = logging.getLogger(__name__)
def split_csv(argument, required):
argument = argument or ""
outlist = list(filter(len, (s.strip() for s in argument.split(","))))
if required and not outlist:
values = list(filter(len, (s.strip() for s in argument.split(","))))
if required and not values:
raise ValueError(
"a non-empty list required; provide at least one value or remove"
" this option"
)
# Order-preserving de-duplication
outlist, seen = list(), set() # pylint: disable=use-list-literal
for value in values:
if value not in seen:
seen.add(value)
outlist.append(value)
return outlist
@ -73,10 +79,8 @@ def domain_factory(domainname, domainlabel, todolist, grammar):
def run(self):
placeholder = todolist("")
placeholder["isc_filter_tags"] = set(self.options.get("filter_tags", []))
placeholder["isc_filter_blocks"] = set(
self.options.get("filter_blocks", [])
)
placeholder["isc_filter_tags"] = self.options.get("filter_tags", [])
placeholder["isc_filter_blocks"] = self.options.get("filter_blocks", [])
return [placeholder]
class ISCConfDomain(Domain):
@ -127,7 +131,7 @@ def domain_factory(domainname, domainlabel, todolist, grammar):
@property
def isc_tags(self):
return set(self.options.get("tags", []))
return self.options.get("tags", [])
@property
def isc_short(self):
@ -475,11 +479,11 @@ def domain_factory(domainname, domainlabel, todolist, grammar):
lambda item: (
(
not acceptable_tags
or item["tags"].intersection(acceptable_tags)
or set(item["tags"]).intersection(acceptable_tags)
)
and (
not acceptable_blocks
or item["block_names"].intersection(
or set(item["block_names"]).intersection(
acceptable_blocks
)
)