Catalogue tool: extract --check finds the catalogue sets 29 times, and extract rewrites all 2,352 catalogues even when none changed #1169
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#1169
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This issue holds 2 findings of the audit that share one fix or the same files.
W1: Catalogue tool:
extract --checkwalks the whole package 29 times and spends a third of its 110 s finding the catalogue sets againWhat exists today
src/postulo/core/messages_tool.py:catalogue_sets()(lines 211-233) runssorted(project().package.rglob("locale"))over the whole package on every call.core_set()(236-237) calls it again, and so doessources()(385-402), which builds itsnestedlist from a freshcatalogue_sets()call (line 392) for each of the 28 sets.cmd_extract()(870-906) loops overcatalogue_sets()and callsextract_all()per set, which callssources(subject), which callscatalogue_sets()again: 29 calls per run.src/postulo: 4,955 directories, of which 4,704 are inside alocale/tree (84 languages times 28 sets, each withLC_MESSAGES). TheSKIP_DIRStest is applied to the results after the walk, so it prunes nothing.Measurement:
uv run python -m cProfile -o … scripts/messages.py extract --checkfrom the core checkout (one run, 1 min 54 s wall under the profiler, 110 s of profiled time, exit 0, nothing written to the repository; stats in the audit folder aswork/w1_extract_check.prof). Cumulative times:catalogue_sets: 29 calls, 33.4 s (28 of them fromsources, 32.5 s). The scout's "21 s" was low.sourcesown walk (rglob("*"),is_file, the_withintest of every file against every nested root): about 8.6 s. The scout's "27 s for the sources walk into the locale dirs" was misattributed: the large cost is the repeatedcatalogue_setswalks, not thesourceswalk.extract_template23.7 s,extract_python19.5 s (tokenising 4.2 million tokens),parseof 2,352 catalogues 20.4 s,dump12.1 s,merge6.1 s.extract --checkruns in the CI Checks job (.forgejo/workflows/ci.yml:383) and in every plugin repository aspostulo-messages extract --check. #724 fixed the same pattern insidebuild_reportonly (it callscatalogue_sets()once); the extract path was not touched. #1033 does not cover the tool's own speed.What would change
cmd_extractalready has the list; pass the nested roots tosources()(or memoisecatalogue_sets()perproject(), cleared byuse()).Path.walk(Python 3.12+) oros.walk, removingSKIP_DIRSfrom the directory list in place, so neither walk enters the 4,704locale/directories,static/or__pycache__.ProcessPoolExecutorover the sets'extract_all, since the remaining cost is CPU-bound tokenising. Not needed for the main win.No library replaces this; the fix uses the standard library's own walk.
What it saves or protects
medium: about 35 s of the 110 s
extract --check(local, profiled), on every developer run and in the CI Checks jobAccessibility
none
Decisions
catalogue_sets()or pass the list down? Recommended: pass it down from the command (explicit, nothing to invalidate in tests that calluse()on a temporary project), and prune the walk.W2: Catalogue tool:
extractrewrites all 2,352 catalogues even when none changedWhat exists today
src/postulo/core/messages_tool.py,cmd_extract()lines 886-893: in--checkmode the current file is read and compared with the new text; without--checkthe comparison is skipped andpath.write_text(text, …)(line 893) runs for every catalogue of every set: 84 languages times 28 sets, 2,352 files, 73 MB of.po(measured withdu --apparent-sizeover everydjango.poundersrc). The content is usually identical, so git shows no change, but every modification time moves: git has to re-hash all of them on the nextgit status, editors with the files open reload them, and IDE indexers and file watchers fire 2,352 times. The same tool runs aspostulo-messages extractin every plugin repository.Not measured by running
extract(forbidden here: it rewrites the tree); the write path is read from the code. The file is already read once forparse(line 884), so the comparison costs nothing extra.What would change
Keep the text read at line 884 and write only when
text != current; print how many catalogues were actually written. The--checkand write branches then share one comparison.What it saves or protects
small: 73 MB of file writes and 2,352 moved modification times saved on a run that changes nothing
Accessibility
none
Decisions
Found by the efficiency and reliability audit of 2026-10-30 (finding W1, W2; index postulo/postulo#1108). Checked against
mainatdaee30b15(2026-10-30).