From d8895311256cc7b3c113c0c3adfb407ce28035eb Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:00:01 +0200 Subject: [PATCH 01/27] add data folder with sample of gnucash sqlite books --- data/README.md | 11 +++++++++++ data/book_prices.gnucash | Bin 0 -> 241664 bytes data/book_schtx.gnucash | Bin 0 -> 177152 bytes data/complex_sample.gnucash | Bin 0 -> 212992 bytes data/default_book.gnucash | Bin 0 -> 225280 bytes data/empty_book.gnucash | Bin 0 -> 62464 bytes data/ghost_kvp_scheduled_transaction.gnucash | Bin 0 -> 62464 bytes data/investment.gnucash | Bin 0 -> 212992 bytes data/invoices.gnucash | Bin 0 -> 225280 bytes .../reference/2_6/default_2_6_21_basic.gnucash | Bin 0 -> 212992 bytes .../2_6/default_2_6_21_full_options.gnucash | Bin 0 -> 212992 bytes data/reference/3_0/default_3_0_0_basic.gnucash | Bin 0 -> 212992 bytes .../3_0/default_3_0_0_full_options.gnucash | Bin 0 -> 212992 bytes data/simple_sample.272.gnucash | Bin 0 -> 212992 bytes data/simple_sample.gnucash | Bin 0 -> 212992 bytes data/test_book.gnucash | Bin 0 -> 78848 bytes 16 files changed, 11 insertions(+) create mode 100644 data/README.md create mode 100644 data/book_prices.gnucash create mode 100644 data/book_schtx.gnucash create mode 100644 data/complex_sample.gnucash create mode 100644 data/default_book.gnucash create mode 100644 data/empty_book.gnucash create mode 100644 data/ghost_kvp_scheduled_transaction.gnucash create mode 100644 data/investment.gnucash create mode 100644 data/invoices.gnucash create mode 100644 data/reference/2_6/default_2_6_21_basic.gnucash create mode 100644 data/reference/2_6/default_2_6_21_full_options.gnucash create mode 100644 data/reference/3_0/default_3_0_0_basic.gnucash create mode 100644 data/reference/3_0/default_3_0_0_full_options.gnucash create mode 100644 data/simple_sample.272.gnucash create mode 100644 data/simple_sample.gnucash create mode 100644 data/test_book.gnucash diff --git a/data/README.md b/data/README.md new file mode 100644 index 0000000..f7dfbf5 --- /dev/null +++ b/data/README.md @@ -0,0 +1,11 @@ +# Sample gnucash books + +This folder holds a set of gnucash books used for testing, examples and debugging. + + +## Default empty books + +The following gnucash books can be used to introspect the SQL schema: +- reference/default_2_6_21_basic.gnucash: empty gnucash books created with gnucash 2.6.21 and no specific options +- reference/default_2_6_21_full_options.gnucash: empty gnucash books created with gnucash 2.6.21 with multiple options enabled (trading accounts, ...) + diff --git a/data/book_prices.gnucash b/data/book_prices.gnucash new file mode 100644 index 0000000000000000000000000000000000000000..0d93c284fb186fe736557686a95095b020314e95 GIT binary patch literal 241664 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 YG2DIH&j9j_>!9o!)n?eU5y# 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 literal 0 HcmV?d00001 diff --git a/data/complex_sample.gnucash b/data/complex_sample.gnucash new file mode 100644 index 0000000000000000000000000000000000000000..3214b5775cf1fb79842d7134c73cb1e8893e8bf5 GIT binary patch literal 212992 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 OQ)aJvjLL*;3jF_Ry#Ag5 literal 0 HcmV?d00001 diff --git a/data/empty_book.gnucash b/data/empty_book.gnucash new file mode 100644 index 0000000000000000000000000000000000000000..75f8a72d5f695fa468d66466a36572795b28c487 GIT binary patch literal 62464 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 literal 0 HcmV?d00001 diff --git a/data/ghost_kvp_scheduled_transaction.gnucash b/data/ghost_kvp_scheduled_transaction.gnucash new file mode 100644 index 0000000000000000000000000000000000000000..3e3af00b2260ed99bf9439d5f560b711afc8dd5a GIT binary patch literal 62464 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 literal 0 HcmV?d00001 diff --git a/data/reference/2_6/default_2_6_21_full_options.gnucash b/data/reference/2_6/default_2_6_21_full_options.gnucash new file mode 100644 index 0000000000000000000000000000000000000000..951beed02b127bf1caee034940af0b1ed7913c6f GIT binary patch literal 212992 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 literal 0 HcmV?d00001 diff --git a/data/simple_sample.272.gnucash b/data/simple_sample.272.gnucash new file mode 100644 index 0000000000000000000000000000000000000000..05c5eb5985a83f30c9d9a191d7038e0725c7540f GIT binary patch literal 212992 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 literal 0 HcmV?d00001 diff --git a/data/test_book.gnucash b/data/test_book.gnucash new file mode 100644 index 0000000000000000000000000000000000000000..b44b5d6958beaf0e5a2fc0fc242eedad398249b7 GIT binary patch literal 78848 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 Date: Tue, 25 Jun 2024 07:01:29 +0200 Subject: [PATCH 02/27] add first working code --- piecash2/__init__.py | 3 + piecash2/base.py | 17 -- piecash2/schema/sa_schema_post.py | 3 + piecash2/schema/sa_schema_pre.py | 347 +++++++++++++++++++++++++++ piecash2/schema/schema_generation.py | 118 +++++++++ piecash2/utils.py | 30 +++ 6 files changed, 501 insertions(+), 17 deletions(-) delete mode 100644 piecash2/base.py create mode 100644 piecash2/schema/sa_schema_post.py create mode 100644 piecash2/schema/sa_schema_pre.py create mode 100644 piecash2/schema/schema_generation.py create mode 100644 piecash2/utils.py diff --git a/piecash2/__init__.py b/piecash2/__init__.py index e69de29..c26ead0 100644 --- a/piecash2/__init__.py +++ b/piecash2/__init__.py @@ -0,0 +1,3 @@ +from .schema.schema_generation import open_book, add_book_module_in_path + +__ALL__ = [open_book, add_book_module_in_path] diff --git a/piecash2/base.py b/piecash2/base.py deleted file mode 100644 index c6cbf0d..0000000 --- a/piecash2/base.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -piecash2 base module. - -This is the principal module of the piecash2 project. -here you put your main classes and objects. - -Be creative! do whatever you want! - -If you want to replace this with a Flask application run: - - $ make init - -and then choose `flask` as template. -""" - -# example constant variable -NAME = "piecash2" diff --git a/piecash2/schema/sa_schema_post.py b/piecash2/schema/sa_schema_post.py new file mode 100644 index 0000000..5afa1f9 --- /dev/null +++ b/piecash2/schema/sa_schema_post.py @@ -0,0 +1,3 @@ +# list all glasses with a guid property (that can be linked to in Slot/Recurrence through obj_guid) +gl = globals() +name2kls = {n: gl[n] for n in klswithguid_names} diff --git a/piecash2/schema/sa_schema_pre.py b/piecash2/schema/sa_schema_pre.py new file mode 100644 index 0000000..9387f9b --- /dev/null +++ b/piecash2/schema/sa_schema_pre.py @@ -0,0 +1,347 @@ +from collections import defaultdict +from decimal import Decimal +from enum import Enum +from fractions import Fraction +from functools import lru_cache + +import sqlalchemy +from sqlalchemy import select, text, union_all +from sqlalchemy.ext.declarative import declarative_base as declarative_base_ +from sqlalchemy.ext.hybrid import Comparator, hybrid_property +from sqlalchemy.orm import DeclarativeMeta as DeclarativeMeta_, Session + +from piecash2 import utils + +odict = dict + +# todo: reduce the list to classes which can really contains slots/recurrences to speed up detection of object class +klswithguid_names = [ + "Account", + "Billterm", + "Book", + "Budget", + "Commodity", + "Customer", + "Employee", + "Entry", + "Invoice", + "Job", + "Lot", + "Order", + "Price", + "Schedxaction", + "Slot", + "Split", + "Taxtable", + "Transaction", + "Vendor", +] + + +class SlotValueType(Enum): + """Enum to define the type of owner""" + + INVALID = -1 + INT64 = 1 + DOUBLE = 2 + NUMERIC = 3 + STRING = 4 + GUID = 5 + TIME64 = 6 + PLACEHOLDER_DONT_USE = 7 + GLIST = 8 + FRAME = 9 + GDATE = 10 + + +class DecimalNumDenom(object): + def __init__(self, num, denom): + self.num = num + self.denom = denom + + @classmethod + def from_db(cls, num, denom): + return DecimalNumDenom(num, denom) + + @classmethod + def from_dt(cls, d: Decimal): + return DecimalNumDenom(d, d) + + def __composite_values__(self): + return (self.dt, self.tz) + + def value(self): + return datetime.datetime(self.dt, self.tz) + + +class OwnerType(Enum): + """Enum to define the type of owner""" + + NONE = 0 + UNDEFINED = 1 + CUSTOMER = 2 + JOB = 3 + VENDOR = 4 + EMPLOYEE = 5 + + def cls_name(self): + return self.name.lower().capitalize() + + @classmethod + def from_cls(cls, obj): + return cls[obj.__class__.__name__.upper()] if obj is not None else cls.NONE + + @property + def cls_name(self): + return self.attr_name.capitalize() + + @property + def attr_name(self): + return self.name.lower() + + @classmethod + def object_classes(cls) -> list["OwnerType"]: + return [cls for cls in cls if cls not in {cls.NONE, cls.UNDEFINED}] + + +class GuidComparator(Comparator): + """Take a guid and compare it to another object's guid""" + + def __eq__(self, other): + # Define custom comparison for equality + return self.__clause_element__() == other.guid + + def __ne__(self, other): + # Define custom comparison for inequality + return self.__clause_element__() != other.guid + + +class DeclarativeMeta(DeclarativeMeta_): + backrefs_already_used = defaultdict(set) + use_decimal = False + + def __new__(cls, name, bases, dict): + """ + The different objects use different naming conventions: + - tablename = underscore plural + - name = CamelCase singular + - fields = underscore singular + """ + + tablename = dict.get("__tablename__") + + if tablename: + assert tablename == utils.underscore( + utils.pluralize(name) + ), f"{tablename} <> {utils.underscore(utils.pluralize(name))}" + + self_id = dict.get("guid", dict.get("id")) + + for k, v in list(dict.items()): + if name == "Slot" and k == "obj_guid": + # replace name of column obj_guid to guid + dict["guid"] = sqlalchemy.orm.synonym("guid_val") + + elif name in {"Slot", "Recurrence"} and k == "guid_val": + attrs_to_expire = [] + # define the n relationships related to guid + for kls_other in klswithguid_names: + kwargs = odict( + argument=kls_other, + backref="slots", + primaryjoin=f"foreign({name}.obj_guid) == remote({kls_other}.guid)", + viewonly=True, + ) + attr_name = f"object_val_{kls_other.lower()}" + dict[attr_name] = sqlalchemy.orm.relationship(**kwargs) + attrs_to_expire.append(attr_name) + + # define the object property + def object_getter(self): + session = Session.object_session(self) + + # detect which type of class is the object related to the obj_guid + qry_object_type_attr = union_all( + *(select(text(f"'{name.lower()}'")).where(kls.guid == self.obj_guid) for name, kls in name2kls.items()), + ).limit(1) + object_type_attr = session.execute(qry_object_type_attr).scalar() + + # return the object related to the obj_guid + return getattr(self, f"object_val_{object_type_attr}") + + def object_comparator(cls): + return GuidComparator(getattr(cls, f"obj_guid")) + + def object_setter(self, object): + object_old = self.object + setattr(self, f"obj_guid", object.guid) + # expire the relationships related to the attr + session = Session.object_session(self) + session.expire(self, attrs_to_expire) # expire link Slot -> Object + session.expire(object_old, ["slots"]) # expire backrefs on old object + session.expire(object, ["slots"]) # expire backrefs on new object + + dict["object"] = object_getter + dict["object"] = hybrid_property(object_getter).setter(object_setter).comparator(object_comparator) + + elif name == "Slot" and k == "slot_type": + # handle slot_type as enum via slot_type_enum + # todo: rename slot_type to _slot_type and slot_type_enum to slot_type + # todo: redefine slot_type to be an Enum type but using the same backed as original + @hybrid_property + def getter(self): + return SlotValueType(self.slot_type) + + @getter.setter + def setter(self, value): + self.slot_type = value.value + + @getter.expression + def expression(cls): + return cls.slot_type + + dict["slot_type_enum"] = getter + + # handle fractions/decimals as numerators/denominators + elif k.endswith("_denom") and k[:-6] + "_num" in dict: + fraction_base = k[:-6] + if cls.use_decimal: + dict[f"{fraction_base}"] = hybrid_property( + lambda self: Decimal(getattr(self, fraction_base + "_num")) / Decimal(getattr(self, fraction_base + "_denom")) + ).setter( + lambda self, value: setattr(self, fraction_base + "_num", (ratio := value.as_integer_ratio())[0]) + or setattr(self, fraction_base + "_denom", ratio[1]) + ) + else: + dict[f"{fraction_base}"] = hybrid_property( + lambda self: Fraction(getattr(self, fraction_base + "_num"), getattr(self, fraction_base + "_denom")) + ).setter( + lambda self, value: setattr(self, fraction_base + "_num", value.numerator) + or setattr(self, fraction_base + "_denom", value.denominator) + ) + + # handle owner/billto _guid/_type combo + elif k.endswith("_guid") and k[:-5] + "_type" in dict: + # define the n relationships related to OwnerTypes + # and the appropriate python getter/setter and SQL comparator + attr = k[:-5] + assert attr in {"billto", "owner"}, attr + + for typ in OwnerType: + if typ in {OwnerType.NONE, OwnerType.UNDEFINED}: + continue + kls_other = typ.cls_name + kwargs = odict( + argument=kls_other, + backref=None, + primaryjoin=f"(foreign({name}.{attr}_guid) == remote({kls_other}.guid)) " + f"& ({name}.{attr}_type == {typ.value})", + viewonly=True, + ) + dict[f"{attr}_{typ.attr_name}"] = sqlalchemy.orm.relationship(**kwargs) + + def attr_getter(self, attr=attr): + typ = OwnerType(getattr(self, f"{attr}_type") or 0) + + if typ in OwnerType.object_classes(): + return getattr(self, f"{attr}_{typ.attr_name}") + else: + return None + + def attr_comparator(cls, attr=attr): + return GuidComparator(getattr(cls, f"{attr}_guid")) + + def attr_setter( + self, value, attr=attr, attrs_to_expire=tuple(f"{attr}_{kls.attr_name}" for kls in OwnerType.object_classes()) + ): + typ = OwnerType.from_cls(value) + setattr(self, f"{attr}_guid", value.guid) + setattr(self, f"{attr}_type", typ.value) + # expire the relationships related to the attr + Session.object_session(self).expire(self, attrs_to_expire) + + dict[f"{attr}"] = hybrid_property(attr_getter).setter(attr_setter).comparator(attr_comparator) + + # create relationships through xxx_guid + elif k.endswith("_guid"): + obj_name = k[:-5] + + kls_self = name + kls_other = utils.camelize(obj_name, uppercase_first_letter=True) + backref = utils.pluralize(utils.underscore(kls_self)) + + if kls_other == "Parent" and kls_self == "Account": + backref = sqlalchemy.orm.backref("parent", remote_side=[self_id]) + kls_other = kls_self + obj_name = "children" + if kls_other in {"RootAccount", "RootTemplate"}: + kls_other = "Account" + backref = None + if kls_other == "Currency": + kls_other = "Commodity" + backref = None + if kls_other == "TemplateAct": + kls_other = "Account" + if kls_other == "Tx": + kls_other = "Transaction" + + if obj_name == "ccard": # credit car account + kls_other = "Account" + if f"{obj_name}_type" in dict: # x_guid to be used with x_type in Entries/Invoicing/... + print(tablename, obj_name) + for kls_other in cls.classes_with_guid: + kls_other = kls_other.__name__ + kwargs = odict( + argument=kls_other, + backref=None, + primaryjoin=f"foreign({kls_self}.{k}) == {kls_other}.guid", + viewonly=True, + ) + dict[f"{obj_name}_{kls_other}"] = sqlalchemy.orm.relationship(**kwargs) + + continue + if obj_name == "obj" and kls_self in {"Recurrence", "Slot"}: + # done via ObjGUIDMixin + continue + + kwargs = odict( + argument=kls_other, + backref=backref, + primaryjoin=f"foreign({kls_self}.{k}) == {kls_other}.guid", + ) + + dict[obj_name] = sqlalchemy.orm.relationship(**kwargs) + + self = super().__new__(cls, name, bases, dict) + + return self + + + +class Base: + def __hash__(self): + return hash((self.__class__.__name__, self.id)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and ((self.__class__.__name__, self.id)) == ((other.__class__.__name__, other.id)) + + def __repr__(self): + return f"{self.__class__.__name__}<{self.name if hasattr(self, 'name') else ''}>[{self.uid}]" + + @property + def uid(self): + """Property to return the id if no Column with id already exists""" + try: + return self.guid + except AttributeError: + return self.id + + @property + def id(self): + """Property to return the id if no Column with id already exists""" + return self.guid + +@lru_cache +def declarative_base(*args, **kwargs): + base = declarative_base_(*args, **kwargs, metaclass=DeclarativeMeta, cls=Base) + return base diff --git a/piecash2/schema/schema_generation.py b/piecash2/schema/schema_generation.py new file mode 100644 index 0000000..dc9f25f --- /dev/null +++ b/piecash2/schema/schema_generation.py @@ -0,0 +1,118 @@ +"""Generate and import the SA schema from a gnucash sqlite file.""" +import importlib.util +import sqlite3 +import sys +from pathlib import Path + +import sqlalchemy +import sqlalchemy.orm + +# folder with code to insert into the schema generated by sqlacodegen +code_templates = Path(__file__).parent + +# folder in HOME to store the generated schemas +path_schemas = Path.home() / ".piecash2" / "schemas" +path_schemas.mkdir(exist_ok=True, parents=True) + + +def import_module_from_path(path: Path): + module_name = path.stem + spec = importlib.util.spec_from_file_location(module_name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + +def import_gnucash(book, regenerate_schema=False): + modulename = get_schema_name(book) + + if not modulename.exists() or regenerate_schema: + generate_schema(book, schema_file=modulename) + + return import_module_from_path(modulename) + + +def generate_schema(db, schema_file: Path): + """Generate the schema from the sqlite database using sqlacodegen and copy the common files to the db folder.""" + + sys.argv = [ + "sqlacodegen_v2", + "--outfile", + str(schema_file), + f"sqlite:///{db.as_posix()}", + "--option", + "use_inflect", + ] + import sqlacodegen_v2.cli + + sqlacodegen_v2.cli.main() + + # insert before/after the generated schema the common schema + schema_file_text = ( + (code_templates / "sa_schema_pre.py").read_text() + schema_file.read_text() + (code_templates / "sa_schema_post.py").read_text() + ) + + schema_file.write_text(schema_file_text) + return schema_file_text + + +def get_version(db: Path): + """Return the table version of a given book file.""" + with sqlite3.connect(db) as conn: + c = conn.cursor() + c.execute("SELECT table_version FROM versions WHERE table_name=='Gnucash'") + (gnucash_version,) = c.fetchone() + return gnucash_version + + +def get_schema_name(book: Path): + """Return the schema file name for a given book file.""" + v = get_version(book) + return path_schemas / f"book_schema_sqlite_{v}.py" + + +def open_book(book, regenerate_schema=False): + if isinstance(book, str): + book = Path(book) + + book_posix = book.as_posix() + + # connect to the local sqlite extract of GECO + sqlite_connection_string = f"sqlite:///{book_posix}" + + # make a backup of the DB in memory + db_memory_name = f":memgeco_{abs(hash(book_posix))}:" + with sqlite3.connect(book_posix) as source: + sqliteconn = f"file:{db_memory_name}?mode=memory&cache=shared" + dest = sqlite3.connect(sqliteconn, uri=True) + source.backup(dest) + + engine = sqlalchemy.create_engine(f"sqlite:///{db_memory_name}", echo=False, creator=lambda: sqlite3.connect(sqliteconn, uri=True)) + + Session = sqlalchemy.orm.sessionmaker(bind=engine, autoflush=True, autocommit=False) + + # must execute some query otherwise future call to the Session raise error + with Session() as s: + s.execute(sqlalchemy.text("")) + + Session.module = import_gnucash(book, regenerate_schema=regenerate_schema) + + return Session + + +def add_book_module_in_path(book): + module_folder = str(get_schema_name(book).parent) + if module_folder not in sys.path: + sys.path.append(module_folder) + + +def remove_book_module_in_path(book): + module_path = get_schema_name(book) + module_folder = str(module_path.parent) + module_name = module_path.stem + + sys.modules.pop(module_name) + + if module_folder in sys.path: + sys.path.remove(module_folder) diff --git a/piecash2/utils.py b/piecash2/utils.py new file mode 100644 index 0000000..5b200e5 --- /dev/null +++ b/piecash2/utils.py @@ -0,0 +1,30 @@ +import re + +import inflect + +inflect.def_classical["names"] = False +engine = inflect.engine() + + +def camelize(string, uppercase_first_letter=True): + """ + Convert strings to CamelCase. + """ + if uppercase_first_letter: + return re.sub(r"(?:^|_)(.)", lambda m: m.group(1).upper(), string) + else: + return string[0].lower() + camelize(string)[1:] + + +def underscore(word): + """ + Make an underscored, lowercase form from the expression in the string. + """ + word = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", word) + word = re.sub(r"([a-z\d])([A-Z])", r"\1_\2", word) + word = word.replace("-", "_") + return word.lower() + + +def pluralize(word): + return engine.plural_noun(word) From c03d7066f74e90895f10f4dc48a2e716bc133d12 Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:01:57 +0200 Subject: [PATCH 03/27] add example in README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3881733..532895f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![codecov](https://codecov.io/gh/sdementen/piecash2/branch/main/graph/badge.svg?token=piecash2_token_here)](https://codecov.io/gh/sdementen/piecash2) [![CI](https://github.com/sdementen/piecash2/actions/workflows/main.yml/badge.svg)](https://github.com/sdementen/piecash2/actions/workflows/main.yml) -piecash using sqlalchemy 2 +A python library to work with [GnuCash](https://www.gnucash.org/) books, a successor of the [piecash](https://github.com/sdementen/piecash) library, built on top of SQLAlchemy 2. ## Install it from PyPI @@ -15,17 +15,17 @@ pip install piecash2 ## Usage ```py -from piecash2 import BaseClass -from piecash2 import base_function +from piecash2 import open_book -BaseClass().base_method() -base_function() -``` +# open the gnucash book (sqlite3 file) +Session = open_book("mybook.gnucash") +# retrieve the module +piecash = Session.module -```bash -$ python -m piecash2 -#or -$ piecash2 +with Session() as session: + # query all accounts in the + for account in session.query(piecash.Account).all(): + print(account.name) ``` ## Development From 342f763d954e549151976340b5fe9532df6fdf57 Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:03:35 +0200 Subject: [PATCH 04/27] add some simple tests --- tests/test_base.py | 52 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index c3fda5a..5179ac8 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,5 +1,51 @@ -from piecash2.base import NAME +import sys +from pathlib import Path +import pytest -def test_base(): - assert NAME == "piecash2" +from piecash2 import open_book +from piecash2.schema.schema_generation import add_book_module_in_path, get_schema_name, path_schemas, remove_book_module_in_path + +path_data = Path(__file__).parent.parent / "data" + + +def test_get_schema_name(): + book = path_data / "test book.gnucash" + assert get_schema_name(book).is_relative_to(path_schemas) + assert get_schema_name(book).stem == "book_schema_sqlite_2060400" + + +def test_direct_import(): + book = path_data / "test book.gnucash" + assert get_schema_name(book).stem == "book_schema_sqlite_2060400" + + with pytest.raises(ImportError): + import book_schema_sqlite_2060400 + + add_book_module_in_path(book) + + # import the module + import book_schema_sqlite_2060400 + + remove_book_module_in_path(book) + + with pytest.raises(ImportError): + import book_schema_sqlite_2060400 + + +def test_open_book(): + book = path_data / "test book.gnucash" + + Session = open_book(book) + piecash = Session.module + assert piecash.__name__ == get_schema_name(book).stem + + +def test_simple_query(): + book = path_data / "test book.gnucash" + + Session = open_book(book) + piecash = Session.module + + with Session() as s: + assert len(s.query(piecash.Slot).all()) == 20 From 6beda56edd841620dd87e9d3bc58bc6c5356559d Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:03:58 +0200 Subject: [PATCH 05/27] update setup.py with maturity and description --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9564ae9..43a901d 100644 --- a/setup.py +++ b/setup.py @@ -32,11 +32,12 @@ def read_requirements(path): setup( name="piecash2", version=read("piecash2", "VERSION"), - description="Awesome piecash2 created by sdementen", + description="piecash2, a python library to work with [GnuCash](https://www.gnucash.org/) books", url="https://github.com/sdementen/piecash2/", long_description=read("README.md"), long_description_content_type="text/markdown", author="sdementen", + maturity="Development Status :: 3 - Alpha", packages=find_packages(exclude=["tests", ".github"]), install_requires=read_requirements("requirements.txt"), entry_points={ From 710887a2727a1ddf76a928fb5a0d3a3dba4aedaa Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:04:14 +0200 Subject: [PATCH 06/27] add sqlacodegen_v2 as dependency --- requirements.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index b05f2a6..6e09bd4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1 @@ -# This template is a low-dependency template. -# By default there is no requirements added here. -# Add the requirements you need to this file. -# or run `make init` to create this file automatically based on the template. -# You can also run `make switch-to-poetry` to use the poetry package manager. +sqlacodegen_v2 From 5b496cad7a8f429ca8b598b37c4c828e17fb7161 Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:05:04 +0200 Subject: [PATCH 07/27] remove the rename_project.yml CI action --- .github/workflows/rename_project.yml | 42 ---------------------------- 1 file changed, 42 deletions(-) delete mode 100644 .github/workflows/rename_project.yml diff --git a/.github/workflows/rename_project.yml b/.github/workflows/rename_project.yml deleted file mode 100644 index 3c9d962..0000000 --- a/.github/workflows/rename_project.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Rename the project from template - -on: [push] - -permissions: write-all - -jobs: - rename-project: - if: ${{ !contains (github.repository, '/python-project-template') }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - # by default, it uses a depth of 1 - # this fetches all history so that we can read each commit - fetch-depth: 0 - ref: ${{ github.head_ref }} - - - run: echo "REPOSITORY_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}' | tr '-' '_' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV - shell: bash - - - run: echo "REPOSITORY_URLNAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV - shell: bash - - - run: echo "REPOSITORY_OWNER=$(echo '${{ github.repository }}' | awk -F '/' '{print $1}')" >> $GITHUB_ENV - shell: bash - - - name: Is this still a template - id: is_template - run: echo "::set-output name=is_template::$(ls .github/template.yml &> /dev/null && echo true || echo false)" - - - name: Rename the project - if: steps.is_template.outputs.is_template == 'true' - run: | - echo "Renaming the project with -a(author) ${{ env.REPOSITORY_OWNER }} -n(name) ${{ env.REPOSITORY_NAME }} -u(urlname) ${{ env.REPOSITORY_URLNAME }}" - .github/rename_project.sh -a ${{ env.REPOSITORY_OWNER }} -n ${{ env.REPOSITORY_NAME }} -u ${{ env.REPOSITORY_URLNAME }} -d "Awesome ${{ env.REPOSITORY_NAME }} created by ${{ env.REPOSITORY_OWNER }}" - - - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "✅ Ready to clone and code." - # commit_options: '--amend --no-edit' - push_options: --force From 7672eeba097f4f891e16b1ebbeb5b1bf8f8a0d21 Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:11:08 +0200 Subject: [PATCH 08/27] adapt linter to use 140 charts per line --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4e10c5e..176174b 100644 --- a/Makefile +++ b/Makefile @@ -33,8 +33,8 @@ fmt: ## Format code using black & isort. .PHONY: lint lint: ## Run pep8, black, mypy linters. $(ENV_PREFIX)flake8 piecash2/ - $(ENV_PREFIX)black -l 79 --check piecash2/ - $(ENV_PREFIX)black -l 79 --check tests/ + $(ENV_PREFIX)black -l 139 --check piecash2/ + $(ENV_PREFIX)black -l 139 --check tests/ $(ENV_PREFIX)mypy --ignore-missing-imports piecash2/ .PHONY: test From daaac749c1930fd3743ed5aeaae27ed053bf4e36 Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:13:44 +0200 Subject: [PATCH 09/27] fix linter issues --- piecash2/schema/sa_schema_pre.py | 59 ++++++++++++---------------- piecash2/schema/schema_generation.py | 3 -- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/piecash2/schema/sa_schema_pre.py b/piecash2/schema/sa_schema_pre.py index 9387f9b..38060c6 100644 --- a/piecash2/schema/sa_schema_pre.py +++ b/piecash2/schema/sa_schema_pre.py @@ -12,7 +12,6 @@ from piecash2 import utils -odict = dict # todo: reduce the list to classes which can really contains slots/recurrences to speed up detection of object class klswithguid_names = [ @@ -70,9 +69,6 @@ def from_dt(cls, d: Decimal): def __composite_values__(self): return (self.dt, self.tz) - def value(self): - return datetime.datetime(self.dt, self.tz) - class OwnerType(Enum): """Enum to define the type of owner""" @@ -84,9 +80,6 @@ class OwnerType(Enum): VENDOR = 4 EMPLOYEE = 5 - def cls_name(self): - return self.name.lower().capitalize() - @classmethod def from_cls(cls, obj): return cls[obj.__class__.__name__.upper()] if obj is not None else cls.NONE @@ -120,7 +113,7 @@ class DeclarativeMeta(DeclarativeMeta_): backrefs_already_used = defaultdict(set) use_decimal = False - def __new__(cls, name, bases, dict): + def __new__(cls, name, bases, attrs): """ The different objects use different naming conventions: - tablename = underscore plural @@ -128,32 +121,30 @@ def __new__(cls, name, bases, dict): - fields = underscore singular """ - tablename = dict.get("__tablename__") + tablename = attrs.get("__tablename__") if tablename: - assert tablename == utils.underscore( - utils.pluralize(name) - ), f"{tablename} <> {utils.underscore(utils.pluralize(name))}" + assert tablename == utils.underscore(utils.pluralize(name)), f"{tablename} <> {utils.underscore(utils.pluralize(name))}" - self_id = dict.get("guid", dict.get("id")) + self_id = attrs.get("guid", attrs.get("id")) - for k, v in list(dict.items()): + for k, v in list(attrs.items()): if name == "Slot" and k == "obj_guid": # replace name of column obj_guid to guid - dict["guid"] = sqlalchemy.orm.synonym("guid_val") + attrs["guid"] = sqlalchemy.orm.synonym("guid_val") elif name in {"Slot", "Recurrence"} and k == "guid_val": attrs_to_expire = [] # define the n relationships related to guid for kls_other in klswithguid_names: - kwargs = odict( + kwargs = dict( argument=kls_other, backref="slots", primaryjoin=f"foreign({name}.obj_guid) == remote({kls_other}.guid)", viewonly=True, ) attr_name = f"object_val_{kls_other.lower()}" - dict[attr_name] = sqlalchemy.orm.relationship(**kwargs) + attrs[attr_name] = sqlalchemy.orm.relationship(**kwargs) attrs_to_expire.append(attr_name) # define the object property @@ -181,8 +172,8 @@ def object_setter(self, object): session.expire(object_old, ["slots"]) # expire backrefs on old object session.expire(object, ["slots"]) # expire backrefs on new object - dict["object"] = object_getter - dict["object"] = hybrid_property(object_getter).setter(object_setter).comparator(object_comparator) + attrs["object"] = object_getter + attrs["object"] = hybrid_property(object_getter).setter(object_setter).comparator(object_comparator) elif name == "Slot" and k == "slot_type": # handle slot_type as enum via slot_type_enum @@ -200,20 +191,20 @@ def setter(self, value): def expression(cls): return cls.slot_type - dict["slot_type_enum"] = getter + attrs["slot_type_enum"] = getter # handle fractions/decimals as numerators/denominators - elif k.endswith("_denom") and k[:-6] + "_num" in dict: + elif k.endswith("_denom") and k[:-6] + "_num" in attrs: fraction_base = k[:-6] if cls.use_decimal: - dict[f"{fraction_base}"] = hybrid_property( + attrs[f"{fraction_base}"] = hybrid_property( lambda self: Decimal(getattr(self, fraction_base + "_num")) / Decimal(getattr(self, fraction_base + "_denom")) ).setter( lambda self, value: setattr(self, fraction_base + "_num", (ratio := value.as_integer_ratio())[0]) or setattr(self, fraction_base + "_denom", ratio[1]) ) else: - dict[f"{fraction_base}"] = hybrid_property( + attrs[f"{fraction_base}"] = hybrid_property( lambda self: Fraction(getattr(self, fraction_base + "_num"), getattr(self, fraction_base + "_denom")) ).setter( lambda self, value: setattr(self, fraction_base + "_num", value.numerator) @@ -221,7 +212,7 @@ def expression(cls): ) # handle owner/billto _guid/_type combo - elif k.endswith("_guid") and k[:-5] + "_type" in dict: + elif k.endswith("_guid") and k[:-5] + "_type" in attrs: # define the n relationships related to OwnerTypes # and the appropriate python getter/setter and SQL comparator attr = k[:-5] @@ -231,14 +222,14 @@ def expression(cls): if typ in {OwnerType.NONE, OwnerType.UNDEFINED}: continue kls_other = typ.cls_name - kwargs = odict( + kwargs = dict( argument=kls_other, backref=None, primaryjoin=f"(foreign({name}.{attr}_guid) == remote({kls_other}.guid)) " f"& ({name}.{attr}_type == {typ.value})", viewonly=True, ) - dict[f"{attr}_{typ.attr_name}"] = sqlalchemy.orm.relationship(**kwargs) + attrs[f"{attr}_{typ.attr_name}"] = sqlalchemy.orm.relationship(**kwargs) def attr_getter(self, attr=attr): typ = OwnerType(getattr(self, f"{attr}_type") or 0) @@ -260,7 +251,7 @@ def attr_setter( # expire the relationships related to the attr Session.object_session(self).expire(self, attrs_to_expire) - dict[f"{attr}"] = hybrid_property(attr_getter).setter(attr_setter).comparator(attr_comparator) + attrs[f"{attr}"] = hybrid_property(attr_getter).setter(attr_setter).comparator(attr_comparator) # create relationships through xxx_guid elif k.endswith("_guid"): @@ -287,37 +278,36 @@ def attr_setter( if obj_name == "ccard": # credit car account kls_other = "Account" - if f"{obj_name}_type" in dict: # x_guid to be used with x_type in Entries/Invoicing/... + if f"{obj_name}_type" in attrs: # x_guid to be used with x_type in Entries/Invoicing/... print(tablename, obj_name) for kls_other in cls.classes_with_guid: kls_other = kls_other.__name__ - kwargs = odict( + kwargs = dict( argument=kls_other, backref=None, primaryjoin=f"foreign({kls_self}.{k}) == {kls_other}.guid", viewonly=True, ) - dict[f"{obj_name}_{kls_other}"] = sqlalchemy.orm.relationship(**kwargs) + attrs[f"{obj_name}_{kls_other}"] = sqlalchemy.orm.relationship(**kwargs) continue if obj_name == "obj" and kls_self in {"Recurrence", "Slot"}: # done via ObjGUIDMixin continue - kwargs = odict( + kwargs = dict( argument=kls_other, backref=backref, primaryjoin=f"foreign({kls_self}.{k}) == {kls_other}.guid", ) - dict[obj_name] = sqlalchemy.orm.relationship(**kwargs) + attrs[obj_name] = sqlalchemy.orm.relationship(**kwargs) - self = super().__new__(cls, name, bases, dict) + self = super().__new__(cls, name, bases, attrs) return self - class Base: def __hash__(self): return hash((self.__class__.__name__, self.id)) @@ -341,6 +331,7 @@ def id(self): """Property to return the id if no Column with id already exists""" return self.guid + @lru_cache def declarative_base(*args, **kwargs): base = declarative_base_(*args, **kwargs, metaclass=DeclarativeMeta, cls=Base) diff --git a/piecash2/schema/schema_generation.py b/piecash2/schema/schema_generation.py index dc9f25f..4427741 100644 --- a/piecash2/schema/schema_generation.py +++ b/piecash2/schema/schema_generation.py @@ -78,9 +78,6 @@ def open_book(book, regenerate_schema=False): book_posix = book.as_posix() - # connect to the local sqlite extract of GECO - sqlite_connection_string = f"sqlite:///{book_posix}" - # make a backup of the DB in memory db_memory_name = f":memgeco_{abs(hash(book_posix))}:" with sqlite3.connect(book_posix) as source: From a817856e4aba96a7c96f279776391ba260fe081e Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 07:21:41 +0200 Subject: [PATCH 10/27] fix flake8 issues --- .flake8 | 2 ++ piecash2/schema/sa_schema_post.py | 2 +- piecash2/schema/sa_schema_pre.py | 9 ++++++--- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..ea97c3a --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 140 diff --git a/piecash2/schema/sa_schema_post.py b/piecash2/schema/sa_schema_post.py index 5afa1f9..ec88583 100644 --- a/piecash2/schema/sa_schema_post.py +++ b/piecash2/schema/sa_schema_post.py @@ -1,3 +1,3 @@ # list all glasses with a guid property (that can be linked to in Slot/Recurrence through obj_guid) gl = globals() -name2kls = {n: gl[n] for n in klswithguid_names} +name2kls = {n: gl[n] for n in klswithguid_names} # noqa: F821 diff --git a/piecash2/schema/sa_schema_pre.py b/piecash2/schema/sa_schema_pre.py index 38060c6..b167548 100644 --- a/piecash2/schema/sa_schema_pre.py +++ b/piecash2/schema/sa_schema_pre.py @@ -153,7 +153,10 @@ def object_getter(self): # detect which type of class is the object related to the obj_guid qry_object_type_attr = union_all( - *(select(text(f"'{name.lower()}'")).where(kls.guid == self.obj_guid) for name, kls in name2kls.items()), + *( + select(text(f"'{name.lower()}'")).where(kls.guid == self.obj_guid) + for name, kls in name2kls.items() # noqa: F821 + ), ).limit(1) object_type_attr = session.execute(qry_object_type_attr).scalar() @@ -161,11 +164,11 @@ def object_getter(self): return getattr(self, f"object_val_{object_type_attr}") def object_comparator(cls): - return GuidComparator(getattr(cls, f"obj_guid")) + return GuidComparator(cls.obj_guid) def object_setter(self, object): object_old = self.object - setattr(self, f"obj_guid", object.guid) + self.obj_guid = object.guid # expire the relationships related to the attr session = Session.object_session(self) session.expire(self, attrs_to_expire) # expire link Slot -> Object From d62df214e929a09f86a8ac2de60e00190669d769 Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 17:55:23 +0200 Subject: [PATCH 11/27] add make CLI implemented in python --- make.bat | 1 + make.py | 33 +++++++++++++++++++++++++++++++++ requirements-test.txt | 1 + 3 files changed, 35 insertions(+) create mode 100644 make.bat create mode 100644 make.py diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..9778dd5 --- /dev/null +++ b/make.bat @@ -0,0 +1 @@ +@py.exe make.py %* \ No newline at end of file diff --git a/make.py b/make.py new file mode 100644 index 0000000..e1dd372 --- /dev/null +++ b/make.py @@ -0,0 +1,33 @@ +import os +from pathlib import Path + +import typer + +app = typer.Typer() + + +@app.command() +def release(tag: str): + print(f"WARNING: This operation will create version {tag=} and push to github") + typer.confirm("Do you want to continue?", abort=True) + Path("piecash2/VERSION").write_text(tag) + os.system("gitchangelog > HISTORY.md") + os.system("git add piecash2/VERSION HISTORY.md") + os.system(f'git commit -m "release: version {tag}') + print(f"creating git tag : {tag}") + os.system(f"git tag {tag}") + os.system("git push -u origin HEAD --tags") + print("Github Actions will detect the new tag and release the new version.") + + +@app.command() +def lint(): + """lint: ## Run pep8, black, mypy linters.""" + os.system("flake8 piecash2/") + os.system("black -l 140 --check piecash2/") + os.system("black -l 140 --check tests/") + os.system("mypy --ignore-missing-imports piecash2/") + + +if __name__ == "__main__": + app() diff --git a/requirements-test.txt b/requirements-test.txt index 11ba2ba..a5963ae 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -8,3 +8,4 @@ pytest-cov mypy gitchangelog mkdocs +typer From 23eb4f4870dee1558026f1b4dbe0b6e7065bc6ec Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 17:56:17 +0200 Subject: [PATCH 12/27] mypy fixes --- piecash2/schema/sa_schema_post.py | 1 + piecash2/schema/sa_schema_pre.py | 20 -------------------- piecash2/schema/schema_generation.py | 10 +++++++--- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/piecash2/schema/sa_schema_post.py b/piecash2/schema/sa_schema_post.py index ec88583..e95943d 100644 --- a/piecash2/schema/sa_schema_post.py +++ b/piecash2/schema/sa_schema_post.py @@ -1,3 +1,4 @@ +# mypy: ignore-errors # list all glasses with a guid property (that can be linked to in Slot/Recurrence through obj_guid) gl = globals() name2kls = {n: gl[n] for n in klswithguid_names} # noqa: F821 diff --git a/piecash2/schema/sa_schema_pre.py b/piecash2/schema/sa_schema_pre.py index b167548..0387105 100644 --- a/piecash2/schema/sa_schema_pre.py +++ b/piecash2/schema/sa_schema_pre.py @@ -1,4 +1,3 @@ -from collections import defaultdict from decimal import Decimal from enum import Enum from fractions import Fraction @@ -12,7 +11,6 @@ from piecash2 import utils - # todo: reduce the list to classes which can really contains slots/recurrences to speed up detection of object class klswithguid_names = [ "Account", @@ -53,23 +51,6 @@ class SlotValueType(Enum): GDATE = 10 -class DecimalNumDenom(object): - def __init__(self, num, denom): - self.num = num - self.denom = denom - - @classmethod - def from_db(cls, num, denom): - return DecimalNumDenom(num, denom) - - @classmethod - def from_dt(cls, d: Decimal): - return DecimalNumDenom(d, d) - - def __composite_values__(self): - return (self.dt, self.tz) - - class OwnerType(Enum): """Enum to define the type of owner""" @@ -110,7 +91,6 @@ def __ne__(self, other): class DeclarativeMeta(DeclarativeMeta_): - backrefs_already_used = defaultdict(set) use_decimal = False def __new__(cls, name, bases, attrs): diff --git a/piecash2/schema/schema_generation.py b/piecash2/schema/schema_generation.py index 4427741..13fb19c 100644 --- a/piecash2/schema/schema_generation.py +++ b/piecash2/schema/schema_generation.py @@ -1,4 +1,5 @@ """Generate and import the SA schema from a gnucash sqlite file.""" + import importlib.util import sqlite3 import sys @@ -18,9 +19,9 @@ def import_module_from_path(path: Path): module_name = path.stem spec = importlib.util.spec_from_file_location(module_name, path) - module = importlib.util.module_from_spec(spec) + module = importlib.util.module_from_spec(spec) # type: ignore[arg-type] sys.modules[module_name] = module - spec.loader.exec_module(module) + spec.loader.exec_module(module) # type: ignore[union-attr] return module @@ -50,7 +51,10 @@ def generate_schema(db, schema_file: Path): # insert before/after the generated schema the common schema schema_file_text = ( - (code_templates / "sa_schema_pre.py").read_text() + schema_file.read_text() + (code_templates / "sa_schema_post.py").read_text() + (code_templates / "sa_schema_pre.py").read_text() + + schema_file.read_text() + + (code_templates / "sa_schema_post.py").read_text() + + "" ) schema_file.write_text(schema_file_text) From 95652ba55c72ec218af46cefb9054b8c9986b20e Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 17:58:29 +0200 Subject: [PATCH 13/27] add blank in some gnucash book name for testing purposes --- data/{test_book.gnucash => test book.gnucash} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename data/{test_book.gnucash => test book.gnucash} (100%) diff --git a/data/test_book.gnucash b/data/test book.gnucash similarity index 100% rename from data/test_book.gnucash rename to data/test book.gnucash From 3525b59c0a1786adf4de111d5c44e2a521c0ec7d Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 18:14:15 +0200 Subject: [PATCH 14/27] use setup.cfg instead of .flake8 --- .flake8 => setup.cfg | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .flake8 => setup.cfg (100%) diff --git a/.flake8 b/setup.cfg similarity index 100% rename from .flake8 rename to setup.cfg From fd2fbd5ee3cbb4d3b492f59b2a0117c4c942239d Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 18:14:44 +0200 Subject: [PATCH 15/27] during tests, path_schemas to point to tmp folder --- tests/conftest.py | 12 ++++++++++++ tests/test_base.py | 20 +++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 1cbb7b1..1d5cb27 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,6 @@ import sys +from pathlib import Path + import pytest @@ -12,3 +14,13 @@ def go_to_tmpdir(request): # Chdir only for the duration of the test. with tmpdir.as_cwd(): yield + + +@pytest.fixture(autouse=True) +def change_schema_path(request): + import piecash2.schema.schema_generation as schema_generation + + schema_generation.path_schemas = Path(request.getfixturevalue("tmpdir")) / "schemas" + schema_generation.path_schemas.mkdir(exist_ok=True, parents=True) + + yield diff --git a/tests/test_base.py b/tests/test_base.py index 5179ac8..64b85a8 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,44 +1,50 @@ +import os import sys from pathlib import Path import pytest from piecash2 import open_book -from piecash2.schema.schema_generation import add_book_module_in_path, get_schema_name, path_schemas, remove_book_module_in_path +from piecash2.schema import schema_generation path_data = Path(__file__).parent.parent / "data" def test_get_schema_name(): book = path_data / "test book.gnucash" - assert get_schema_name(book).is_relative_to(path_schemas) - assert get_schema_name(book).stem == "book_schema_sqlite_2060400" + assert schema_generation.get_schema_name(book).is_relative_to(schema_generation.path_schemas) + assert schema_generation.get_schema_name(book).stem == "book_schema_sqlite_2060400" def test_direct_import(): book = path_data / "test book.gnucash" - assert get_schema_name(book).stem == "book_schema_sqlite_2060400" + assert schema_generation.get_schema_name(book).stem == "book_schema_sqlite_2060400" + path_module = schema_generation.get_schema_name(book) + schema_generation.generate_schema(book, schema_file=path_module) with pytest.raises(ImportError): import book_schema_sqlite_2060400 - add_book_module_in_path(book) + schema_generation.add_book_module_in_path(book) # import the module import book_schema_sqlite_2060400 - remove_book_module_in_path(book) + schema_generation.remove_book_module_in_path(book) with pytest.raises(ImportError): import book_schema_sqlite_2060400 + # remove module + path_module.unlink() + def test_open_book(): book = path_data / "test book.gnucash" Session = open_book(book) piecash = Session.module - assert piecash.__name__ == get_schema_name(book).stem + assert piecash.__name__ == schema_generation.get_schema_name(book).stem def test_simple_query(): From ad4f6ce92aadb848e8a4864369df7f09256a88c1 Mon Sep 17 00:00:00 2001 From: sdementen Date: Tue, 25 Jun 2024 18:20:03 +0200 Subject: [PATCH 16/27] release: version 0.1.2 --- HISTORY.md | 25 +++++++++++++++++++++++-- piecash2/VERSION | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index d3ee8c0..7f585ee 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,10 +2,31 @@ Changelog ========= +(unreleased) +------------ +- During tests, path_schemas to point to tmp folder. [sdementen] +- Use setup.cfg instead of .flake8. [sdementen] +- Add blank in some gnucash book name for testing purposes. [sdementen] +- Mypy fixes. [sdementen] +- Add make CLI implemented in python. [sdementen] +- Fix flake8 issues. [sdementen] +- Fix linter issues. [sdementen] +- Adapt linter to use 140 charts per line. [sdementen] +- Remove the rename_project.yml CI action. [sdementen] +- Add sqlacodegen_v2 as dependency. [sdementen] +- Update setup.py with maturity and description. [sdementen] +- Add some simple tests. [sdementen] +- Add example in README.md. [sdementen] +- Add first working code. [sdementen] +- Add data folder with sample of gnucash sqlite books. [sdementen] +- Release: version 0.1.1 🚀 [sdementen] + + 0.1.1 (2024-06-24) ------------------ -- Release: version 0.1.1 🚀 [sdementen] -- Clean up repo generated from template. [sdementen] +- Release: version 0.1.1 🚀 [Sébastien de Menten] +- Clean up repo generated from template. [Sébastien de Menten] +- ✅ Ready to clone and code. [sdementen] - Initial commit. [sdementen] diff --git a/piecash2/VERSION b/piecash2/VERSION index 17e51c3..8294c18 100644 --- a/piecash2/VERSION +++ b/piecash2/VERSION @@ -1 +1 @@ -0.1.1 +0.1.2 \ No newline at end of file From 418ec2d2f2221fca3ee5451d12a703af9589dcf0 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 07:36:37 +0200 Subject: [PATCH 17/27] add commands to make.py to mimic Makefile --- make.py | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/make.py b/make.py index e1dd372..ef2a62d 100644 --- a/make.py +++ b/make.py @@ -1,10 +1,15 @@ import os +import shutil from pathlib import Path import typer +os.environ["PYTHONIOENCODING"] = "utf-8" + app = typer.Typer() +HERE = Path(__file__).parent + @app.command() def release(tag: str): @@ -12,6 +17,8 @@ def release(tag: str): typer.confirm("Do you want to continue?", abort=True) Path("piecash2/VERSION").write_text(tag) os.system("gitchangelog > HISTORY.md") + os.startfile("HISTORY.md") + typer.confirm("Did you update the changelog?", abort=True) os.system("git add piecash2/VERSION HISTORY.md") os.system(f'git commit -m "release: version {tag}') print(f"creating git tag : {tag}") @@ -29,5 +36,67 @@ def lint(): os.system("mypy --ignore-missing-imports piecash2/") +@app.command() +def fmt(): + """fmt: ## Format code using black & isort.""" + os.system("isort piecash2/") + os.system("black -l 140 piecash2/") + os.system("black -l 140 tests/") + + +@app.command() +def docs(): + """fmt: ## Format code using black & isort.""" + os.system("mkdocs build") + os.startfile(Path(__file__).parent / "site" / "index.html") + + +@app.command() +def clean(): + """clean: ## Clean up unused files.""" + patterns = [ + "**/*.pyc", + "**/__pycache__", + "**/Thumbs.db", + "**/*~", + ".cache", + ".pytest_cache", + ".mypy_cache", + ".tox", + "build", + "dist", + "*.egg-info", + "htmlcov", + "docs/_build", + ] + + for fp in patterns: + for f in HERE.glob(fp): + if f.is_file(): + f.unlink() + else: + shutil.rmtree(f) + + +@app.command() +def test(): + """test: ## Run tests and generate coverage report.""" + os.system("pytest -v --cov-config .coveragerc --cov=piecash2 -l --tb=short --maxfail=1 tests/") + os.system("coverage xml") + os.system("coverage html") + os.startfile(HERE / "htmlcov" / "index.html") + + +@app.command() +def schema(): + """schema: ## Generate the schema from the sqlite database using sqlacodegen.""" + import piecash2.schema.generation.schema_generation as schema_generation + import piecash2.schema.generated as generated + + schema_generation.path_schemas = Path(generated.__file__).parent + for book in (HERE / "data").glob("*.gnucash"): + schema_generation.generate_schema(book, schema_generation.get_schema_name(book)) + + if __name__ == "__main__": app() From 211c622a924193019f28be96da20e3ff56c06021 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 07:37:11 +0200 Subject: [PATCH 18/27] fix bug in camelize --- piecash2/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piecash2/utils.py b/piecash2/utils.py index 5b200e5..2cca0b9 100644 --- a/piecash2/utils.py +++ b/piecash2/utils.py @@ -11,7 +11,7 @@ def camelize(string, uppercase_first_letter=True): Convert strings to CamelCase. """ if uppercase_first_letter: - return re.sub(r"(?:^|_)(.)", lambda m: m.group(1).upper(), string) + return re.sub(r"(?:^|_|-)(.)", lambda m: m.group(1).upper(), string) else: return string[0].lower() + camelize(string)[1:] From e12a6a53a7e9de7a57484f01aa26550e4b449648 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 07:37:42 +0200 Subject: [PATCH 19/27] reorganise modules --- piecash2/__init__.py | 4 +- piecash2/core/__init__.py | 0 piecash2/core/book.py | 33 +++++++++++ piecash2/schema/__init__.py | 0 piecash2/schema/generated/__init__.py | 0 piecash2/schema/generation/__init__.py | 0 .../schema/{ => generation}/sa_schema_post.py | 0 .../schema/{ => generation}/sa_schema_pre.py | 17 +++++- .../{ => generation}/schema_generation.py | 55 ++++++++----------- 9 files changed, 74 insertions(+), 35 deletions(-) create mode 100644 piecash2/core/__init__.py create mode 100644 piecash2/core/book.py create mode 100644 piecash2/schema/__init__.py create mode 100644 piecash2/schema/generated/__init__.py create mode 100644 piecash2/schema/generation/__init__.py rename piecash2/schema/{ => generation}/sa_schema_post.py (100%) rename piecash2/schema/{ => generation}/sa_schema_pre.py (96%) rename piecash2/schema/{ => generation}/schema_generation.py (71%) diff --git a/piecash2/__init__.py b/piecash2/__init__.py index c26ead0..783cb4e 100644 --- a/piecash2/__init__.py +++ b/piecash2/__init__.py @@ -1,3 +1,5 @@ -from .schema.schema_generation import open_book, add_book_module_in_path +from piecash2.schema.generation.schema_generation import add_book_module_in_path + +from .core.book import open_book __ALL__ = [open_book, add_book_module_in_path] diff --git a/piecash2/core/__init__.py b/piecash2/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/piecash2/core/book.py b/piecash2/core/book.py new file mode 100644 index 0000000..2cc1ef1 --- /dev/null +++ b/piecash2/core/book.py @@ -0,0 +1,33 @@ +import sqlite3 +from pathlib import Path + +import sqlalchemy +import sqlalchemy.orm + +from piecash2.schema.generation.schema_generation import import_gnucash + + +def open_book(book, regenerate_schema=False): + if isinstance(book, str): + book = Path(book) + + book_posix = book.as_posix() + + # make a backup of the DB in memory + db_memory_name = f":memgeco_{abs(hash(book_posix))}:" + with sqlite3.connect(book_posix) as source: + sqliteconn = f"file:{db_memory_name}?mode=memory&cache=shared" + dest = sqlite3.connect(sqliteconn, uri=True) + source.backup(dest) + + engine = sqlalchemy.create_engine(f"sqlite:///{db_memory_name}", echo=False, creator=lambda: sqlite3.connect(sqliteconn, uri=True)) + + Session = sqlalchemy.orm.sessionmaker(bind=engine, autoflush=True, autocommit=False) + + # must execute some query otherwise future call to the Session raise error + with Session() as s: + s.execute(sqlalchemy.text("")) + + Session.module = import_gnucash(book, regenerate_schema=regenerate_schema) + + return Session diff --git a/piecash2/schema/__init__.py b/piecash2/schema/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/piecash2/schema/generated/__init__.py b/piecash2/schema/generated/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/piecash2/schema/generation/__init__.py b/piecash2/schema/generation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/piecash2/schema/sa_schema_post.py b/piecash2/schema/generation/sa_schema_post.py similarity index 100% rename from piecash2/schema/sa_schema_post.py rename to piecash2/schema/generation/sa_schema_post.py diff --git a/piecash2/schema/sa_schema_pre.py b/piecash2/schema/generation/sa_schema_pre.py similarity index 96% rename from piecash2/schema/sa_schema_pre.py rename to piecash2/schema/generation/sa_schema_pre.py index 0387105..75114f9 100644 --- a/piecash2/schema/sa_schema_pre.py +++ b/piecash2/schema/generation/sa_schema_pre.py @@ -7,7 +7,8 @@ from sqlalchemy import select, text, union_all from sqlalchemy.ext.declarative import declarative_base as declarative_base_ from sqlalchemy.ext.hybrid import Comparator, hybrid_property -from sqlalchemy.orm import DeclarativeMeta as DeclarativeMeta_, Session +from sqlalchemy.orm import DeclarativeMeta as DeclarativeMeta_ +from sqlalchemy.orm import Session from piecash2 import utils @@ -299,7 +300,14 @@ def __eq__(self, other): return isinstance(other, self.__class__) and ((self.__class__.__name__, self.id)) == ((other.__class__.__name__, other.id)) def __repr__(self): - return f"{self.__class__.__name__}<{self.name if hasattr(self, 'name') else ''}>[{self.uid}]" + return f"{self.__class__.__name__}<{self._human_id()}>[{self.uid}]" + + def _human_id(self): + if hasattr(self, "name"): + return self.name + elif hasattr(self, "table_version"): + return self.table_version + return "" @property def uid(self): @@ -312,7 +320,10 @@ def uid(self): @property def id(self): """Property to return the id if no Column with id already exists""" - return self.guid + try: + return self.guid + except AttributeError: + return self.table_name @lru_cache diff --git a/piecash2/schema/schema_generation.py b/piecash2/schema/generation/schema_generation.py similarity index 71% rename from piecash2/schema/schema_generation.py rename to piecash2/schema/generation/schema_generation.py index 13fb19c..4635cc2 100644 --- a/piecash2/schema/schema_generation.py +++ b/piecash2/schema/generation/schema_generation.py @@ -3,11 +3,10 @@ import importlib.util import sqlite3 import sys +import textwrap +from datetime import datetime from pathlib import Path -import sqlalchemy -import sqlalchemy.orm - # folder with code to insert into the schema generated by sqlacodegen code_templates = Path(__file__).parent @@ -17,6 +16,7 @@ def import_module_from_path(path: Path): + """Import a module from a path.""" module_name = path.stem spec = importlib.util.spec_from_file_location(module_name, path) module = importlib.util.module_from_spec(spec) # type: ignore[arg-type] @@ -26,6 +26,7 @@ def import_module_from_path(path: Path): def import_gnucash(book, regenerate_schema=False): + """Import the gnucash schema from the sqlite database as a module. If the schema does not exist, generate it.""" modulename = get_schema_name(book) if not modulename.exists() or regenerate_schema: @@ -51,8 +52,20 @@ def generate_schema(db, schema_file: Path): # insert before/after the generated schema the common schema schema_file_text = ( - (code_templates / "sa_schema_pre.py").read_text() + textwrap.dedent( + """ + # -*- coding: utf-8 -*- + '''This file has been generated by piecash2.schema.generation.generate_schema on {datetime.now().isoformat()}. + ''' + """ + ) + + (code_templates / "sa_schema_pre.py").read_text() + schema_file.read_text() + .replace( + "from sqlalchemy.ext.declarative import declarative_base as declarative_base_", + "from sqlalchemy.orm import declarative_base as declarative_base_", + ) + .replace("from sqlalchemy.orm import Mapped, declarative_base, mapped_column", "from sqlalchemy.orm import Mapped, mapped_column") + (code_templates / "sa_schema_post.py").read_text() + "" ) @@ -67,6 +80,7 @@ def get_version(db: Path): c = conn.cursor() c.execute("SELECT table_version FROM versions WHERE table_name=='Gnucash'") (gnucash_version,) = c.fetchone() + return gnucash_version @@ -76,44 +90,23 @@ def get_schema_name(book: Path): return path_schemas / f"book_schema_sqlite_{v}.py" -def open_book(book, regenerate_schema=False): - if isinstance(book, str): - book = Path(book) - - book_posix = book.as_posix() - - # make a backup of the DB in memory - db_memory_name = f":memgeco_{abs(hash(book_posix))}:" - with sqlite3.connect(book_posix) as source: - sqliteconn = f"file:{db_memory_name}?mode=memory&cache=shared" - dest = sqlite3.connect(sqliteconn, uri=True) - source.backup(dest) - - engine = sqlalchemy.create_engine(f"sqlite:///{db_memory_name}", echo=False, creator=lambda: sqlite3.connect(sqliteconn, uri=True)) - - Session = sqlalchemy.orm.sessionmaker(bind=engine, autoflush=True, autocommit=False) - - # must execute some query otherwise future call to the Session raise error - with Session() as s: - s.execute(sqlalchemy.text("")) - - Session.module = import_gnucash(book, regenerate_schema=regenerate_schema) - - return Session - - def add_book_module_in_path(book): module_folder = str(get_schema_name(book).parent) if module_folder not in sys.path: sys.path.append(module_folder) +def unload_module(mod): + if mod in sys.modules: + del sys.modules[mod] + + def remove_book_module_in_path(book): module_path = get_schema_name(book) module_folder = str(module_path.parent) module_name = module_path.stem - sys.modules.pop(module_name) + unload_module(module_name) if module_folder in sys.path: sys.path.remove(module_folder) From 1f4809f7240f62cd9cc44099774c48ba05331573 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 07:38:11 +0200 Subject: [PATCH 20/27] omit from coverage template .py files --- setup.cfg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup.cfg b/setup.cfg index ea97c3a..de5d629 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,7 @@ [flake8] max-line-length = 140 + +[coverage:run] +omit = + sa_schema_post.py + sa_schema_pre.py \ No newline at end of file From 20d31766ac76c903e5b92e681e32c7e7ce3d8701 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 07:38:23 +0200 Subject: [PATCH 21/27] reformat file --- setup.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 43a901d..c2ad0a3 100644 --- a/setup.py +++ b/setup.py @@ -22,11 +22,7 @@ def read(*paths, **kwargs): def read_requirements(path): - return [ - line.strip() - for line in read(path).split("\n") - if not line.startswith(('"', "#", "-", "git+")) - ] + return [line.strip() for line in read(path).split("\n") if not line.startswith(('"', "#", "-", "git+"))] setup( @@ -40,8 +36,6 @@ def read_requirements(path): maturity="Development Status :: 3 - Alpha", packages=find_packages(exclude=["tests", ".github"]), install_requires=read_requirements("requirements.txt"), - entry_points={ - "console_scripts": ["piecash2 = piecash2.__main__:main"] - }, + entry_points={"console_scripts": ["piecash2 = piecash2.__main__:main"]}, extras_require={"test": read_requirements("requirements-test.txt")}, ) From 8058922ec8ab1c6eb9f6f2088efadfdf15a5fd9e Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 07:38:34 +0200 Subject: [PATCH 22/27] extend tests --- tests/conftest.py | 15 +++++++-- tests/test_base.py | 57 ------------------------------- tests/test_core.py | 34 +++++++++++++++++++ tests/test_schemas.py | 78 +++++++++++++++++++++++++++++++++++++++++++ tests/test_utils.py | 27 +++++++++++++++ 5 files changed, 151 insertions(+), 60 deletions(-) delete mode 100644 tests/test_base.py create mode 100644 tests/test_core.py create mode 100644 tests/test_schemas.py create mode 100644 tests/test_utils.py diff --git a/tests/conftest.py b/tests/conftest.py index 1d5cb27..037038f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,6 +3,8 @@ import pytest +HERE = Path(__file__).parent + # each test runs on cwd to its temp dir @pytest.fixture(autouse=True) @@ -18,9 +20,16 @@ def go_to_tmpdir(request): @pytest.fixture(autouse=True) def change_schema_path(request): - import piecash2.schema.schema_generation as schema_generation + import piecash2.schema.generation.schema_generation as schema_generation + + # schema_generation.path_schemas = Path(request.getfixturevalue("tmpdir")) / "schemas" + # schema_generation.path_schemas.mkdir(exist_ok=True, parents=True) + + import piecash2.schema.generated as generated + + schema_generation.path_schemas = Path(generated.__file__).parent - schema_generation.path_schemas = Path(request.getfixturevalue("tmpdir")) / "schemas" - schema_generation.path_schemas.mkdir(exist_ok=True, parents=True) + for book in (HERE.parent / "data").glob("*.gnucash"): + schema_generation.generate_schema(book, schema_generation.get_schema_name(book)) yield diff --git a/tests/test_base.py b/tests/test_base.py deleted file mode 100644 index 64b85a8..0000000 --- a/tests/test_base.py +++ /dev/null @@ -1,57 +0,0 @@ -import os -import sys -from pathlib import Path - -import pytest - -from piecash2 import open_book -from piecash2.schema import schema_generation - -path_data = Path(__file__).parent.parent / "data" - - -def test_get_schema_name(): - book = path_data / "test book.gnucash" - assert schema_generation.get_schema_name(book).is_relative_to(schema_generation.path_schemas) - assert schema_generation.get_schema_name(book).stem == "book_schema_sqlite_2060400" - - -def test_direct_import(): - book = path_data / "test book.gnucash" - assert schema_generation.get_schema_name(book).stem == "book_schema_sqlite_2060400" - path_module = schema_generation.get_schema_name(book) - schema_generation.generate_schema(book, schema_file=path_module) - - with pytest.raises(ImportError): - import book_schema_sqlite_2060400 - - schema_generation.add_book_module_in_path(book) - - # import the module - import book_schema_sqlite_2060400 - - schema_generation.remove_book_module_in_path(book) - - with pytest.raises(ImportError): - import book_schema_sqlite_2060400 - - # remove module - path_module.unlink() - - -def test_open_book(): - book = path_data / "test book.gnucash" - - Session = open_book(book) - piecash = Session.module - assert piecash.__name__ == schema_generation.get_schema_name(book).stem - - -def test_simple_query(): - book = path_data / "test book.gnucash" - - Session = open_book(book) - piecash = Session.module - - with Session() as s: - assert len(s.query(piecash.Slot).all()) == 20 diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..78eff82 --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,34 @@ +import pytest + +from piecash2 import open_book +from piecash2.schema.generation import schema_generation +from tests.test_schemas import path_data + + +def test_simple_query(): + book = path_data / "test book.gnucash" + + Session = open_book(book) + piecash = Session.module + print(piecash.__file__) + + with Session() as s: + for name, attr in piecash.__dict__.items(): + # print(name, type(attr)) + if isinstance(attr, type) and issubclass(attr, piecash.Base) and attr is not piecash.Base: + for obj in s.query(attr).all(): + print(obj) + assert len(list(s.query(attr).all())) >= 0 + + +@pytest.mark.parametrize( + "book", + [ + path_data / "test book.gnucash", + str(path_data / "test book.gnucash"), + ], +) +def test_open_book(book): + Session = open_book(book) + piecash = Session.module + assert piecash.__name__ == schema_generation.get_schema_name(book).stem diff --git a/tests/test_schemas.py b/tests/test_schemas.py new file mode 100644 index 0000000..311092b --- /dev/null +++ b/tests/test_schemas.py @@ -0,0 +1,78 @@ +import importlib +from pathlib import Path + +import pytest + +from piecash2.schema.generation import schema_generation + +path_data = Path(__file__).parent.parent / "data" + + +def test_get_schema_name(): + book = path_data / "test book.gnucash" + assert schema_generation.get_schema_name(book).is_relative_to(schema_generation.path_schemas) + assert schema_generation.get_schema_name(book).stem == "book_schema_sqlite_2060400" + + +@pytest.fixture +def change_schema_path(request): + import piecash2.schema.generation.schema_generation as schema_generation + + ops = schema_generation.path_schemas + + tmp_path = Path(request.getfixturevalue("tmpdir")) / "schemas" + tmp_path.mkdir(exist_ok=True, parents=True) + schema_generation.path_schemas = tmp_path + + yield + + schema_generation.path_schemas = ops + + +@pytest.mark.parametrize("book", list(path_data.glob("*.gnucash"))) +def test_import_dynamic(book): + schema_generation.import_gnucash(book) + + +@pytest.mark.parametrize("book", list(path_data.glob("*.gnucash"))) +def test_import_explicit(book): + module_name = schema_generation.get_schema_name(book).stem + importlib.import_module(f"piecash2.schema.generated.{module_name}") + + +@pytest.mark.parametrize("book", [path_data / "test book.gnucash"]) +def test_import_regenerate(book): + schema_generation.import_gnucash(book, regenerate_schema=True) + + +@pytest.mark.parametrize("book", [path_data / "test book.gnucash"]) +def test_add_book_module_in_path(book, change_schema_path): + importlib.invalidate_caches() + + if True: + path_module = schema_generation.get_schema_name(book) + module_name = path_module.stem + assert module_name.startswith("book_schema_sqlite_") + + # clean up existing file and unload module + if path_module.exists(): + path_module.unlink() + schema_generation.unload_module(module_name) + + # generate the schema + schema_generation.generate_schema(book, schema_file=path_module) + + # if True: + with pytest.raises(ImportError): + importlib.import_module(module_name) + + schema_generation.add_book_module_in_path(book) + + # import the module + importlib.import_module(module_name) + schema_generation.unload_module(module_name) + + schema_generation.remove_book_module_in_path(book) + + with pytest.raises(ImportError): + importlib.import_module(module_name) diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..0d8126f --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,27 @@ +import pytest + + +def test_camelize(): + from piecash2.utils import camelize + + assert camelize("hello_world") == "HelloWorld" + assert camelize("hello_world", uppercase_first_letter=False) == "helloWorld" + assert camelize("hello-world") == "HelloWorld" + assert camelize("hello-world", uppercase_first_letter=False) == "helloWorld" + + +def test_underscore(): + from piecash2.utils import underscore + + assert underscore("HelloWorld") == "hello_world" + assert underscore("helloWorld") == "hello_world" + assert underscore("hello-world") == "hello_world" + assert underscore("helloWorld") == "hello_world" + + +def test_pluralize(): + from piecash2.utils import pluralize + + assert pluralize("word") == "words" + assert pluralize("commodity") == "commodities" + assert pluralize("Commodity") == "Commodities" From 2106000043ce8f264224378db7b69b961c2fef72 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 09:50:35 +0200 Subject: [PATCH 23/27] rename Base to DeclarativeBase to avoid name shadowing --- piecash2/schema/generation/sa_schema_pre.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/piecash2/schema/generation/sa_schema_pre.py b/piecash2/schema/generation/sa_schema_pre.py index 75114f9..82663b9 100644 --- a/piecash2/schema/generation/sa_schema_pre.py +++ b/piecash2/schema/generation/sa_schema_pre.py @@ -7,8 +7,7 @@ from sqlalchemy import select, text, union_all from sqlalchemy.ext.declarative import declarative_base as declarative_base_ from sqlalchemy.ext.hybrid import Comparator, hybrid_property -from sqlalchemy.orm import DeclarativeMeta as DeclarativeMeta_ -from sqlalchemy.orm import Session +from sqlalchemy.orm import DeclarativeMeta as DeclarativeMeta_, Session from piecash2 import utils @@ -292,7 +291,7 @@ def attr_setter( return self -class Base: +class DeclarativeBase: def __hash__(self): return hash((self.__class__.__name__, self.id)) @@ -328,5 +327,5 @@ def id(self): @lru_cache def declarative_base(*args, **kwargs): - base = declarative_base_(*args, **kwargs, metaclass=DeclarativeMeta, cls=Base) + base = declarative_base_(*args, **kwargs, metaclass=DeclarativeMeta, cls=DeclarativeBase) return base From d372e66db82bc1fdf162ce4aed2329011ddb25c9 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 09:50:57 +0200 Subject: [PATCH 24/27] print path where schemas exported --- make.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/make.py b/make.py index ef2a62d..6e622a8 100644 --- a/make.py +++ b/make.py @@ -94,6 +94,8 @@ def schema(): import piecash2.schema.generated as generated schema_generation.path_schemas = Path(generated.__file__).parent + + print(f"Generating schemas in {schema_generation.path_schemas}") for book in (HERE / "data").glob("*.gnucash"): schema_generation.generate_schema(book, schema_generation.get_schema_name(book)) From 6b560f042259d2bbf86af6b36fbe5e17b561c101 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 09:51:21 +0200 Subject: [PATCH 25/27] isort/black generated schemas + remove unused imports --- .../schema/generation/schema_generation.py | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/piecash2/schema/generation/schema_generation.py b/piecash2/schema/generation/schema_generation.py index 4635cc2..c4dd0b0 100644 --- a/piecash2/schema/generation/schema_generation.py +++ b/piecash2/schema/generation/schema_generation.py @@ -53,7 +53,7 @@ def generate_schema(db, schema_file: Path): # insert before/after the generated schema the common schema schema_file_text = ( textwrap.dedent( - """ + f""" # -*- coding: utf-8 -*- '''This file has been generated by piecash2.schema.generation.generate_schema on {datetime.now().isoformat()}. ''' @@ -65,12 +65,33 @@ def generate_schema(db, schema_file: Path): "from sqlalchemy.ext.declarative import declarative_base as declarative_base_", "from sqlalchemy.orm import declarative_base as declarative_base_", ) - .replace("from sqlalchemy.orm import Mapped, declarative_base, mapped_column", "from sqlalchemy.orm import Mapped, mapped_column") + .replace( + "from sqlalchemy.orm import Mapped, declarative_base, mapped_column", + "from sqlalchemy.orm import mapped_column", + ) + .replace("from sqlalchemy.orm.base import Mapped", "") + (code_templates / "sa_schema_post.py").read_text() + "" ) + try: + # isort the imports if isort is available + import isort + + schema_file_text = isort.code(schema_file_text, float_to_top=True) + except ImportError: + pass + + try: + # reformat with black if black is available + import black + + schema_file_text = black.format_str(schema_file_text, mode=black.FileMode(line_length=140)) + except ImportError: + pass + schema_file.write_text(schema_file_text) + return schema_file_text From f226d91f20da112b5b5580c1724f3f19ade577b8 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 09:51:52 +0200 Subject: [PATCH 26/27] cleanup --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index c2ad0a3..c08c61b 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -"""Python setup.py for piecash2 package""" import io import os from setuptools import find_packages, setup From 42b281563fd2199dba48c9bc750388c01f918a18 Mon Sep 17 00:00:00 2001 From: sdementen Date: Wed, 26 Jun 2024 09:52:05 +0200 Subject: [PATCH 27/27] add tool.isort option section --- setup.cfg | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index de5d629..3354cbb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,4 +4,7 @@ max-line-length = 140 [coverage:run] omit = sa_schema_post.py - sa_schema_pre.py \ No newline at end of file + sa_schema_pre.py + +[tool.isort] +profile = "black"