-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor API to use typer as CLI interface (#70)
- Loading branch information
1 parent
76ba527
commit 3e9836d
Showing
16 changed files
with
382 additions
and
366 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
""" | ||
Parse an input file and create transactions in YNAB. | ||
""" | ||
import pathlib | ||
import re | ||
from pathlib import Path | ||
|
||
import pandas as pd | ||
from moneyed import Money | ||
from moneyed import USD | ||
|
||
from bany.cmd.extract.extractors import EXTRACTORS | ||
from bany.cmd.extract.extractors.base import Extractor | ||
from bany.core.logger import logger | ||
from bany.core.logger import logline | ||
from bany.ynab.api import YNAB | ||
|
||
|
||
def main(extractor: str, inp: Path, config: Path, upload: bool) -> None: | ||
ynab = YNAB() | ||
|
||
if inp.is_dir(): | ||
inp = _get_latest_pdf(root=inp) | ||
|
||
logger.info("inp: %s", inp) | ||
|
||
extractor: Extractor = EXTRACTORS[extractor].create(ynab=ynab, config=config) | ||
extracted = pd.DataFrame( | ||
extract.model_dump() | dict(transaction=extract) for extract in extractor.extract(path=inp) | ||
) | ||
|
||
if extracted.empty: | ||
logger.error("no extracted found in PDF") | ||
else: | ||
logline() | ||
excluded = {"transaction", "account_id", "budget_id", "category_id", "import_id"} | ||
logger.info("extracted:\n%s", extracted.loc[:, ~extracted.columns.isin(excluded)]) | ||
|
||
logline() | ||
logger.info("%-9s : %12s", "TOTAL [+]", Money(extracted[extracted.amount > 0].amount.sum() / 1000, USD)) | ||
logger.info("%-9s : %12s", "TOTAL [-]", Money(extracted[extracted.amount < 0].amount.sum() / 1000, USD)) | ||
logger.info("%-9s : %12s", "TOTAL", Money(extracted.amount.sum() / 1000, USD)) | ||
|
||
if upload: | ||
for i, extract in extracted.iterrows(): | ||
transaction = extract.transaction | ||
ynab.transact(transaction.budget_id, transaction) | ||
|
||
|
||
def _get_latest_pdf(root: pathlib.Path) -> pathlib.Path: | ||
for path in sorted(root.glob("*.pdf"), key=lambda p: [int(v) for v in re.findall(r"\d+", p.name)], reverse=True): | ||
return path | ||
raise FileNotFoundError(root.joinpath("*.pdf")) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +0,0 @@ | ||
from .controller import Controller # noqa: F401 | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
""" | ||
Parse an input file and create transactions in YNAB. | ||
""" | ||
from pathlib import Path | ||
|
||
import networkx as nx | ||
import pandas as pd | ||
|
||
import bany.cmd.solve.network.loader | ||
import bany.cmd.solve.network.visualize as visualize | ||
import bany.cmd.solve.solvers.constrained | ||
import bany.cmd.solve.solvers.graphsolver | ||
import bany.cmd.solve.solvers.montecarlo | ||
import bany.cmd.solve.solvers.unconstrained | ||
from bany.cmd.solve.network.algo import aggregate_quantity | ||
from bany.cmd.solve.network.attrs import node_attrs | ||
from bany.cmd.solve.solvers.basesolver import BucketSolver | ||
from bany.cmd.solve.solvers.graphsolver import solve | ||
from bany.core.logger import logger | ||
from bany.core.logger import logline | ||
from bany.core.money import moneyfmt | ||
|
||
|
||
def main(solver: type[BucketSolver], config: Path) -> None: | ||
frame: pd.DataFrame = bany.cmd.solve.network.loader.load(path=config) | ||
logger.info("frame:\n%s\n", frame) | ||
|
||
graph: nx.DiGraph = bany.cmd.solve.network.algo.create(frame) | ||
visualize.log("graph", graph, **visualize.FORMATS_INP) | ||
|
||
solved: nx.DiGraph = solve(graph, solver=solver, inplace=False) | ||
visualize.log("solved", solved, **visualize.FORMATS_OUT) | ||
|
||
_display_results(solved, fmt=f"%-{max(15, max(len(n) for n in solved.nodes))}s: %s") | ||
|
||
|
||
def _display_results(graph: nx.DiGraph, fmt: str): | ||
amount_to_add: float = aggregate_quantity(graph, key=node_attrs.amount_to_add.column) | ||
logger.info(fmt, "amount_to_add", moneyfmt(amount_to_add)) | ||
|
||
results_value: float = aggregate_quantity(graph, key=node_attrs.results_value.column, leaves=True) | ||
logger.info(fmt, "results_value", moneyfmt(results_value)) | ||
|
||
results_ratio: float = aggregate_quantity(graph, key=node_attrs.results_ratio.column, leaves=True) | ||
logger.info(fmt, "results_ratio", moneyfmt(results_ratio, decimals=10)) | ||
|
||
logline() | ||
for node in graph: | ||
# noinspection PyCallingNonCallable | ||
if graph.out_degree(node) == 0 and graph.in_degree(node) == 1: | ||
amount_to_add: float = graph.nodes[node][node_attrs.amount_to_add.column] | ||
logger.info(fmt, node, moneyfmt(amount_to_add)) |
Oops, something went wrong.