From 07d06d9aee4299df78692c2ea663f696e1f489a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Bastian=20P=C3=B6ttner?= Date: Thu, 8 Feb 2018 09:01:55 +0100 Subject: [PATCH 1/5] Extends the regex to find dates in documents as reported by @isaacsando --- src/paperless_tesseract/parsers.py | 8 ++++-- .../tests/samples/tests_date_8.pdf | Bin 0 -> 21583 bytes .../tests/samples/tests_date_9.pdf | Bin 0 -> 22020 bytes src/paperless_tesseract/tests/test_date.py | 26 ++++++++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/paperless_tesseract/tests/samples/tests_date_8.pdf create mode 100644 src/paperless_tesseract/tests/samples/tests_date_9.pdf diff --git a/src/paperless_tesseract/parsers.py b/src/paperless_tesseract/parsers.py index 85209dd8e..847e87f1a 100644 --- a/src/paperless_tesseract/parsers.py +++ b/src/paperless_tesseract/parsers.py @@ -208,11 +208,13 @@ class RasterisedDocumentParser(DocumentParser): # - XX/YY/ZZZZ with XX + YY being 1 or 2 and ZZZZ being 2 or 4 digits # - XX-YY-ZZZZ with XX + YY being 1 or 2 and ZZZZ being 2 or 4 digits # - XX. MONTH ZZZZ with XX being 1 or 2 and ZZZZ being 2 or 4 digits - # - MONTH ZZZZ + # - MONTH ZZZZ, with ZZZZ being 4 digits + # - MONTH XX, ZZZZ with XX being 1 or 2 and ZZZZ being 4 digits m = re.search( r'\b([0-9]{1,2})[\.\/-]([0-9]{1,2})[\.\/-]([0-9]{4}|[0-9]{2})\b|' + - r'\b([0-9]{1,2}\. [^ ]{3,9} ([0-9]{4}|[0-9]{2}))\b|' + - r'\b([^ ]{3,9} [0-9]{4})\b', text) + r'\b([0-9]{1,2}[\. ]+[^ ]{3,9} ([0-9]{4}|[0-9]{2}))\b|' + + r'\b([\w]{3,9} [0-9]{1,2}, ([0-9]{4}))\b|' + + r'\b([\w]{3,9} [0-9]{4})\b', text) if m is None: return None diff --git a/src/paperless_tesseract/tests/samples/tests_date_8.pdf b/src/paperless_tesseract/tests/samples/tests_date_8.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ea7495f29020f6b4c0897556f7616b75d362e155 GIT binary patch literal 21583 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 Date: Mon, 12 Feb 2018 21:49:24 +0100 Subject: [PATCH 2/5] Added log output for date detected in document --- src/paperless_tesseract/parsers.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/paperless_tesseract/parsers.py b/src/paperless_tesseract/parsers.py index 847e87f1a..37b2610c1 100644 --- a/src/paperless_tesseract/parsers.py +++ b/src/paperless_tesseract/parsers.py @@ -219,11 +219,19 @@ class RasterisedDocumentParser(DocumentParser): if m is None: return None - return dateparser.parse(m.group(0), + date = dateparser.parse(m.group(0), settings={'DATE_ORDER': self.DATE_ORDER, 'PREFER_DAY_OF_MONTH': 'first', 'RETURN_AS_TIMEZONE_AWARE': True}) + if date is not None: + self.log("info", "Detected document date " + date.strftime("%x") + + " based on string " + m.group(0)) + else: + self.log("info", "Unable to detect date for document") + + return date + def run_convert(*args): From 39f198138a14e2ee5b903db873dda61015f42075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Bastian=20P=C3=B6ttner?= Date: Mon, 12 Feb 2018 22:07:03 +0100 Subject: [PATCH 3/5] Extended exception handling --- src/paperless_tesseract/parsers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/paperless_tesseract/parsers.py b/src/paperless_tesseract/parsers.py index 37b2610c1..b5f012bdc 100644 --- a/src/paperless_tesseract/parsers.py +++ b/src/paperless_tesseract/parsers.py @@ -200,7 +200,10 @@ class RasterisedDocumentParser(DocumentParser): return text def get_date(self): - text = self.get_text() + try: + text = self.get_text() + except ParseError as e: + return None # This regular expression will try to find dates in the document at # hand and will match the following formats: From 1737e27b3417cdca743876d8a9ec6dedcbae62e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Bastian=20P=C3=B6ttner?= Date: Tue, 13 Feb 2018 22:46:44 +0100 Subject: [PATCH 4/5] Add more (fast-running) unit tests --- src/paperless_tesseract/tests/test_date.py | 91 ++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/paperless_tesseract/tests/test_date.py b/src/paperless_tesseract/tests/test_date.py index 7b1f75f6c..a687cd4f1 100644 --- a/src/paperless_tesseract/tests/test_date.py +++ b/src/paperless_tesseract/tests/test_date.py @@ -12,6 +12,97 @@ from dateutil import tz class TestDate(TestCase): SAMPLE_FILES = os.path.join(os.path.dirname(__file__), "samples") + @mock.patch( + "paperless_tesseract.parsers.RasterisedDocumentParser.SCRATCH", + SAMPLE_FILES + ) + def test_date_format_1(self): + input_file = os.path.join(self.SAMPLE_FILES, "") + document = RasterisedDocumentParser(input_file) + document.TEXT_CACHE = "lorem ipsum 130218 lorem ipsum" + self.assertEqual(document.get_date(), + None) + + @mock.patch( + "paperless_tesseract.parsers.RasterisedDocumentParser.SCRATCH", + SAMPLE_FILES + ) + def test_date_format_2(self): + input_file = os.path.join(self.SAMPLE_FILES, "") + document = RasterisedDocumentParser(input_file) + document.TEXT_CACHE = "lorem ipsum 2018 lorem ipsum" + self.assertEqual(document.get_date(), + None) + + @mock.patch( + "paperless_tesseract.parsers.RasterisedDocumentParser.SCRATCH", + SAMPLE_FILES + ) + def test_date_format_3(self): + input_file = os.path.join(self.SAMPLE_FILES, "") + document = RasterisedDocumentParser(input_file) + document.TEXT_CACHE = "lorem ipsum 20180213 lorem ipsum" + self.assertEqual(document.get_date(), + None) + + @mock.patch( + "paperless_tesseract.parsers.RasterisedDocumentParser.SCRATCH", + SAMPLE_FILES + ) + def test_date_format_4(self): + input_file = os.path.join(self.SAMPLE_FILES, "") + document = RasterisedDocumentParser(input_file) + document.TEXT_CACHE = "lorem ipsum 13.02.2018 lorem ipsum" + self.assertEqual(document.get_date(), + datetime.datetime(2018, 2, 13, 0, 0, + tzinfo=tz.tzutc())) + + @mock.patch( + "paperless_tesseract.parsers.RasterisedDocumentParser.SCRATCH", + SAMPLE_FILES + ) + def test_date_format_5(self): + input_file = os.path.join(self.SAMPLE_FILES, "") + document = RasterisedDocumentParser(input_file) + document.TEXT_CACHE = ("lorem ipsum 130218, 2018, 20180213 and " + "13.02.2018 lorem ipsum") + self.assertEqual(document.get_date(), + datetime.datetime(2018, 2, 13, 0, 0, + tzinfo=tz.tzutc())) + + @mock.patch( + "paperless_tesseract.parsers.RasterisedDocumentParser.SCRATCH", + SAMPLE_FILES + ) + def test_date_format_6(self): + input_file = os.path.join(self.SAMPLE_FILES, "") + document = RasterisedDocumentParser(input_file) + document.TEXT_CACHE = ("lorem ipsum\n" + "Wohnort\n" + "3100\n" + "IBAN\n" + "AT87 4534\n" + "1234\n" + "1234 5678\n" + "BIC\n" + "lorem ipsum") + self.assertEqual(document.get_date(), + None) + + @mock.patch( + "paperless_tesseract.parsers.RasterisedDocumentParser.SCRATCH", + SAMPLE_FILES + ) + def test_date_format_7(self): + input_file = os.path.join(self.SAMPLE_FILES, "") + document = RasterisedDocumentParser(input_file) + document.TEXT_CACHE = ("lorem ipsum\n" + "März 2019\n" + "lorem ipsum") + self.assertEqual(document.get_date(), + datetime.datetime(2019, 3, 1, 0, 0, + tzinfo=tz.tzutc())) + @mock.patch( "paperless_tesseract.parsers.RasterisedDocumentParser.SCRATCH", SAMPLE_FILES From 96c72222693d584f1f5cecd56efa62ef6faddce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Bastian=20P=C3=B6ttner?= Date: Wed, 14 Feb 2018 21:33:19 +0100 Subject: [PATCH 5/5] Improved regular expression to only match for (unicode) characters in month names + parsed one regex match after another until one gave a parsable date --- src/paperless_tesseract/parsers.py | 32 ++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/paperless_tesseract/parsers.py b/src/paperless_tesseract/parsers.py index b5f012bdc..f50bc2798 100644 --- a/src/paperless_tesseract/parsers.py +++ b/src/paperless_tesseract/parsers.py @@ -200,6 +200,9 @@ class RasterisedDocumentParser(DocumentParser): return text def get_date(self): + date = None + datestring = None + try: text = self.get_text() except ParseError as e: @@ -213,23 +216,32 @@ class RasterisedDocumentParser(DocumentParser): # - XX. MONTH ZZZZ with XX being 1 or 2 and ZZZZ being 2 or 4 digits # - MONTH ZZZZ, with ZZZZ being 4 digits # - MONTH XX, ZZZZ with XX being 1 or 2 and ZZZZ being 4 digits - m = re.search( + pattern = re.compile( r'\b([0-9]{1,2})[\.\/-]([0-9]{1,2})[\.\/-]([0-9]{4}|[0-9]{2})\b|' + r'\b([0-9]{1,2}[\. ]+[^ ]{3,9} ([0-9]{4}|[0-9]{2}))\b|' + - r'\b([\w]{3,9} [0-9]{1,2}, ([0-9]{4}))\b|' + - r'\b([\w]{3,9} [0-9]{4})\b', text) + r'\b([^\W\d_]{3,9} [0-9]{1,2}, ([0-9]{4}))\b|' + + r'\b([^\W\d_]{3,9} [0-9]{4})\b') - if m is None: - return None + # Iterate through all regex matches and try to parse the date + for m in re.finditer(pattern, text): + datestring = m.group(0) - date = dateparser.parse(m.group(0), - settings={'DATE_ORDER': self.DATE_ORDER, - 'PREFER_DAY_OF_MONTH': 'first', - 'RETURN_AS_TIMEZONE_AWARE': True}) + try: + date = dateparser.parse( + datestring, + settings={'DATE_ORDER': self.DATE_ORDER, + 'PREFER_DAY_OF_MONTH': 'first', + 'RETURN_AS_TIMEZONE_AWARE': True}) + except TypeError: + # Skip all matches that do not parse to a proper date + continue + + if date is not None: + break if date is not None: self.log("info", "Detected document date " + date.strftime("%x") + - " based on string " + m.group(0)) + " based on string " + datestring) else: self.log("info", "Unable to detect date for document")