You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What happens._apply_column_type() in xlsx_tools/helpers.py normalises thousands and decimal separators for the number and currency branches, but not for percent. The percent branch calls float() on the raw text, so a European decimal fails to parse and the cell silently stays text — no number, no percent format, no warning.
Reproduced against b36ebfb:
types:number cell '4,3' -> NUMBER 4.3
types:percent cell '4,3' -> text '4,3'
types:number cell '1.234,56' -> NUMBER 1234.56
types:percent cell '1.234,56' -> text '1.234,56'
types:currency:€ cell '1.234,56 €' -> NUMBER 1234.56
types:percent cell '4.3' -> NUMBER 0.043
The same value, in the same spreadsheet, is a number in one column and a string in the next — decided only by which type the column declares. A 4,3% written by a European author lands as text, so it does not sum, chart or sort.
number (:930) and currency (:916) both pass their text through _strip_thousands_separators() first. That helper already handles English 1,234.56, European 1.234,56 and bare thousands 1,234, and its docstring records the 1,5 → 15 silent 10x error that motivated it. The percent branch never got the same treatment.
Fix. Route the percent branch through _strip_thousands_separators() like the other two:
Two things to check while doing it, since they are the same omission one layer over:
resolve_cell() (:403-410) detects a trailing % outside the types: directive entirely and calls float(percent_body) directly — same gap, different entry point. An untyped 4,3% in a plain table has the same problem.
_percent_decimals() (:162-165) already does .replace(',', '.') before counting fraction digits, so it is more lenient than the coercion that feeds it. Once the coercion accepts 4,3%, confirm the two agree on the resulting format — a mismatch between a learner and its coercion is exactly what xlsx: a formula in a percent column gets a flat 0% format #126 fixed for a different pair.
Warning channel. Whatever the fix, a percent cell that cannot be parsed should say so rather than quietly becoming text — xlsx_tools/warnings.py exists for this since #114, and "the caller asked for a percent and got a string" is a warning-severity substitution by the rubric in AGENTS.md.
Tests.tests/test_xlsx_percent_columns.py covers the types: percent path; a European-decimal case belongs beside the existing ones, and should be confirmed to fail on the commit before the fix.
Found while working on #126.
What happens.
_apply_column_type()inxlsx_tools/helpers.pynormalises thousands and decimal separators for thenumberandcurrencybranches, but not forpercent. The percent branch callsfloat()on the raw text, so a European decimal fails to parse and the cell silently stays text — no number, no percent format, no warning.Reproduced against
b36ebfb:The same value, in the same spreadsheet, is a number in one column and a string in the next — decided only by which type the column declares. A
4,3%written by a European author lands as text, so it does not sum, chart or sort.Why.
helpers.py:963-966:number(:930) andcurrency(:916) both pass their text through_strip_thousands_separators()first. That helper already handles English1,234.56, European1.234,56and bare thousands1,234, and its docstring records the1,5→15silent 10x error that motivated it. The percent branch never got the same treatment.Fix. Route the percent branch through
_strip_thousands_separators()like the other two:Two things to check while doing it, since they are the same omission one layer over:
resolve_cell()(:403-410) detects a trailing%outside thetypes:directive entirely and callsfloat(percent_body)directly — same gap, different entry point. An untyped4,3%in a plain table has the same problem._percent_decimals()(:162-165) already does.replace(',', '.')before counting fraction digits, so it is more lenient than the coercion that feeds it. Once the coercion accepts4,3%, confirm the two agree on the resulting format — a mismatch between a learner and its coercion is exactly what xlsx: a formula in a percent column gets a flat 0% format #126 fixed for a different pair.Warning channel. Whatever the fix, a percent cell that cannot be parsed should say so rather than quietly becoming text —
xlsx_tools/warnings.pyexists for this since #114, and "the caller asked for a percent and got a string" is awarning-severity substitution by the rubric in AGENTS.md.Tests.
tests/test_xlsx_percent_columns.pycovers thetypes: percentpath; a European-decimal case belongs beside the existing ones, and should be confirmed to fail on the commit before the fix.