[Refactor] Export ops move to Client interface

Introduce new `Manager` parameter database to use new DB client API.
Fix TransactionCategory format.
Fix Client kwargs type.
This commit is contained in:
Luís Murta 2023-04-27 19:24:38 +01:00
parent ad62317e56
commit 9f39836083
Signed by: satprog
GPG Key ID: 169EF1BBD7049F94
4 changed files with 47 additions and 21 deletions

View File

@ -67,7 +67,7 @@ def argparser() -> argparse.ArgumentParser:
pimport = subparsers.add_parser("import") pimport = subparsers.add_parser("import")
pimport.set_defaults(op=Operation.Import) pimport.set_defaults(op=Operation.Import)
pimport.add_argument("file", nargs=1, type=str) file_options(pimport)
# Parse from .csv # Parse from .csv
parse = subparsers.add_parser("parse") parse = subparsers.add_parser("parse")

View File

@ -1,10 +1,12 @@
import csv import csv
import json
from pathlib import Path from pathlib import Path
import pickle import pickle
from typing import Optional
import webbrowser import webbrowser
from pfbudget.common.types import Operation from pfbudget.common.types import Operation
from pfbudget.db.postgresql import DbClient from pfbudget.db.client import Client
from pfbudget.db.model import ( from pfbudget.db.model import (
Bank, Bank,
BankTransaction, BankTransaction,
@ -24,6 +26,7 @@ from pfbudget.db.model import (
Transaction, Transaction,
TransactionCategory, TransactionCategory,
) )
from pfbudget.db.postgresql import DbClient
from pfbudget.extract.nordigen import NordigenClient, NordigenCredentialsManager from pfbudget.extract.nordigen import NordigenClient, NordigenCredentialsManager
from pfbudget.extract.parsers import parse_data from pfbudget.extract.parsers import parse_data
from pfbudget.extract.psd2 import PSD2Extractor from pfbudget.extract.psd2 import PSD2Extractor
@ -35,6 +38,7 @@ from pfbudget.transform.tagger import Tagger
class Manager: class Manager:
def __init__(self, db: str, verbosity: int = 0): def __init__(self, db: str, verbosity: int = 0):
self._db = db self._db = db
self._database: Optional[Client] = None
self._verbosity = verbosity self._verbosity = verbosity
def action(self, op: Operation, params=None): def action(self, op: Operation, params=None):
@ -49,10 +53,7 @@ class Manager:
pass pass
case Operation.Transactions: case Operation.Transactions:
with self.db.session() as session: return [t.format for t in self.database.select(Transaction)]
transactions = session.get(Transaction)
ret = [t.format for t in transactions]
return ret
case Operation.Parse: case Operation.Parse:
# Adapter for the parse_data method. Can be refactored. # Adapter for the parse_data method. Can be refactored.
@ -263,8 +264,10 @@ class Manager:
session.insert(transactions) session.insert(transactions)
case Operation.Export: case Operation.Export:
with self.db.session() as session: with self.database.session as session:
self.dump(params[0], params[1], sorted(session.get(Transaction))) self.dump(
params[0], params[1], self.database.select(Transaction, session)
)
case Operation.Import: case Operation.Import:
transactions = [] transactions = []
@ -301,8 +304,8 @@ class Manager:
session.insert(transactions) session.insert(transactions)
case Operation.ExportBanks: case Operation.ExportBanks:
with self.db.session() as session: with self.database.session as session:
self.dump(params[0], params[1], session.get(Bank)) self.dump(params[0], params[1], self.database.select(Bank, session))
case Operation.ImportBanks: case Operation.ImportBanks:
banks = [] banks = []
@ -317,8 +320,12 @@ class Manager:
session.insert(banks) session.insert(banks)
case Operation.ExportCategoryRules: case Operation.ExportCategoryRules:
with self.db.session() as session: with self.database.session as session:
self.dump(params[0], params[1], session.get(CategoryRule)) self.dump(
params[0],
params[1],
self.database.select(CategoryRule, session),
)
case Operation.ImportCategoryRules: case Operation.ImportCategoryRules:
rules = [CategoryRule(**row) for row in self.load(params[0], params[1])] rules = [CategoryRule(**row) for row in self.load(params[0], params[1])]
@ -328,8 +335,10 @@ class Manager:
session.insert(rules) session.insert(rules)
case Operation.ExportTagRules: case Operation.ExportTagRules:
with self.db.session() as session: with self.database.session as session:
self.dump(params[0], params[1], session.get(TagRule)) self.dump(
params[0], params[1], self.database.select(TagRule, session)
)
case Operation.ImportTagRules: case Operation.ImportTagRules:
rules = [TagRule(**row) for row in self.load(params[0], params[1])] rules = [TagRule(**row) for row in self.load(params[0], params[1])]
@ -339,8 +348,10 @@ class Manager:
session.insert(rules) session.insert(rules)
case Operation.ExportCategories: case Operation.ExportCategories:
with self.db.session() as session: with self.database.session as session:
self.dump(params[0], params[1], session.get(Category)) self.dump(
params[0], params[1], self.database.select(Category, session)
)
case Operation.ImportCategories: case Operation.ImportCategories:
# rules = [Category(**row) for row in self.load(params[0])] # rules = [Category(**row) for row in self.load(params[0])]
@ -363,8 +374,12 @@ class Manager:
session.insert(categories) session.insert(categories)
case Operation.ExportCategoryGroups: case Operation.ExportCategoryGroups:
with self.db.session() as session: with self.database.session as session:
self.dump(params[0], params[1], session.get(CategoryGroup)) self.dump(
params[0],
params[1],
self.database.select(CategoryGroup, session),
)
case Operation.ImportCategoryGroups: case Operation.ImportCategoryGroups:
groups = [ groups = [
@ -397,6 +412,9 @@ class Manager:
elif format == "csv": elif format == "csv":
with open(fn, "w", newline="") as f: with open(fn, "w", newline="") as f:
csv.writer(f).writerows([e.format.values() for e in sequence]) csv.writer(f).writerows([e.format.values() for e in sequence])
elif format == "json":
with open(fn, "w", newline="") as f:
json.dump([e.format for e in sequence], f, indent=4, default=str)
else: else:
print("format not well specified") print("format not well specified")
@ -418,9 +436,15 @@ class Manager:
return False return False
@property @property
def db(self) -> DbClient: def db(self) -> Client:
return DbClient(self._db, self._verbosity > 2) return DbClient(self._db, self._verbosity > 2)
@property
def database(self) -> Client:
if not self._database:
self._database = Client(self._db, echo=self._verbosity > 2)
return self._database
@db.setter @db.setter
def db(self, url: str): def db(self, url: str):
self._db = url self._db = url

View File

@ -8,7 +8,7 @@ from pfbudget.db.model import Transaction
class Client: class Client:
def __init__(self, url: str, **kwargs: dict[str, Any]) -> None: def __init__(self, url: str, **kwargs: Any) -> None:
assert url, "Database URL is empty!" assert url, "Database URL is empty!"
self._engine = create_engine(url, **kwargs) self._engine = create_engine(url, **kwargs)
self._sessionmaker: Optional[sessionmaker[Session]] = None self._sessionmaker: Optional[sessionmaker[Session]] = None

View File

@ -216,7 +216,9 @@ class TransactionCategory(Base, Export):
@property @property
def format(self): def format(self):
return dict(name=self.name, selector=self.selector.format) return dict(
name=self.name, selector=self.selector.format if self.selector else None
)
class Note(Base): class Note(Base):