beanhub-cli 2.0.0__tar.gz → 2.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.
Files changed (253) hide show
  1. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/PKG-INFO +4 -2
  2. beanhub_cli-2.1.0/beanhub_cli/api_helpers.py +41 -0
  3. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/cli.py +2 -0
  4. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/config.py +1 -1
  5. beanhub_cli-2.1.0/beanhub_cli/connect/config.py +70 -0
  6. beanhub_cli-2.1.0/beanhub_cli/connect/file_io.py +12 -0
  7. beanhub_cli-2.1.0/beanhub_cli/connect/main.py +267 -0
  8. beanhub_cli-2.1.0/beanhub_cli/internal_api/__init__.py +8 -0
  9. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/__init__.py +1 -0
  10. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/auth/__init__.py +0 -0
  11. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/auth/create_auth_session.py +168 -0
  12. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/auth/poll_auth_session.py +233 -0
  13. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/connect/__init__.py +0 -0
  14. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/connect/create_dump_request.py +194 -0
  15. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/connect/create_sync_batch.py +171 -0
  16. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/connect/get_dump_request.py +185 -0
  17. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/connect/get_sync_batch.py +185 -0
  18. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/repo/__init__.py +0 -0
  19. beanhub_cli-2.1.0/beanhub_cli/internal_api/api/repo/list_repo.py +129 -0
  20. beanhub_cli-2.1.0/beanhub_cli/internal_api/client.py +290 -0
  21. beanhub_cli-2.1.0/beanhub_cli/internal_api/errors.py +16 -0
  22. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/__init__.py +42 -0
  23. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/auth_session_not_ready_response.py +67 -0
  24. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/auth_session_poll_response.py +95 -0
  25. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/auth_session_request.py +59 -0
  26. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/auth_session_response.py +109 -0
  27. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/create_dump_request_request.py +59 -0
  28. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/create_dump_request_response.py +60 -0
  29. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/create_sync_batch_response.py +60 -0
  30. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/dump_request_state.py +11 -0
  31. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/generic_error.py +61 -0
  32. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/get_dump_request_response.py +134 -0
  33. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/get_sync_batch_response.py +83 -0
  34. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/http_validation_error.py +78 -0
  35. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/item_data.py +75 -0
  36. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/list_repositories_response.py +74 -0
  37. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/plaid_item_sync_state.py +14 -0
  38. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/repository.py +93 -0
  39. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/repository_type.py +9 -0
  40. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/sync_data.py +108 -0
  41. beanhub_cli-2.1.0/beanhub_cli/internal_api/models/validation_error.py +90 -0
  42. beanhub_cli-2.1.0/beanhub_cli/internal_api/py.typed +1 -0
  43. beanhub_cli-2.1.0/beanhub_cli/internal_api/types.py +49 -0
  44. beanhub_cli-2.1.0/beanhub_cli/login.py +97 -0
  45. beanhub_cli-2.1.0/beanhub_cli/utils.py +66 -0
  46. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/pyproject.toml +11 -6
  47. beanhub_cli-2.0.0/beanhub_cli/connect/config.py +0 -30
  48. beanhub_cli-2.0.0/beanhub_cli/connect/main.py +0 -301
  49. beanhub_cli-2.0.0/beanhub_cli/login.py +0 -88
  50. beanhub_cli-2.0.0/beanhub_cli/utils.py +0 -24
  51. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/LICENSE +0 -0
  52. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/README.md +0 -0
  53. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/__init__.py +0 -0
  54. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/aliase.py +0 -0
  55. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/connect/__init__.py +0 -0
  56. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/connect/cli.py +0 -0
  57. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/connect/encryption.py +0 -0
  58. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/environment.py +0 -0
  59. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/format.py +0 -0
  60. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/__init__.py +0 -0
  61. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/__init__.py +0 -0
  62. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/constants.py +0 -0
  63. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/data/sample_forms_doc.yaml +0 -0
  64. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/deps.py +0 -0
  65. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/helpers.py +0 -0
  66. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/main.py +0 -0
  67. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/routes.py +0 -0
  68. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/settings.py +0 -0
  69. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/js/beanhub-web-react-0.3.0.js +0 -0
  70. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/js/beanhub-web-react-0.3.0.js.LICENSE.txt +0 -0
  71. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/js/beanhub-web-react-0.3.0.js.map +0 -0
  72. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/LICENSE +0 -0
  73. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/css/bootstrap-datepicker.css +0 -0
  74. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/css/bootstrap-datepicker.css.map +0 -0
  75. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/css/bootstrap-datepicker.min.css +0 -0
  76. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/js/bootstrap-datepicker.js +0 -0
  77. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/js/bootstrap-datepicker.min.js +0 -0
  78. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker-en-CA.min.js +0 -0
  79. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ar-DZ.min.js +0 -0
  80. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ar-tn.min.js +0 -0
  81. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ar.min.js +0 -0
  82. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.az.min.js +0 -0
  83. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.bg.min.js +0 -0
  84. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.bm.min.js +0 -0
  85. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.bn.min.js +0 -0
  86. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.br.min.js +0 -0
  87. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.bs.min.js +0 -0
  88. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ca.min.js +0 -0
  89. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.cs.min.js +0 -0
  90. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.cy.min.js +0 -0
  91. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.da.min.js +0 -0
  92. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.de.min.js +0 -0
  93. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.el.min.js +0 -0
  94. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.en-AU.min.js +0 -0
  95. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.en-CA.min.js +0 -0
  96. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.en-GB.min.js +0 -0
  97. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.en-IE.min.js +0 -0
  98. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.en-NZ.min.js +0 -0
  99. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.en-US.min.js +0 -0
  100. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.en-ZA.min.js +0 -0
  101. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.eo.min.js +0 -0
  102. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.es.min.js +0 -0
  103. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.et.min.js +0 -0
  104. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.eu.min.js +0 -0
  105. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.fa.min.js +0 -0
  106. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.fi.min.js +0 -0
  107. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.fo.min.js +0 -0
  108. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.fr-CH.min.js +0 -0
  109. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.fr.min.js +0 -0
  110. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.gl.min.js +0 -0
  111. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.he.min.js +0 -0
  112. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.hi.min.js +0 -0
  113. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.hr.min.js +0 -0
  114. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.hu.min.js +0 -0
  115. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.hy.min.js +0 -0
  116. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.id.min.js +0 -0
  117. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.is.min.js +0 -0
  118. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.it-CH.min.js +0 -0
  119. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.it.min.js +0 -0
  120. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ja.min.js +0 -0
  121. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ka.min.js +0 -0
  122. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.kh.min.js +0 -0
  123. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.kk.min.js +0 -0
  124. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.km.min.js +0 -0
  125. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ko.min.js +0 -0
  126. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.kr.min.js +0 -0
  127. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.lt.min.js +0 -0
  128. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.lv.min.js +0 -0
  129. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.me.min.js +0 -0
  130. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.mk.min.js +0 -0
  131. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.mn.min.js +0 -0
  132. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.mr.min.js +0 -0
  133. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ms.min.js +0 -0
  134. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.nl-BE.min.js +0 -0
  135. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.nl.min.js +0 -0
  136. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.no.min.js +0 -0
  137. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.oc.min.js +0 -0
  138. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.pl.min.js +0 -0
  139. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.pt-BR.min.js +0 -0
  140. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.pt.min.js +0 -0
  141. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ro.min.js +0 -0
  142. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.rs-latin.min.js +0 -0
  143. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.rs.min.js +0 -0
  144. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ru.min.js +0 -0
  145. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.si.min.js +0 -0
  146. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.sk.min.js +0 -0
  147. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.sl.min.js +0 -0
  148. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.sq.min.js +0 -0
  149. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.sr-latin.min.js +0 -0
  150. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.sr.min.js +0 -0
  151. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.sv.min.js +0 -0
  152. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.sw.min.js +0 -0
  153. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.ta.min.js +0 -0
  154. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.tg.min.js +0 -0
  155. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.th.min.js +0 -0
  156. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.tk.min.js +0 -0
  157. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.tr.min.js +0 -0
  158. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.uk.min.js +0 -0
  159. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.uz-cyrl.min.js +0 -0
  160. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.uz-latn.min.js +0 -0
  161. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.vi.min.js +0 -0
  162. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js +0 -0
  163. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.zh-TW.min.js +0 -0
  164. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/LICENSE.txt +0 -0
  165. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/css/all.min.css +0 -0
  166. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/webfonts/fa-brands-400.ttf +0 -0
  167. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/webfonts/fa-brands-400.woff2 +0 -0
  168. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/webfonts/fa-regular-400.ttf +0 -0
  169. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/webfonts/fa-regular-400.woff2 +0 -0
  170. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/webfonts/fa-solid-900.ttf +0 -0
  171. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/webfonts/fa-solid-900.woff2 +0 -0
  172. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/webfonts/fa-v4compatibility.ttf +0 -0
  173. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/fontawesome6/webfonts/fa-v4compatibility.woff2 +0 -0
  174. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/LICENSE.md +0 -0
  175. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/css/select2.css +0 -0
  176. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/css/select2.min.css +0 -0
  177. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/af.js +0 -0
  178. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ar.js +0 -0
  179. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/az.js +0 -0
  180. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/bg.js +0 -0
  181. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/bn.js +0 -0
  182. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/bs.js +0 -0
  183. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ca.js +0 -0
  184. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/cs.js +0 -0
  185. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/da.js +0 -0
  186. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/de.js +0 -0
  187. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/dsb.js +0 -0
  188. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/el.js +0 -0
  189. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/en.js +0 -0
  190. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/eo.js +0 -0
  191. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/es.js +0 -0
  192. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/et.js +0 -0
  193. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/eu.js +0 -0
  194. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/fa.js +0 -0
  195. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/fi.js +0 -0
  196. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/fr.js +0 -0
  197. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/gl.js +0 -0
  198. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/he.js +0 -0
  199. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/hi.js +0 -0
  200. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/hr.js +0 -0
  201. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/hsb.js +0 -0
  202. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/hu.js +0 -0
  203. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/hy.js +0 -0
  204. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/id.js +0 -0
  205. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/is.js +0 -0
  206. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/it.js +0 -0
  207. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ja.js +0 -0
  208. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ka.js +0 -0
  209. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/km.js +0 -0
  210. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ko.js +0 -0
  211. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/lt.js +0 -0
  212. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/lv.js +0 -0
  213. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/mk.js +0 -0
  214. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ms.js +0 -0
  215. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/nb.js +0 -0
  216. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ne.js +0 -0
  217. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/nl.js +0 -0
  218. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/pa.js +0 -0
  219. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/pl.js +0 -0
  220. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ps.js +0 -0
  221. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/pt-BR.js +0 -0
  222. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/pt.js +0 -0
  223. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ro.js +0 -0
  224. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/ru.js +0 -0
  225. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/sk.js +0 -0
  226. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/sl.js +0 -0
  227. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/sq.js +0 -0
  228. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/sr-Cyrl.js +0 -0
  229. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/sr.js +0 -0
  230. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/sv.js +0 -0
  231. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/te.js +0 -0
  232. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/th.js +0 -0
  233. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/tk.js +0 -0
  234. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/tr.js +0 -0
  235. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/uk.js +0 -0
  236. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/vi.js +0 -0
  237. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/zh-CN.js +0 -0
  238. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/i18n/zh-TW.js +0 -0
  239. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/select2.full.js +0 -0
  240. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/select2.full.min.js +0 -0
  241. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/select2.js +0 -0
  242. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/static/vendor/select2/js/select2.min.js +0 -0
  243. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/templates/errors.html +0 -0
  244. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/templates/flash_messages.html +0 -0
  245. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/templates/footer.html +0 -0
  246. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/templates/form.html +0 -0
  247. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/templates/home.html +0 -0
  248. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/app/templates/layout.html +0 -0
  249. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/cli.py +0 -0
  250. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/main.py +0 -0
  251. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/forms/validator.py +0 -0
  252. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/import_cli.py +0 -0
  253. {beanhub_cli-2.0.0 → beanhub_cli-2.1.0}/beanhub_cli/main.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: beanhub-cli
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: Command line tools for BeanHub
5
5
  License: MIT
