linter &c
This commit is contained in:
		
							
								
								
									
										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
 | 
				
			||||||
							
								
								
									
										3
									
								
								model.py
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								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:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user