From b17559d8ede422a0b91bcc1a2a01e71cd9b905b3 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 11 Aug 2023 14:07:32 +0200 Subject: extract the models and utility function into separate source files --- geldschieberbot.py | 90 ++---------------------------------------------------- models.py | 71 ++++++++++++++++++++++++++++++++++++++++++ utils.py | 28 +++++++++++++++++ 3 files changed, 101 insertions(+), 88 deletions(-) create mode 100644 models.py create mode 100644 utils.py diff --git a/geldschieberbot.py b/geldschieberbot.py index f876461..0b766c0 100644 --- a/geldschieberbot.py +++ b/geldschieberbot.py @@ -3,100 +3,14 @@ import argparse from datetime import date, datetime, timedelta -from dataclasses import dataclass, field import json import os import subprocess import sys import typing as T - -@dataclass -class MessageContext: - """Class representing the context of a message passed to a command function""" - sender_number: str - sender: T.Optional[str] - args: list[str] - body: list[str] - timestamp: str - - -@dataclass -class Modification: - """Class representing a single modification to the balance - - Amount is transfered from donor to the recipient. - """ - recipient: str - donor: str - amount: int - - def in_string(self) -> str: - """Format the change using the recipient as initiator""" - return f'{self.recipient} {"->" if self.amount < 0 else "<-"} {to_euro(abs(self.amount))} {self.donor}' - - def out_string(self) -> str: - """Format the change using the donor as initiator""" - return f'{self.donor} {"->" if self.amount < 0 else "<-"} {to_euro(abs(self.amount))} {self.recipient}' - - -@dataclass -class Change: - """Class representing a change to the state caused by a single command""" - cmd: list[str] - modifications: list[Modification] - timestamp: str - rewind_cmds: list[list[str]] = field(default_factory=lambda: []) - - -@dataclass -class Quote: - """Class representing a message to quote""" - timestamp: str - author: str - - -class GeldschieberbotJSONEncoder(json.JSONEncoder): - """Custom JSONEncoder supporting our dataclasses""" - - def default(self, o): - if isinstance(o, (Modification, Change)): - return o.__dict__ - return json.JSONEncoder.default(self, o) - - -@dataclass -class Reply: - """Class representing a reply from the bot""" - msg: str - attachment: T.Optional[str] = None - - -def to_cent(euro) -> int: - """Parse string containing euros into a cent value""" - if '.' in euro: - euro = euro.split('.') - else: - euro = euro.split(',') - if len(euro) > 2: - raise TypeError - euro[0] = int(euro[0]) - if len(euro) < 2: - euro.append(0) - else: - if len(euro[1]) == 1: - euro[1] = int(euro[1]) * 10 - else: - euro[1] = int(euro[1]) - amount = euro[0] * 100 + euro[1] - if amount < 0: - raise ValueError - return amount - - -def to_euro(cents) -> str: - """Format cents as euro""" - return f"{cents/100:.2f}" +from models import MessageContext, Modification, Change, Quote, GeldschieberbotJSONEncoder, Reply +from utils import to_euro, to_cent class Geldschieberbot: diff --git a/models.py b/models.py new file mode 100644 index 0000000..5cee04a --- /dev/null +++ b/models.py @@ -0,0 +1,71 @@ +"""Models used by geldschieberbot""" + +import json +import typing as T + +from dataclasses import dataclass, field + +from utils import to_euro + + +@dataclass +class MessageContext: + """Class representing the context of a message passed to a command function""" + sender_number: str + sender: T.Optional[str] + args: list[str] + body: list[str] + timestamp: str + + +@dataclass +class Modification: + """Class representing a single modification to the balance + + Amount is transfered from donor to the recipient. + """ + recipient: str + donor: str + amount: int + + def in_string(self) -> str: + """Format the change using the recipient as initiator""" + return (f'{self.recipient} {"->" if self.amount < 0 else "<-"}' + f' {to_euro(abs(self.amount))} {self.donor}') + + def out_string(self) -> str: + """Format the change using the donor as initiator""" + return (f'{self.donor} {"->" if self.amount < 0 else "<-"}' + f' {to_euro(abs(self.amount))} {self.recipient}') + + +@dataclass +class Change: + """Class representing a change to the state caused by a single command""" + cmd: list[str] + modifications: list[Modification] + timestamp: str + rewind_cmds: list[list[str]] = field(default_factory=lambda: []) + + +@dataclass +class Quote: + """Class representing a message to quote""" + timestamp: str + author: str + + +class GeldschieberbotJSONEncoder(json.JSONEncoder): + """Custom JSONEncoder supporting our dataclasses""" + + def default(self, o): + if isinstance(o, (Modification, Change)): + return o.__dict__ + return json.JSONEncoder.default(self, o) + + +@dataclass +class Reply: + """Class representing a reply from the bot""" + msg: str + attachment: T.Optional[str] = None diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..353e562 --- /dev/null +++ b/utils.py @@ -0,0 +1,28 @@ +"""Utility functions used by the geldschieberbot""" + + +def to_cent(euro) -> int: + """Parse string containing euros into a cent value""" + if '.' in euro: + euro = euro.split('.') + else: + euro = euro.split(',') + if len(euro) > 2: + raise TypeError + euro[0] = int(euro[0]) + if len(euro) < 2: + euro.append(0) + else: + if len(euro[1]) == 1: + euro[1] = int(euro[1]) * 10 + else: + euro[1] = int(euro[1]) + amount = euro[0] * 100 + euro[1] + if amount < 0: + raise ValueError + return amount + + +def to_euro(cents) -> str: + """Format cents as euro""" + return f"{cents/100:.2f}" -- cgit v1.2.3