6
6
  Author: Fang-Pen Lin
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Provides-Extra: connect
15
15
  Provides-Extra: login
16
+ Requires-Dist: attrs (>=22.2.0) ; extra == "login" or extra == "connect"
16
17
  Requires-Dist: beancount-black (>=1.0.1,<2.0.0)
17
18
  Requires-Dist: beancount-parser (>=1.2.3,<1.3.0)
18
19
  Requires-Dist: beanhub-extract (>=0.1.0,<1.0.0)
@@ -21,12 +22,13 @@ Requires-Dist: beanhub-import (>=1.0.0,<2.0.0)
21
22
  Requires-Dist: click (>=8.1.7,<9.0.0)
22
23
  Requires-Dist: cryptography (>=44.0.0,<45.0.0) ; extra == "connect"
23
24
  Requires-Dist: fastapi (>=0.98.0,<1.0.0)
25
+ Requires-Dist: httpx (>=0.20.0,<0.29.0) ; extra == "login" or extra == "connect"
24
26
  Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
25
27
  Requires-Dist: pydantic (>=2.4.0,<3.0.0)
26
28
  Requires-Dist: pydantic-settings (>=2.0.3,<3.0.0)
27
29
  Requires-Dist: pynacl (>=1.5.0,<2.0.0) ; extra == "connect"
