ynab-api-cli 0.1.0__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.
- ynab_api_cli-0.1.0/.github/workflows/ci.yml +48 -0
- ynab_api_cli-0.1.0/.github/workflows/release.yml +172 -0
- ynab_api_cli-0.1.0/.release-please-manifest.json +3 -0
- ynab_api_cli-0.1.0/CHANGELOG.md +8 -0
- ynab_api_cli-0.1.0/PKG-INFO +90 -0
- ynab_api_cli-0.1.0/README.md +75 -0
- ynab_api_cli-0.1.0/docs/live-testing.md +27 -0
- ynab_api_cli-0.1.0/docs/maintenance.md +19 -0
- ynab_api_cli-0.1.0/docs/privacy-review.md +14 -0
- ynab_api_cli-0.1.0/docs/publishing.md +39 -0
- ynab_api_cli-0.1.0/docs/python-development-review.md +76 -0
- ynab_api_cli-0.1.0/docs/verification.md +34 -0
- ynab_api_cli-0.1.0/pyproject.toml +245 -0
- ynab_api_cli-0.1.0/pyproject.toml.orig +180 -0
- ynab_api_cli-0.1.0/release-please-config.json +21 -0
- ynab_api_cli-0.1.0/skills/ynab-api-cli/SKILL.md +21 -0
- ynab_api_cli-0.1.0/skills/ynab-api-cli/references/operations.md +36 -0
- ynab_api_cli-0.1.0/skills/ynab-api-cli/references/setup.md +32 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/__main__.py +266 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/cli.py +171 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/compat.py +120 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/config.py +110 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/contract.py +197 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/contract_testing.py +141 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/development.py +269 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/distribution.py +123 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/exceptions.py +7 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/accounts/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/accounts/create_account.py +54 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/accounts/get_account_by_id.py +53 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/accounts/get_accounts.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/create_category.py +54 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/create_category_group.py +58 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/get_categories.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/get_category_by_id.py +52 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/get_month_category_by_id.py +58 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/update_category.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/update_category_group.py +63 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/categories/update_month_category.py +65 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/money_movements/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/money_movements/get_money_movement_groups.py +51 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/money_movements/get_money_movement_groups_by_month.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/money_movements/get_money_movements.py +51 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/money_movements/get_money_movements_by_month.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/months/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/months/get_plan_month.py +55 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/months/get_plan_months.py +59 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payee_locations/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payee_locations/get_payee_location_by_id.py +54 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payee_locations/get_payee_locations.py +51 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payee_locations/get_payee_locations_by_payee.py +54 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payees/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payees/create_payee.py +54 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payees/get_payee_by_id.py +52 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payees/get_payees.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/payees/update_payee.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/plans/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/plans/get_plan_by_id.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/plans/get_plan_settings_by_id.py +49 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/plans/get_plans.py +51 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/scheduled_transactions/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/scheduled_transactions/create_scheduled_transaction.py +58 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/scheduled_transactions/delete_scheduled_transaction.py +56 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/scheduled_transactions/get_scheduled_transaction_by_id.py +56 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/scheduled_transactions/get_scheduled_transactions.py +59 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/scheduled_transactions/update_scheduled_transaction.py +63 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/create_transaction.py +58 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/delete_transaction.py +54 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/get_transaction_by_id.py +54 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/get_transactions.py +80 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/get_transactions_by_account.py +87 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/get_transactions_by_category.py +89 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/get_transactions_by_month.py +87 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/get_transactions_by_payee.py +89 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/import_transactions.py +54 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/update_transaction.py +59 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/transactions/update_transactions.py +58 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/user/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/api/user/get_user.py +42 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/bindings.py +141 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/__init__.py +416 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/account.py +71 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/account_base.py +57 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/account_response.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/account_response_data.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/account_type.py +23 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/accounts_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/accounts_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/bulk_response.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/bulk_response_data.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/bulk_response_data_bulk.py +15 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/bulk_transactions.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/categories_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/categories_response_data.py +22 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/category.py +104 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/category_base.py +74 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/category_group.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/category_group_with_categories.py +25 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/category_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/category_response_data.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/currency_format_type_0.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/date_format_type_0.py +14 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/debt_1.py +18 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/debt_2.py +18 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/debt_3.py +18 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/error_detail.py +16 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/error_response.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/existing_category.py +34 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/existing_transaction.py +43 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/flag_1.py +17 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/flag_2.py +17 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/flag_3.py +17 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/get_transactions_by_account_type.py +12 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/get_transactions_by_category_type.py +12 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/get_transactions_by_month_type.py +12 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/get_transactions_by_payee_type.py +12 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/get_transactions_type.py +12 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/goal_1.py +15 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/goal_2.py +15 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/goal_3.py +15 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/hybrid_transaction.py +70 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/hybrid_transaction_type.py +12 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/hybrid_transactions_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/hybrid_transactions_response_data.py +22 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/loan_account_periodic_value_type_0.py +33 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/money_movement.py +35 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/money_movement_base.py +33 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/money_movement_group.py +25 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/money_movement_groups_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/money_movement_groups_response_data.py +22 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/money_movements_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/money_movements_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/month_detail.py +42 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/month_detail_base.py +30 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/month_detail_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/month_detail_response_data.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/month_summaries_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/month_summaries_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/month_summary.py +37 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/month_summary_base.py +25 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/new_category.py +34 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/new_transaction.py +44 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/patch_category_group_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/patch_category_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/patch_month_category_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/patch_payee_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/patch_transactions_wrapper.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payee.py +23 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payee_location.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payee_location_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payee_location_response_data.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payee_locations_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payee_locations_response_data.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payee_response.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payee_response_data.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payees_response.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/payees_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_detail.py +74 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_detail_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_detail_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_settings.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_settings_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_settings_response_data.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_summary.py +38 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_summary_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/plan_summary_response_data.py +24 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/post_account_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/post_category_group_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/post_category_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/post_payee.py +14 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/post_payee_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/post_scheduled_transaction_wrapper.py +23 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/post_transactions_wrapper.py +24 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/put_scheduled_transaction_wrapper.py +23 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/put_transaction_wrapper.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_account.py +18 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_account_type.py +16 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_category.py +34 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_category_goal_frequency.py +13 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_category_group.py +14 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_category_group_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_category_group_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_category_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_category_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_month_category.py +14 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_payee.py +16 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_payee_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_payee_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_scheduled_transaction.py +37 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_sub_transaction.py +22 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_transaction_with_id_or_import_id.py +45 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_transaction_with_optional_fields.py +43 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_transactions_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/save_transactions_response_data.py +29 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_sub_transaction.py +31 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_sub_transaction_base.py +29 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transaction_detail.py +53 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transaction_frequency.py +23 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transaction_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transaction_response_data.py +23 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transaction_summary.py +43 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transaction_summary_base.py +41 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transaction_summary_base_frequency.py +23 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transactions_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/scheduled_transactions_response_data.py +24 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/sub_transaction.py +34 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/sub_transaction_base.py +32 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transaction_cleared_status.py +13 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transaction_detail.py +70 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transaction_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transaction_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transaction_summary.py +62 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transaction_summary_base.py +60 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transactions_import_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transactions_import_response_data.py +14 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transactions_response.py +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/transactions_response_data.py +20 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/user.py +16 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/user_response.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/generated/models/user_response_data.py +19 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/live.py +449 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/py.typed +0 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/resources/__init__.py +3 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/resources/catalog.json +178 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/resources/openapi.yaml +4035 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/resources/provenance.json +9 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/resources/schema_features.json +913 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/resources/skill/SKILL.md +21 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/resources/skill/references/operations.md +36 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/resources/skill/references/setup.md +32 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/security.py +83 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/transport.py +133 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/types.py +110 -0
- ynab_api_cli-0.1.0/src/ynab_api_cli/verification.py +167 -0
- ynab_api_cli-0.1.0/templates/endpoint_module.py.jinja +53 -0
- ynab_api_cli-0.1.0/templates/model.py.jinja +40 -0
- ynab_api_cli-0.1.0/tests/conftest.py +25 -0
- ynab_api_cli-0.1.0/tests/fixtures/wire_cases.json +46 -0
- ynab_api_cli-0.1.0/tests/support.py +57 -0
- ynab_api_cli-0.1.0/tests/test_cli.py +274 -0
- ynab_api_cli-0.1.0/tests/test_compat.py +87 -0
- ynab_api_cli-0.1.0/tests/test_config.py +153 -0
- ynab_api_cli-0.1.0/tests/test_contract.py +176 -0
- ynab_api_cli-0.1.0/tests/test_development.py +175 -0
- ynab_api_cli-0.1.0/tests/test_distribution.py +74 -0
- ynab_api_cli-0.1.0/tests/test_features.py +131 -0
- ynab_api_cli-0.1.0/tests/test_live.py +327 -0
- ynab_api_cli-0.1.0/tests/test_transport.py +204 -0
- ynab_api_cli-0.1.0/tests/test_typing.py +58 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Contract and quality
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
workflow_call:
|
|
8
|
+
inputs:
|
|
9
|
+
ref:
|
|
10
|
+
description: Exact revision to validate for a release
|
|
11
|
+
type: string
|
|
12
|
+
required: true
|
|
13
|
+
schedule:
|
|
14
|
+
- cron: '17 9 * * *'
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
jobs:
|
|
18
|
+
quality:
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
os: [ubuntu-latest, windows-latest]
|
|
23
|
+
runs-on: ${{ matrix.os }}
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
ref: ${{ inputs.ref || github.sha }}
|
|
29
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
30
|
+
with:
|
|
31
|
+
enable-cache: true
|
|
32
|
+
- run: uv sync --locked
|
|
33
|
+
- run: uv run poe check
|
|
34
|
+
- run: uv run poe codegen-check
|
|
35
|
+
- run: uv run poe contract-check
|
|
36
|
+
- run: uv run poe skill-check
|
|
37
|
+
- run: uv build
|
|
38
|
+
- run: uv run poe distribution-check
|
|
39
|
+
upstream:
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
43
|
+
with:
|
|
44
|
+
persist-credentials: false
|
|
45
|
+
ref: ${{ inputs.ref || github.sha }}
|
|
46
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
47
|
+
- run: uv sync --locked
|
|
48
|
+
- run: uv run poe compat-check
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
tag:
|
|
9
|
+
description: Existing release tag to validate and publish (for example v0.1.0)
|
|
10
|
+
type: string
|
|
11
|
+
required: true
|
|
12
|
+
testpypi:
|
|
13
|
+
description: Publish to TestPyPI instead of PyPI
|
|
14
|
+
type: boolean
|
|
15
|
+
default: false
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
concurrency:
|
|
21
|
+
group: release
|
|
22
|
+
cancel-in-progress: false
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
release-please:
|
|
26
|
+
if: github.event_name == 'push'
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
permissions:
|
|
29
|
+
actions: write
|
|
30
|
+
contents: write
|
|
31
|
+
pull-requests: write
|
|
32
|
+
issues: write
|
|
33
|
+
outputs:
|
|
34
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
35
|
+
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
36
|
+
steps:
|
|
37
|
+
- id: release
|
|
38
|
+
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
|
|
39
|
+
with:
|
|
40
|
+
token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }}
|
|
41
|
+
config-file: release-please-config.json
|
|
42
|
+
manifest-file: .release-please-manifest.json
|
|
43
|
+
- name: Validate release pull request
|
|
44
|
+
if: steps.release.outputs.prs_created == 'true'
|
|
45
|
+
env:
|
|
46
|
+
GH_TOKEN: ${{ github.token }}
|
|
47
|
+
PR_JSON: ${{ steps.release.outputs.pr }}
|
|
48
|
+
run: |
|
|
49
|
+
branch=$(jq -er '.headBranchName' <<< "$PR_JSON")
|
|
50
|
+
gh workflow run ci.yml --repo "$GITHUB_REPOSITORY" --ref "$branch"
|
|
51
|
+
|
|
52
|
+
target:
|
|
53
|
+
needs: release-please
|
|
54
|
+
if: >-
|
|
55
|
+
always() && github.ref == 'refs/heads/main' &&
|
|
56
|
+
(needs.release-please.outputs.release_created == 'true' || github.event_name == 'workflow_dispatch')
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
outputs:
|
|
59
|
+
tag: ${{ steps.resolve.outputs.tag }}
|
|
60
|
+
sha: ${{ steps.resolve.outputs.sha }}
|
|
61
|
+
steps:
|
|
62
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
63
|
+
with:
|
|
64
|
+
persist-credentials: false
|
|
65
|
+
fetch-depth: 0
|
|
66
|
+
- name: Resolve and validate release tag
|
|
67
|
+
id: resolve
|
|
68
|
+
env:
|
|
69
|
+
TAG: ${{ needs.release-please.outputs.tag_name || inputs.tag }}
|
|
70
|
+
run: |
|
|
71
|
+
[[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo 'Expected a vMAJOR.MINOR.PATCH tag'; exit 1; }
|
|
72
|
+
sha=$(git rev-parse --verify "refs/tags/$TAG^{commit}")
|
|
73
|
+
git merge-base --is-ancestor "$sha" origin/main
|
|
74
|
+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
75
|
+
echo "sha=$sha" >> "$GITHUB_OUTPUT"
|
|
76
|
+
|
|
77
|
+
ci:
|
|
78
|
+
needs: target
|
|
79
|
+
if: always() && needs.target.result == 'success'
|
|
80
|
+
uses: ./.github/workflows/ci.yml
|
|
81
|
+
with:
|
|
82
|
+
ref: ${{ needs.target.outputs.sha }}
|
|
83
|
+
permissions:
|
|
84
|
+
contents: read
|
|
85
|
+
|
|
86
|
+
build:
|
|
87
|
+
needs: [target, ci]
|
|
88
|
+
if: always() && needs.ci.result == 'success' && needs.target.result == 'success'
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
steps:
|
|
91
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
92
|
+
with:
|
|
93
|
+
persist-credentials: false
|
|
94
|
+
ref: ${{ needs.target.outputs.sha }}
|
|
95
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
96
|
+
- run: uv sync --locked
|
|
97
|
+
- name: Version must match tag
|
|
98
|
+
env:
|
|
99
|
+
TAG: ${{ needs.target.outputs.tag }}
|
|
100
|
+
run: >-
|
|
101
|
+
uv run python -c 'import os, tomllib; from pathlib import Path;
|
|
102
|
+
version = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"];
|
|
103
|
+
assert os.environ["TAG"] == "v" + version, "Release tag does not match package version"'
|
|
104
|
+
- run: uv build
|
|
105
|
+
- run: uvx --from twine==6.2.0 twine check --strict dist/*.whl dist/*.tar.gz
|
|
106
|
+
- run: uv run poe distribution-check
|
|
107
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
108
|
+
with:
|
|
109
|
+
name: python-distributions
|
|
110
|
+
path: |
|
|
111
|
+
dist/*.whl
|
|
112
|
+
dist/*.tar.gz
|
|
113
|
+
if-no-files-found: error
|
|
114
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
115
|
+
with:
|
|
116
|
+
name: release-archive
|
|
117
|
+
path: dist/*-release.zip
|
|
118
|
+
if-no-files-found: error
|
|
119
|
+
|
|
120
|
+
publish-pypi:
|
|
121
|
+
needs: [target, build]
|
|
122
|
+
if: always() && needs.build.result == 'success' && !inputs.testpypi
|
|
123
|
+
runs-on: ubuntu-latest
|
|
124
|
+
environment:
|
|
125
|
+
name: pypi
|
|
126
|
+
url: https://pypi.org/project/ynab-api-cli/
|
|
127
|
+
permissions:
|
|
128
|
+
id-token: write
|
|
129
|
+
attestations: write
|
|
130
|
+
contents: write
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
133
|
+
with:
|
|
134
|
+
name: python-distributions
|
|
135
|
+
path: dist/
|
|
136
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
137
|
+
with:
|
|
138
|
+
name: release-archive
|
|
139
|
+
path: release-assets/
|
|
140
|
+
- uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
141
|
+
with:
|
|
142
|
+
subject-path: dist/*
|
|
143
|
+
- name: Publish through trusted publishing
|
|
144
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
145
|
+
- name: Attach distributions to GitHub release
|
|
146
|
+
env:
|
|
147
|
+
GH_TOKEN: ${{ github.token }}
|
|
148
|
+
TAG: ${{ needs.target.outputs.tag }}
|
|
149
|
+
SHA: ${{ needs.target.outputs.sha }}
|
|
150
|
+
run: |
|
|
151
|
+
if ! gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
|
152
|
+
gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --verify-tag --target "$SHA" --title "$TAG" --generate-notes
|
|
153
|
+
fi
|
|
154
|
+
gh release upload "$TAG" dist/* release-assets/* --repo "$GITHUB_REPOSITORY" --clobber
|
|
155
|
+
|
|
156
|
+
publish-testpypi:
|
|
157
|
+
needs: build
|
|
158
|
+
if: always() && needs.build.result == 'success' && inputs.testpypi
|
|
159
|
+
runs-on: ubuntu-latest
|
|
160
|
+
environment:
|
|
161
|
+
name: testpypi
|
|
162
|
+
url: https://test.pypi.org/project/ynab-api-cli/
|
|
163
|
+
permissions:
|
|
164
|
+
id-token: write
|
|
165
|
+
steps:
|
|
166
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
167
|
+
with:
|
|
168
|
+
name: python-distributions
|
|
169
|
+
path: dist/
|
|
170
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
171
|
+
with:
|
|
172
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Provide a standalone YNAB REST API CLI with typed generated endpoints and request validation.
|
|
6
|
+
- Include XDG connection configuration, diagnostics, discovery, mutation previews, and explicit execution guards.
|
|
7
|
+
- Bundle the supplementary `ynab-api-cli` Codex skill and isolated live-test runner.
|
|
8
|
+
- Verify reviewed operations, schema features, deterministic generation, and clean installation.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: ynab-api-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Complete contract-driven REST CLI for YNAB
|
|
5
|
+
Author: Mike Hill
|
|
6
|
+
Requires-Dist: httpx>=0.28.1
|
|
7
|
+
Requires-Dist: jsonschema[format]>=4.26.0
|
|
8
|
+
Requires-Dist: pydantic>=2.14.1
|
|
9
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Project-URL: Homepage, https://github.com/mikejhill/ynab-api-cli
|
|
12
|
+
Project-URL: Repository, https://github.com/mikejhill/ynab-api-cli
|
|
13
|
+
Project-URL: Issues, https://github.com/mikejhill/ynab-api-cli/issues
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# YNAB API CLI
|
|
17
|
+
|
|
18
|
+
Complete, synchronous REST CLI for the reviewed YNAB API contract. The official SDK is not a dependency. Generated, strictly typed endpoint classes and models are included for Python callers.
|
|
19
|
+
|
|
20
|
+
## Install and connect
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
uv tool install ynab-api-cli
|
|
24
|
+
ynab-api-cli configure
|
|
25
|
+
ynab-api-cli doctor
|
|
26
|
+
ynab-api-cli plans get-plans
|
|
27
|
+
ynab-api-cli select-plan PLAN_UUID
|
|
28
|
+
ynab-api-cli doctor
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Generate your personal token in [YNAB Developer Settings](https://app.ynab.com/settings/developer), then enter it through the hidden terminal prompt. Do not put it in command arguments. Configuration is stored under `$XDG_CONFIG_HOME/ynab-api-cli`, falling back to `~/.config/ynab-api-cli` on all platforms. Credentials are plaintext and protected with private POSIX permissions or a current-user Windows ACL.
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
ynab-api-cli discover
|
|
35
|
+
ynab-api-cli discover transactions
|
|
36
|
+
ynab-api-cli inspect createTransaction
|
|
37
|
+
ynab-api-cli transactions get-transactions --since-date 2026-01-01
|
|
38
|
+
ynab-api-cli call getTransactions --request @request.json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Uniform requests use `{"path":{},"query":{},"body":{}}`; omit body for operations without one. `--request -` and `--body -` read stdin. Endpoint flags use kebab-case names. Boolean flags take `true` or `false`.
|
|
42
|
+
|
|
43
|
+
Writes preview by default. Add `--execute` only for an intended mutation and verify its result through reads. Requests use TLS, a 30-second timeout, and no automatic retries or redirects. An uncertain write must be reconciled before retrying. Amounts are integer milliunits, and explicit null differs from omission.
|
|
44
|
+
|
|
45
|
+
`--metadata` adds status, selected headers, and contract version. Exit codes: 0 success, 1 configuration/API/compatibility failure, 2 usage error, and 130 interruption. `doctor --offline` does not validate API access. `configure --replace` explicitly rotates credentials while preserving unrelated fields.
|
|
46
|
+
|
|
47
|
+
## Typed Python interface
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from ynab_api_cli.generated.api.transactions.get_transactions import Endpoint
|
|
51
|
+
from ynab_api_cli.transport import Connection, Transport
|
|
52
|
+
|
|
53
|
+
# Load protected credentials through ConfigStore in real applications.
|
|
54
|
+
response = Endpoint.execute(transport=Transport(Connection(token)), plan_id=plan_id)
|
|
55
|
+
raw_json = response.raw
|
|
56
|
+
typed_result = response.parsed
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Typed endpoint execution directly submits mutations; preview guards belong to the CLI. The transport independently validates requests and responses against the bundled contract. Raw JSON remains available alongside typed parsing.
|
|
60
|
+
|
|
61
|
+
## Development and maintenance
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
uv sync --locked
|
|
65
|
+
uv run poe fix
|
|
66
|
+
uv run poe check
|
|
67
|
+
uv run poe codegen-check
|
|
68
|
+
uv run poe contract-check
|
|
69
|
+
uv run poe compat-check
|
|
70
|
+
uv build
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The contract snapshot, reviewed operation catalog, and provenance are packaged resources. Generator configuration lives in pyproject.toml; templates and deterministic transforms produce all generated code. Do not edit generated files manually.
|
|
74
|
+
|
|
75
|
+
See [maintenance](docs/maintenance.md) for reviewed upgrades, test coverage, and CI. See [live testing](docs/live-testing.md) before enabling writes against a dedicated test plan.
|
|
76
|
+
|
|
77
|
+
## Supplementary Codex skill
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
ynab-api-cli skill show
|
|
81
|
+
ynab-api-cli skill export /path/to/codex/skills/ynab-api-cli
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Export refuses an existing destination. The canonical skill is in skills/ynab-api-cli and is also included as installed package data. The CLI works independently of Codex.
|
|
85
|
+
|
|
86
|
+
For a source checkout, install with `uv tool install .` or run commands with `uv run ynab-api-cli`.
|
|
87
|
+
|
|
88
|
+
## Releases
|
|
89
|
+
|
|
90
|
+
The publishing pipeline follows VerdiClip's release-please and PyPI trusted-publishing pattern. See [publishing](docs/publishing.md) for the initial project setup, release process, and TestPyPI option.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# YNAB API CLI
|
|
2
|
+
|
|
3
|
+
Complete, synchronous REST CLI for the reviewed YNAB API contract. The official SDK is not a dependency. Generated, strictly typed endpoint classes and models are included for Python callers.
|
|
4
|
+
|
|
5
|
+
## Install and connect
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
uv tool install ynab-api-cli
|
|
9
|
+
ynab-api-cli configure
|
|
10
|
+
ynab-api-cli doctor
|
|
11
|
+
ynab-api-cli plans get-plans
|
|
12
|
+
ynab-api-cli select-plan PLAN_UUID
|
|
13
|
+
ynab-api-cli doctor
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Generate your personal token in [YNAB Developer Settings](https://app.ynab.com/settings/developer), then enter it through the hidden terminal prompt. Do not put it in command arguments. Configuration is stored under `$XDG_CONFIG_HOME/ynab-api-cli`, falling back to `~/.config/ynab-api-cli` on all platforms. Credentials are plaintext and protected with private POSIX permissions or a current-user Windows ACL.
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
ynab-api-cli discover
|
|
20
|
+
ynab-api-cli discover transactions
|
|
21
|
+
ynab-api-cli inspect createTransaction
|
|
22
|
+
ynab-api-cli transactions get-transactions --since-date 2026-01-01
|
|
23
|
+
ynab-api-cli call getTransactions --request @request.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Uniform requests use `{"path":{},"query":{},"body":{}}`; omit body for operations without one. `--request -` and `--body -` read stdin. Endpoint flags use kebab-case names. Boolean flags take `true` or `false`.
|
|
27
|
+
|
|
28
|
+
Writes preview by default. Add `--execute` only for an intended mutation and verify its result through reads. Requests use TLS, a 30-second timeout, and no automatic retries or redirects. An uncertain write must be reconciled before retrying. Amounts are integer milliunits, and explicit null differs from omission.
|
|
29
|
+
|
|
30
|
+
`--metadata` adds status, selected headers, and contract version. Exit codes: 0 success, 1 configuration/API/compatibility failure, 2 usage error, and 130 interruption. `doctor --offline` does not validate API access. `configure --replace` explicitly rotates credentials while preserving unrelated fields.
|
|
31
|
+
|
|
32
|
+
## Typed Python interface
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from ynab_api_cli.generated.api.transactions.get_transactions import Endpoint
|
|
36
|
+
from ynab_api_cli.transport import Connection, Transport
|
|
37
|
+
|
|
38
|
+
# Load protected credentials through ConfigStore in real applications.
|
|
39
|
+
response = Endpoint.execute(transport=Transport(Connection(token)), plan_id=plan_id)
|
|
40
|
+
raw_json = response.raw
|
|
41
|
+
typed_result = response.parsed
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Typed endpoint execution directly submits mutations; preview guards belong to the CLI. The transport independently validates requests and responses against the bundled contract. Raw JSON remains available alongside typed parsing.
|
|
45
|
+
|
|
46
|
+
## Development and maintenance
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
uv sync --locked
|
|
50
|
+
uv run poe fix
|
|
51
|
+
uv run poe check
|
|
52
|
+
uv run poe codegen-check
|
|
53
|
+
uv run poe contract-check
|
|
54
|
+
uv run poe compat-check
|
|
55
|
+
uv build
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The contract snapshot, reviewed operation catalog, and provenance are packaged resources. Generator configuration lives in pyproject.toml; templates and deterministic transforms produce all generated code. Do not edit generated files manually.
|
|
59
|
+
|
|
60
|
+
See [maintenance](docs/maintenance.md) for reviewed upgrades, test coverage, and CI. See [live testing](docs/live-testing.md) before enabling writes against a dedicated test plan.
|
|
61
|
+
|
|
62
|
+
## Supplementary Codex skill
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
ynab-api-cli skill show
|
|
66
|
+
ynab-api-cli skill export /path/to/codex/skills/ynab-api-cli
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Export refuses an existing destination. The canonical skill is in skills/ynab-api-cli and is also included as installed package data. The CLI works independently of Codex.
|
|
70
|
+
|
|
71
|
+
For a source checkout, install with `uv tool install .` or run commands with `uv run ynab-api-cli`.
|
|
72
|
+
|
|
73
|
+
## Releases
|
|
74
|
+
|
|
75
|
+
The publishing pipeline follows VerdiClip's release-please and PyPI trusted-publishing pattern. See [publishing](docs/publishing.md) for the initial project setup, release process, and TestPyPI option.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Isolated live testing
|
|
2
|
+
|
|
3
|
+
Live testing is excluded from default pytest and scheduled CI. Every endpoint is tested offline; a live run reports its actual completed operations and capability gaps separately.
|
|
4
|
+
|
|
5
|
+
1. Create a disposable YNAB plan manually. Its name must begin `YNAB API CLI TEST`; the API does not create plans.
|
|
6
|
+
2. Create a separate protected auth.json for the test account. The runner never falls back to ordinary CLI credentials or a default plan.
|
|
7
|
+
3. Run read-only checks first:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
uv run poe live --plan-id EXPLICIT_UUID --auth-file /private/test/auth.json --state-directory /private/test/state
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
4. Enable writes only for that isolated plan:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
uv run poe live --plan-id EXPLICIT_UUID --auth-file /private/test/auth.json --state-directory /private/test/state --enable-writes
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The runner creates or reuses two accounts, a category group, a category, and a payee named with the `ynab-api-cli-test` prefix. These resources persist because the API has no corresponding delete operations. Do not mix unrelated data into them.
|
|
20
|
+
|
|
21
|
+
It exercises transaction creation, bulk creation/update, splits, transfers, duplicate import IDs, scheduled transaction lifecycle, category/group/payee updates, and monthly budgeting. Created transaction records are deleted after verification where supported. Deleted records can remain as tombstones.
|
|
22
|
+
|
|
23
|
+
Before each mutation, the runner writes a private intent journal. An uncertain operation leaves the intent unresolved, and subsequent runs stop. Inspect the recorded target and the actual API state before manually clearing `pending`; never simply rerun a failed write. Readback mismatches also require investigation.
|
|
24
|
+
|
|
25
|
+
Payee-location reads require location fixtures. Direct Import needs a linked bank account; manual test accounts cannot verify actual bank imports. The report lists these gaps and never claims full live coverage when they remain.
|
|
26
|
+
|
|
27
|
+
No live account connection is provisioned by installing this project. Supply credentials and a designated plan explicitly to run these tests.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Contract maintenance
|
|
2
|
+
|
|
3
|
+
The upstream contract is https://api.ynab.com/papi/open_api_spec.yaml. Runtime uses the bundled reviewed snapshot rather than silently adopting remote changes.
|
|
4
|
+
|
|
5
|
+
1. Run `ynab-api-cli compat check` or `uv run poe compat-check`. Structural additions, removals, changed parameters, schemas, and server declarations fail compatibility. Documentation-only changes are reported separately.
|
|
6
|
+
2. Inspect the candidate report, generated code, and typing results. Additions need reviewed catalog entries and independent wire fixtures; optional fields also require feature-matrix updates.
|
|
7
|
+
3. Update the bundled specification and provenance deliberately. Regenerate through `uv run poe generate`; fix templates or documented transforms rather than generated output.
|
|
8
|
+
4. Review the static operation catalog, schema-feature manifest, and independent fixtures. Never regenerate acceptance manifests automatically during CI.
|
|
9
|
+
5. Run every quality gate, build distributions, and smoke-test a clean installation before releasing.
|
|
10
|
+
|
|
11
|
+
The pinned openapi-python-client generator supplies parsed schema and endpoint structure. Custom templates emit Pydantic models and class-based typed methods. Deterministic transforms change relative imports to absolute imports, use StrEnum, resolve forward references, and create static endpoint dispatch. Naming overrides shorten duplicate nullable enum classes without changing wire values.
|
|
12
|
+
|
|
13
|
+
Tests combine independently authored request expectations for every endpoint, runtime JSON Schema probes, a reviewed feature manifest, generated-model round trips, deliberate static typing failures, property tests, and failure-path tests. Synthetic schema responses supplement the independent wire fixtures; they are not evidence of live API behavior.
|
|
14
|
+
|
|
15
|
+
The daily GitHub Actions workflow checks the public contract without account credentials. It becomes active only when this project is hosted in GitHub. Scheduled checks detect drift but never adopt it or run live writes.
|
|
16
|
+
|
|
17
|
+
Semantic overlay: transaction creation must specify exactly one transaction representation, as documented in the createTransaction operation description. Milliunits, transfer linkage, split restrictions, import matching, and delta deletion semantics remain explicitly tested examples and documented API behavior; tests do not invent stricter server rules absent from the contract.
|
|
18
|
+
|
|
19
|
+
The published OpenAPI 3.1 document retains legacy `nullable: true` annotations. Runtime validation maps them to explicit JSON Schema null branches, matching the generator's interpretation; the original snapshot stays unchanged. Nullable witnesses and typed additional-property models are tested.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Initial publication privacy review
|
|
2
|
+
|
|
3
|
+
Reviewed on 2026-10-18 before uploading source to the public repository.
|
|
4
|
+
|
|
5
|
+
- Git contained zero commits, no refs, and no reflog entries. There was no earlier commit history to sanitize. The initial commit uses a GitHub noreply address.
|
|
6
|
+
- Reviewed authored source, generated source, templates, tests, fixtures, contract resources, skill resources, documentation, package metadata, and workflow configuration.
|
|
7
|
+
- Removed an author email from package metadata and a machine-specific checkout path from documentation.
|
|
8
|
+
- A detect-secrets 1.5.0 scan found only published contract SHA-256 fingerprints and ignored cache identifiers. Those were inspected as false positives. Additional credential-pattern, local-path, email, and credential-file searches found no sensitive publishable content.
|
|
9
|
+
- Test tokens and records are synthetic. The specification and its examples come from the published YNAB contract. No personal YNAB records or credentials were used for tests or included in the source.
|
|
10
|
+
- Credentials, environment files, caches, virtual environments, and build artifacts are excluded from Git. Old build artifacts were moved outside the repository before rebuilding under the new package name.
|
|
11
|
+
- Extracted the rebuilt wheel, source distribution, and release archive. Credential-file and local-path searches found no sensitive content; secret detection on extracted source and wheel files found only the same reviewed contract hashes.
|
|
12
|
+
- No credentials are copied from the former configuration directory. Connection setup remains a hidden local prompt.
|
|
13
|
+
|
|
14
|
+
Secret scanners cannot prove the absence of every possible sensitive value. This review combines automated detection, inspection of scanner findings, and source/history checks; future contributions and releases require their own review.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Publishing ynab-api-cli
|
|
2
|
+
|
|
3
|
+
The release workflow follows VerdiClip: Conventional Commits feed release-please, a reviewed version/changelog pull request produces a tag, and the tagged revision passes validation before upload. Wheels, source archives, and the supplementary skill are checked through a clean uv tool installation. The publishing job receives immutable build artifacts and uses short-lived GitHub OIDC credentials, PyPI attestations, and build provenance. No long-lived PyPI token is required.
|
|
4
|
+
|
|
5
|
+
## Initial account setup
|
|
6
|
+
|
|
7
|
+
1. Host this project in a GitHub repository with default branch `main` and enable Actions to create pull requests. Use the repository owner and name consistently below.
|
|
8
|
+
2. Create the GitHub environment `pypi`. Restrict release workflows to `main`; add required reviewers if appropriate for the repository's ownership.
|
|
9
|
+
3. In [PyPI account publishing](https://pypi.org/manage/account/publishing/), add a pending GitHub publisher with project name `ynab-api-cli`, the repository owner/name, workflow filename `release.yml`, and environment `pypi`.
|
|
10
|
+
4. Optionally repeat for TestPyPI using environment `testpypi` and [TestPyPI account publishing](https://test.pypi.org/manage/account/publishing/).
|
|
11
|
+
|
|
12
|
+
A pending publisher does not reserve or create a PyPI project. The first successful upload creates it, as described in the [PyPI documentation](https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/). Account login, 2FA, and any required environment review must be completed by the appropriate account owner.
|
|
13
|
+
|
|
14
|
+
## First release or retry
|
|
15
|
+
|
|
16
|
+
Commit and push the fully validated source to `main`, create and push tag `v0.1.0` at that commit, then dispatch **Release** on `main` with `tag=v0.1.0` and `testpypi=false`. The workflow resolves the existing tag to a commit, verifies it belongs to main's history, tests that exact commit on Windows and Linux, checks its package version, builds distributions, and publishes them. A tag push alone does not publish.
|
|
17
|
+
|
|
18
|
+
Use `testpypi=true` to publish to TestPyPI instead. TestPyPI has separate accounts and trusted-publisher configuration. Production publication deliberately does not skip existing versions; investigate a partial upload rather than silently treating it as a complete release.
|
|
19
|
+
|
|
20
|
+
After publication, verify:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
uv tool install ynab-api-cli==0.1.0
|
|
24
|
+
ynab-api-cli --help
|
|
25
|
+
ynab-api-cli discover
|
|
26
|
+
ynab-api-cli skill show
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The package should appear at [PyPI](https://pypi.org/project/ynab-api-cli/) with wheel, source archive, and publishing attestations. The GitHub release also receives the standalone release archive.
|
|
30
|
+
|
|
31
|
+
## Subsequent releases
|
|
32
|
+
|
|
33
|
+
Use Conventional Commits on main. Release-please updates `pyproject.toml`, the project's package version in `uv.lock`, and `CHANGELOG.md`. Review and merge its pull request to create the release and run the same publication gates. A manual CI dispatch validates release-please pull requests even when GitHub suppresses automatic runs for its own bot token.
|
|
34
|
+
|
|
35
|
+
`RELEASE_PLEASE_TOKEN` is optional; by default the workflow uses `GITHUB_TOKEN`. Repository settings must permit that token to create pull requests. No personal token is provisioned by this project.
|
|
36
|
+
|
|
37
|
+
## Naming and connection configuration
|
|
38
|
+
|
|
39
|
+
The package, executable, and skill are named `ynab-api-cli`; Python imports use `ynab_api_cli`. Configuration is read from `$XDG_CONFIG_HOME/ynab-api-cli/`, or `~/.config/ynab-api-cli/` when XDG_CONFIG_HOME is unset. It does not read the former generic directory. Run `ynab-api-cli configure` locally to create protected credentials at the new location; no credentials are copied automatically.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Python development review and disposable-plan testing
|
|
2
|
+
|
|
3
|
+
Reviewed on 2026-10-18 against the installed `python-development` skill and its code, CLI, project, and testing references.
|
|
4
|
+
|
|
5
|
+
## Verdict
|
|
6
|
+
|
|
7
|
+
The supplementary YNAB skill has valid Codex metadata, uses progressive discovery, and matches its packaged copy. The Python CLI follows the required toolchain and layout, but it does **not fully comply** with the skill's manual design rules. Automated linting and typing do not establish full compliance.
|
|
8
|
+
|
|
9
|
+
| Finding | Evidence | Required correction |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| Construction performs I/O | `contract.py:36` reads contract resources; `live.py:40` reads the fixture journal; `__main__.py:31` constructs the contract | Move loading into explicit factories; inject loaded collaborators |
|
|
12
|
+
| Services expose mutable implementation state | `live.py:45-58`, `contract.py`, and `__main__.py` | Use private attributes and deliberate public interfaces |
|
|
13
|
+
| Generated models execute initialization during import | `generated/models/__init__.py:394` calls `ModelRegistry.rebuild()` | Resolve through generation templates and explicit initialization; never patch generated output manually |
|
|
14
|
+
| Large classes combine responsibilities | `LiveRunner` spans more than 400 lines; `Application` owns multiple command handlers | Separate fixture lifecycle, journal persistence, and command handlers; use subcommand settings types |
|
|
15
|
+
| Tests patch application internals | `test_cli.py:232`, `test_development.py:158`, and `test_live.py:265`; `SyntheticLive` overrides the runner's dispatch path | Inject collaborators and mock the HTTP/process boundary; retain end-to-end orchestration tests |
|
|
16
|
+
| Live orchestration reads the clock directly | `live.py:56`, `live.py:255`, and `live.py:369` | Inject a clock for deterministic orchestration tests |
|
|
17
|
+
|
|
18
|
+
The existing coverage threshold uses coverage.py's combined statement-and-branch metric. It does not independently enforce a minimum branch-only percentage. Generated code is excluded from runtime coverage, but included in strict typing and contract checks.
|
|
19
|
+
|
|
20
|
+
Current validation results:
|
|
21
|
+
|
|
22
|
+
- `uv run --offline --locked poe check`: passed; 147 tests, 96.34% combined coverage, and 319/346 branches covered (92.20%). Formatting, linting, and strict ty passed.
|
|
23
|
+
- `uv run --offline --locked poe codegen-check`: passed; regeneration occurred in a temporary directory and matched checked-in generated source.
|
|
24
|
+
- `uv run --offline --locked poe skill-check`: passed; canonical and packaged skill resources match.
|
|
25
|
+
- Codex `skill-creator/scripts/quick_validate.py skills/ynab-api-cli`: passed.
|
|
26
|
+
- Live-runner help and poe argument forwarding: checked without account access.
|
|
27
|
+
- Upstream compatibility and clean-wheel installation were not rerun in this review; prior delivery results are documented separately in `verification.md`.
|
|
28
|
+
|
|
29
|
+
## Test a real account with a disposable budget
|
|
30
|
+
|
|
31
|
+
YNAB's current API calls budgets **plans**. Create a new, empty plan in the YNAB web application named `YNAB API CLI TEST - disposable`. Do not link bank accounts or copy real transactions into it.
|
|
32
|
+
|
|
33
|
+
Generate your own personal access token under **Account Settings → Developer Settings → New Token**. See [YNAB's official authentication instructions](https://api.ynab.com/#personal-access-tokens). Enter the token only into the CLI's hidden local prompt. A separate configuration directory isolates local settings; it does not restrict the token to the dummy plan. The runner's explicit UUID and name check are application guards, not account permissions.
|
|
34
|
+
|
|
35
|
+
Open a dedicated PowerShell terminal, then run:
|
|
36
|
+
|
|
37
|
+
```powershell
|
|
38
|
+
Set-Location 'path\to\ynab-api-cli'
|
|
39
|
+
uv sync --locked
|
|
40
|
+
$env:XDG_CONFIG_HOME = Join-Path $env:USERPROFILE '.config/ynab-api-cli-test'
|
|
41
|
+
uv run ynab-api-cli configure
|
|
42
|
+
uv run ynab-api-cli doctor
|
|
43
|
+
uv run ynab-api-cli plans get-plans
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Copy the UUID for the disposable plan from the output. Replace the placeholder below with that exact UUID:
|
|
47
|
+
|
|
48
|
+
```powershell
|
|
49
|
+
$testPlan = 'REPLACE-WITH-DISPOSABLE-PLAN-UUID'
|
|
50
|
+
$testAuth = Join-Path $env:XDG_CONFIG_HOME 'ynab-api-cli/auth.json'
|
|
51
|
+
$testState = Join-Path $env:USERPROFILE '.local/state/ynab-api-cli-test'
|
|
52
|
+
uv run ynab-api-cli select-plan $testPlan
|
|
53
|
+
uv run ynab-api-cli doctor
|
|
54
|
+
uv run poe live --plan-id $testPlan --auth-file $testAuth --state-directory $testState
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
That first live run is read-only. It checks the plan identity and available read operations; missing fixture-dependent operations are expected. An offline doctor result cannot establish authentication or API access.
|
|
58
|
+
|
|
59
|
+
When ready to create and update dummy records, run:
|
|
60
|
+
|
|
61
|
+
```powershell
|
|
62
|
+
uv run poe live --plan-id $testPlan --auth-file $testAuth --state-directory $testState --enable-writes
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The live runner submits writes directly when `--enable-writes` is present; this is separate from the ordinary CLI's preview/`--execute` flow. It always requires the explicit plan and auth-file arguments and does not fall back to normal CLI defaults.
|
|
66
|
+
|
|
67
|
+
## Interpret results and clean up
|
|
68
|
+
|
|
69
|
+
- Review `completed_operations`, `missing_operations`, `gaps`, `retained_fixture_ids`, and `complete_live_coverage` in the JSON report. A successful process exit alone does not prove complete live coverage.
|
|
70
|
+
- The runner exercises transaction creation, bulk changes, duplicate import IDs, splits, transfers, scheduled transactions, and category budgeting. It verifies many writes through subsequent reads. The current implementation does not independently read back every mutation, including category-group updates and split/transfer deletions.
|
|
71
|
+
- Manual accounts cannot verify actual Direct Import. Payee-location tests also need suitable fixtures. Do not link a real bank solely to remove a coverage gap.
|
|
72
|
+
- Accounts, category groups, categories, and payees remain for reuse; transaction deletions may leave API tombstones. Delete the entire disposable plan through YNAB after testing if you no longer need it.
|
|
73
|
+
- On failure, inspect the journal at `<state-directory>/<plan-uuid>.json` and read the affected API records. Reconcile any `pending` mutation before changing the journal. Do not clear it and retry blindly.
|
|
74
|
+
- Close the dedicated PowerShell terminal to discard its XDG override. Revoke the test token in Developer Settings when finished, and remove its isolated credential file when no longer needed.
|
|
75
|
+
|
|
76
|
+
No real-account connection or live write was performed during this review. The procedure above is a path for user-run integration testing, not evidence that the live harness has already passed against YNAB.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Delivery verification
|
|
2
|
+
|
|
3
|
+
Verified on Windows with Python 3.12.13 on 2026-10-11.
|
|
4
|
+
|
|
5
|
+
| Check | Result |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| Reviewed API surface | All 44 operations across 10 groups |
|
|
8
|
+
| Reviewed schema witnesses | All 911 manifest entries exercised |
|
|
9
|
+
| Generated client | Pinned openapi-python-client 0.29.0; reproducible generation |
|
|
10
|
+
| Formatting, linting, and typing | Ruff and ty pass; every ty rule is an error |
|
|
11
|
+
| Unit and contract tests | 147 tests pass; combined statement-and-branch coverage exceeds 96% |
|
|
12
|
+
| codegen-check | Pass |
|
|
13
|
+
| contract-check | Pass; independent wire cases, static typing cases, and schema tests |
|
|
14
|
+
| compat-check | Pass against the published API 1.87.0; candidate generation, typing, and tests pass |
|
|
15
|
+
| Skill | Valid frontmatter and matching canonical/package resources |
|
|
16
|
+
| Distributions | Wheel and source archive contain required resources |
|
|
17
|
+
| Clean installation | Temporary uv tool install passes help, discovery, inspection, offline doctor, and skill export |
|
|
18
|
+
|
|
19
|
+
The default tests use synthetic credentials, temporary files, mock HTTP, and simulated live workflows. No real YNAB account was read or changed. Actual live tests require separately supplied protected credentials and an explicit disposable plan named with the `YNAB API CLI TEST` prefix.
|
|
20
|
+
|
|
21
|
+
The GitHub Actions workflow is bundled but becomes active only after the project is hosted in GitHub. No repository publication or account provisioning was performed.
|
|
22
|
+
|
|
23
|
+
## Rename and release-pipeline validation, 2026-10-18
|
|
24
|
+
|
|
25
|
+
Renamed the package, executable, skill, and configuration directory to `ynab-api-cli`, with Python imports under `ynab_api_cli`. Regenerated all endpoint bindings and models through the maintained templates and transforms.
|
|
26
|
+
|
|
27
|
+
- `poe check`: 147 tests passed; 96.34% combined statement-and-branch coverage.
|
|
28
|
+
- `poe codegen-check`, `poe contract-check` (55 tests), and `poe compat-check` (63 candidate tests): passed. Upstream API remains 1.87.0 with no detected contract changes.
|
|
29
|
+
- `poe skill-check` and Codex skill validation: passed.
|
|
30
|
+
- Wheel, source archive, release archive, clean uv tool installation, and strict twine metadata validation: passed.
|
|
31
|
+
- GitHub workflow actionlint and release-please schema validation: passed.
|
|
32
|
+
- Source/history and extracted artifact privacy checks: completed; see [privacy review](privacy-review.md).
|
|
33
|
+
|
|
34
|
+
These automated results do not resolve the manual design findings documented in [the Python development review](python-development-review.md). No live YNAB account was accessed.
|