fix bmo parser for new format / lints
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
# .pre-commit-config.yaml
|
# .pre-commit-config.yaml
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.1.5 # Check for the latest version
|
rev: v0.15.12 # Check for the latest version
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: ["check", "--select", "I", "--fix"]
|
args: ["check", "--select", "I", "--fix"]
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.5.0 # Check for the latest version
|
rev: v6.0.0 # Check for the latest version
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
@@ -16,6 +16,6 @@ repos:
|
|||||||
- id: requirements-txt-fixer
|
- id: requirements-txt-fixer
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 6.0.0 # Check for the latest version
|
rev: 7.3.0 # Check for the latest version
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import datetime
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import date
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ class Transaction:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
account: UUID
|
account: UUID
|
||||||
date: date
|
date: datetime.date
|
||||||
amount: Decimal # Note: decimal dollars, JS shim will convert to cents as described in the API
|
amount: Decimal # Note: decimal dollars, JS shim will convert to cents as described in the API
|
||||||
payee: str # imported_payee in API
|
payee: str # imported_payee in API
|
||||||
notes: str
|
notes: str
|
||||||
|
|||||||
@@ -58,6 +58,18 @@ class TransactionParser(ABC):
|
|||||||
raise TransactionParsingFailed("No content of message found")
|
raise TransactionParsingFailed("No content of message found")
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def strip_html(msg: EmailMessage) -> str:
|
||||||
|
body = msg.get_body(preferencelist=("html", "plain"))
|
||||||
|
if body is None:
|
||||||
|
raise TransactionParsingFailed("No HTML body of message found")
|
||||||
|
content = body.get_content()
|
||||||
|
if content is None:
|
||||||
|
raise TransactionParsingFailed("No content of message found")
|
||||||
|
|
||||||
|
soup = BeautifulSoup(content, "html.parser")
|
||||||
|
return soup.get_text()
|
||||||
|
|
||||||
|
|
||||||
class TransactionParsingFailed(Exception):
|
class TransactionParsingFailed(Exception):
|
||||||
pass
|
pass
|
||||||
@@ -136,8 +148,8 @@ class MBNAParser(TransactionParser):
|
|||||||
|
|
||||||
class BMOParser(TransactionParser):
|
class BMOParser(TransactionParser):
|
||||||
EXTRACT_RE = re.compile(
|
EXTRACT_RE = re.compile(
|
||||||
r"We want to let you know that a (withdrawal|deposit) of\s+\$([0-9,]+\.\d{2})\s+has been made (?:to|from) your account ending\s+in\s+(\d{3})", # noqa: E501
|
r"There was a (withdrawal|deposit).*Amount:\s*\$([0-9,]+\.\d{2}).*Account:\s*Ending in ([0-9]+)", # noqa: E501
|
||||||
flags=re.MULTILINE,
|
flags=re.DOTALL,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, account_map: dict[int, UUID]):
|
def __init__(self, account_map: dict[int, UUID]):
|
||||||
@@ -147,9 +159,8 @@ class BMOParser(TransactionParser):
|
|||||||
return msg["From"] == "bmoalerts@bmo.com"
|
return msg["From"] == "bmoalerts@bmo.com"
|
||||||
|
|
||||||
def extract(self, msg: EmailMessage) -> Optional[Transaction]:
|
def extract(self, msg: EmailMessage) -> Optional[Transaction]:
|
||||||
content = self.get_content(msg)
|
content = self.strip_html(msg)
|
||||||
soup = BeautifulSoup(content, "html.parser")
|
matches = self.EXTRACT_RE.search(content)
|
||||||
matches = self.EXTRACT_RE.search(soup.get_text())
|
|
||||||
if matches is None:
|
if matches is None:
|
||||||
raise TransactionParsingFailed("No matches for extraction RE")
|
raise TransactionParsingFailed("No matches for extraction RE")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user