30
+ Requires-Dist: python-dateutil (>=2.8.0,<3.0.0) ; extra == "login" or extra == "connect"
28
31
  Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
29
- Requires-Dist: requests (>=2.32.3,<3.0.0) ; extra == "login" or extra == "connect"
30
32
  Requires-Dist: rich (>=13.6.0,<14.0.0)
31
33
  Requires-Dist: starlette-wtf (>=0.4.3,<0.5.0)
32
34
  Requires-Dist: tomli (>=2.2.1,<3.0.0) ; extra == "login" or extra == "connect"
@@ -0,0 +1,41 @@
1
+ import functools
2
+ import json
3
+ import logging
4
+ import sys
5
+ import typing
6
+
7
+
8
+ def handle_api_exception(logger: logging.Logger | None = None):
9
+ def decorator(func: typing.Callable):
10
+ @functools.wraps(func)
11
+ def callee(*args, **kwargs):
12
+ from .internal_api.errors import UnexpectedStatus
13
+ from .internal_api.models import GenericError
14
+
15
+ try:
16
+ return func(*args, **kwargs)
17
+ except UnexpectedStatus as exp:
18
+ log = logger or logging.getLogger(__name__)
19
+ error = None
20
+ try:
21
+ error = GenericError.from_dict(json.loads(exp.content))
22
+ except ValueError:
23
+ pass
24
+ log.error(
25
+ "Failed to make BeanHub API call with code %s and error: %s",
26
+ exp.status_code,
27
+ error.detail if error is not None else exp.content,
28
+ )
29
+ sys.exit(-1)
30
+
31
+ return callee
32
+
33
+ return decorator
34
+
35
+
36
+ def make_auth_client(base_url: str, token: str) -> "AuthenticatedClient":
37
+ from .internal_api.client import AuthenticatedClient
38
+
39
+ return AuthenticatedClient(
40
+ base_url=base_url, prefix="", auth_header_name="access-token", token=token
41
+ )
@@ -34,3 +34,5 @@ def cli(env: Environment, log_level: str):
34
34
  handlers=[RichHandler(console=console)],
