Skip to content

Fix shadowed "тңг." currency symbol dropping its trailing dot - #80

Open
Sanjays2402 wants to merge 1 commit into
scrapinghub:masterfrom
Sanjays2402:fix/tenge-dotted-currency-shadowed
Open

Sanjays2402 wants to merge 1 commit into
scrapinghub:masterfrom
Sanjays2402:fix/tenge-dotted-currency-shadowed

Conversation

@Sanjays2402

Copy link
Copy Markdown

Problem

Price.fromstring("1000 тңг.") returns currency="тңг" (Kazakhstani tenge
without its trailing dot) instead of currency="тңг.", silently dropping the
period that is part of the symbol as it appears in the text.

>>> from price_parser import Price
>>> Price.fromstring("1000 тңг.").currency
'тңг'          # expected 'тңг.'

For comparison, the other dotted national abbreviations behave correctly:

input currency (before) currency (after)
1000 тңг. 'тңг' 'тңг.'
1000 руб. 'руб.' 'руб.'
1000 грн. 'грн.' 'грн.'
1000 лв. 'лв.' 'лв.'
1000 тңг (no dot) 'тңг' 'тңг'

Root cause

SAFE_CURRENCY_SYMBOLS is turned into an ordered regex alternation by
or_regex() ("|".join(...)). In an ordered alternation the first matching
branch wins, so when a shorter symbol is a prefix of a longer one and is listed
first, the longer one becomes unreachable.

"тңг" was listed before "тңг.":

    "р.",
    "тңг",     # <- shorter form matches first
    "тңг.",    # <- unreachable: the dot is never captured
    "ман.",

"тңг" is the only dotted/undotted pair in the wrong order. Every sibling
(руб./руб, грн./грн, лв./лв) already lists the dotted form first, so
those symbols keep their dot. The comment at the top of the list even notes that
longer variants "need to be before" shorter ones.

Fix

Swap the two entries so the dotted form comes first, matching the existing
convention for руб., грн., and лв.. This makes the previously dead
"тңг." entry effective without affecting the dot-less "тңг" form.

     "р.",
-    "тңг",
     "тңг.",
+    "тңг",
     "ман.",

+2/−1 in price_parser/parser.py (one swap), +4 in the test file.

Testing

Added a regression example to PRICE_PARSING_EXAMPLES_BUGS_CAUGHT
(the list documented for "bugs we've found in a wild"):

Example(None, "1000 тңг.", "тңг.", "1000", 1000),

Proof it guards the bug (source fix stashed, test kept):

# without the fix:
E   assert Price(amount=Decimal('1000'), currency='тңг') == Example(..., currency='тңг.')
FAILED tests/test_price_parsing.py::test_parsing[None, '1000 тңг.']

# with the fix:
1 passed

Full suite after the fix: 1060 passed, 134 xfailed (was 1059 passed +
the 1 new case, no regressions). ruff check and ruff format --check are
clean on both changed files.

This pull request was prepared with the assistance of AI, under my direction
and review.

The dotted Kazakhstani tenge abbreviation "тңг." was listed *after* the
dot-less "тңг" in SAFE_CURRENCY_SYMBOLS. or_regex() builds an ordered
alternation, so the shorter "тңг" always matched first and the trailing
dot was silently dropped: Price.fromstring("1000 тңг.").currency was
"тңг" instead of "тңг.".

"тңг" was the only dotted/undotted national-abbreviation pair listed in
the wrong order; every sibling (руб., грн., лв.) already lists the dotted
form first so it wins the alternation. Swap the two entries to match that
convention, which also makes the previously unreachable "тңг." entry
effective.

Add a regression example to PRICE_PARSING_EXAMPLES_BUGS_CAUGHT covering
"1000 тңг." -> currency "тңг.".
@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.23%. Comparing base (64e213a) to head (72a5fd3).

Additional details and impacted files
@@           Coverage Diff           @@
##           master      #80   +/-   ##
=======================================
  Coverage   98.23%   98.23%           
=======================================
  Files           3        3           
  Lines         113      113           
  Branches       16       16           
=======================================
  Hits          111      111           
  Misses          1        1           
  Partials        1        1           
Files with missing lines Coverage Δ
price_parser/parser.py 97.67% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants