Repository navigation
Read the direction of a relative expression written next to punctuation (#706) - #1391
Merged
Merged
Conversation
…on (#706) A future expression such as "через 2 часа" is translated into "in 2 hour", and the "in" is what tells the parser to count forward. A preposition translated into the same word has to be dropped instead, which is decided by looking for a unit of time among the words next to it. A unit keeps the punctuation it was written next to, so "через 2 часа, пожалуйста" translates into "in 2 hour," and the unit is looked up as "hour,". No unit is found, the "in" is dropped as a preposition, and what is left parses as a past date two hours before the reference time instead of two hours after it. Look the unit up without the punctuation it carries. The expression is translated into English before it is parsed, so this reaches every language the same way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1391 +/- ##
=======================================
Coverage 97.20% 97.21%
=======================================
Files 236 236
Lines 3081 3084 +3
=======================================
+ Hits 2995 2998 +3
Misses 86 86 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
AdrianAtZyte
approved these changes
Sep 21, 2026
The direction fix only holds while _clear_future_words strips exactly the punctuation translate_search re-attaches to a translated unit. Give that set one name so the two sites cannot drift apart, and say in the test what it covers: what the translation carries on, not any punctuation at all. No behaviour change: the differential run over the same 14,326 inputs is identical to the previous commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
3 tasks done
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.
Fixes #706.
What was left of the issue
The example as it was reported,
'через 2 часа'on its own, already works on master, and Ireproduced the original report against 0.7.6 to be sure it was read right:
The two halves of the report were one bug.
'через'was simply missing from the ru searchdictionary, so
translate_searchhit it as an unknown word and flushed the chunk there. Thatdropped
'через'from the original chunk — the wrong span — and with it the"in"from thetranslation, which is what left
'2 hour'to be read as a past date. A later data update addedчерез → inand fixed both at once. The reporter's guess about two competing candidate matchesis not what happens: there is one
(translated, original)chunk pair, aligned token by token.Half of it is still live, though, in a narrower form: put any punctuation after the unit and the
direction flips again, in every language, English included.
Why punctuation flipped the direction
"через 2 часа"is translated into"in 2 hour", and the"in"is what tells the freshnessparser to count forward. An
"in"that came from a preposition ("in January") has to be droppedinstead, and
_clear_future_wordstells the two apart by looking for a unit of time among thewords next to it.
A unit keeps the punctuation it was written next to, so
"через 2 часа, пожалуйста"translatesinto
"in 2 hour,"and the unit is looked up as"hour,":{"in", "2", "hour,"}.isdisjoint({"day", "week", "month", "year", "hour", "minute", "second"}) # True — no unit found, so the "in" is dropped as a prepositionWhat is left,
"2 hour,", parses as two hours ago.The fix
Look the unit up without the punctuation it carries. The set is the one
translate_searchstrips before the dictionary lookup and re-attaches to the translation, and the fix only holds
while the two agree, so it is now a single module-level
PUNCTUATIONused by both. Falsy tokensare skipped because the list holds the empty strings that removed skip words leave behind.
This only ever makes the function keep an
"in"it used to drop, and only when a time unit isactually there, so a preposition with no unit next to it is still dropped exactly as before.
Evidence
24251 passed, 16 skipped, 1 xfailed;ruffandruff-formatclean.Differential run against master over 14,326 inputs — a future and a past phrase per unit per
locale, generated from each locale's own
relative-type-regex(1,659 phrases, 121 languages) insix punctuation variants each, plus every string mined from
tests/run with language detection:None)Every one of the 312 is the bug: a future phrase that master read as past (307 generated
across 16 languages, 5 mined). Each now returns exactly what the same phrase without the
punctuation returns on both master and this branch — the punctuated form stops disagreeing with
the bare one. No past phrase changed.
One of the mined five is worth calling out, because it is not a comma and not Russian:
tests/test_freshness_date_parser.py:1769already asserts thatparsereads that same string asthree weeks in the future, so
search_dateswas contradictingparseon it. It is now one of thenew test cases.
Tests
One new test method,
test_search_dates_with_a_relative_expression_reads_its_direction, eightparams:
через 2 часаbare, with a trailing comma, and inside a sentence;через 3 дня,; both2 часа назадforms, so the past direction is held in place; the Englishin 2 hours, please,since the bug is not language-specific; and
in three weeks' timefor punctuation that is not acomma. Reverting
locale.pyalone fails five of the eight and leaves the other three passing.No existing test was touched.
Deliberately not fixed
Three neighbours of this bug came up in review. Each behaves identically on master, and none
goes through the
"in"decision this PR changes:translate_searchcomputes the carriedpunctuation as
word[len(bare_word):], so"(in"becomes"inn"andsearch_dates("(in 2 hours)")returns garbage — with or without this PR. A separate bug, one line, worth its ownissue.
:(’ “ ” « ») are not in the strip set, soin three weeks’ timeand
«через 2 часа»returnNonebefore and after; the chunk breaks at the word and neverreaches this code.
parsehandles them."in"s in one chunk. Only the first is ever examined, soin January in 2 hours,nowreturns what
in January in 2 hoursalready returned on master (a split intoJanuaryandhours). The comma form stops disagreeing with the bare form; the bare form's answer is apre-existing problem.
The "gained 0 / lost 0" above is over the corpus described, which does not contain the third
shape.
🤖 Generated with Claude Code