Repository navigation
Speed up message sorting in write_mo() and sorted write_po() - #1438
Open
DicksonWu654 wants to merge 1 commit into
Open
DicksonWu654 wants to merge 1 commit into
DicksonWu654 wants to merge 1 commit into
Conversation
write_mo() always sorts the catalog, and write_po(sort_output=True) does too. list.sort() calls Message.__lt__, which goes through __cmp__ and builds both (id, context) tuples again for every comparison. For plain Message objects with string keys, compute each key once and sort by key; the order, including ties, is the same. Subclasses and unusual ids keep using the comparison methods. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
write_mo()always sorts the catalog's messages, andwrite_po(sort_output=True)does too.list.sort()callsMessage.__lt__, which goes through__cmp__and rebuilds both(id, context)tuples (plus a nested helper function) for every comparison, so a catalog of n messages builds about 2·n·log2(n) tuples. On real catalogs the sort is a large part ofpybabel compile.This adds a small private helper,
_sort_messages_by_id(), used bywrite_mo()andpofile._sort_messages(). For plainMessageobjects whose id (or first plural id) and context arestr/None, it builds the same(id, context or '')key that__cmp__compares, once per message, and does a key sort. Python's sort is stable either way, so ties keep their order and the output is the same. If any message is aMessagesubclass or has an unusual id/context, it falls back tomessages.sort(), so custom comparison methods and the existing errors are unchanged.Benchmarks
Real catalogs: Sphinx (ar, ca, fi, hu, sv, zh_TW; 869 messages each) and Django 5.2.8 (de, ja; 348 messages each), all eight per sample. Each sample was a separate process pinned to one core on Linux. master and this branch ran in alternating order (AB, BA, ...); the table gives the median per-pair ratio over 8 pairs on 3.12 and 6 on 3.15 and 3.9.
read_po+write_mo(whatpybabel compiledoes)write_po(..., sort_output=True)write_moalone (catalogs already parsed) goes from 16.0 ms to 5.0 ms on 3.12 (3.2x, 6 pairs). The defaultwrite_po()(no sorting) doesn't change.Checks
write_mo(with and withoutuse_fuzzy) andwrite_po(sorted by message, by file and unsorted) for the 8 real catalogs and 6 generated catalogs with plurals, contexts (None,'', mixed case, non-ASCII) and duplicate ids, plus subclass and invalid-id cases (empty plural tuple,Noneid, non-string context). Output bytes, and exception types and messages, were identical on Python 3.9, 3.12 and 3.15.tests/messages/test_catalog.pycheck the order againstsorted()(plurals, contexts, ties) and that a subclass's__cmp__is still used.pre-commit run --all-filespasses.Related: #1374 (open) adds a second sort of the MO offset table by encoded key further down in
write_mo(). It doesn't touch the message sort, so the two changes are independent and don't conflict.🤖 Generated with Claude Code