sqlite-export-for-ynab 2.8.0__tar.gz → 2.9.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sqlite_export_for_ynab-2.8.0/sqlite_export_for_ynab.egg-info → sqlite_export_for_ynab-2.9.1}/PKG-INFO +5 -11
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/README.md +1 -1
- sqlite_export_for_ynab-2.9.1/pyproject.toml +133 -0
- sqlite_export_for_ynab-2.9.1/setup.cfg +4 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/_main.py +38 -87
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1/sqlite_export_for_ynab.egg-info}/PKG-INFO +5 -11
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab.egg-info/SOURCES.txt +0 -2
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab.egg-info/requires.txt +0 -6
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab.egg-info/top_level.txt +1 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/tests/_main_test.py +32 -8
- sqlite_export_for_ynab-2.8.0/pyproject.toml +0 -63
- sqlite_export_for_ynab-2.8.0/setup.cfg +0 -71
- sqlite_export_for_ynab-2.8.0/setup.py +0 -5
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/LICENSE +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/__init__.py +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/__main__.py +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/ddl/__init__.py +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/ddl/create-relations.sql +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/ddl/drop-relations.sql +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/py.typed +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab.egg-info/dependency_links.txt +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab.egg-info/entry_points.txt +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/testing/__init__.py +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/testing/fixtures.py +0 -0
- {sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/tests/__init__.py +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlite_export_for_ynab
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.1
|
|
4
4
|
Summary: SQLite Export for YNAB - Export YNAB Data to SQLite
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
License: MIT
|
|
5
|
+
Author-email: Max R <mxr@users.noreply.github.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mxr/sqlite-export-for-ynab
|
|
9
8
|
Keywords: ynab,sqlite,sql,budget,plan,cli
|
|
10
9
|
Classifier: Programming Language :: Python :: 3
|
|
11
10
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -21,11 +20,6 @@ Requires-Dist: asyncio-for-ynab~=1.84.0
|
|
|
21
20
|
Requires-Dist: fasteners
|
|
22
21
|
Requires-Dist: rich>=10
|
|
23
22
|
Requires-Dist: tenacity
|
|
24
|
-
Provides-Extra: dev
|
|
25
|
-
Requires-Dist: covdefaults>=2.1.0; extra == "dev"
|
|
26
|
-
Requires-Dist: coverage; extra == "dev"
|
|
27
|
-
Requires-Dist: pytest; extra == "dev"
|
|
28
|
-
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
29
23
|
Dynamic: license-file
|
|
30
24
|
|
|
31
25
|
# sqlite-export-for-ynab
|
|
@@ -272,7 +266,7 @@ WITH interest_by_account AS (
|
|
|
272
266
|
SELECT
|
|
273
267
|
plan_id
|
|
274
268
|
, account_name
|
|
275
|
-
, SUM(
|
|
269
|
+
, SUM(amount_currency) AS total
|
|
276
270
|
FROM flat_transactions
|
|
277
271
|
WHERE
|
|
278
272
|
TRUE
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "setuptools.build_meta"
|
|
3
|
+
requires = ["setuptools"]
|
|
4
|
+
|
|
5
|
+
[dependency-groups]
|
|
6
|
+
dev = [
|
|
7
|
+
"covdefaults>=2.1.0",
|
|
8
|
+
"coverage",
|
|
9
|
+
"pytest",
|
|
10
|
+
"pytest-asyncio",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[project]
|
|
14
|
+
authors = [{name = "Max R", email = "mxr@users.noreply.github.com"}]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
19
|
+
"Programming Language :: Python :: Implementation :: PyPy",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"aiohttp>=3",
|
|
23
|
+
"aiopathlib",
|
|
24
|
+
"aiosqlite",
|
|
25
|
+
"asyncio-for-ynab~=1.84.0",
|
|
26
|
+
"fasteners",
|
|
27
|
+
"rich>=10",
|
|
28
|
+
"tenacity",
|
|
29
|
+
]
|
|
30
|
+
description = "SQLite Export for YNAB - Export YNAB Data to SQLite"
|
|
31
|
+
keywords = ["ynab", "sqlite", "sql", "budget", "plan", "cli"]
|
|
32
|
+
license = "MIT"
|
|
33
|
+
license-files = ["LICENSE"]
|
|
34
|
+
name = "sqlite_export_for_ynab"
|
|
35
|
+
readme = "README.md"
|
|
36
|
+
requires-python = ">=3.12"
|
|
37
|
+
version = "2.9.1"
|
|
38
|
+
|
|
39
|
+
[project.scripts]
|
|
40
|
+
sqlite-export-for-ynab = "sqlite_export_for_ynab._main:main"
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/mxr/sqlite-export-for-ynab"
|
|
44
|
+
|
|
45
|
+
[tool.coverage.run]
|
|
46
|
+
plugins = ["covdefaults"]
|
|
47
|
+
|
|
48
|
+
[tool.mypy]
|
|
49
|
+
check_untyped_defs = true
|
|
50
|
+
disallow_any_generics = true
|
|
51
|
+
disallow_incomplete_defs = true
|
|
52
|
+
disallow_untyped_defs = true
|
|
53
|
+
warn_redundant_casts = true
|
|
54
|
+
warn_unused_ignores = true
|
|
55
|
+
|
|
56
|
+
[[tool.mypy.overrides]]
|
|
57
|
+
disallow_untyped_defs = false
|
|
58
|
+
module = "testing.*"
|
|
59
|
+
|
|
60
|
+
[[tool.mypy.overrides]]
|
|
61
|
+
disallow_untyped_defs = false
|
|
62
|
+
module = "tests.*"
|
|
63
|
+
|
|
64
|
+
[tool.pytest.ini_options]
|
|
65
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
66
|
+
|
|
67
|
+
[tool.ruff]
|
|
68
|
+
target-version = "py312"
|
|
69
|
+
|
|
70
|
+
[tool.ruff.lint]
|
|
71
|
+
extend-select = [
|
|
72
|
+
"UP", # see pyupgrade
|
|
73
|
+
"B", # see flake8-bugbear
|
|
74
|
+
"A", # see flake8-builtins
|
|
75
|
+
"C4", # see flake8-comprehension
|
|
76
|
+
"SIM", # see flake8-simplify
|
|
77
|
+
"TC", # see flake8-type-checking
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
[tool.setuptools.package-data]
|
|
81
|
+
"*" = ["*.sql"]
|
|
82
|
+
sqlite_export_for_ynab = ["py.typed"]
|
|
83
|
+
|
|
84
|
+
[tool.setuptools.packages]
|
|
85
|
+
find = {}
|
|
86
|
+
|
|
87
|
+
[tool.sqlfluff.layout.type.comma]
|
|
88
|
+
line_position = "leading"
|
|
89
|
+
spacing_before = "touch"
|
|
90
|
+
|
|
91
|
+
[tool.sqlfluff.layout.type.from_clause]
|
|
92
|
+
keyword_line_position = "leading"
|
|
93
|
+
|
|
94
|
+
[tool.sqlfluff.layout.type.when_clause]
|
|
95
|
+
keyword_line_position = "leading"
|
|
96
|
+
|
|
97
|
+
[tool.sqlfluff.rules.capitalisation.functions]
|
|
98
|
+
extended_capitalisation_policy = 'upper'
|
|
99
|
+
|
|
100
|
+
[tool.sqlfluff.rules.capitalisation.identifiers]
|
|
101
|
+
extended_capitalisation_policy = 'lower'
|
|
102
|
+
|
|
103
|
+
[tool.sqlfluff.rules.capitalisation.keywords]
|
|
104
|
+
capitalisation_policy = 'upper'
|
|
105
|
+
|
|
106
|
+
[tool.sqlfluff.rules.capitalisation.literals]
|
|
107
|
+
capitalisation_policy = 'upper'
|
|
108
|
+
|
|
109
|
+
[tool.sqlfluff.rules.convention.not_equal]
|
|
110
|
+
preferred_not_equal_style = "c_style"
|
|
111
|
+
|
|
112
|
+
[tool.sqlfluff.rules.convention.terminator]
|
|
113
|
+
multiline_newline = true
|
|
114
|
+
require_final_semicolon = true
|
|
115
|
+
|
|
116
|
+
[tool.sqlfluff.rules.references.quoting]
|
|
117
|
+
prefer_quoted_keywords = true
|
|
118
|
+
|
|
119
|
+
[tool.tox]
|
|
120
|
+
env_list = ["py", "pypy3", "pre-commit"]
|
|
121
|
+
|
|
122
|
+
[tool.tox.env.pre-commit]
|
|
123
|
+
commands = [["pre-commit", "run", "--all-files", "--show-diff-on-failure"]]
|
|
124
|
+
deps = ["pre-commit-uv"]
|
|
125
|
+
skip_install = true
|
|
126
|
+
|
|
127
|
+
[tool.tox.env_run_base]
|
|
128
|
+
commands = [
|
|
129
|
+
["coverage", "erase"],
|
|
130
|
+
["coverage", "run", "-m", "pytest", "{posargs:tests}"],
|
|
131
|
+
["coverage", "report"],
|
|
132
|
+
]
|
|
133
|
+
dependency_groups = ["dev"]
|
{sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/_main.py
RENAMED
|
@@ -46,6 +46,8 @@ from sqlite_export_for_ynab import ddl
|
|
|
46
46
|
|
|
47
47
|
if TYPE_CHECKING:
|
|
48
48
|
from collections.abc import AsyncIterator
|
|
49
|
+
from collections.abc import Awaitable
|
|
50
|
+
from collections.abc import Callable
|
|
49
51
|
from collections.abc import Iterator
|
|
50
52
|
from collections.abc import Sequence
|
|
51
53
|
|
|
@@ -305,7 +307,7 @@ async def sync(
|
|
|
305
307
|
|
|
306
308
|
|
|
307
309
|
async def contents(filename: str) -> str:
|
|
308
|
-
return await AsyncPath(resources.files(ddl) / filename).read_text()
|
|
310
|
+
return await AsyncPath(str(resources.files(ddl) / filename)).read_text()
|
|
309
311
|
|
|
310
312
|
|
|
311
313
|
async def get_relations(cur: aiosqlite.Cursor) -> set[str]:
|
|
@@ -603,7 +605,13 @@ async def insert_entries(
|
|
|
603
605
|
if not entries:
|
|
604
606
|
return
|
|
605
607
|
|
|
606
|
-
|
|
608
|
+
async with context.con.cursor() as cur:
|
|
609
|
+
await cur.execute(f"PRAGMA table_info({table})")
|
|
610
|
+
table_columns = {row["name"] async for row in cur}
|
|
611
|
+
|
|
612
|
+
# Ignore any keys the YNAB API returns that aren't columns in the DDL so
|
|
613
|
+
# newly-added API fields don't break the insert.
|
|
614
|
+
entry_keys = tuple(k for k in entries[0] if k in table_columns)
|
|
607
615
|
sql = f"INSERT OR REPLACE INTO {table} ({', '.join(entry_keys + ('plan_id',))}) VALUES ({', '.join('?' * (len(entry_keys) + 1))})"
|
|
608
616
|
|
|
609
617
|
async with context.con.cursor() as cur:
|
|
@@ -634,100 +642,43 @@ async def _get_all_ynab(
|
|
|
634
642
|
async def _get_plan_data(
|
|
635
643
|
context: _Context, plan_id: str, lkos: dict[str, int], task_id: TaskID
|
|
636
644
|
) -> tuple[str, _YnabPlanData]:
|
|
637
|
-
(
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
_get_accounts(context, plan_id, lkos, task_id),
|
|
645
|
-
_get_categories(context, plan_id, lkos, task_id),
|
|
646
|
-
_get_payees(context, plan_id, lkos, task_id),
|
|
647
|
-
_get_transactions(context, plan_id, lkos, task_id),
|
|
648
|
-
_get_scheduled_transactions(context, plan_id, lkos, task_id),
|
|
645
|
+
py = _ProgressYnab(context, plan_id, lkos, task_id)
|
|
646
|
+
accounts, categories, payees, transactions, scheduled = await asyncio.gather(
|
|
647
|
+
py.get(AccountsApi(context.api_client).get_accounts),
|
|
648
|
+
py.get(CategoriesApi(context.api_client).get_categories),
|
|
649
|
+
py.get(PayeesApi(context.api_client).get_payees),
|
|
650
|
+
py.get(TransactionsApi(context.api_client).get_transactions),
|
|
651
|
+
py.get(ScheduledTransactionsApi(context.api_client).get_scheduled_transactions),
|
|
649
652
|
)
|
|
650
|
-
transactions, server_knowledge = transactions_serverknowledge
|
|
651
653
|
return (
|
|
652
654
|
plan_id,
|
|
653
655
|
_YnabPlanData(
|
|
654
|
-
accounts=accounts,
|
|
655
|
-
category_groups=categories,
|
|
656
|
-
payees=payees,
|
|
657
|
-
transactions=transactions,
|
|
658
|
-
server_knowledge=server_knowledge,
|
|
659
|
-
scheduled_transactions=scheduled_transactions,
|
|
656
|
+
accounts=accounts.data.accounts,
|
|
657
|
+
category_groups=categories.data.category_groups,
|
|
658
|
+
payees=payees.data.payees,
|
|
659
|
+
transactions=transactions.data.transactions,
|
|
660
|
+
server_knowledge=transactions.data.server_knowledge,
|
|
661
|
+
scheduled_transactions=scheduled.data.scheduled_transactions,
|
|
660
662
|
),
|
|
661
663
|
)
|
|
662
664
|
|
|
663
665
|
|
|
664
|
-
@
|
|
665
|
-
|
|
666
|
-
context: _Context
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
)
|
|
671
|
-
context.progress.update(task_id, advance=1)
|
|
672
|
-
return resp.data.accounts
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
@retry(stop=stop_after_attempt(3))
|
|
676
|
-
async def _get_categories(
|
|
677
|
-
context: _Context, plan_id: str, lkos: dict[str, int], task_id: TaskID
|
|
678
|
-
) -> list[CategoryGroupWithCategories]:
|
|
679
|
-
resp = await CategoriesApi(context.api_client).get_categories(
|
|
680
|
-
plan_id=plan_id, last_knowledge_of_server=lkos.get(plan_id)
|
|
681
|
-
)
|
|
682
|
-
context.progress.update(task_id, advance=1)
|
|
683
|
-
return resp.data.category_groups
|
|
684
|
-
|
|
666
|
+
@dataclass(slots=True)
|
|
667
|
+
class _ProgressYnab:
|
|
668
|
+
context: _Context
|
|
669
|
+
plan_id: str
|
|
670
|
+
lkos: dict[str, int]
|
|
671
|
+
task_id: TaskID
|
|
685
672
|
|
|
686
|
-
@retry(stop=stop_after_attempt(3))
|
|
687
|
-
async def
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
@retry(stop=stop_after_attempt(3))
|
|
698
|
-
async def _get_transactions(
|
|
699
|
-
context: _Context, plan_id: str, lkos: dict[str, int], task_id: TaskID
|
|
700
|
-
) -> tuple[list[TransactionDetail], int]:
|
|
701
|
-
resp = await TransactionsApi(context.api_client).get_transactions(
|
|
702
|
-
plan_id=plan_id, last_knowledge_of_server=lkos.get(plan_id)
|
|
703
|
-
)
|
|
704
|
-
context.progress.update(task_id, advance=1)
|
|
705
|
-
return resp.data.transactions, resp.data.server_knowledge
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
@retry(stop=stop_after_attempt(3))
|
|
709
|
-
async def _get_scheduled_transactions(
|
|
710
|
-
context: _Context, plan_id: str, lkos: dict[str, int], task_id: TaskID
|
|
711
|
-
) -> list[ScheduledTransactionDetail]:
|
|
712
|
-
resp = await ScheduledTransactionsApi(
|
|
713
|
-
context.api_client
|
|
714
|
-
).get_scheduled_transactions(
|
|
715
|
-
plan_id=plan_id, last_knowledge_of_server=lkos.get(plan_id)
|
|
716
|
-
)
|
|
717
|
-
context.progress.update(task_id, advance=1)
|
|
718
|
-
return resp.data.scheduled_transactions
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
# @retry(stop=stop_after_attempt(3))
|
|
722
|
-
# async def _get_ynab[T](
|
|
723
|
-
# context: _Context,
|
|
724
|
-
# getter: Callable[..., Awaitable[T]],
|
|
725
|
-
# task_id: TaskID,
|
|
726
|
-
# ) -> T:
|
|
727
|
-
# try:
|
|
728
|
-
# return await getter()
|
|
729
|
-
# finally:
|
|
730
|
-
# context.progress.update(task_id, advance=1)
|
|
673
|
+
@retry(stop=stop_after_attempt(3))
|
|
674
|
+
async def get[T](self, endpoint: Callable[..., Awaitable[T]]) -> T:
|
|
675
|
+
try:
|
|
676
|
+
return await endpoint(
|
|
677
|
+
plan_id=self.plan_id,
|
|
678
|
+
last_knowledge_of_server=self.lkos.get(self.plan_id),
|
|
679
|
+
)
|
|
680
|
+
finally:
|
|
681
|
+
self.context.progress.update(self.task_id, advance=1)
|
|
731
682
|
|
|
732
683
|
|
|
733
684
|
def main(
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlite_export_for_ynab
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.1
|
|
4
4
|
Summary: SQLite Export for YNAB - Export YNAB Data to SQLite
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
License: MIT
|
|
5
|
+
Author-email: Max R <mxr@users.noreply.github.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mxr/sqlite-export-for-ynab
|
|
9
8
|
Keywords: ynab,sqlite,sql,budget,plan,cli
|
|
10
9
|
Classifier: Programming Language :: Python :: 3
|
|
11
10
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -21,11 +20,6 @@ Requires-Dist: asyncio-for-ynab~=1.84.0
|
|
|
21
20
|
Requires-Dist: fasteners
|
|
22
21
|
Requires-Dist: rich>=10
|
|
23
22
|
Requires-Dist: tenacity
|
|
24
|
-
Provides-Extra: dev
|
|
25
|
-
Requires-Dist: covdefaults>=2.1.0; extra == "dev"
|
|
26
|
-
Requires-Dist: coverage; extra == "dev"
|
|
27
|
-
Requires-Dist: pytest; extra == "dev"
|
|
28
|
-
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
29
23
|
Dynamic: license-file
|
|
30
24
|
|
|
31
25
|
# sqlite-export-for-ynab
|
|
@@ -272,7 +266,7 @@ WITH interest_by_account AS (
|
|
|
272
266
|
SELECT
|
|
273
267
|
plan_id
|
|
274
268
|
, account_name
|
|
275
|
-
, SUM(
|
|
269
|
+
, SUM(amount_currency) AS total
|
|
276
270
|
FROM flat_transactions
|
|
277
271
|
WHERE
|
|
278
272
|
TRUE
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import tomllib
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Any
|
|
6
|
-
from typing import cast
|
|
7
5
|
from unittest.mock import AsyncMock
|
|
8
6
|
from unittest.mock import Mock
|
|
9
7
|
from unittest.mock import patch
|
|
@@ -29,6 +27,7 @@ from sqlite_export_for_ynab._main import get_last_knowledge_of_server
|
|
|
29
27
|
from sqlite_export_for_ynab._main import get_relations
|
|
30
28
|
from sqlite_export_for_ynab._main import insert_accounts
|
|
31
29
|
from sqlite_export_for_ynab._main import insert_category_groups
|
|
30
|
+
from sqlite_export_for_ynab._main import insert_entries
|
|
32
31
|
from sqlite_export_for_ynab._main import insert_payees
|
|
33
32
|
from sqlite_export_for_ynab._main import insert_plans
|
|
34
33
|
from sqlite_export_for_ynab._main import insert_scheduled_transactions
|
|
@@ -453,7 +452,7 @@ async def test_insert_category_group_without_categories(context):
|
|
|
453
452
|
await insert_category_groups(
|
|
454
453
|
context,
|
|
455
454
|
PLAN_ID_1,
|
|
456
|
-
|
|
455
|
+
[CATEGORY_GROUPS[0].model_copy(update={"categories": []})],
|
|
457
456
|
)
|
|
458
457
|
|
|
459
458
|
assert_rows(
|
|
@@ -499,6 +498,31 @@ async def test_insert_payees(context):
|
|
|
499
498
|
)
|
|
500
499
|
|
|
501
500
|
|
|
501
|
+
@pytest.mark.asyncio
|
|
502
|
+
async def test_insert_entries_ignores_unknown_keys(context):
|
|
503
|
+
task_id = context.progress.add_task("Payees", total=1)
|
|
504
|
+
entry = {
|
|
505
|
+
"id": PAYEE_ID_1,
|
|
506
|
+
"name": "Payee",
|
|
507
|
+
"transfer_account_id": None,
|
|
508
|
+
"deleted": False,
|
|
509
|
+
"brand_new_api_field": "surprise",
|
|
510
|
+
}
|
|
511
|
+
await insert_entries(context, "payees", PLAN_ID_1, [entry], task_id)
|
|
512
|
+
assert_rows(
|
|
513
|
+
await fetchall(context.con, "SELECT * FROM payees"),
|
|
514
|
+
[
|
|
515
|
+
{
|
|
516
|
+
"id": PAYEE_ID_1,
|
|
517
|
+
"plan_id": PLAN_ID_1,
|
|
518
|
+
"name": "Payee",
|
|
519
|
+
"transfer_account_id": None,
|
|
520
|
+
"deleted": False,
|
|
521
|
+
}
|
|
522
|
+
],
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
|
|
502
526
|
@pytest.mark.asyncio
|
|
503
527
|
async def test_insert_transactions(context):
|
|
504
528
|
await insert_transactions(context, PLAN_ID_1, [])
|
|
@@ -834,7 +858,7 @@ async def test_insert_scheduled_transactions(context):
|
|
|
834
858
|
)
|
|
835
859
|
@pytest.mark.asyncio
|
|
836
860
|
async def test_get_plan_summaries_retries():
|
|
837
|
-
assert await _get_plan_summaries(
|
|
861
|
+
assert await _get_plan_summaries(Mock(spec=asyncio_for_ynab.ApiClient)) == PLANS
|
|
838
862
|
|
|
839
863
|
|
|
840
864
|
@patch("sqlite_export_for_ynab._main.sync")
|
|
@@ -851,9 +875,9 @@ async def test_async_main_parses_full_refresh_and_quiet(sync, tmp_path, monkeypa
|
|
|
851
875
|
|
|
852
876
|
|
|
853
877
|
def test_main_version(capsys):
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
expected_version =
|
|
878
|
+
with open(Path(__file__).parent.parent / "pyproject.toml", "rb") as f:
|
|
879
|
+
data = tomllib.load(f)
|
|
880
|
+
expected_version = data["project"]["version"]
|
|
857
881
|
|
|
858
882
|
with pytest.raises(SystemExit) as excinfo:
|
|
859
883
|
main(("--version",))
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
[tool.mypy]
|
|
2
|
-
check_untyped_defs = true
|
|
3
|
-
disallow_any_generics = true
|
|
4
|
-
disallow_incomplete_defs = true
|
|
5
|
-
disallow_untyped_defs = true
|
|
6
|
-
warn_redundant_casts = true
|
|
7
|
-
warn_unused_ignores = true
|
|
8
|
-
|
|
9
|
-
[[tool.mypy.overrides]]
|
|
10
|
-
disallow_untyped_defs = false
|
|
11
|
-
module = "testing.*"
|
|
12
|
-
|
|
13
|
-
[[tool.mypy.overrides]]
|
|
14
|
-
disallow_untyped_defs = false
|
|
15
|
-
module = "tests.*"
|
|
16
|
-
|
|
17
|
-
[tool.pytest.ini_options]
|
|
18
|
-
asyncio_default_fixture_loop_scope = "function"
|
|
19
|
-
|
|
20
|
-
[tool.ruff]
|
|
21
|
-
target-version = "py312"
|
|
22
|
-
|
|
23
|
-
[tool.ruff.lint]
|
|
24
|
-
extend-select = [
|
|
25
|
-
"UP", # see pyupgrade
|
|
26
|
-
"B", # see flake8-bugbear
|
|
27
|
-
"A", # see flake8-builtins
|
|
28
|
-
"C4", # see flake8-comprehension
|
|
29
|
-
"SIM", # see flake8-simplify
|
|
30
|
-
"TC", # see flake8-type-checking
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
[tool.sqlfluff.layout.type.comma]
|
|
34
|
-
line_position = "leading"
|
|
35
|
-
spacing_before = "touch"
|
|
36
|
-
|
|
37
|
-
[tool.sqlfluff.layout.type.from_clause]
|
|
38
|
-
keyword_line_position = "leading"
|
|
39
|
-
|
|
40
|
-
[tool.sqlfluff.layout.type.when_clause]
|
|
41
|
-
keyword_line_position = "leading"
|
|
42
|
-
|
|
43
|
-
[tool.sqlfluff.rules.capitalisation.functions]
|
|
44
|
-
extended_capitalisation_policy = 'upper'
|
|
45
|
-
|
|
46
|
-
[tool.sqlfluff.rules.capitalisation.identifiers]
|
|
47
|
-
extended_capitalisation_policy = 'lower'
|
|
48
|
-
|
|
49
|
-
[tool.sqlfluff.rules.capitalisation.keywords]
|
|
50
|
-
capitalisation_policy = 'upper'
|
|
51
|
-
|
|
52
|
-
[tool.sqlfluff.rules.capitalisation.literals]
|
|
53
|
-
capitalisation_policy = 'upper'
|
|
54
|
-
|
|
55
|
-
[tool.sqlfluff.rules.convention.not_equal]
|
|
56
|
-
preferred_not_equal_style = "c_style"
|
|
57
|
-
|
|
58
|
-
[tool.sqlfluff.rules.convention.terminator]
|
|
59
|
-
multiline_newline = true
|
|
60
|
-
require_final_semicolon = true
|
|
61
|
-
|
|
62
|
-
[tool.sqlfluff.rules.references.quoting]
|
|
63
|
-
prefer_quoted_keywords = true
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
[metadata]
|
|
2
|
-
name = sqlite_export_for_ynab
|
|
3
|
-
version = 2.8.0
|
|
4
|
-
description = SQLite Export for YNAB - Export YNAB Data to SQLite
|
|
5
|
-
long_description = file: README.md
|
|
6
|
-
long_description_content_type = text/markdown
|
|
7
|
-
url = https://github.com/mxr/sqlite-export-for-ynab
|
|
8
|
-
author = Max R
|
|
9
|
-
author_email = maxr@outlook.com
|
|
10
|
-
license = MIT
|
|
11
|
-
license_files = LICENSE
|
|
12
|
-
classifiers =
|
|
13
|
-
Programming Language :: Python :: 3
|
|
14
|
-
Programming Language :: Python :: 3 :: Only
|
|
15
|
-
Programming Language :: Python :: Implementation :: CPython
|
|
16
|
-
Programming Language :: Python :: Implementation :: PyPy
|
|
17
|
-
keywords = ynab, sqlite, sql, budget, plan, cli
|
|
18
|
-
|
|
19
|
-
[options]
|
|
20
|
-
packages = find:
|
|
21
|
-
install_requires =
|
|
22
|
-
aiohttp>=3
|
|
23
|
-
aiopathlib
|
|
24
|
-
aiosqlite
|
|
25
|
-
asyncio-for-ynab~=1.84.0
|
|
26
|
-
fasteners
|
|
27
|
-
rich>=10
|
|
28
|
-
tenacity
|
|
29
|
-
python_requires = >=3.12
|
|
30
|
-
|
|
31
|
-
[options.entry_points]
|
|
32
|
-
console_scripts =
|
|
33
|
-
sqlite-export-for-ynab = sqlite_export_for_ynab._main:main
|
|
34
|
-
|
|
35
|
-
[options.extras_require]
|
|
36
|
-
dev =
|
|
37
|
-
covdefaults>=2.1.0
|
|
38
|
-
coverage
|
|
39
|
-
pytest
|
|
40
|
-
pytest-asyncio
|
|
41
|
-
|
|
42
|
-
[options.package_data]
|
|
43
|
-
* = *.sql
|
|
44
|
-
sqlite_export_for_ynab =
|
|
45
|
-
py.typed
|
|
46
|
-
|
|
47
|
-
[bdist_wheel]
|
|
48
|
-
universal = True
|
|
49
|
-
|
|
50
|
-
[coverage:run]
|
|
51
|
-
plugins = covdefaults
|
|
52
|
-
|
|
53
|
-
[tox:tox]
|
|
54
|
-
envlist = py,pypy3,pre-commit
|
|
55
|
-
|
|
56
|
-
[testenv]
|
|
57
|
-
extras = dev
|
|
58
|
-
commands =
|
|
59
|
-
coverage erase
|
|
60
|
-
coverage run -m pytest {posargs:tests}
|
|
61
|
-
coverage report
|
|
62
|
-
|
|
63
|
-
[testenv:pre-commit]
|
|
64
|
-
skip_install = true
|
|
65
|
-
deps = pre-commit-uv
|
|
66
|
-
commands = pre-commit run --all-files --show-diff-on-failure
|
|
67
|
-
|
|
68
|
-
[egg_info]
|
|
69
|
-
tag_build =
|
|
70
|
-
tag_date = 0
|
|
71
|
-
|
|
File without changes
|
{sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/__init__.py
RENAMED
|
File without changes
|
{sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/__main__.py
RENAMED
|
File without changes
|
{sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/ddl/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sqlite_export_for_ynab-2.8.0 → sqlite_export_for_ynab-2.9.1}/sqlite_export_for_ynab/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|