From 78d94a583b99090f425c0f078b74d07e1c23f6ea2927cb98b404475ca4f1b763 Mon Sep 17 00:00:00 2001 From: wlfb Date: Fri, 17 Jul 2026 17:34:39 +0200 Subject: [PATCH] fix: NBSP-Betraege und ParserError bei ungueltigem Datum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - parse_german_amount: Fix non-breaking space (U+00A0) handling in second replace call was: .replace(" ", "").replace(" ", "") → now: .replace(" ", "").replace("\xa0", "") - parse_german_date: Catch ValueError from invalid calendar dates (e.g., 31.02.2026) and raise ParserError with "Ungültiges Datum" message instead - Add test for non-breaking space amount parsing - Add test for invalid date error handling with pytest.raises Co-Authored-By: Claude Fable 5 --- finance/app/parsers/base.py | 7 +++++-- finance/tests/test_parser_base.py | 10 +++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/finance/app/parsers/base.py b/finance/app/parsers/base.py index fe68406..8b81ae4 100644 --- a/finance/app/parsers/base.py +++ b/finance/app/parsers/base.py @@ -29,7 +29,7 @@ class ParsedStatement: def parse_german_amount(s: str) -> Decimal: - s = s.strip().replace(" ", "").replace(" ", "") + s = s.strip().replace(" ", "").replace("\xa0", "") neg = s.endswith("-") or s.startswith("-") or s.endswith("S") s = s.strip("+-SH") value = Decimal(s.replace(".", "").replace(",", ".")) @@ -43,4 +43,7 @@ def parse_german_date(s: str, default_year: int | None = None) -> date: year = int(m.group(3)) if m.group(3) else default_year if year is None: raise ParserError(f"Jahr fehlt: {s!r}") - return date(year, int(m.group(2)), int(m.group(1))) + try: + return date(year, int(m.group(2)), int(m.group(1))) + except ValueError: + raise ParserError(f"Ungültiges Datum: {s!r}") diff --git a/finance/tests/test_parser_base.py b/finance/tests/test_parser_base.py index bafdef7..b91c235 100644 --- a/finance/tests/test_parser_base.py +++ b/finance/tests/test_parser_base.py @@ -1,7 +1,9 @@ from datetime import date from decimal import Decimal -from app.parsers.base import (ParsedStatement, ParsedTransaction, +import pytest + +from app.parsers.base import (ParsedStatement, ParsedTransaction, ParserError, parse_german_amount, parse_german_date) from app.parsers.detect import detect_bank from app.parsers.validate import balance_difference, dedup_hash @@ -12,6 +14,7 @@ def test_parse_german_amount(): assert parse_german_amount("1.234,56-") == Decimal("-1234.56") assert parse_german_amount("12,00 S") == Decimal("-12.00") assert parse_german_amount("12,00 H") == Decimal("12.00") + assert parse_german_amount("1\xa0234,56") == Decimal("1234.56") def test_parse_german_date(): @@ -19,6 +22,11 @@ def test_parse_german_date(): assert parse_german_date("03.06.", default_year=2026) == date(2026, 6, 3) +def test_parse_german_date_invalid(): + with pytest.raises(ParserError): + parse_german_date("31.02.2026") + + def test_detect_bank(): assert detect_bank("... Volksbank Musterstadt eG ...") == "vr" assert detect_bank("... Raiffeisenbank ...") == "vr"