From 9a23860aeb460ecbeb03b6accbec81a361e2d0a5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 21:06:56 +0000 Subject: [PATCH 1/4] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: 2700fd5671c633760d912769c041bfcde2b9a01b → cb8c523fd4835aba42af70f4cad5568db4df0b6c](https://github.com/astral-sh/ruff-pre-commit/compare/2700fd5671c633760d912769c041bfcde2b9a01b...cb8c523fd4835aba42af70f4cad5568db4df0b6c) - [github.com/mxr/mirrors-ty: febed8a7b2665e80a9d3855c59ac716a6284d628 → d7f08bf6b37691c482773f198ba01539eb331d6a](https://github.com/mxr/mirrors-ty/compare/febed8a7b2665e80a9d3855c59ac716a6284d628...d7f08bf6b37691c482773f198ba01539eb331d6a) - [github.com/mxr/sync-typing-deps: c2ec0c01a31703615c17e3fe11d1fe28c003f1d8 → a8b960f5e2bb3627b5a1fc8171fe224cdd64ff0a](https://github.com/mxr/sync-typing-deps/compare/c2ec0c01a31703615c17e3fe11d1fe28c003f1d8...a8b960f5e2bb3627b5a1fc8171fe224cdd64ff0a) - [github.com/zizmorcore/zizmor-pre-commit: 64a97fb7fa63188393d3215c6e312f5f9c6d0f78 → 067260dc5fe6ea86b7551bfd6f8b3ba4e6c93129](https://github.com/zizmorcore/zizmor-pre-commit/compare/64a97fb7fa63188393d3215c6e312f5f9c6d0f78...067260dc5fe6ea86b7551bfd6f8b3ba4e6c93129) --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e7183f5..02ac9f5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: - id: reorder-python-imports args: [--py312-plus, --add-import, from __future__ import annotations] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 2700fd5671c633760d912769c041bfcde2b9a01b # frozen: v0.15.22 + rev: cb8c523fd4835aba42af70f4cad5568db4df0b6c # frozen: v0.16.0 hooks: - id: ruff-check args: [--fix] @@ -54,7 +54,7 @@ repos: - tenacity language_version: python3.12 - repo: https://github.com/mxr/mirrors-ty - rev: febed8a7b2665e80a9d3855c59ac716a6284d628 # frozen: v0.0.61 + rev: d7f08bf6b37691c482773f198ba01539eb331d6a # frozen: v0.0.63 hooks: - id: ty additional_dependencies: @@ -70,11 +70,11 @@ repos: - setuptools - tenacity - repo: https://github.com/mxr/sync-typing-deps - rev: c2ec0c01a31703615c17e3fe11d1fe28c003f1d8 # frozen: v0.5.3 + rev: a8b960f5e2bb3627b5a1fc8171fe224cdd64ff0a # frozen: v0.5.4 hooks: - id: sync-typing-deps - repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: 64a97fb7fa63188393d3215c6e312f5f9c6d0f78 # frozen: v1.27.0 + rev: 067260dc5fe6ea86b7551bfd6f8b3ba4e6c93129 # frozen: v1.28.0 hooks: - id: zizmor args: [--no-progress, --fix] From ea9d58008ffe4a17103be97b02ce3bd9bab5628a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 21:10:00 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .pre-commit-config.yaml | 4 +- sqlite_export_for_ynab/__init__.py | 3 +- sqlite_export_for_ynab/_main.py | 125 ++++++++++-------------- testing/fixtures.py | 56 +++++------ tests/_main_test.py | 148 +++++++++++++++-------------- 5 files changed, 155 insertions(+), 181 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 02ac9f5..66bd46b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -50,8 +50,8 @@ repos: - pytest - pytest-asyncio - rich>=10 - - setuptools - tenacity + - types-setuptools language_version: python3.12 - repo: https://github.com/mxr/mirrors-ty rev: d7f08bf6b37691c482773f198ba01539eb331d6a # frozen: v0.0.63 @@ -67,8 +67,8 @@ repos: - pytest - pytest-asyncio - rich>=10 - - setuptools - tenacity + - types-setuptools - repo: https://github.com/mxr/sync-typing-deps rev: a8b960f5e2bb3627b5a1fc8171fe224cdd64ff0a # frozen: v0.5.4 hooks: diff --git a/sqlite_export_for_ynab/__init__.py b/sqlite_export_for_ynab/__init__.py index 8a61281..92a5194 100644 --- a/sqlite_export_for_ynab/__init__.py +++ b/sqlite_export_for_ynab/__init__.py @@ -1,6 +1,5 @@ from __future__ import annotations -from sqlite_export_for_ynab._main import default_db_path -from sqlite_export_for_ynab._main import sync +from sqlite_export_for_ynab._main import default_db_path, sync __all__ = ["default_db_path", "sync"] diff --git a/sqlite_export_for_ynab/_main.py b/sqlite_export_for_ynab/_main.py index f5dc4e1..11d4ebd 100644 --- a/sqlite_export_for_ynab/_main.py +++ b/sqlite_export_for_ynab/_main.py @@ -3,65 +3,50 @@ import argparse import asyncio import os -from contextlib import asynccontextmanager -from contextlib import contextmanager -from dataclasses import dataclass -from dataclasses import fields -from datetime import date -from datetime import timedelta +from contextlib import asynccontextmanager, contextmanager +from dataclasses import dataclass, fields +from datetime import date, timedelta from importlib import resources from importlib.metadata import version from itertools import batched from pathlib import Path -from typing import Any -from typing import Literal -from typing import overload -from typing import override -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Literal, overload, override import aiosqlite import asyncio_for_ynab # noqa: F401 import fasteners from aiopathlib import AsyncPath -from asyncio_for_ynab import Account -from asyncio_for_ynab import AccountsApi -from asyncio_for_ynab import ApiClient -from asyncio_for_ynab import CategoriesApi -from asyncio_for_ynab import CategoryGroupWithCategories -from asyncio_for_ynab import Configuration -from asyncio_for_ynab import Payee -from asyncio_for_ynab import PayeesApi -from asyncio_for_ynab import PlansApi -from asyncio_for_ynab import PlanSummary -from asyncio_for_ynab import ScheduledTransactionDetail -from asyncio_for_ynab import ScheduledTransactionsApi -from asyncio_for_ynab import TransactionDetail -from asyncio_for_ynab import TransactionsApi -from asyncio_for_ynab import TransactionsResponse -from asyncio_for_ynab import TransactionsResponseData -from rich.progress import BarColumn -from rich.progress import Progress -from rich.progress import TaskID -from rich.progress import TextColumn -from rich.progress import TimeElapsedColumn -from tenacity import retry -from tenacity import stop_after_attempt +from asyncio_for_ynab import ( + Account, + AccountsApi, + ApiClient, + CategoriesApi, + CategoryGroupWithCategories, + Configuration, + Payee, + PayeesApi, + PlansApi, + PlanSummary, + ScheduledTransactionDetail, + ScheduledTransactionsApi, + TransactionDetail, + TransactionsApi, + TransactionsResponse, + TransactionsResponseData, +) +from rich.progress import BarColumn, Progress, TaskID, TextColumn, TimeElapsedColumn +from tenacity import retry, stop_after_attempt from sqlite_export_for_ynab import ddl if TYPE_CHECKING: - from collections.abc import AsyncIterator - from collections.abc import Awaitable - from collections.abc import Callable - from collections.abc import Iterator - from collections.abc import Sequence + from collections.abc import AsyncIterator, Awaitable, Callable, Iterator, Sequence try: from rich.progress import MofNCompleteColumn # https://github.com/benleb/surepy/issues/240 except ImportError: # pragma: no cover - from rich.progress import ProgressColumn - from rich.progress import Task + from rich.progress import ProgressColumn, Task from rich.text import Text if TYPE_CHECKING: @@ -84,24 +69,20 @@ def render(self, task: Task) -> Text: ) -_EntryTable = ( - Literal["accounts"] - | Literal["account_periodic_values"] - | Literal["category_groups"] - | Literal["categories"] - | Literal["payees"] - | Literal["transactions"] - | Literal["subtransactions"] - | Literal["scheduled_transactions"] - | Literal["scheduled_subtransactions"] -) -_Endpoint = ( - Literal["accounts"] - | Literal["categories"] - | Literal["payees"] - | Literal["transactions"] - | Literal["scheduled_transactions"] -) +_EntryTable = Literal[ + "accounts", + "account_periodic_values", + "category_groups", + "categories", + "payees", + "transactions", + "subtransactions", + "scheduled_transactions", + "scheduled_subtransactions", +] +_Endpoint = Literal[ + "accounts", "categories", "payees", "transactions", "scheduled_transactions" +] _ENDPOINTS = tuple(lit.__args__[0] for lit in _Endpoint.__args__) _ALL_RELATIONS = frozenset( ("plans", "flat_transactions", "scheduled_flat_transactions") @@ -556,28 +537,20 @@ async def insert_nested_entries( context: _Context, plan_id: str, entries: list[dict[str, Any]], - desc: ( - Literal["Accounts"] - | Literal["Categories"] - | Literal["Transactions"] - | Literal["Scheduled Transactions"] - ), + desc: (Literal["Accounts", "Categories", "Transactions", "Scheduled Transactions"]), entries_name: ( - Literal["accounts"] - | Literal["category_groups"] - | Literal["transactions"] - | Literal["scheduled_transactions"] + Literal["accounts", "category_groups", "transactions", "scheduled_transactions"] ), subentries_name: ( - Literal["account_periodic_values"] - | Literal["categories"] - | Literal["subtransactions"] + Literal["account_periodic_values", "categories", "subtransactions"] ), subentries_table_name: ( - Literal["account_periodic_values"] - | Literal["categories"] - | Literal["subtransactions"] - | Literal["scheduled_subtransactions"] + Literal[ + "account_periodic_values", + "categories", + "subtransactions", + "scheduled_subtransactions", + ] ), ) -> None: if not entries: diff --git a/testing/fixtures.py b/testing/fixtures.py index a570f51..981c0c6 100644 --- a/testing/fixtures.py +++ b/testing/fixtures.py @@ -1,34 +1,34 @@ from __future__ import annotations from datetime import date -from uuid import UUID -from uuid import uuid4 - -from asyncio_for_ynab import Account -from asyncio_for_ynab import AccountsResponse -from asyncio_for_ynab import AccountsResponseData -from asyncio_for_ynab import AccountType -from asyncio_for_ynab import CategoriesResponse -from asyncio_for_ynab import CategoriesResponseData -from asyncio_for_ynab import Category -from asyncio_for_ynab import CategoryGroupWithCategories -from asyncio_for_ynab import CurrencyFormat -from asyncio_for_ynab import Payee -from asyncio_for_ynab import PayeesResponse -from asyncio_for_ynab import PayeesResponseData -from asyncio_for_ynab import PlanSummary -from asyncio_for_ynab import PlanSummaryResponse -from asyncio_for_ynab import PlanSummaryResponseData -from asyncio_for_ynab import ScheduledSubTransaction -from asyncio_for_ynab import ScheduledTransactionDetail -from asyncio_for_ynab import ScheduledTransactionsResponse -from asyncio_for_ynab import ScheduledTransactionsResponseData -from asyncio_for_ynab import SubTransaction -from asyncio_for_ynab import TransactionClearedStatus -from asyncio_for_ynab import TransactionDetail -from asyncio_for_ynab import TransactionsResponse -from asyncio_for_ynab import TransactionsResponseData - +from uuid import UUID, uuid4 + +from asyncio_for_ynab import ( + Account, + AccountsResponse, + AccountsResponseData, + AccountType, + CategoriesResponse, + CategoriesResponseData, + Category, + CategoryGroupWithCategories, + CurrencyFormat, + Payee, + PayeesResponse, + PayeesResponseData, + PlanSummary, + PlanSummaryResponse, + PlanSummaryResponseData, + ScheduledSubTransaction, + ScheduledTransactionDetail, + ScheduledTransactionsResponse, + ScheduledTransactionsResponseData, + SubTransaction, + TransactionClearedStatus, + TransactionDetail, + TransactionsResponse, + TransactionsResponseData, +) PLAN_ID_1 = str(uuid4()) PLAN_ID_2 = str(uuid4()) diff --git a/tests/_main_test.py b/tests/_main_test.py index df59dda..89cee17 100644 --- a/tests/_main_test.py +++ b/tests/_main_test.py @@ -3,9 +3,7 @@ import tomllib from datetime import date from pathlib import Path -from unittest.mock import AsyncMock -from unittest.mock import Mock -from unittest.mock import patch +from unittest.mock import AsyncMock, Mock, patch import aiosqlite import fasteners @@ -14,76 +12,80 @@ from rich.progress import Progress from sqlite_export_for_ynab import default_db_path -from sqlite_export_for_ynab._main import _ALL_RELATIONS -from sqlite_export_for_ynab._main import _Context -from sqlite_export_for_ynab._main import _context -from sqlite_export_for_ynab._main import _ENV_TOKEN -from sqlite_export_for_ynab._main import _get_plan_summaries -from sqlite_export_for_ynab._main import _PACKAGE -from sqlite_export_for_ynab._main import _PROGRESS_COLUMNS -from sqlite_export_for_ynab._main import _quarterly -from sqlite_export_for_ynab._main import async_main -from sqlite_export_for_ynab._main import asyncio_for_ynab -from sqlite_export_for_ynab._main import ChunkedTransactionsApi -from sqlite_export_for_ynab._main import contents -from sqlite_export_for_ynab._main import get_last_knowledge_of_server -from sqlite_export_for_ynab._main import get_relations -from sqlite_export_for_ynab._main import insert_accounts -from sqlite_export_for_ynab._main import insert_category_groups -from sqlite_export_for_ynab._main import insert_entries -from sqlite_export_for_ynab._main import insert_payees -from sqlite_export_for_ynab._main import insert_plans -from sqlite_export_for_ynab._main import insert_scheduled_transactions -from sqlite_export_for_ynab._main import insert_transactions -from sqlite_export_for_ynab._main import main -from sqlite_export_for_ynab._main import resolve_token -from sqlite_export_for_ynab._main import sync -from testing.fixtures import ACCOUNT_ID_1 -from testing.fixtures import ACCOUNT_ID_2 -from testing.fixtures import ACCOUNTS -from testing.fixtures import accounts_response -from testing.fixtures import categories_response -from testing.fixtures import CATEGORY_GOAL_TARGET_DATE_1 -from testing.fixtures import CATEGORY_GROUP_ID_1 -from testing.fixtures import CATEGORY_GROUP_ID_2 -from testing.fixtures import CATEGORY_GROUP_NAME_1 -from testing.fixtures import CATEGORY_GROUP_NAME_2 -from testing.fixtures import CATEGORY_GROUPS -from testing.fixtures import CATEGORY_ID_1 -from testing.fixtures import CATEGORY_ID_2 -from testing.fixtures import CATEGORY_ID_3 -from testing.fixtures import CATEGORY_ID_4 -from testing.fixtures import CATEGORY_NAME_1 -from testing.fixtures import CATEGORY_NAME_2 -from testing.fixtures import CATEGORY_NAME_3 -from testing.fixtures import CATEGORY_NAME_4 -from testing.fixtures import LKOS -from testing.fixtures import PAYEE_ID_1 -from testing.fixtures import PAYEE_ID_2 -from testing.fixtures import PAYEES -from testing.fixtures import payees_response -from testing.fixtures import PLAN_ID_1 -from testing.fixtures import PLAN_ID_2 -from testing.fixtures import plan_response -from testing.fixtures import PLANS -from testing.fixtures import SCHEDULED_SUBTRANSACTION_ID_1 -from testing.fixtures import SCHEDULED_SUBTRANSACTION_ID_2 -from testing.fixtures import SCHEDULED_TRANSACTION_ID_1 -from testing.fixtures import SCHEDULED_TRANSACTION_ID_2 -from testing.fixtures import SCHEDULED_TRANSACTION_ID_3 -from testing.fixtures import SCHEDULED_TRANSACTIONS -from testing.fixtures import scheduled_transactions_response -from testing.fixtures import SERVER_KNOWLEDGE_1 -from testing.fixtures import SERVER_KNOWLEDGE_2 -from testing.fixtures import SUBTRANSACTION_ID_1 -from testing.fixtures import SUBTRANSACTION_ID_2 -from testing.fixtures import TOKEN -from testing.fixtures import TRANSACTION_CHUNKS -from testing.fixtures import TRANSACTION_ID_1 -from testing.fixtures import TRANSACTION_ID_2 -from testing.fixtures import TRANSACTION_ID_3 -from testing.fixtures import TRANSACTIONS -from testing.fixtures import transactions_response +from sqlite_export_for_ynab._main import ( + _ALL_RELATIONS, + _ENV_TOKEN, + _PACKAGE, + _PROGRESS_COLUMNS, + ChunkedTransactionsApi, + _Context, + _context, + _get_plan_summaries, + _quarterly, + async_main, + asyncio_for_ynab, + contents, + get_last_knowledge_of_server, + get_relations, + insert_accounts, + insert_category_groups, + insert_entries, + insert_payees, + insert_plans, + insert_scheduled_transactions, + insert_transactions, + main, + resolve_token, + sync, +) +from testing.fixtures import ( + ACCOUNT_ID_1, + ACCOUNT_ID_2, + ACCOUNTS, + CATEGORY_GOAL_TARGET_DATE_1, + CATEGORY_GROUP_ID_1, + CATEGORY_GROUP_ID_2, + CATEGORY_GROUP_NAME_1, + CATEGORY_GROUP_NAME_2, + CATEGORY_GROUPS, + CATEGORY_ID_1, + CATEGORY_ID_2, + CATEGORY_ID_3, + CATEGORY_ID_4, + CATEGORY_NAME_1, + CATEGORY_NAME_2, + CATEGORY_NAME_3, + CATEGORY_NAME_4, + LKOS, + PAYEE_ID_1, + PAYEE_ID_2, + PAYEES, + PLAN_ID_1, + PLAN_ID_2, + PLANS, + SCHEDULED_SUBTRANSACTION_ID_1, + SCHEDULED_SUBTRANSACTION_ID_2, + SCHEDULED_TRANSACTION_ID_1, + SCHEDULED_TRANSACTION_ID_2, + SCHEDULED_TRANSACTION_ID_3, + SCHEDULED_TRANSACTIONS, + SERVER_KNOWLEDGE_1, + SERVER_KNOWLEDGE_2, + SUBTRANSACTION_ID_1, + SUBTRANSACTION_ID_2, + TOKEN, + TRANSACTION_CHUNKS, + TRANSACTION_ID_1, + TRANSACTION_ID_2, + TRANSACTION_ID_3, + TRANSACTIONS, + accounts_response, + categories_response, + payees_response, + plan_response, + scheduled_transactions_response, + transactions_response, +) async def fetchall(con, query): From 0f5dfec79ea3c16a01f241223bea5cc7a1ec0174 Mon Sep 17 00:00:00 2001 From: Max R Date: Mon, 27 Jul 2026 18:59:12 -0400 Subject: [PATCH 3/4] Drop reorder-python-imports for ruff isort Ruff's isort rule now sorts imports and enforces the future annotations import, replacing the separate reorder-python-imports hook. --- .pre-commit-config.yaml | 5 - pyproject.toml | 9 +- sqlite_export_for_ynab/__init__.py | 3 +- sqlite_export_for_ynab/_main.py | 67 ++++++++----- testing/fixtures.py | 55 ++++++----- tests/_main_test.py | 148 ++++++++++++++--------------- 6 files changed, 150 insertions(+), 137 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 66bd46b..a1642ad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,11 +13,6 @@ repos: args: [--autofix, --trailing-commas] - id: pretty-format-yaml args: [--autofix] -- repo: https://github.com/asottile/reorder-python-imports - rev: 5e38415c12154247a099c7023c210e3d458275b5 # frozen: v3.17.0 - hooks: - - id: reorder-python-imports - args: [--py312-plus, --add-import, from __future__ import annotations] - repo: https://github.com/astral-sh/ruff-pre-commit rev: cb8c523fd4835aba42af70f4cad5568db4df0b6c # frozen: v0.16.0 hooks: diff --git a/pyproject.toml b/pyproject.toml index aa70cba..131c0f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,14 +69,19 @@ target-version = "py312" [tool.ruff.lint] extend-select = [ - "UP", # see pyupgrade - "B", # see flake8-bugbear "A", # see flake8-builtins + "B", # see flake8-bugbear "C4", # see flake8-comprehension + "I", # sort imports "SIM", # see flake8-simplify "TC", # see flake8-type-checking + "UP", # see pyupgrade ] +[tool.ruff.lint.isort] +force-single-line = true +required-imports = ["from __future__ import annotations"] + [tool.setuptools.package-data] sqlite_export_for_ynab = ["py.typed"] "sqlite_export_for_ynab.ddl" = ["*.sql"] diff --git a/sqlite_export_for_ynab/__init__.py b/sqlite_export_for_ynab/__init__.py index 92a5194..8a61281 100644 --- a/sqlite_export_for_ynab/__init__.py +++ b/sqlite_export_for_ynab/__init__.py @@ -1,5 +1,6 @@ from __future__ import annotations -from sqlite_export_for_ynab._main import default_db_path, sync +from sqlite_export_for_ynab._main import default_db_path +from sqlite_export_for_ynab._main import sync __all__ = ["default_db_path", "sync"] diff --git a/sqlite_export_for_ynab/_main.py b/sqlite_export_for_ynab/_main.py index 11d4ebd..ae9e067 100644 --- a/sqlite_export_for_ynab/_main.py +++ b/sqlite_export_for_ynab/_main.py @@ -3,50 +3,65 @@ import argparse import asyncio import os -from contextlib import asynccontextmanager, contextmanager -from dataclasses import dataclass, fields -from datetime import date, timedelta +from contextlib import asynccontextmanager +from contextlib import contextmanager +from dataclasses import dataclass +from dataclasses import fields +from datetime import date +from datetime import timedelta from importlib import resources from importlib.metadata import version from itertools import batched from pathlib import Path -from typing import TYPE_CHECKING, Any, Literal, overload, override +from typing import TYPE_CHECKING +from typing import Any +from typing import Literal +from typing import overload +from typing import override import aiosqlite import asyncio_for_ynab # noqa: F401 import fasteners from aiopathlib import AsyncPath -from asyncio_for_ynab import ( - Account, - AccountsApi, - ApiClient, - CategoriesApi, - CategoryGroupWithCategories, - Configuration, - Payee, - PayeesApi, - PlansApi, - PlanSummary, - ScheduledTransactionDetail, - ScheduledTransactionsApi, - TransactionDetail, - TransactionsApi, - TransactionsResponse, - TransactionsResponseData, -) -from rich.progress import BarColumn, Progress, TaskID, TextColumn, TimeElapsedColumn -from tenacity import retry, stop_after_attempt +from asyncio_for_ynab import Account +from asyncio_for_ynab import AccountsApi +from asyncio_for_ynab import ApiClient +from asyncio_for_ynab import CategoriesApi +from asyncio_for_ynab import CategoryGroupWithCategories +from asyncio_for_ynab import Configuration +from asyncio_for_ynab import Payee +from asyncio_for_ynab import PayeesApi +from asyncio_for_ynab import PlansApi +from asyncio_for_ynab import PlanSummary +from asyncio_for_ynab import ScheduledTransactionDetail +from asyncio_for_ynab import ScheduledTransactionsApi +from asyncio_for_ynab import TransactionDetail +from asyncio_for_ynab import TransactionsApi +from asyncio_for_ynab import TransactionsResponse +from asyncio_for_ynab import TransactionsResponseData +from rich.progress import BarColumn +from rich.progress import Progress +from rich.progress import TaskID +from rich.progress import TextColumn +from rich.progress import TimeElapsedColumn +from tenacity import retry +from tenacity import stop_after_attempt from sqlite_export_for_ynab import ddl if TYPE_CHECKING: - from collections.abc import AsyncIterator, Awaitable, Callable, Iterator, Sequence + from collections.abc import AsyncIterator + from collections.abc import Awaitable + from collections.abc import Callable + from collections.abc import Iterator + from collections.abc import Sequence try: from rich.progress import MofNCompleteColumn # https://github.com/benleb/surepy/issues/240 except ImportError: # pragma: no cover - from rich.progress import ProgressColumn, Task + from rich.progress import ProgressColumn + from rich.progress import Task from rich.text import Text if TYPE_CHECKING: diff --git a/testing/fixtures.py b/testing/fixtures.py index 981c0c6..425873a 100644 --- a/testing/fixtures.py +++ b/testing/fixtures.py @@ -1,34 +1,33 @@ from __future__ import annotations from datetime import date -from uuid import UUID, uuid4 - -from asyncio_for_ynab import ( - Account, - AccountsResponse, - AccountsResponseData, - AccountType, - CategoriesResponse, - CategoriesResponseData, - Category, - CategoryGroupWithCategories, - CurrencyFormat, - Payee, - PayeesResponse, - PayeesResponseData, - PlanSummary, - PlanSummaryResponse, - PlanSummaryResponseData, - ScheduledSubTransaction, - ScheduledTransactionDetail, - ScheduledTransactionsResponse, - ScheduledTransactionsResponseData, - SubTransaction, - TransactionClearedStatus, - TransactionDetail, - TransactionsResponse, - TransactionsResponseData, -) +from uuid import UUID +from uuid import uuid4 + +from asyncio_for_ynab import Account +from asyncio_for_ynab import AccountsResponse +from asyncio_for_ynab import AccountsResponseData +from asyncio_for_ynab import AccountType +from asyncio_for_ynab import CategoriesResponse +from asyncio_for_ynab import CategoriesResponseData +from asyncio_for_ynab import Category +from asyncio_for_ynab import CategoryGroupWithCategories +from asyncio_for_ynab import CurrencyFormat +from asyncio_for_ynab import Payee +from asyncio_for_ynab import PayeesResponse +from asyncio_for_ynab import PayeesResponseData +from asyncio_for_ynab import PlanSummary +from asyncio_for_ynab import PlanSummaryResponse +from asyncio_for_ynab import PlanSummaryResponseData +from asyncio_for_ynab import ScheduledSubTransaction +from asyncio_for_ynab import ScheduledTransactionDetail +from asyncio_for_ynab import ScheduledTransactionsResponse +from asyncio_for_ynab import ScheduledTransactionsResponseData +from asyncio_for_ynab import SubTransaction +from asyncio_for_ynab import TransactionClearedStatus +from asyncio_for_ynab import TransactionDetail +from asyncio_for_ynab import TransactionsResponse +from asyncio_for_ynab import TransactionsResponseData PLAN_ID_1 = str(uuid4()) PLAN_ID_2 = str(uuid4()) diff --git a/tests/_main_test.py b/tests/_main_test.py index 89cee17..83c8add 100644 --- a/tests/_main_test.py +++ b/tests/_main_test.py @@ -3,7 +3,9 @@ import tomllib from datetime import date from pathlib import Path -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import AsyncMock +from unittest.mock import Mock +from unittest.mock import patch import aiosqlite import fasteners @@ -12,80 +14,76 @@ from rich.progress import Progress from sqlite_export_for_ynab import default_db_path -from sqlite_export_for_ynab._main import ( - _ALL_RELATIONS, - _ENV_TOKEN, - _PACKAGE, - _PROGRESS_COLUMNS, - ChunkedTransactionsApi, - _Context, - _context, - _get_plan_summaries, - _quarterly, - async_main, - asyncio_for_ynab, - contents, - get_last_knowledge_of_server, - get_relations, - insert_accounts, - insert_category_groups, - insert_entries, - insert_payees, - insert_plans, - insert_scheduled_transactions, - insert_transactions, - main, - resolve_token, - sync, -) -from testing.fixtures import ( - ACCOUNT_ID_1, - ACCOUNT_ID_2, - ACCOUNTS, - CATEGORY_GOAL_TARGET_DATE_1, - CATEGORY_GROUP_ID_1, - CATEGORY_GROUP_ID_2, - CATEGORY_GROUP_NAME_1, - CATEGORY_GROUP_NAME_2, - CATEGORY_GROUPS, - CATEGORY_ID_1, - CATEGORY_ID_2, - CATEGORY_ID_3, - CATEGORY_ID_4, - CATEGORY_NAME_1, - CATEGORY_NAME_2, - CATEGORY_NAME_3, - CATEGORY_NAME_4, - LKOS, - PAYEE_ID_1, - PAYEE_ID_2, - PAYEES, - PLAN_ID_1, - PLAN_ID_2, - PLANS, - SCHEDULED_SUBTRANSACTION_ID_1, - SCHEDULED_SUBTRANSACTION_ID_2, - SCHEDULED_TRANSACTION_ID_1, - SCHEDULED_TRANSACTION_ID_2, - SCHEDULED_TRANSACTION_ID_3, - SCHEDULED_TRANSACTIONS, - SERVER_KNOWLEDGE_1, - SERVER_KNOWLEDGE_2, - SUBTRANSACTION_ID_1, - SUBTRANSACTION_ID_2, - TOKEN, - TRANSACTION_CHUNKS, - TRANSACTION_ID_1, - TRANSACTION_ID_2, - TRANSACTION_ID_3, - TRANSACTIONS, - accounts_response, - categories_response, - payees_response, - plan_response, - scheduled_transactions_response, - transactions_response, -) +from sqlite_export_for_ynab._main import _ALL_RELATIONS +from sqlite_export_for_ynab._main import _ENV_TOKEN +from sqlite_export_for_ynab._main import _PACKAGE +from sqlite_export_for_ynab._main import _PROGRESS_COLUMNS +from sqlite_export_for_ynab._main import ChunkedTransactionsApi +from sqlite_export_for_ynab._main import _Context +from sqlite_export_for_ynab._main import _context +from sqlite_export_for_ynab._main import _get_plan_summaries +from sqlite_export_for_ynab._main import _quarterly +from sqlite_export_for_ynab._main import async_main +from sqlite_export_for_ynab._main import asyncio_for_ynab +from sqlite_export_for_ynab._main import contents +from sqlite_export_for_ynab._main import get_last_knowledge_of_server +from sqlite_export_for_ynab._main import get_relations +from sqlite_export_for_ynab._main import insert_accounts +from sqlite_export_for_ynab._main import insert_category_groups +from sqlite_export_for_ynab._main import insert_entries +from sqlite_export_for_ynab._main import insert_payees +from sqlite_export_for_ynab._main import insert_plans +from sqlite_export_for_ynab._main import insert_scheduled_transactions +from sqlite_export_for_ynab._main import insert_transactions +from sqlite_export_for_ynab._main import main +from sqlite_export_for_ynab._main import resolve_token +from sqlite_export_for_ynab._main import sync +from testing.fixtures import ACCOUNT_ID_1 +from testing.fixtures import ACCOUNT_ID_2 +from testing.fixtures import ACCOUNTS +from testing.fixtures import CATEGORY_GOAL_TARGET_DATE_1 +from testing.fixtures import CATEGORY_GROUP_ID_1 +from testing.fixtures import CATEGORY_GROUP_ID_2 +from testing.fixtures import CATEGORY_GROUP_NAME_1 +from testing.fixtures import CATEGORY_GROUP_NAME_2 +from testing.fixtures import CATEGORY_GROUPS +from testing.fixtures import CATEGORY_ID_1 +from testing.fixtures import CATEGORY_ID_2 +from testing.fixtures import CATEGORY_ID_3 +from testing.fixtures import CATEGORY_ID_4 +from testing.fixtures import CATEGORY_NAME_1 +from testing.fixtures import CATEGORY_NAME_2 +from testing.fixtures import CATEGORY_NAME_3 +from testing.fixtures import CATEGORY_NAME_4 +from testing.fixtures import LKOS +from testing.fixtures import PAYEE_ID_1 +from testing.fixtures import PAYEE_ID_2 +from testing.fixtures import PAYEES +from testing.fixtures import PLAN_ID_1 +from testing.fixtures import PLAN_ID_2 +from testing.fixtures import PLANS +from testing.fixtures import SCHEDULED_SUBTRANSACTION_ID_1 +from testing.fixtures import SCHEDULED_SUBTRANSACTION_ID_2 +from testing.fixtures import SCHEDULED_TRANSACTION_ID_1 +from testing.fixtures import SCHEDULED_TRANSACTION_ID_2 +from testing.fixtures import SCHEDULED_TRANSACTION_ID_3 +from testing.fixtures import SCHEDULED_TRANSACTIONS +from testing.fixtures import SERVER_KNOWLEDGE_1 +from testing.fixtures import SERVER_KNOWLEDGE_2 +from testing.fixtures import SUBTRANSACTION_ID_1 +from testing.fixtures import SUBTRANSACTION_ID_2 +from testing.fixtures import TOKEN +from testing.fixtures import TRANSACTION_CHUNKS +from testing.fixtures import TRANSACTION_ID_1 +from testing.fixtures import TRANSACTION_ID_2 +from testing.fixtures import TRANSACTION_ID_3 +from testing.fixtures import TRANSACTIONS +from testing.fixtures import accounts_response +from testing.fixtures import categories_response +from testing.fixtures import payees_response +from testing.fixtures import plan_response +from testing.fixtures import scheduled_transactions_response +from testing.fixtures import transactions_response async def fetchall(con, query): From 3ab8eea2eced6532db59667fc05ddafd5c0d9b41 Mon Sep 17 00:00:00 2001 From: Max R Date: Mon, 27 Jul 2026 19:07:15 -0400 Subject: [PATCH 4/4] Fix Literal introspection broken by ruff's union-to-flat-literal fix _Endpoint and _EntryTable were collapsed from unions of single-value Literals into flat Literals, so the old lit.__args__[0] unwrap crashed at import time since each item is now a plain str. Use get_args() directly, and make the timezone-naive date.today() tz-aware. --- sqlite_export_for_ynab/_main.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sqlite_export_for_ynab/_main.py b/sqlite_export_for_ynab/_main.py index ae9e067..edfccf8 100644 --- a/sqlite_export_for_ynab/_main.py +++ b/sqlite_export_for_ynab/_main.py @@ -8,6 +8,7 @@ from dataclasses import dataclass from dataclasses import fields from datetime import date +from datetime import datetime from datetime import timedelta from importlib import resources from importlib.metadata import version @@ -16,6 +17,7 @@ from typing import TYPE_CHECKING from typing import Any from typing import Literal +from typing import get_args from typing import overload from typing import override @@ -98,10 +100,10 @@ def render(self, task: Task) -> Text: _Endpoint = Literal[ "accounts", "categories", "payees", "transactions", "scheduled_transactions" ] -_ENDPOINTS = tuple(lit.__args__[0] for lit in _Endpoint.__args__) +_ENDPOINTS = get_args(_Endpoint) _ALL_RELATIONS = frozenset( ("plans", "flat_transactions", "scheduled_flat_transactions") - + tuple(lit.__args__[0] for lit in _EntryTable.__args__) + + get_args(_EntryTable) ) _ENV_TOKEN = "YNAB_PERSONAL_ACCESS_TOKEN" @@ -701,7 +703,7 @@ async def get_transactions( async def _get( self, transactions_api: TransactionsApi, plan_id: str ) -> TransactionsResponse: - today = date.today() + today = datetime.now().astimezone().date() responses = await asyncio.gather( *( self._chunk(transactions_api, plan_id, sd, ud)