diff --git a/nummus/commands/base.py b/nummus/commands/base.py index 74df91c4..33286796 100644 --- a/nummus/commands/base.py +++ b/nummus/commands/base.py @@ -6,6 +6,7 @@ from abc import ABC, abstractmethod from typing import TYPE_CHECKING +import colorama from colorama import Fore if TYPE_CHECKING: @@ -40,6 +41,7 @@ def __init__( """ super().__init__() + colorama.init(autoreset=True) path_db = path_db.expanduser().absolute() if path_password: diff --git a/nummus/controllers/budgeting.py b/nummus/controllers/budgeting.py index d77607ef..8b7b9bae 100644 --- a/nummus/controllers/budgeting.py +++ b/nummus/controllers/budgeting.py @@ -606,7 +606,7 @@ def target(uri: str) -> str | flask.Response: new_target = tar is None if tar is None: # New target - tar = Target( + tar = Target( # nummus: ignore category_id=t_cat_id, amount=0, type_=TargetType.ACCUMULATE, @@ -635,7 +635,7 @@ def target(uri: str) -> str | flask.Response: try: if flask.request.method == "POST": with s.begin_nested(): - s.add(tar) + s.add(tar) # nummus: ignore return base.dialog_swap( event="budget", snackbar=f"{emoji_name} target created", diff --git a/nummus/controllers/transactions.py b/nummus/controllers/transactions.py index 42e45c47..c3bb671d 100644 --- a/nummus/controllers/transactions.py +++ b/nummus/controllers/transactions.py @@ -413,12 +413,12 @@ def new() -> str | flask.Response: try: with s.begin_nested(): - txn = Transaction( + txn = Transaction( # nummus: ignore statement="Manually added", ) if err := _transaction_edit(txn, today): return base.error(err) - s.add(txn) + s.add(txn) # nummus: ignore s.flush() if err := _transaction_split_edit(txn): return base.error(err) diff --git a/nummus/portfolio.py b/nummus/portfolio.py index 18c40a90..3fc9cbc2 100644 --- a/nummus/portfolio.py +++ b/nummus/portfolio.py @@ -574,7 +574,7 @@ def _import_asset_transaction( payee=d["payee"], cleared=True, ) - TransactionSplit( + TransactionSplit.create( parent=txn, amount=d["amount"], memo=d["memo"], diff --git a/nummus/web.py b/nummus/web.py index f2b19e33..9d8e345b 100644 --- a/nummus/web.py +++ b/nummus/web.py @@ -56,7 +56,7 @@ def init_app(self, app: flask.Flask) -> None: app: Flask app to initialize """ - config = flask.Config(app.root_path) + config = flask.Config(app.root_path) # nummus: ignore config.from_prefixed_env("NUMMUS") self._portfolio = self._open_portfolio(config) diff --git a/tests/commands/test_backup.py b/tests/commands/test_backup.py index e6108f44..5bc3bddb 100644 --- a/tests/commands/test_backup.py +++ b/tests/commands/test_backup.py @@ -2,8 +2,6 @@ from typing import TYPE_CHECKING -from colorama import Fore - from nummus.commands.backup import Backup, Restore if TYPE_CHECKING: @@ -22,10 +20,7 @@ def test_backup(capsys: pytest.CaptureFixture[str], empty_portfolio: Portfolio) assert path_backup.exists() captured = capsys.readouterr() - target = ( - f"{Fore.GREEN}Portfolio is unlocked\n" - f"{Fore.GREEN}Portfolio backed up to {path_backup}\n" - ) + target = f"Portfolio is unlocked\nPortfolio backed up to {path_backup}\n" assert captured.out == target assert not captured.err @@ -39,10 +34,7 @@ def test_restore( assert c.run() == 0 captured = capsys.readouterr() - target = ( - f"{Fore.CYAN}Extracted backup tar\n" - f"{Fore.GREEN}Portfolio restored for {empty_portfolio.path}\n" - ) + target = f"Extracted backup tar\nPortfolio restored for {empty_portfolio.path}\n" assert captured.out == target assert not captured.err @@ -56,7 +48,7 @@ def test_restore_missing( captured = capsys.readouterr() assert not captured.out - target = f"{Fore.RED}No backup exists for {empty_portfolio.path}\n" + target = f"No backup exists for {empty_portfolio.path}\n" assert captured.err == target @@ -69,7 +61,7 @@ def test_restore_list_empty( captured = capsys.readouterr() assert not captured.out - target = f"{Fore.RED}No backups found, run 'nummus backup'\n" + target = "No backups found, run 'nummus backup'\n" assert captured.err == target @@ -85,6 +77,6 @@ def test_restore_list( ts_local = utc_frozen.astimezone().isoformat(timespec="seconds") captured = capsys.readouterr() - target = f"{Fore.CYAN}Backup # 1 created at {ts_local} (0.0 seconds ago)\n" + target = f"Backup # 1 created at {ts_local} (0.0 seconds ago)\n" assert captured.out == target assert not captured.err diff --git a/tests/commands/test_base.py b/tests/commands/test_base.py index 050a0b27..998f3fa4 100644 --- a/tests/commands/test_base.py +++ b/tests/commands/test_base.py @@ -5,7 +5,6 @@ from typing import override, TYPE_CHECKING import pytest -from colorama import Fore from nummus.commands.backup import Backup, Restore from nummus.commands.base import Command @@ -50,7 +49,7 @@ def test_no_file(capsys: pytest.CaptureFixture[str], tmp_path: Path) -> None: captured = capsys.readouterr() assert not captured.out - target = f"{Fore.RED}Portfolio does not exist at {path}. Run nummus create\n" + target = f"Portfolio does not exist at {path}. Run nummus create\n" assert captured.err == target @@ -58,7 +57,7 @@ def test_unlock(capsys: pytest.CaptureFixture[str], empty_portfolio: Portfolio) MockCommand(empty_portfolio.path, None) captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n" + target = "Portfolio is unlocked\n" assert captured.out == target assert not captured.err @@ -73,10 +72,7 @@ def test_migration_required( captured = capsys.readouterr() assert not captured.out v = MIGRATORS[-1].min_version() - target = ( - f"{Fore.RED}Portfolio requires migration to v{v}\n" - f"{Fore.YELLOW}Run 'nummus migrate' to resolve\n" - ) + target = f"Portfolio requires migration to v{v}\nRun 'nummus migrate' to resolve\n" assert captured.err == target @@ -94,7 +90,7 @@ def test_unlock_encrypted_path( MockCommand(p.path, path_password) captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n" + target = "Portfolio is unlocked\n" assert captured.out == target assert not captured.err @@ -115,7 +111,7 @@ def test_unlock_encrypted_path_bad_key( captured = capsys.readouterr() assert not captured.out - target = f"{Fore.RED}Could not decrypt with password file\n" + target = "Could not decrypt with password file\n" assert captured.err == target @@ -138,10 +134,10 @@ def mock_get_pass(to_print: str) -> str | None: MockCommand(p.path, None) captured = capsys.readouterr() - assert captured.out == f"{Fore.GREEN}Portfolio is unlocked\n" + assert captured.out == "Portfolio is unlocked\n" target = ( "\u26bf Please enter password: \n" - f"{Fore.RED}Incorrect password\n" + "Incorrect password\n" "\u26bf Please enter password: \n" ) assert captured.err == target @@ -193,12 +189,12 @@ def mock_get_pass(to_print: str) -> str | None: assert not captured.out target = ( "\u26bf Please enter password: \n" - f"{Fore.RED}Incorrect password\n" + "Incorrect password\n" "\u26bf Please enter password: \n" - f"{Fore.RED}Incorrect password\n" + "Incorrect password\n" "\u26bf Please enter password: \n" - f"{Fore.RED}Incorrect password\n" - f"{Fore.RED}Too many incorrect attempts\n" + "Incorrect password\n" + "Too many incorrect attempts\n" ) assert captured.err == target diff --git a/tests/commands/test_change_password.py b/tests/commands/test_change_password.py index 2ac0b1b3..1f886923 100644 --- a/tests/commands/test_change_password.py +++ b/tests/commands/test_change_password.py @@ -4,7 +4,6 @@ from typing import override, TYPE_CHECKING import pytest -from colorama import Fore from nummus.commands.change_password import ChangePassword from nummus.portfolio import Portfolio @@ -37,8 +36,8 @@ def test_no_change_unencrypted( assert c.run() != 0 captured = capsys.readouterr() - assert captured.out == f"{Fore.GREEN}Portfolio is unlocked\n" - assert captured.err == f"{Fore.YELLOW}Neither password changing\n" + assert captured.out == "Portfolio is unlocked\n" + assert captured.err == "Neither password changing\n" @pytest.mark.parametrize( @@ -66,9 +65,9 @@ def test_change( captured = capsys.readouterr() target_out = ( - f"{Fore.GREEN}Portfolio is unlocked\n" - f"{Fore.GREEN}Changed password(s)\n" - f"{Fore.CYAN}Run 'nummus clean' to remove backups with old password\n" + "Portfolio is unlocked\n" + "Changed password(s)\n" + "Run 'nummus clean' to remove backups with old password\n" ) assert captured.out == target_out assert captured.err == target diff --git a/tests/commands/test_clean.py b/tests/commands/test_clean.py index 8d6cd964..41ff929f 100644 --- a/tests/commands/test_clean.py +++ b/tests/commands/test_clean.py @@ -2,8 +2,6 @@ from typing import TYPE_CHECKING -from colorama import Fore - from nummus.commands.clean import Clean if TYPE_CHECKING: @@ -21,9 +19,9 @@ def test_clean(capsys: pytest.CaptureFixture[str], empty_portfolio: Portfolio) - captured = capsys.readouterr() target = ( - f"{Fore.GREEN}Portfolio is unlocked\n" - f"{Fore.GREEN}Portfolio cleaned\n" - f"{Fore.CYAN}Portfolio was optimized by 0.0KB/0.0KiB\n" + "Portfolio is unlocked\n" + "Portfolio cleaned\n" + "Portfolio was optimized by 0.0KB/0.0KiB\n" ) assert captured.out == target assert not captured.err diff --git a/tests/commands/test_create.py b/tests/commands/test_create.py index 49a0c2d4..d5591dd4 100644 --- a/tests/commands/test_create.py +++ b/tests/commands/test_create.py @@ -3,8 +3,6 @@ import sys from typing import override, TYPE_CHECKING -from colorama import Fore - from nummus.commands.create import Create from nummus.portfolio import Portfolio @@ -39,7 +37,7 @@ def test_create_existing( captured = capsys.readouterr() assert not captured.out - target = f"{Fore.RED}Cannot overwrite portfolio at {path}. Try with --force\n" + target = f"Cannot overwrite portfolio at {path}. Try with --force\n" assert captured.err == target @@ -56,7 +54,7 @@ def test_create_unencrypted_forced( assert c.run() == 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio created at {path}\n" + target = f"Portfolio created at {path}\n" assert captured.out == target target = f"Creating {path} with None\n" assert captured.err == target @@ -74,7 +72,7 @@ def test_create_unencrypted( assert c.run() == 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio created at {path}\n" + target = f"Portfolio created at {path}\n" assert captured.out == target target = f"Creating {path} with None\n" assert captured.err == target @@ -101,7 +99,7 @@ def mock_get_pass(_: str) -> str | None: assert c.run() == 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio created at {path}\n" + target = f"Portfolio created at {path}\n" assert captured.out == target target = f"Creating {path} with {rand_str}\n" assert captured.err == target @@ -123,7 +121,7 @@ def test_create_encrypted_pass_file( assert c.run() == 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio created at {path}\n" + target = f"Portfolio created at {path}\n" assert captured.out == target target = f"Creating {path} with {rand_str}\n" assert captured.err == target diff --git a/tests/commands/test_export.py b/tests/commands/test_export.py index d84e46bc..a7d540d0 100644 --- a/tests/commands/test_export.py +++ b/tests/commands/test_export.py @@ -2,8 +2,6 @@ from typing import TYPE_CHECKING -from colorama import Fore - from nummus.commands.export import Export from nummus.models.currency import CURRENCY_FORMATS, DEFAULT_CURRENCY @@ -28,10 +26,7 @@ def test_export_empty( assert c.run() == 0 captured = capsys.readouterr() - target = ( - f"{Fore.GREEN}Portfolio is unlocked\n" - f"{Fore.GREEN}0 transactions exported to {path_csv}\n" - ) + target = f"Portfolio is unlocked\n0 transactions exported to {path_csv}\n" assert captured.out == target assert not captured.err @@ -57,10 +52,7 @@ def test_export( assert c.run() == 0 captured = capsys.readouterr() - target = ( - f"{Fore.GREEN}Portfolio is unlocked\n" - f"{Fore.GREEN}1 transactions exported to {path_csv}\n" - ) + target = f"Portfolio is unlocked\n1 transactions exported to {path_csv}\n" assert captured.out == target assert not captured.err diff --git a/tests/commands/test_health.py b/tests/commands/test_health.py index 5a33d96a..edc6242f 100644 --- a/tests/commands/test_health.py +++ b/tests/commands/test_health.py @@ -3,8 +3,6 @@ import datetime from typing import TYPE_CHECKING -from colorama import Fore - from nummus.commands.health import Health from nummus.health_checks.top import HEALTH_CHECKS from nummus.models.config import Config, ConfigKey @@ -37,13 +35,13 @@ def test_issues( captured = capsys.readouterr() # big output, use "" in checks - assert f"{Fore.GREEN}Check 'Database integrity'" in captured.out - assert f"{Fore.CYAN} Checks for issues in the underlying" in captured.out - assert f"{Fore.YELLOW}Check 'Unused categories'" in captured.out - assert f"{Fore.YELLOW} Has the following issues:" in captured.out + assert "Check 'Database integrity'" in captured.out + assert "Checks for issues in the underlying" in captured.out + assert "Check 'Unused categories'" in captured.out + assert "Has the following issues:" in captured.out assert "has no transactions nor budget assignments" in captured.out assert "more issues, use --limit flag to see more" in captured.out - assert f"{Fore.MAGENTA}Use web interface to fix issues" in captured.out + assert "Use web interface to fix issues" in captured.out assert not captured.err with empty_portfolio.begin_session(): @@ -75,13 +73,13 @@ def test_no_limit_severe( captured = capsys.readouterr() # big output, use "" in checks - assert f"{Fore.GREEN}Check 'Database integrity'" in captured.out - assert f"{Fore.CYAN} Checks for issues in the underlying" in captured.out - assert f"{Fore.RED}Check 'Unused categories'" in captured.out - assert f"{Fore.RED} Has the following issues:" in captured.out + assert "Check 'Database integrity'" in captured.out + assert "Checks for issues in the underlying" in captured.out + assert "Check 'Unused categories'" in captured.out + assert "Has the following issues:" in captured.out assert "has no transactions nor budget assignments" in captured.out assert "more issues, use --limit flag to see more" not in captured.out - assert f"{Fore.MAGENTA}Use web interface to fix issues" in captured.out + assert "Use web interface to fix issues" in captured.out assert not captured.err with empty_portfolio.begin_session(): @@ -120,13 +118,12 @@ def test_ignore_all( captured = capsys.readouterr() # big output, use "" in checks - assert f"{Fore.GREEN}Check 'Database integrity'" in captured.out - assert f"{Fore.CYAN} Checks for issues in the underlying" not in captured.out - assert f"{Fore.YELLOW}Check 'Unused categories'" not in captured.out - assert f"{Fore.YELLOW} Has the following issues:" not in captured.out + assert "Check 'Database integrity'" in captured.out + assert "Checks for issues in the underlying" not in captured.out + assert "Has the following issues:" not in captured.out assert "has no transactions nor budget assignments" not in captured.out assert "more issues, use --limit flag to see more" not in captured.out - assert f"{Fore.MAGENTA}Use web interface to fix issues" not in captured.out + assert "Use web interface to fix issues" not in captured.out assert not captured.err with empty_portfolio.begin_session(): @@ -161,8 +158,8 @@ def test_clear_ignores( captured = capsys.readouterr() # big output, use "" in checks - assert f"{Fore.YELLOW}Check 'Unused categories'" in captured.out - assert f"{Fore.YELLOW} Has the following issues:" in captured.out + assert "Check 'Unused categories'" in captured.out + assert "Has the following issues:" in captured.out assert "has no transactions nor budget assignments" in captured.out assert not captured.err diff --git a/tests/commands/test_import_files.py b/tests/commands/test_import_files.py index c7b4e8ac..4bb7cc0d 100644 --- a/tests/commands/test_import_files.py +++ b/tests/commands/test_import_files.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING import pytest -from colorama import Fore from nummus.commands.import_files import Import @@ -24,7 +23,7 @@ def test_empty(capsys: pytest.CaptureFixture[str], empty_portfolio: Portfolio) - assert c.run() == 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n{Fore.GREEN}Imported 0 files\n" + target = "Portfolio is unlocked\nImported 0 files\n" assert captured.out == target assert not captured.err @@ -43,12 +42,9 @@ def test_non_existant( assert c.run() != 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n" + target = "Portfolio is unlocked\n" assert captured.out == target - target = ( - f"{Fore.RED}File does not exist: {path}\n" - f"{Fore.RED}Abandoned import, restored from backup\n" - ) + target = f"File does not exist: {path}\nAbandoned import, restored from backup\n" assert captured.err == target assert not path_debug.exists() @@ -76,7 +72,7 @@ def test_data_dir( assert c.run() == 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n{Fore.GREEN}Imported 2 files\n" + target = "Portfolio is unlocked\nImported 2 files\n" assert captured.out == target assert not captured.err @@ -101,12 +97,12 @@ def test_unknown_importer( assert c.run() != 0 captured = capsys.readouterr() - assert captured.out == f"{Fore.GREEN}Portfolio is unlocked\n" + assert captured.out == "Portfolio is unlocked\n" target = ( - f"{Fore.RED}Unknown importer for {path}\n" - f"{Fore.YELLOW}Create a custom importer in {empty_portfolio.importers_path}\n" - f"{Fore.RED}Abandoned import, restored from backup\n" - f"{Fore.YELLOW}Raw imported file may help at {path_debug}\n" + f"Unknown importer for {path}\n" + f"Create a custom importer in {empty_portfolio.importers_path}\n" + "Abandoned import, restored from backup\n" + f"Raw imported file may help at {path_debug}\n" ) assert captured.err == target @@ -132,12 +128,12 @@ def test_duplicate( assert c.run() != 0 captured = capsys.readouterr() - assert captured.out == f"{Fore.GREEN}Portfolio is unlocked\n" + assert captured.out == "Portfolio is unlocked\n" target = ( - f"{Fore.RED}Already imported {path} on {today}\n" - f"{Fore.YELLOW}Delete file or run import with --force flag which " + f"Already imported {path} on {today}\n" + "Delete file or run import with --force flag which " "may create duplicate transactions.\n" - f"{Fore.RED}Abandoned import, restored from backup\n" + "Abandoned import, restored from backup\n" ) assert captured.err == target @@ -159,10 +155,10 @@ def test_data_dir_no_account( assert c.run() != 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n" + target = "Portfolio is unlocked\n" assert captured.out == target target = ( - f"{Fore.RED}Abandoned import, restored from backup\n" - f"{Fore.YELLOW}Raw imported file may help at {path_debug}\n" + "Abandoned import, restored from backup\n" + f"Raw imported file may help at {path_debug}\n" ) assert captured.err == target diff --git a/tests/commands/test_migrate.py b/tests/commands/test_migrate.py index b4322ff3..c1c8f8e9 100644 --- a/tests/commands/test_migrate.py +++ b/tests/commands/test_migrate.py @@ -3,8 +3,6 @@ import shutil from typing import TYPE_CHECKING -from colorama import Fore - from nummus.commands.migrate import Migrate if TYPE_CHECKING: @@ -24,10 +22,7 @@ def test_not_required( assert c.run() == 0 captured = capsys.readouterr() - target = ( - f"{Fore.GREEN}Portfolio is unlocked\n" - f"{Fore.GREEN}Portfolio does not need migration\n" - ) + target = "Portfolio is unlocked\nPortfolio does not need migration\n" assert captured.out == target assert not captured.err @@ -45,17 +40,17 @@ def test_v0_1_migration( captured = capsys.readouterr() target = ( - f"{Fore.GREEN}Portfolio is unlocked\n" - f"{Fore.CYAN}This transaction had multiple payees, only one allowed: " + "Portfolio is unlocked\n" + "This transaction had multiple payees, only one allowed: " "1948-03-15 Savings, please validate\n" - f"{Fore.GREEN}Portfolio migrated to v0.2.0\n" - f"{Fore.GREEN}Portfolio migrated to v0.10.0\n" - f"{Fore.GREEN}Portfolio migrated to v0.11.0\n" - f"{Fore.GREEN}Portfolio migrated to v0.13.0\n" - f"{Fore.GREEN}Portfolio migrated to v0.15.0\n" - f"{Fore.CYAN}Portfolio currency set to USD (US Dollar), use web to edit\n" - f"{Fore.GREEN}Portfolio migrated to v0.16.0\n" - f"{Fore.GREEN}Portfolio model schemas updated\n" + "Portfolio migrated to v0.2.0\n" + "Portfolio migrated to v0.10.0\n" + "Portfolio migrated to v0.11.0\n" + "Portfolio migrated to v0.13.0\n" + "Portfolio migrated to v0.15.0\n" + "Portfolio currency set to USD (US Dollar), use web to edit\n" + "Portfolio migrated to v0.16.0\n" + "Portfolio model schemas updated\n" ) assert captured.out == target assert not captured.err diff --git a/tests/commands/test_unlock.py b/tests/commands/test_unlock.py index 03844c52..1c6129ef 100644 --- a/tests/commands/test_unlock.py +++ b/tests/commands/test_unlock.py @@ -2,8 +2,6 @@ from typing import TYPE_CHECKING -from colorama import Fore - from nummus.commands.unlock import Unlock if TYPE_CHECKING: @@ -22,6 +20,6 @@ def test_empty( assert c.run() == 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n" + target = "Portfolio is unlocked\n" assert captured.out == target assert not captured.err diff --git a/tests/commands/test_update_assets.py b/tests/commands/test_update_assets.py index e5afeef5..0405183b 100644 --- a/tests/commands/test_update_assets.py +++ b/tests/commands/test_update_assets.py @@ -3,8 +3,6 @@ import datetime from typing import TYPE_CHECKING -from colorama import Fore - from nummus.commands.update_assets import UpdateAssets from nummus.models.asset import ( Asset, @@ -27,11 +25,10 @@ def test_empty( assert c.run() == 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n" + target = "Portfolio is unlocked\n" assert captured.out == target target = ( - f"{Fore.YELLOW}No assets were updated, " - "add a ticker to an Asset to download market data\n" + "No assets were updated, add a ticker to an Asset to download market data\n" ) assert captured.err == target @@ -51,8 +48,8 @@ def test_one( captured = capsys.readouterr() target = ( - f"{Fore.GREEN}Portfolio is unlocked\n" - f"{Fore.GREEN}Asset {asset.name} ({asset.ticker}) updated " + "Portfolio is unlocked\n" + f"Asset {asset.name} ({asset.ticker}) updated " f"from {today - datetime.timedelta(days=9)} to {today}\n" ) assert captured.out == target @@ -74,10 +71,10 @@ def test_failed( assert c.run() != 0 captured = capsys.readouterr() - target = f"{Fore.GREEN}Portfolio is unlocked\n" + target = "Portfolio is unlocked\n" assert captured.out == target target = ( - f"{Fore.RED}Asset {asset.name} ({asset.ticker}) failed to update. " + f"Asset {asset.name} ({asset.ticker}) failed to update. " "Error: FAKE: No timezone found, symbol may be delisted\n" ) assert captured.err == target diff --git a/tests/controllers/budgeting/test_endpoints.py b/tests/controllers/budgeting/test_endpoints.py index 0aedd8da..0a8efc51 100644 --- a/tests/controllers/budgeting/test_endpoints.py +++ b/tests/controllers/budgeting/test_endpoints.py @@ -426,7 +426,7 @@ def test_parse_form( due: bool | str | int, repeat_every: int, ) -> None: - target = Target( + target = Target( # nummus: ignore amount=0, type_=TargetType.ACCUMULATE, period=TargetPeriod.MONTH, diff --git a/tests/models/asset/test_asset.py b/tests/models/asset/test_asset.py index 8adf82d5..f296cda4 100644 --- a/tests/models/asset/test_asset.py +++ b/tests/models/asset/test_asset.py @@ -82,7 +82,7 @@ def test_init_properties( def test_short() -> None: with pytest.raises(exc.InvalidORMValueError): - Asset(name="a") + Asset.create(name="a") def test_get_value_empty( diff --git a/tests/models/base/test_orm_base.py b/tests/models/base/test_orm_base.py index 0aea5fea..a6e55ed1 100644 --- a/tests/models/base/test_orm_base.py +++ b/tests/models/base/test_orm_base.py @@ -354,32 +354,47 @@ def test_find_missing(parent: Parent) -> None: assert not cache +re_check_no_session_add = re.compile(r"^ *(s|session)\.add\(\w+\)") +re_check_no_model_new = re.compile(rf"({'|'.join(m.__name__ for m in Base._MODELS)})\(") +re_check_no_session_query = re.compile(r"[( ](s|session)\.query\(") +re_check_no_scalar_query = re.compile(r"(\w*)\.scalar\(") +re_check_no_query_one = re.compile(r"(\w*)\.one\(") +re_check_no_query_all = re.compile(r"(\w*)\.all\(") +re_check_no_query_col0 = re.compile(r"for \w+,? in query") + + def check_no_session_add(line: str) -> str: - if re.match(r"^ *(s|session)\.add\(\w\)", line): + if re_check_no_session_add.match(line): return "Use of session.add found, use Model.create()" return "" +def check_no_model_new(line: str) -> str: + if not line.startswith("class") and re_check_no_model_new.search(line): + return "Use of Model(...) found, use Model.create()" + return "" + + def check_no_session_query(line: str) -> str: - if re.search(r"[( ](s|session)\.query\(", line): + if re_check_no_session_query.search(line): return "Use of session.query found, use Model.query()" return "" def check_no_query_with_entities(line: str) -> str: - if ".with_entities" in line: # nummus: ignore + if ".with_entities" in line: return "Use of with_entities found, use Model.query(col, ...)" return "" def check_no_query_scalar(line: str) -> str: - if (m := re.search(r"(\w*)\.scalar\(", line)) and m.group(1) != "sql": + if (m := re_check_no_scalar_query.search(line)) and m.group(1) != "sql": return "Use of query.scalar found, use sql.scalar()" return "" def check_no_query_one(line: str) -> str: - if not (m := re.search(r"(\w*)\.one\(", line)): + if not (m := re_check_no_query_one.search(line)): return "" g = m.group(1) if (g and g[0] == g[0].upper()) or g == "sql": @@ -389,7 +404,7 @@ def check_no_query_one(line: str) -> str: def check_no_query_all(line: str) -> str: - if not (m := re.search(r"(\w*)\.all\(", line)): + if not (m := re_check_no_query_all.search(line)): return "" g = m.group(1) if (g and g[0] == g[0].upper()) or g == "sql": @@ -399,7 +414,7 @@ def check_no_query_all(line: str) -> str: def check_no_query_col0(line: str) -> str: - if re.search(r"for \w+,? in query", line): + if re_check_no_query_col0.search(line): return "Use of first column iterator found, use sql.col0()" return "" @@ -423,14 +438,20 @@ def test_use_of_mixins(path: Path) -> None: for i, line in enumerate(lines): checks = [ - check_no_session_add(line), - check_no_session_query(line), - check_no_query_with_entities(line), - check_no_query_scalar(line), - check_no_query_one(line), - check_no_query_all(line), check_no_query_col0(line), ] + if "(" in line: + checks.extend( + [ + check_no_session_add(line), + check_no_model_new(line), + check_no_session_query(line), + check_no_query_with_entities(line), + check_no_query_scalar(line), + check_no_query_one(line), + check_no_query_all(line), + ], + ) checks = [f"{path:}:{i + 1}: {c}" for c in checks if c] if checks: if not line.endswith(ignore): diff --git a/tests/models/label/test_label.py b/tests/models/label/test_label.py index ff7ab0e9..e2857d85 100644 --- a/tests/models/label/test_label.py +++ b/tests/models/label/test_label.py @@ -16,4 +16,4 @@ def test_init_properties(rand_str: str) -> None: def test_short() -> None: with pytest.raises(exc.InvalidORMValueError): - Label(name="a") + Label.create(name="a") diff --git a/tests/models/test_health_checks.py b/tests/models/test_health_checks.py index 7b13457a..7254b622 100644 --- a/tests/models/test_health_checks.py +++ b/tests/models/test_health_checks.py @@ -51,7 +51,7 @@ def test_short_check(rand_str_generator: RandomStringGenerator) -> None: "ignore": False, } with pytest.raises(exc.InvalidORMValueError): - HealthCheckIssue(**d) + HealthCheckIssue.create(**d) def test_short_value( diff --git a/tests/models/test_transaction_category.py b/tests/models/test_transaction_category.py index ac3a559b..2df816a8 100644 --- a/tests/models/test_transaction_category.py +++ b/tests/models/test_transaction_category.py @@ -44,17 +44,17 @@ def test_init_properties( def test_empty() -> None: with pytest.raises(exc.InvalidORMValueError): - TransactionCategory(emoji_name="😀") + TransactionCategory.create(emoji_name="😀") def test_short() -> None: with pytest.raises(exc.InvalidORMValueError): - TransactionCategory(emoji_name="a") + TransactionCategory.create(emoji_name="a") def test_name_direct() -> None: with pytest.raises(exc.ParentAttributeError): - TransactionCategory(name="a") + TransactionCategory.create(name="a") def test_name_no_position(budget_group: BudgetGroup) -> None: @@ -73,7 +73,7 @@ def test_name_no_group() -> None: def test_essential_income() -> None: with pytest.raises(exc.InvalidORMValueError): - TransactionCategory( + TransactionCategory.create( group=TransactionCategoryGroup.INCOME, essential_spending=True, ) @@ -94,7 +94,7 @@ def test_essential_expense() -> None: def test_essential_none() -> None: with pytest.raises(TypeError): - TransactionCategory(essential_spending=None) + TransactionCategory.create(essential_spending=None) def test_emergency_fund_missing() -> None: diff --git a/tests/models/transaction/test_transaction_split.py b/tests/models/transaction/test_transaction_split.py index 40fa1829..adb0419d 100644 --- a/tests/models/transaction/test_transaction_split.py +++ b/tests/models/transaction/test_transaction_split.py @@ -72,7 +72,7 @@ def test_zero_amount(session: orm.Session, transactions: list[Transaction]) -> N def test_short() -> None: with pytest.raises(exc.InvalidORMValueError): - TransactionSplit(memo="a") + TransactionSplit.create(memo="a") def test_parent_attributes_direct(transactions: list[Transaction]) -> None: diff --git a/tests/portfolio/test_import.py b/tests/portfolio/test_import.py index 6ede35eb..2b453557 100644 --- a/tests/portfolio/test_import.py +++ b/tests/portfolio/test_import.py @@ -147,6 +147,8 @@ def test_import_file_investments( with empty_portfolio.begin_session(): assert sql.count(Transaction.query()) == 4 + # 2 normal, 2 dividends = 6 + assert sql.count(TransactionSplit.query()) == 6 query = Transaction.query().where( Transaction.date_ord == datetime.date(2023, 1, 3).toordinal(), diff --git a/tests/test_main.py b/tests/test_main.py index 79dea1b4..c429f667 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -6,7 +6,6 @@ from typing import TYPE_CHECKING import pytest -from colorama import Fore from nummus import main, version @@ -47,4 +46,4 @@ def test_unlock_successful( ) -> None: args = ["--portfolio", str(empty_portfolio.path), "unlock"] assert main.main(args) == 0 - assert capsys.readouterr().out == f"{Fore.GREEN}Portfolio is unlocked\n" + assert capsys.readouterr().out == "Portfolio is unlocked\n"