35
35
  force=True,
36
36
  )
37
+ httpx_logger = logging.getLogger("httpx")
38
+ httpx_logger.level = logging.WARNING
@@ -45,5 +45,5 @@ def save_config(config: Config, file_path: pathlib.Path | None = None):
45
45
  # TODO: for now we save the config as plaintext. We should consider to use OS keychain service in the future
46
46
  # for better security
47
47
  with file_path.open("wb") as fo:
48
- obj = config.model_dump(mode="json")
48
+ obj = config.model_dump(mode="json", exclude_none=True)
49
49
  tomli_w.dump(obj, fo)
@@ -0,0 +1,70 @@
1
+ import dataclasses
2
+ import logging
3
+ import sys
4
+ import typing
5
+
6
+ from ..api_helpers import make_auth_client
7
+ from ..config import load_config
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class ConnectConfig:
14
+ token: str
15
+ username: str
16
+ repo: str
17
+
18
+
19
+ def parse_repo(repo: str | None) -> typing.Tuple[str | None, str | None]:
20
+ if repo is None:
21
+ return None, None
22
+ return tuple(repo.split("/", 1))
23
+
24
+
25
+ # TODO: maybe extract this part to a shared env for connect command?
26
+ def ensure_config(api_base_url: str, repo: str | None) -> ConnectConfig:
27
+ config = load_config()
28
+ if config is None or config.access_token is None:
29
+ logger.error(
30
+ 'You need to login into your BeanHub account with "bh login" command first'
31
+ )
32
+ sys.exit(-1)
33
+ if repo is None and (config.repo is None or config.repo.default is None):
34
+ logger.info(
35
+ "No repo provided, try to determine which repo to use automatically ..."
36
+ )
37
+
38
+ from ..internal_api.api.repo import list_repo
39
+
40
+ with make_auth_client(
41
+ base_url=api_base_url, token=config.access_token.token
42
+ ) as client:
43
+ client.raise_on_unexpected_status = True
44
+ resp = list_repo.sync(client=client)
45
+ active_repos = list(filter(lambda repo: repo.active, resp.repositories))
46
+ if len(active_repos) == 1:
47
+ active_repo = active_repos[0]
48
+ username = active_repo.username
49
+ repo_name = active_repo.name
50
+ else:
51
+ if len(active_repos) > 1:
52
+ logger.error(
53
+ "Cannot determine repo automatically because there are multiple active repos: %s",
54
+ ", ".join(
55
+ [f"{repo.username}/{repo.name}" for repo in active_repos]
56
+ ),
57
+ )
58
+ logger.error(
59
+ 'You need to provide a repo by -r argument, such as "myuser/myrepo" or define a default repo in your config file'
60
+ )
61
+ sys.exit(-1)
62
+ else:
63
+ username, repo_name = parse_repo(
64
+ repo if repo is not None else config.repo.default
65
+ )
66
+ return ConnectConfig(
67
+ token=config.access_token.token,
68
+ username=username,
69
+ repo=repo_name,
70
+ )
@@ -0,0 +1,12 @@
1
+ import io
2
+ import logging
3
+ import tarfile
4
+
5
+
6
+ def extract_tar(input_file: io.BytesIO, logger: logging.Logger):
7
+ with tarfile.open(fileobj=input_file, mode="r:gz") as tar_file:
8
+ if hasattr(tarfile, "data_filter"):
9
+ tar_file.extractall(filter="data")
10
+ else:
11
+ logger.warning("Performing unsafe tar file extracting")
12
+ tar_file.extractall()
@@ -0,0 +1,267 @@
1
+ import json
2
+ import logging
3
+ import sys
4
+ import tarfile
5
+ import tempfile
6
+ import time
7
+
8
+ import click
9
+ import rich
10
+ from rich import box
11
+ from rich.markup import escape
12
+ from rich.padding import Padding
13
+ from rich.table import Table
14
+
15
+ from ..api_helpers import handle_api_exception
16
+ from ..api_helpers import make_auth_client
17
+ from ..environment import Environment
18
+ from ..environment import pass_env
19
+ from ..utils import check_imports
20
+ from ..utils import ExtraDepsSet
21
+ from .cli import cli
22
+ from .config import ConnectConfig
23
+ from .config import ensure_config
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ TABLE_HEADER_STYLE = "yellow"
28
+ TABLE_COLUMN_STYLE = "cyan"
29
+ SPOOLED_FILE_MAX_SIZE = 1024 * 1024 * 5
30
+
31
+
32
+ def run_sync(env: Environment, config: ConnectConfig):
33
+ from ..internal_api.api.connect import create_sync_batch
34
+ from ..internal_api.api.connect import get_sync_batch
35
+ from ..internal_api.models import CreateSyncBatchResponse
36
+ from ..internal_api.models import GetSyncBatchResponse
37
+ from ..internal_api.models import HTTPValidationError
38
+ from ..internal_api.models import PlaidItemSyncState
39
+
40
+ GOOD_TERMINAL_SYNC_STATES = frozenset(
41
+ [
42
+ PlaidItemSyncState.IMPORT_COMPLETE,
43
+ PlaidItemSyncState.IMPORT_COMPLETE_NO_CHANGES,
44
+ ]
45
+ )
46
+ BAD_TERMINAL_SYNC_STATES = frozenset(
47
+ [
48
+ PlaidItemSyncState.IMPORT_FAILED,
49
+ PlaidItemSyncState.SYNC_FAILED,
50
+ ]
51
+ )
52
+
53
+ logger.info(
54
+ "Running sync batch for repo [green]%s[/]",
55
+ config.repo,
56
+ extra={"markup": True, "highlighter": None},
57
+ )
58
+
59
+ with make_auth_client(base_url=env.api_base_url, token=config.token) as client:
60
+ client.raise_on_unexpected_status = True
61
+ resp: CreateSyncBatchResponse = create_sync_batch.sync(
62
+ username=config.username, repo_name=config.repo, client=client
63
+ )
64
+ if isinstance(resp, HTTPValidationError):
65
+ logger.error(
66
+ "Failed to create sync batch with error: %s",
67
+ resp.additional_properties.get("error", resp.detail),
68
+ )
69
+ sys.exit(-1)
70
+ batch_id = resp.id
71
+ logger.info(
72
+ "Created sync batch [green]%s[/], waiting for updates ...",
73
+ batch_id,
74
+ extra={"markup": True, "highlighter": None},
75
+ )
76
+
77
+ while True:
78
+ time.sleep(5)
79
+ resp: GetSyncBatchResponse = get_sync_batch.sync(
80
+ username=config.username,
81
+ repo_name=config.repo,
82
+ sync_batch_id=batch_id,
83
+ client=client,
84
+ )
85
+ total = len(resp.syncs)
86
+ good_terms = list(
87
+ sync
88
+ for sync in resp.syncs
89
+ if PlaidItemSyncState[sync.state.value] in GOOD_TERMINAL_SYNC_STATES
90
+ )
91
+ bad_terms = list(
92
+ sync for sync in resp.syncs if sync.state in BAD_TERMINAL_SYNC_STATES
93
+ )
94
+ progress = len(good_terms) + len(bad_terms)
95
+ if progress >= total:
96
+ break
97
+ else:
98
+ logger.info(
99
+ "Still processing, [green]%s[/] out of [green]%s[/]",
100
+ progress,
101
+ total,
102
+ extra={"markup": True, "highlighter": None},
103
+ )
104
+ table = Table(
105
+ title="Sync finished successfully",
106
+ box=box.SIMPLE,
107
+ header_style=TABLE_HEADER_STYLE,
108
+ expand=True,
109
+ )
110
+ table.add_column("Id", style=TABLE_COLUMN_STYLE)
111
+ table.add_column("Institution", style=TABLE_COLUMN_STYLE)
112
+ table.add_column("State", style=TABLE_COLUMN_STYLE)
113
+ for sync in good_terms:
114
+ table.add_row(
115
+ escape(sync.id),
116
+ escape(sync.item.institution_name),
117
+ escape(sync.state),
118
+ )
119
+ rich.print(Padding(table, (1, 0, 0, 4)))
120
+
121
+ table = Table(
122
+ title="Sync finished with error",
123
+ box=box.SIMPLE,
124
+ header_style=TABLE_HEADER_STYLE,
125
+ expand=True,
126
+ )
127
+ table.add_column("Id", style=TABLE_COLUMN_STYLE)
128
+ table.add_column("Institution", style=TABLE_COLUMN_STYLE)
129
+ table.add_column("State", style=TABLE_COLUMN_STYLE)
130
+ table.add_column("Error", style=TABLE_COLUMN_STYLE)
131
+ for sync in bad_terms:
132
+ table.add_row(
133
+ escape(sync.id),
134
+ escape(sync.item.institution_name),
135
+ escape(sync.state),
136
+ escape(sync.error_message),
137
+ )
138
+ rich.print(Padding(table, (1, 0, 0, 4)))
139
+
140
+
141
+ @cli.command(help="Sync transactions for all BeanHub Connect banks")
142
+ @click.option(
143
+ "-r",
144
+ "--repo",
145
+ type=str,
146
+ help='Which repository to run sync on, in "<username>/<repo_name>" format',
147
+ )
148
+ @pass_env
149
+ @check_imports(ExtraDepsSet.LOGIN, logger)
150
+ @handle_api_exception(logger)
151
+ def sync(env: Environment, repo: str | None):
152
+ config = ensure_config(api_base_url=env.api_base_url, repo=repo)
153
+ run_sync(env, config)
154
+ env.logger.info("done")
155
+
156
+
157
+ @cli.command(
158
+ help="Dump transaction CSV files from BeanHub Connect to your local environment"
159
+ )
160
+ @click.option(
161
+ "-r",
162
+ "--repo",
163
+ type=str,
164
+ help='Which repository to run sync on, in "<username>/<repo_name>" format',
165
+ )
166
+ @click.option(
167
+ "-s",
168
+ "--sync",
169
+ type=bool,
170
+ is_flag=True,
171
+ help="Run sync first before running dump",
172
+ )
173
+ @click.option(
174
+ "--unsafe-tar-extract",
175
+ type=bool,
176
+ is_flag=True,
177
+ help="Allow unsafe tar extraction, mostly for Python < 3.11",
178
+ )
179
+ @pass_env
180
+ @check_imports(ExtraDepsSet.CONNECT, logger)
181
+ @handle_api_exception(logger)
182
+ def dump(env: Environment, repo: str | None, sync: bool, unsafe_tar_extract: bool):
183
+ import httpx
184
+ from ..internal_api.api.connect import create_dump_request
185
+ from ..internal_api.api.connect import get_dump_request
186
+ from ..internal_api.models import CreateDumpRequestRequest
187
+ from ..internal_api.models import CreateDumpRequestResponse
188
+ from ..internal_api.models import DumpRequestState
189
+ from ..internal_api.models import GetDumpRequestResponse
190
+ from nacl.encoding import URLSafeBase64Encoder
191
+ from nacl.public import PrivateKey
192
+ from nacl.public import SealedBox
193
+
194
+ if not hasattr(tarfile, "data_filter") and not unsafe_tar_extract:
195
+ logger.error(
196
+ "You need to use Python >= 3.11 in order to safely unpack the downloaded tar file, or you need to pass "
197
+ "in --unsafe-tar-extract argument to allow unsafe tar file extracting"
198
+ )
199
+ sys.exit(-1)
200
+ config = ensure_config(api_base_url=env.api_base_url, repo=repo)
201
+ if sync:
202
+ run_sync(env, config)
203
+
204
+ private_key = PrivateKey.generate()
205
+ public_key = private_key.public_key.encode(URLSafeBase64Encoder).decode("ascii")
206
+
207
+ with make_auth_client(base_url=env.api_base_url, token=config.token) as client:
208
+ client.raise_on_unexpected_status = True
209
+ resp: CreateDumpRequestResponse = create_dump_request.sync(
210
+ body=CreateDumpRequestRequest(public_key=public_key),
211
+ username=config.username,
212
+ repo_name=config.repo,
213
+ client=client,
214
+ )
215
+ dump_id = resp.id
216
+ logger.info(
217
+ "Created dump [green]%s[/] with public_key [green]%s[/], waiting for updates ...",
218
+ dump_id,
219
+ public_key,
220
+ extra={"markup": True, "highlighter": None},
221
+ )
222
+
223
+ while True:
224
+ time.sleep(5)
225
+ resp: GetDumpRequestResponse = get_dump_request.sync(
226
+ dump_request_id=dump_id,
227
+ username=config.username,
228
+ repo_name=config.repo,
229
+ client=client,
230
+ )
231
+ if resp.state == DumpRequestState.FAILED:
232
+ logger.error("Failed to dump with error: %s", resp.error_message)
233
+ sys.exit(-1)
234
+ elif resp.state == DumpRequestState.COMPLETE:
235
+ break
236
+ else:
237
+ logger.debug("State is %s, keep polling...", resp.state)
238
+
239
+ download_url = resp.download_url
240
+ sealed_box = SealedBox(private_key)
241
+ encryption_key = json.loads(
242
+ sealed_box.decrypt(URLSafeBase64Encoder.decode(resp.encryption_key))
243
+ )
244
+ key = URLSafeBase64Encoder.decode(encryption_key["key"])
245
+ iv = URLSafeBase64Encoder.decode(encryption_key["iv"])
246
+
247
+ with (
248
+ tempfile.SpooledTemporaryFile(SPOOLED_FILE_MAX_SIZE) as encrypted_file,
249
+ tempfile.SpooledTemporaryFile(SPOOLED_FILE_MAX_SIZE) as decrypted_file,
250
+ ):
251
+ with httpx.stream("GET", download_url) as req:
252
+ for chunk in req.iter_bytes():
253
+ encrypted_file.write(chunk)
254
+ encrypted_file.flush()
255
+ encrypted_file.seek(0)
256
+ logger.info("Decrypting downloaded file ...")
257
+
258
+ # delay import for testing purpose
259
+ from .encryption import decrypt_file
260
+ from .file_io import extract_tar
261
+
262
+ decrypt_file(
263
+ input_file=encrypted_file, output_file=decrypted_file, key=key, iv=iv
264
+ )
265
+ extract_tar(input_file=decrypted_file, logger=env.logger)
266
+
267
+ logger.info("done")
@@ -0,0 +1,8 @@
1
+ """A client library for accessing BeanHub Internal API"""
2
+ from .client import AuthenticatedClient
3
+ from .client import Client
4
+
5
+ __all__ = (
6
+ "AuthenticatedClient",
7
+ "Client",
8
+ )
@@ -0,0 +1 @@
1
+ """Contains methods for accessing the API"""
@@ -0,0 +1,168 @@
1
+ from http import HTTPStatus
2
+ from typing import Any
3
+ from typing import Optional
4
+ from typing import Union
5
+
6
+ import httpx
7
+
8
+ from ... import errors
9
+ from ...client import AuthenticatedClient
10
+ from ...client import Client
11
+ from ...models.auth_session_request import AuthSessionRequest
12
+ from ...models.auth_session_response import AuthSessionResponse
13
+ from ...models.http_validation_error import HTTPValidationError
14
+ from ...types import Response
15
+
16
+
17
+ def _get_kwargs(
18
+ *,
19
+ body: AuthSessionRequest,
20
+ ) -> dict[str, Any]:
21
+ headers: dict[str, Any] = {}
22
+
23
+ _kwargs: dict[str, Any] = {
24
+ "method": "post",
25
+ "url": "/v1/auth/sessions",
26
+ }
27
+
28
+ _body = body.to_dict()
29
+
30
+ _kwargs["json"] = _body
31
+ headers["Content-Type"] = "application/json"
32
+
33
+ _kwargs["headers"] = headers
34
+ return _kwargs
35
+
36
+
37
+ def _parse_response(
38
+ *, client: Union[AuthenticatedClient, Client], response: httpx.Response
39
+ ) -> Optional[Union[AuthSessionResponse, HTTPValidationError]]:
40
+ if response.status_code == 201:
41
+ response_201 = AuthSessionResponse.from_dict(response.json())
42
+
43
+ return response_201
44
+ if response.status_code == 422:
45
+ response_422 = HTTPValidationError.from_dict(response.json())
46
+
47
+ return response_422
48
+ if client.raise_on_unexpected_status:
49
+ raise errors.UnexpectedStatus(response.status_code, response.content)
50
+ else:
51
+ return None
52
+
53
+
54
+ def _build_response(
55
+ *, client: Union[AuthenticatedClient, Client], response: httpx.Response
56
+ ) -> Response[Union[AuthSessionResponse, HTTPValidationError]]:
57
+ return Response(
58
+ status_code=HTTPStatus(response.status_code),
59
+ content=response.content,
60
+ headers=response.headers,
61
+ parsed=_parse_response(client=client, response=response),
62
+ )
63
+
64
+
65
+ def sync_detailed(
66
+ *,
67
+ client: Union[AuthenticatedClient, Client],
68
+ body: AuthSessionRequest,
69
+ ) -> Response[Union[AuthSessionResponse, HTTPValidationError]]:
70
+ """Create auth session
71
+
72
+ Args:
73
+ body (AuthSessionRequest):
74
+
75
+ Raises:
76
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
77
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
78
+
79
+ Returns:
80
+ Response[Union[AuthSessionResponse, HTTPValidationError]]
81
+ """
82
+
83
+ kwargs = _get_kwargs(
84
+ body=body,
85
+ )
86
+
87
+ response = client.get_httpx_client().request(
88
+ **kwargs,
89
+ )
90
+
91
+ return _build_response(client=client, response=response)
92
+
93
+
94
+ def sync(
95
+ *,
96
+ client: Union[AuthenticatedClient, Client],
97
+ body: AuthSessionRequest,
98
+ ) -> Optional[Union[AuthSessionResponse, HTTPValidationError]]:
99
+ """Create auth session
100
+
101
+ Args:
102
+ body (AuthSessionRequest):
103
+
104
+ Raises:
105
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
106
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
107
+
108
+ Returns:
109
+ Union[AuthSessionResponse, HTTPValidationError]
110
+ """
111
+
112
+ return sync_detailed(
113
+ client=client,
114
+ body=body,
115
+ ).parsed
116
+
117
+
118
+ async def asyncio_detailed(
119
+ *,
120
+ client: Union[AuthenticatedClient, Client],
121
+ body: AuthSessionRequest,
122
+ ) -> Response[Union[AuthSessionResponse, HTTPValidationError]]:
123
+ """Create auth session
124
+
125
+ Args:
126
+ body (AuthSessionRequest):
127
+
128
+ Raises:
129
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
130
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
131
+
132
+ Returns:
133
+ Response[Union[AuthSessionResponse, HTTPValidationError]]
134
+ """
135
+
136
+ kwargs = _get_kwargs(
137
+ body=body,
138
+ )
139
+
140
+ response = await client.get_async_httpx_client().request(**kwargs)
141
+
142
+ return _build_response(client=client, response=response)
143
+
144
+
145
+ async def asyncio(
146
+ *,
147
+ client: Union[AuthenticatedClient, Client],
148
+ body: AuthSessionRequest,
149
+ ) -> Optional[Union[AuthSessionResponse, HTTPValidationError]]:
150
+ """Create auth session
151
+
152
+ Args:
153
+ body (AuthSessionRequest):
154
+
155
+ Raises:
156
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
157
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
158
+
159
+ Returns:
160
+ Union[AuthSessionResponse, HTTPValidationError]
161
+ """
162
+
163
+ return (
164
+ await asyncio_detailed(
165
+ client=client,
166
+ body=body,
167
+ )
168
+ ).parsed