ynab-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_cli-0.1.0/.env-sample +7 -0
- ynab_cli-0.1.0/.github/FUNDING.yml +1 -0
- ynab_cli-0.1.0/.github/workflows/pr.yml +24 -0
- ynab_cli-0.1.0/.github/workflows/publish-to-pypi.yml +43 -0
- ynab_cli-0.1.0/.gitignore +12 -0
- ynab_cli-0.1.0/.python-version +1 -0
- ynab_cli-0.1.0/CHANGELOG.md +25 -0
- ynab_cli-0.1.0/LICENSE.md +21 -0
- ynab_cli-0.1.0/Makefile +45 -0
- ynab_cli-0.1.0/PKG-INFO +106 -0
- ynab_cli-0.1.0/README.md +82 -0
- ynab_cli-0.1.0/docs/index.md +42 -0
- ynab_cli-0.1.0/docs/transaction_rules.md +42 -0
- ynab_cli-0.1.0/mkdocs.yml +28 -0
- ynab_cli-0.1.0/pyproject.toml +133 -0
- ynab_cli-0.1.0/src/ynab_cli/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/rich/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/rich/io.py +38 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/textual/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/textual/io.py +62 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/__init__.py +8 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/accounts/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/accounts/create_account.py +186 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/accounts/get_account_by_id.py +177 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/accounts/get_accounts.py +184 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/budgets/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/budgets/get_budget_by_id.py +188 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/budgets/get_budget_settings_by_id.py +163 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/budgets/get_budgets.py +171 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/categories/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/categories/get_categories.py +188 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/categories/get_category_by_id.py +180 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/categories/get_month_category_by_id.py +194 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/categories/update_category.py +199 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/categories/update_month_category.py +213 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/months/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/months/get_budget_month.py +177 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/months/get_budget_months.py +184 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/payee_locations/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/payee_locations/get_payee_location_by_id.py +176 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/payee_locations/get_payee_locations.py +163 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/payee_locations/get_payee_locations_by_payee.py +176 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/payees/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/payees/get_payee_by_id.py +176 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/payees/get_payees.py +184 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/payees/update_payee.py +199 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/scheduled_transactions/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/scheduled_transactions/create_scheduled_transaction.py +186 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/scheduled_transactions/delete_scheduled_transaction.py +176 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/scheduled_transactions/get_scheduled_transaction_by_id.py +176 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/scheduled_transactions/get_scheduled_transactions.py +184 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/scheduled_transactions/update_scheduled_transaction.py +199 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/create_transaction.py +202 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/delete_transaction.py +176 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/get_transaction_by_id.py +176 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/get_transactions.py +227 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/get_transactions_by_account.py +236 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/get_transactions_by_category.py +236 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/get_transactions_by_month.py +236 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/get_transactions_by_payee.py +236 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/import_transactions.py +183 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/update_transaction.py +199 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/transactions/update_transactions.py +177 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/user/__init__.py +1 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/api/user/get_user.py +130 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/client.py +268 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/errors.py +16 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/__init__.py +229 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/account.py +345 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/account_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/account_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/account_type.py +23 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/accounts_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/accounts_response_data.py +81 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_detail.py +405 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_detail_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_detail_response_data.py +73 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_settings.py +115 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_settings_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_settings_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_summary.py +216 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_summary_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/budget_summary_response_data.py +91 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/bulk_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/bulk_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/bulk_response_data_bulk.py +68 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/bulk_transactions.py +75 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/categories_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/categories_response_data.py +81 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/category.py +519 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/category_goal_type_type_1.py +15 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/category_goal_type_type_2_type_1.py +15 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/category_goal_type_type_3_type_1.py +15 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/category_group.py +85 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/category_group_with_categories.py +108 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/category_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/category_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/currency_format_type_0.py +117 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/date_format_type_0.py +61 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/error_detail.py +75 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/error_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/existing_transaction.py +322 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/get_transactions_by_account_type.py +12 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/get_transactions_by_category_type.py +12 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/get_transactions_by_month_type.py +12 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/get_transactions_by_payee_type.py +12 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/get_transactions_type.py +12 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/hybrid_transaction.py +567 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/hybrid_transaction_type.py +12 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/hybrid_transactions_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/hybrid_transactions_response_data.py +84 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/loan_account_periodic_value_type_0.py +44 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/month_detail.py +168 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/month_detail_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/month_detail_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/month_summaries_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/month_summaries_response_data.py +81 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/month_summary.py +145 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/new_transaction.py +352 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/patch_category_wrapper.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/patch_month_category_wrapper.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/patch_payee_wrapper.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/patch_transactions_wrapper.py +73 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payee.py +100 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payee_location.py +93 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payee_location_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payee_location_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payee_locations_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payee_locations_response_data.py +73 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payee_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payee_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payees_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/payees_response_data.py +81 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/post_account_wrapper.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/post_scheduled_transaction_wrapper.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/post_transactions_wrapper.py +91 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/put_scheduled_transaction_wrapper.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/put_transaction_wrapper.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_account.py +77 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_category.py +129 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_category_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_category_response_data.py +73 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_month_category.py +59 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_payee.py +59 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_payee_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_payee_response_data.py +73 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_scheduled_transaction.py +269 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_sub_transaction.py +166 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_transaction_with_id_or_import_id.py +366 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_transaction_with_optional_fields.py +322 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_transactions_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/save_transactions_response_data.py +123 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_sub_transaction.py +238 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_transaction_detail.py +381 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_transaction_frequency.py +23 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_transaction_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_transaction_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_transaction_summary.py +310 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_transaction_summary_frequency.py +23 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_transactions_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/scheduled_transactions_response_data.py +81 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/sub_transaction.py +259 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_cleared_status.py +13 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_detail.py +570 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_flag_color_type_1.py +16 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_flag_color_type_2_type_1.py +16 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_flag_color_type_3_type_1.py +16 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_summary.py +499 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_summary_debt_transaction_type_type_1.py +18 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_summary_debt_transaction_type_type_2_type_1.py +18 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transaction_summary_debt_transaction_type_type_3_type_1.py +18 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transactions_import_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transactions_import_response_data.py +59 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transactions_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/transactions_response_data.py +81 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/user.py +60 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/user_response.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/models/user_response_data.py +65 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/types.py +46 -0
- ynab_cli-0.1.0/src/ynab_cli/adapters/ynab/util.py +78 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/constants.py +3 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/models/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/models/rules.py +37 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/ports/__init__.py +5 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/ports/io.py +63 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/settings.py +16 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/use_cases/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/use_cases/budgets.py +33 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/use_cases/categories.py +105 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/use_cases/payees.py +232 -0
- ynab_cli-0.1.0/src/ynab_cli/domain/use_cases/transactions.py +93 -0
- ynab_cli-0.1.0/src/ynab_cli/host/__init__.py +14 -0
- ynab_cli-0.1.0/src/ynab_cli/host/cli.py +38 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/cli.py +43 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/commands/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/commands/budgets.py +54 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/commands/categories.py +96 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/commands/payees.py +161 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/commands/rich/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/commands/rich/progress_table.py +37 -0
- ynab_cli-0.1.0/src/ynab_cli/host/click/commands/transactions.py +80 -0
- ynab_cli-0.1.0/src/ynab_cli/host/constants.py +3 -0
- ynab_cli-0.1.0/src/ynab_cli/host/textual/__init__.py +0 -0
- ynab_cli-0.1.0/src/ynab_cli/host/textual/app.py +98 -0
- ynab_cli-0.1.0/src/ynab_cli/host/textual/app.tcss +47 -0
- ynab_cli-0.1.0/src/ynab_cli/host/textual/cli.py +42 -0
- ynab_cli-0.1.0/src/ynab_cli/host/textual/widgets/__init__.py +58 -0
- ynab_cli-0.1.0/src/ynab_cli/host/textual/widgets/categories.py +90 -0
- ynab_cli-0.1.0/src/ynab_cli/host/textual/widgets/payees.py +154 -0
- ynab_cli-0.1.0/src/ynab_cli/host/textual/widgets/transactions.py +89 -0
- ynab_cli-0.1.0/src/ynab_cli/py.typed +0 -0
- ynab_cli-0.1.0/tests/__init__.py +0 -0
- ynab_cli-0.1.0/tests/factories/__init__.py +0 -0
- ynab_cli-0.1.0/tests/factories/ynab.py +18 -0
- ynab_cli-0.1.0/tests/unit/__init__.py +0 -0
- ynab_cli-0.1.0/tests/unit/conftest.py +17 -0
- ynab_cli-0.1.0/tests/unit/domain/__init__.py +0 -0
- ynab_cli-0.1.0/tests/unit/domain/use_cases/__init__.py +0 -0
- ynab_cli-0.1.0/tests/unit/domain/use_cases/test_categories.py +68 -0
- ynab_cli-0.1.0/tests/unit/domain/use_cases/test_payees.py +72 -0
- ynab_cli-0.1.0/tests/unit/domain/use_cases/test_transactions.py +106 -0
- ynab_cli-0.1.0/uv.lock +1567 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Make a copy of this file called `.env` and update the variables below if you want to use dotenv files
|
|
2
|
+
|
|
3
|
+
# Get this from your developer settings https://api.ynab.com/#personal-access-tokens
|
|
4
|
+
YNAB_CLI_ACCESS_TOKEN=YourAccessToken
|
|
5
|
+
|
|
6
|
+
# Uncomment the below line and update it if you only use ynab-cli with one budget
|
|
7
|
+
# YNAB_CLI_BUDGET_ID=YourBudgetID
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
github: jeffsawatzky
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: pr
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
types: [opened, reopened, synchronize]
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
matrix:
|
|
10
|
+
python-version: ['3.11', '3.12', '3.13']
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- name: Install the latest version of uv
|
|
14
|
+
uses: astral-sh/setup-uv@v6
|
|
15
|
+
with:
|
|
16
|
+
version: latest
|
|
17
|
+
python-version: ${{ matrix.python-version }}
|
|
18
|
+
- run: uv sync --locked # abort if the lockfile changes
|
|
19
|
+
- run: uv run ruff format --check . # check formatting is correct
|
|
20
|
+
- run: uv run ruff check --no-fix . # and linting
|
|
21
|
+
- run: uv run mypy . # typecheck too
|
|
22
|
+
- run: uv run pytest tests # then run your tests!
|
|
23
|
+
- run: uv build # make sure the package builds
|
|
24
|
+
- run: uv run mkdocs build # make sure the docs build
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- v*
|
|
6
|
+
jobs:
|
|
7
|
+
build:
|
|
8
|
+
name: Build distribution
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
with:
|
|
13
|
+
persist-credentials: false
|
|
14
|
+
- name: Install the latest version of uv
|
|
15
|
+
uses: astral-sh/setup-uv@v6
|
|
16
|
+
with:
|
|
17
|
+
version: latest
|
|
18
|
+
- name: Build a binary wheel and a source tarball
|
|
19
|
+
run: uv build
|
|
20
|
+
- name: Store the distribution packages
|
|
21
|
+
uses: actions/upload-artifact@v4
|
|
22
|
+
with:
|
|
23
|
+
name: python-package-distributions
|
|
24
|
+
path: dist/
|
|
25
|
+
publish-to-pypi:
|
|
26
|
+
name: Publish to PyPI
|
|
27
|
+
if: 'startsWith(github.ref, ''refs/tags/'')'
|
|
28
|
+
needs:
|
|
29
|
+
- build
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
environment:
|
|
32
|
+
name: pypi
|
|
33
|
+
url: 'https://pypi.org/p/ynab-cli'
|
|
34
|
+
permissions:
|
|
35
|
+
id-token: write
|
|
36
|
+
steps:
|
|
37
|
+
- name: Download all the dists
|
|
38
|
+
uses: actions/download-artifact@v4
|
|
39
|
+
with:
|
|
40
|
+
name: python-package-distributions
|
|
41
|
+
path: dist/
|
|
42
|
+
- name: Publish to PyPI
|
|
43
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## v0.1.0 (2025-06-06)
|
|
9
|
+
|
|
10
|
+
### BREAKING CHANGE
|
|
11
|
+
|
|
12
|
+
- changes the way the commands need to be run. You now need to specify the "run" command before any of the subcommands
|
|
13
|
+
|
|
14
|
+
### Feat
|
|
15
|
+
|
|
16
|
+
- **budgets**: added a command to list all budgets
|
|
17
|
+
- added a feature to prefix unused payees to make them easier to find and delete in ynab
|
|
18
|
+
- added a list all command to payees
|
|
19
|
+
- add a textual based tui
|
|
20
|
+
- use rich for better user feedback
|
|
21
|
+
- implement initial cli
|
|
22
|
+
|
|
23
|
+
### Refactor
|
|
24
|
+
|
|
25
|
+
- cleaned up some code, sorted lists, and improved the file selector
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Jeff Sawatzky
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ynab_cli-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
.PHONY: lint test clean version
|
|
2
|
+
|
|
3
|
+
.venv: pyproject.toml # the python virtual environment
|
|
4
|
+
uv sync
|
|
5
|
+
touch .venv
|
|
6
|
+
|
|
7
|
+
lint: .venv # run linters and type checkers
|
|
8
|
+
uv run ruff format .
|
|
9
|
+
uv run ruff check .
|
|
10
|
+
uv run mypy .
|
|
11
|
+
|
|
12
|
+
test: .venv lint # run tests with coverage
|
|
13
|
+
uv run pytest --cov=src tests
|
|
14
|
+
|
|
15
|
+
clean: # clean up build artifacts and caches
|
|
16
|
+
rm -f .coverage
|
|
17
|
+
rm -rf dist
|
|
18
|
+
rm -rf htmlcov
|
|
19
|
+
rm -rf site
|
|
20
|
+
find . -type f -name .DS_Store | xargs rm -rf
|
|
21
|
+
find . -type d -name __pycache__ | xargs rm -rf
|
|
22
|
+
find . -type d -name .mypy_cache | xargs rm -rf
|
|
23
|
+
find . -type d -name .pytest_cache | xargs rm -rf
|
|
24
|
+
find . -type d -name .ruff_cache | xargs rm -rf
|
|
25
|
+
find . -type d -empty -delete
|
|
26
|
+
|
|
27
|
+
ynab-sdk: # regenerate the YNAB SDK from the OpenAPI spec
|
|
28
|
+
rm -rf ./src/ynab_cli/adapters/ynab
|
|
29
|
+
mkdir -p ./src/ynab_cli/adapters/ynab
|
|
30
|
+
uvx openapi-python-client generate --meta none --url https://api.ynab.com/papi/open_api_spec.yaml --output-path ./src/ynab_cli/adapters/ynab --overwrite
|
|
31
|
+
|
|
32
|
+
dist: clean # build the distribution package
|
|
33
|
+
uv build
|
|
34
|
+
|
|
35
|
+
site: clean # build the documentation site
|
|
36
|
+
uv run mkdocs build
|
|
37
|
+
|
|
38
|
+
site-serve: clean # serve the documentation site locally
|
|
39
|
+
uv run mkdocs serve
|
|
40
|
+
|
|
41
|
+
site-gh: clean # deploy the documentation site to GitHub Pages
|
|
42
|
+
uv run mkdocs gh-deploy
|
|
43
|
+
|
|
44
|
+
version: clean # update the version in pyproject.toml and create a new tag
|
|
45
|
+
cz bump
|
ynab_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ynab-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: YNAB Command Line Interface
|
|
5
|
+
Project-URL: documentation, https://jeffsawatzky.github.io/ynab-cli/
|
|
6
|
+
Project-URL: source, https://github.com/jeffsawatzky/ynab-cli
|
|
7
|
+
Project-URL: funding, https://github.com/sponsors/jeffsawatzky
|
|
8
|
+
Author: Jeff Sawatzky
|
|
9
|
+
License-File: LICENSE.md
|
|
10
|
+
Keywords: budget,cli,click,textual,ynab
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Requires-Dist: attrs~=25.3
|
|
13
|
+
Requires-Dist: click-default-group~=1.2
|
|
14
|
+
Requires-Dist: click~=8.2
|
|
15
|
+
Requires-Dist: httpx~=0.28
|
|
16
|
+
Requires-Dist: python-dotenv~=1.1
|
|
17
|
+
Requires-Dist: rapidfuzz~=3.13
|
|
18
|
+
Requires-Dist: rich~=14.0
|
|
19
|
+
Requires-Dist: rule-engine~=4.5
|
|
20
|
+
Requires-Dist: textual-fspicker~=0.4
|
|
21
|
+
Requires-Dist: textual~=3.3
|
|
22
|
+
Requires-Dist: typing-extensions~=4.14
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# YNAB CLI
|
|
26
|
+
|
|
27
|
+
A command-line interface for interacting with YNAB (You Need A Budget).
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Full user documentation available [here](http://jeffsawatzky.github.io/ynab-cli)
|
|
32
|
+
|
|
33
|
+
## Project Structure
|
|
34
|
+
|
|
35
|
+
- `src/ynab_cli/`: Main source code
|
|
36
|
+
- `tests/`: Unit and integration tests
|
|
37
|
+
- `docs/`: Documentation (built with MkDocs)
|
|
38
|
+
|
|
39
|
+
## Getting Started
|
|
40
|
+
|
|
41
|
+
### Prerequisites
|
|
42
|
+
- Python 3.11+
|
|
43
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
44
|
+
|
|
45
|
+
### Installation
|
|
46
|
+
|
|
47
|
+
Clone the repository:
|
|
48
|
+
```sh
|
|
49
|
+
$ git clone https://github.com/jeffsawatzky/ynab-cli.git
|
|
50
|
+
$ cd ynab-cli
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Install dependencies with uv:
|
|
54
|
+
```sh
|
|
55
|
+
$ uv sync
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Running the CLI
|
|
59
|
+
|
|
60
|
+
With uv:
|
|
61
|
+
```sh
|
|
62
|
+
$ uv run ynab-cli --help
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
- Source code is in `src/ynab_cli/`.
|
|
68
|
+
- Use feature branches for new work.
|
|
69
|
+
- Follow PEP8 and use type hints where possible.
|
|
70
|
+
|
|
71
|
+
### Linting & Formatting
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
$ make lint
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Running Tests
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
$ make test
|
|
81
|
+
```
|
|
82
|
+
Or directly with pytest:
|
|
83
|
+
```sh
|
|
84
|
+
uv run pytest
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Documentation
|
|
88
|
+
|
|
89
|
+
- Docs are in `docs/` and built with MkDocs.
|
|
90
|
+
- To serve docs locally:
|
|
91
|
+
```sh
|
|
92
|
+
$ uv run mkdocs serve
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Contributing
|
|
96
|
+
|
|
97
|
+
1. Fork the repository
|
|
98
|
+
2. Create a feature branch (`git checkout -b feature/your-feature`)
|
|
99
|
+
3. Commit your changes. Commits should follow conventional commits. The repo is configured with [commitizen](https://commitizen-tools.github.io/commitizen/)
|
|
100
|
+
4. Push to your fork and open a pull request
|
|
101
|
+
|
|
102
|
+
Please include tests for new features and bug fixes.
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
See [LICENSE.md](LICENSE.md)
|
ynab_cli-0.1.0/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# YNAB CLI
|
|
2
|
+
|
|
3
|
+
A command-line interface for interacting with YNAB (You Need A Budget).
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Full user documentation available [here](http://jeffsawatzky.github.io/ynab-cli)
|
|
8
|
+
|
|
9
|
+
## Project Structure
|
|
10
|
+
|
|
11
|
+
- `src/ynab_cli/`: Main source code
|
|
12
|
+
- `tests/`: Unit and integration tests
|
|
13
|
+
- `docs/`: Documentation (built with MkDocs)
|
|
14
|
+
|
|
15
|
+
## Getting Started
|
|
16
|
+
|
|
17
|
+
### Prerequisites
|
|
18
|
+
- Python 3.11+
|
|
19
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
20
|
+
|
|
21
|
+
### Installation
|
|
22
|
+
|
|
23
|
+
Clone the repository:
|
|
24
|
+
```sh
|
|
25
|
+
$ git clone https://github.com/jeffsawatzky/ynab-cli.git
|
|
26
|
+
$ cd ynab-cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Install dependencies with uv:
|
|
30
|
+
```sh
|
|
31
|
+
$ uv sync
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Running the CLI
|
|
35
|
+
|
|
36
|
+
With uv:
|
|
37
|
+
```sh
|
|
38
|
+
$ uv run ynab-cli --help
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Development
|
|
42
|
+
|
|
43
|
+
- Source code is in `src/ynab_cli/`.
|
|
44
|
+
- Use feature branches for new work.
|
|
45
|
+
- Follow PEP8 and use type hints where possible.
|
|
46
|
+
|
|
47
|
+
### Linting & Formatting
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
$ make lint
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Running Tests
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
$ make test
|
|
57
|
+
```
|
|
58
|
+
Or directly with pytest:
|
|
59
|
+
```sh
|
|
60
|
+
uv run pytest
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Documentation
|
|
64
|
+
|
|
65
|
+
- Docs are in `docs/` and built with MkDocs.
|
|
66
|
+
- To serve docs locally:
|
|
67
|
+
```sh
|
|
68
|
+
$ uv run mkdocs serve
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Contributing
|
|
72
|
+
|
|
73
|
+
1. Fork the repository
|
|
74
|
+
2. Create a feature branch (`git checkout -b feature/your-feature`)
|
|
75
|
+
3. Commit your changes. Commits should follow conventional commits. The repo is configured with [commitizen](https://commitizen-tools.github.io/commitizen/)
|
|
76
|
+
4. Push to your fork and open a pull request
|
|
77
|
+
|
|
78
|
+
Please include tests for new features and bug fixes.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
See [LICENSE.md](LICENSE.md)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Welcome to YNAB CLI
|
|
2
|
+
|
|
3
|
+
This is a simple cli/tui application written in python to help manage your YNAB data.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- [uv](https://docs.astral.sh/uv/getting-started/installation/) which allows you to easily run python applications.
|
|
8
|
+
- Your [YNAB developer access token](https://api.ynab.com/#personal-access-tokens).
|
|
9
|
+
|
|
10
|
+
!!! warning
|
|
11
|
+
Developer access tokens are rate limited to 200 requests per hour. Some of the commands below will provide you an opportunity to enter a new developer access token when the current one has exceeded it's limit. It also seems like there is a limit to how many developer access tokens you can create from the developer settings UI.
|
|
12
|
+
|
|
13
|
+
- Your YNAB budget ID. Once you have `uv` and your `access token` you can list your budgets by running:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
$ uvx ynab-cli run --access-token your_access_token budgets list-all
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
!!! note
|
|
22
|
+
YNAB CLI supports environment variables and dotenv (`.env`) files for specifying options. See the `.env-sample` file for some examples. YNAB CLI looks for the `.env` file in current working directory. If you create a `.env` file with the following information you won't need to keep entering it on the command line.
|
|
23
|
+
|
|
24
|
+
``` title=".env"
|
|
25
|
+
YNAB_CLI_ACCESS_TOKEN=your_access_token
|
|
26
|
+
YNAB_CLI_BUDGET_ID=your_budget_id
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
To run the text ui, execute the following command:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
$ uvx ynab-cli
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The individual CLI commands can be similarily run using `uvx`. Full command line usage is below.
|
|
36
|
+
|
|
37
|
+
::: mkdocs-click
|
|
38
|
+
:module: ynab_cli.host.cli
|
|
39
|
+
:command: cli
|
|
40
|
+
:prog_name: ynab-cli
|
|
41
|
+
:style: table
|
|
42
|
+
:list_subcommands: True
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
!!! note
|
|
2
|
+
Amounts are in milliunits and can be either positive or negative depending on if they are inflow or outflow.
|
|
3
|
+
|
|
4
|
+
!!! note
|
|
5
|
+
To get the category IDs you can use the `ynab run categories list-all` command.
|
|
6
|
+
|
|
7
|
+
The rules use the [rule-engine](https://zerosteiner.github.io/rule-engine/getting_started.html) library, so read that documentation to figure out how to write the rules. If ANY of the rules in the `rules` list match a transaction then it will be updated with the `patch` details.
|
|
8
|
+
The rules are supplied an instance of a `TransactionDetail`, and the `patch` needs to be an instance of a `SaveTransactionWithIdOrImportId`. Read the [YNAB API documention](https://api.ynab.com/v1) to see what properties are available to base your rules on and update.
|
|
9
|
+
|
|
10
|
+
This assumes you have a `rules.json` file with your rules to apply. It could look something like this:
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"transaction_rules": [
|
|
14
|
+
{
|
|
15
|
+
"rules": [
|
|
16
|
+
"payee_name == 'My Payee' and amount == -213490"
|
|
17
|
+
],
|
|
18
|
+
"patch": {
|
|
19
|
+
"category_id": "insert the category id you want to assign it to here"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"rules": [
|
|
24
|
+
"payee_name == 'My Split Transaction Payee' and amount == -346500"
|
|
25
|
+
],
|
|
26
|
+
"patch": {
|
|
27
|
+
"category_id": null,
|
|
28
|
+
"subtransactions": [
|
|
29
|
+
{
|
|
30
|
+
"category_id": "insert the first category id you want to assign it to here",
|
|
31
|
+
"amount": -51980
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"category_id": "insert the other category id you want to assign it to here",
|
|
35
|
+
"amount": -294520
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
site_name: YNAB CLI
|
|
2
|
+
site_url: https://jeffsawatzky.github.io/ynab-cli/
|
|
3
|
+
repo_url: https://github.com/jeffsawatzky/ynab-cli
|
|
4
|
+
|
|
5
|
+
theme:
|
|
6
|
+
name: material
|
|
7
|
+
features:
|
|
8
|
+
- content.code.copy
|
|
9
|
+
|
|
10
|
+
plugins:
|
|
11
|
+
- search
|
|
12
|
+
|
|
13
|
+
markdown_extensions:
|
|
14
|
+
- admonition
|
|
15
|
+
- attr_list
|
|
16
|
+
- mkdocs-click
|
|
17
|
+
- pymdownx.details
|
|
18
|
+
- pymdownx.highlight:
|
|
19
|
+
anchor_linenums: true
|
|
20
|
+
line_spans: __span
|
|
21
|
+
pygments_lang_class: true
|
|
22
|
+
- pymdownx.inlinehilite
|
|
23
|
+
- pymdownx.snippets
|
|
24
|
+
- pymdownx.superfences
|
|
25
|
+
|
|
26
|
+
nav:
|
|
27
|
+
- Home: index.md
|
|
28
|
+
- Transaction Rules: transaction_rules.md
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ynab-cli"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "YNAB Command Line Interface"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license-files = [
|
|
8
|
+
"LICENSE.md"
|
|
9
|
+
]
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Jeff Sawatzky" }
|
|
12
|
+
]
|
|
13
|
+
keywords = [
|
|
14
|
+
"ynab",
|
|
15
|
+
"cli",
|
|
16
|
+
"textual",
|
|
17
|
+
"click",
|
|
18
|
+
"budget",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"attrs~=25.3",
|
|
22
|
+
"click-default-group~=1.2",
|
|
23
|
+
"click~=8.2",
|
|
24
|
+
"httpx~=0.28",
|
|
25
|
+
"python-dotenv~=1.1",
|
|
26
|
+
"rapidfuzz~=3.13",
|
|
27
|
+
"rich~=14.0",
|
|
28
|
+
"rule-engine~=4.5",
|
|
29
|
+
"textual-fspicker~=0.4",
|
|
30
|
+
"textual~=3.3",
|
|
31
|
+
"typing-extensions~=4.14",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
documentation = "https://jeffsawatzky.github.io/ynab-cli/"
|
|
36
|
+
source = "https://github.com/jeffsawatzky/ynab-cli"
|
|
37
|
+
funding = "https://github.com/sponsors/jeffsawatzky"
|
|
38
|
+
|
|
39
|
+
[project.scripts]
|
|
40
|
+
ynab-cli = "ynab_cli.host.cli:main"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
[dependency-groups]
|
|
44
|
+
dev = [
|
|
45
|
+
"factory-boy>=3.3.3",
|
|
46
|
+
"mkdocs-click>=0.9.0",
|
|
47
|
+
"mkdocs-material>=9.6.14",
|
|
48
|
+
"mkdocs>=1.6.1",
|
|
49
|
+
"mypy>=1.16.0",
|
|
50
|
+
"pytest-asyncio>=1.0.0",
|
|
51
|
+
"pytest-cov>=6.1.1",
|
|
52
|
+
"pytest-mock>=3.14.1",
|
|
53
|
+
"pytest>=8.4.0",
|
|
54
|
+
"ruff>=0.11.12",
|
|
55
|
+
"textual-dev>=1.7.0",
|
|
56
|
+
"types-python-dateutil>=2.9.0.20250516",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
[tool.mypy]
|
|
61
|
+
python_version = "3.11"
|
|
62
|
+
exclude = [
|
|
63
|
+
'^tests/.*\.py$'
|
|
64
|
+
]
|
|
65
|
+
pretty = true
|
|
66
|
+
show_column_numbers = true
|
|
67
|
+
show_error_codes = true
|
|
68
|
+
show_error_context = true
|
|
69
|
+
strict = true
|
|
70
|
+
warn_unreachable = true
|
|
71
|
+
enable_error_code = [
|
|
72
|
+
"explicit-override",
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[[tool.mypy.overrides]]
|
|
76
|
+
module = [
|
|
77
|
+
"click_default_group.*",
|
|
78
|
+
"factory.*",
|
|
79
|
+
"rule_engine.*",
|
|
80
|
+
]
|
|
81
|
+
ignore_missing_imports = true
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
[tool.ruff]
|
|
85
|
+
fix = true
|
|
86
|
+
line-length = 120
|
|
87
|
+
target-version = "py311"
|
|
88
|
+
|
|
89
|
+
[tool.ruff.lint]
|
|
90
|
+
extend-select = [
|
|
91
|
+
"W", # warnings
|
|
92
|
+
"I", # isort
|
|
93
|
+
"C90", # mccabe
|
|
94
|
+
"N", # pep8-naming
|
|
95
|
+
"UP", # pyupgrade
|
|
96
|
+
"S", # flake8-bandit
|
|
97
|
+
"B", # flake8-bugbear
|
|
98
|
+
"A", # flake8-builtins
|
|
99
|
+
"DTZ", # flake8-datetimez
|
|
100
|
+
"PT", # flake8-pytest-style
|
|
101
|
+
"TID", # flake8-tidy-imports
|
|
102
|
+
"RUF", # ruff specific rules
|
|
103
|
+
]
|
|
104
|
+
extend-ignore = [
|
|
105
|
+
"S110", # `try`-`except`-`pass` detected
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint.per-file-ignores]
|
|
109
|
+
"tests/**/*.py" = ["S"]
|
|
110
|
+
|
|
111
|
+
[tool.ruff.lint.isort]
|
|
112
|
+
known-first-party = ["ynab_cli", "tests"]
|
|
113
|
+
|
|
114
|
+
[tool.ruff.lint.mccabe]
|
|
115
|
+
max-complexity = 70
|
|
116
|
+
|
|
117
|
+
[tool.ruff.lint.flake8-builtins]
|
|
118
|
+
builtins-ignorelist = ["type", "id"]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
[tool.commitizen]
|
|
122
|
+
name = "cz_conventional_commits"
|
|
123
|
+
annotated_tag = true
|
|
124
|
+
tag_format = "v$version"
|
|
125
|
+
version_scheme = "pep440"
|
|
126
|
+
version_provider = "uv"
|
|
127
|
+
update_changelog_on_bump = true
|
|
128
|
+
major_version_zero = true
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
[build-system]
|
|
132
|
+
requires = ["hatchling"]
|
|
133
|
+
build-backend = "hatchling.build"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from rich import progress as rich_progress
|
|
2
|
+
from rich import prompt as rich_prompt
|
|
3
|
+
from typing_extensions import override
|
|
4
|
+
|
|
5
|
+
from ynab_cli.domain.ports.io import IO, Progress
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RichProgress(Progress):
|
|
9
|
+
def __init__(self, progress_info: tuple[rich_progress.Progress, rich_progress.TaskID]) -> None:
|
|
10
|
+
self._progress, self._task_id = progress_info
|
|
11
|
+
|
|
12
|
+
@override
|
|
13
|
+
async def update(
|
|
14
|
+
self, *, total: float | None = None, completed: float | None = None, advance: float | None = None
|
|
15
|
+
) -> None:
|
|
16
|
+
task = self._progress.tasks[self._task_id]
|
|
17
|
+
if not task.started:
|
|
18
|
+
self._progress.start_task(self._task_id)
|
|
19
|
+
self._progress.update(self._task_id, total=total, completed=completed, advance=advance)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class RichIO(IO):
|
|
23
|
+
def __init__(self, progress_info: tuple[rich_progress.Progress, rich_progress.TaskID]) -> None:
|
|
24
|
+
progress, _ = progress_info
|
|
25
|
+
self._progress = progress
|
|
26
|
+
self.progress = RichProgress(progress_info)
|
|
27
|
+
|
|
28
|
+
@override
|
|
29
|
+
async def prompt(self, prompt: str, password: bool = False) -> str:
|
|
30
|
+
try:
|
|
31
|
+
self._progress.stop()
|
|
32
|
+
return rich_prompt.Prompt.ask(prompt, console=self._progress.console, password=password)
|
|
33
|
+
finally:
|
|
34
|
+
self._progress.start()
|
|
35
|
+
|
|
36
|
+
@override
|
|
37
|
+
async def print(self, message: str) -> None:
|
|
38
|
+
return self._progress.console.print(message)
|
|
File without changes
|