linter &c
This commit is contained in:
parent
0b13bb3692
commit
f453222bf7
25
.pre-commit-config.yaml
Normal file
25
.pre-commit-config.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# .pre-commit-config.yaml
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
|
rev: v0.1.5 # Check for the latest version
|
||||||
|
hooks:
|
||||||
|
- id: ruff
|
||||||
|
- id: ruff-format
|
||||||
|
|
||||||
|
- repo: https://github.com/asottile/reorder-python-imports
|
||||||
|
rev: v3.11.0 # Check for the latest version
|
||||||
|
hooks:
|
||||||
|
- id: reorder-python-imports
|
||||||
|
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v4.5.0 # Check for the latest version
|
||||||
|
hooks:
|
||||||
|
- id: check-yaml
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- id: requirements-txt-fixer
|
||||||
|
|
||||||
|
- repo: https://github.com/PyCQA/flake8
|
||||||
|
rev: 6.0.0 # Check for the latest version
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
5
model.py
5
model.py
@ -1,7 +1,8 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from uuid import UUID
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Transaction:
|
class Transaction:
|
||||||
@ -10,4 +11,4 @@ class Transaction:
|
|||||||
amount: Decimal
|
amount: Decimal
|
||||||
payee: str # imported_payee in API
|
payee: str # imported_payee in API
|
||||||
notes: str
|
notes: str
|
||||||
imported_id: str
|
imported_id: str
|
||||||
|
23
parsers.py
23
parsers.py
@ -1,16 +1,18 @@
|
|||||||
|
import re
|
||||||
|
from abc import ABC
|
||||||
|
from abc import abstractmethod
|
||||||
|
from datetime import datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
from model import Transaction
|
from email.message import Message
|
||||||
import re
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from datetime import datetime
|
|
||||||
from logging import debug
|
from model import Transaction
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
|
|
||||||
class TransactionParser(ABC):
|
class TransactionParser(ABC):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def match(self, msg: EmailMessage) -> bool:
|
def match(self, msg: Message) -> bool:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@ -30,16 +32,19 @@ class RogersBankParser(TransactionParser):
|
|||||||
def __init__(self, account_id: UUID):
|
def __init__(self, account_id: UUID):
|
||||||
self.account_id = account_id
|
self.account_id = account_id
|
||||||
|
|
||||||
def match(self, msg: EmailMessage) -> bool:
|
def match(self, msg: Message) -> bool:
|
||||||
return (
|
return (
|
||||||
msg["From"] == "Rogers Bank <onlineservices@RogersBank.com>"
|
msg["From"] == "Rogers Bank <onlineservices@RogersBank.com>"
|
||||||
and msg["Subject"] == "Purchase amount alert"
|
and msg["Subject"] == "Purchase amount alert"
|
||||||
)
|
)
|
||||||
|
|
||||||
def extract(self, msg: EmailMessage) -> Transaction:
|
def extract(self, msg: EmailMessage) -> Transaction:
|
||||||
matches = RogersBankParser.EXTRACT_RE.search(msg.get_body().as_string())
|
body = msg.get_body()
|
||||||
|
if body is None:
|
||||||
|
raise TransactionParsingFailed("No body of message found")
|
||||||
|
matches = RogersBankParser.EXTRACT_RE.search(body.as_string())
|
||||||
if matches is None:
|
if matches is None:
|
||||||
return TransactionParsingFailed("No matches for extraction RE")
|
raise TransactionParsingFailed("No matches for extraction RE")
|
||||||
amount = Decimal(matches[1])
|
amount = Decimal(matches[1])
|
||||||
date_raw = matches[2]
|
date_raw = matches[2]
|
||||||
payee = matches[3]
|
payee = matches[3]
|
||||||
|
40
watcher.py
40
watcher.py
@ -1,17 +1,22 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
import asyncio
|
||||||
from email.message import EmailMessage
|
|
||||||
import logging
|
|
||||||
import asyncio, ssl, email
|
|
||||||
from os import getenv
|
|
||||||
from imaplib import IMAP4
|
|
||||||
from logging import info, debug, error, warning
|
|
||||||
from pprint import pprint
|
|
||||||
from model import Transaction
|
|
||||||
from config import PARSERS
|
|
||||||
from parsers import TransactionParsingFailed
|
|
||||||
import email.policy
|
import email.policy
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import ssl
|
||||||
|
from email.message import EmailMessage
|
||||||
|
from imaplib import IMAP4
|
||||||
|
from logging import debug
|
||||||
|
from logging import error
|
||||||
|
from logging import info
|
||||||
|
from logging import warning
|
||||||
|
from os import getenv
|
||||||
|
from pprint import pprint
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
|
from config import PARSERS
|
||||||
|
from model import Transaction
|
||||||
|
from parsers import TransactionParsingFailed
|
||||||
|
|
||||||
IMAP_SERVER = getenv("IMAP_SERVER")
|
IMAP_SERVER = getenv("IMAP_SERVER")
|
||||||
IMAP_PORT = int(getenv("IMAP_PORT", 143))
|
IMAP_PORT = int(getenv("IMAP_PORT", 143))
|
||||||
@ -32,7 +37,14 @@ async def ticker(interval: float):
|
|||||||
|
|
||||||
|
|
||||||
async def submit_transaction(t: Transaction):
|
async def submit_transaction(t: Transaction):
|
||||||
cmd=ACTUAL_PATH + f' -a "{t.account}"' + f' -p "{t.payee}"' + f' -m "{t.amount}"' + f' -d "{t.date}"' f' -n "{t.notes}"'
|
cmd = (
|
||||||
|
ACTUAL_PATH
|
||||||
|
+ f' -a "{t.account}"'
|
||||||
|
+ f' -p "{t.payee}"'
|
||||||
|
+ f' -m "{t.amount}"'
|
||||||
|
+ f' -d "{t.date}"'
|
||||||
|
f' -n "{t.notes}"'
|
||||||
|
)
|
||||||
debug("Actual command: %s", cmd)
|
debug("Actual command: %s", cmd)
|
||||||
proc = await asyncio.create_subprocess_shell(
|
proc = await asyncio.create_subprocess_shell(
|
||||||
cmd=cmd,
|
cmd=cmd,
|
||||||
@ -47,7 +59,9 @@ async def submit_transaction(t: Transaction):
|
|||||||
|
|
||||||
async def process_message(msg_b: bytes):
|
async def process_message(msg_b: bytes):
|
||||||
debug("parsing message")
|
debug("parsing message")
|
||||||
msg = email.message_from_bytes(msg_b, policy=email.policy.default)
|
msg = cast(
|
||||||
|
EmailMessage, email.message_from_bytes(msg_b, policy=email.policy.default)
|
||||||
|
)
|
||||||
pprint(msg)
|
pprint(msg)
|
||||||
info(
|
info(
|
||||||
"Found message from %s to %s subject %s",
|
"Found message from %s to %s subject %s",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user