dart-tools 0.4.8__tar.gz → 0.5.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 (186) hide show
  1. {dart-tools-0.4.8 → dart-tools-0.5.0}/PKG-INFO +8 -7
  2. {dart-tools-0.4.8 → dart-tools-0.5.0}/README.md +7 -6
  3. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/dart.py +48 -35
  4. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/filter_applicability.py +2 -0
  5. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/filter_assignee.py +2 -0
  6. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/filter_set.py +2 -0
  7. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/folder.py +8 -0
  8. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/folder_create.py +26 -0
  9. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/folder_kind.py +1 -0
  10. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/folder_update.py +27 -0
  11. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/user.py +7 -0
  12. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/order_manager.py +4 -2
  13. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart_tools.egg-info/PKG-INFO +8 -7
  14. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart_tools.egg-info/requires.txt +1 -0
  15. {dart-tools-0.4.8 → dart-tools-0.5.0}/pyproject.toml +3 -2
  16. {dart-tools-0.4.8 → dart-tools-0.5.0}/LICENSE +0 -0
  17. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/__init__.py +0 -0
  18. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/exception.py +0 -0
  19. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/__init__.py +0 -0
  20. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/api/__init__.py +0 -0
  21. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/api/transactions/__init__.py +0 -0
  22. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/api/transactions/transactions_create.py +0 -0
  23. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/client.py +0 -0
  24. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/errors.py +0 -0
  25. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/__init__.py +0 -0
  26. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/batch.py +0 -0
  27. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/color_name.py +0 -0
  28. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment.py +0 -0
  29. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment_create.py +0 -0
  30. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment_create_text.py +0 -0
  31. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment_reaction.py +0 -0
  32. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment_reaction_create.py +0 -0
  33. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment_reaction_update.py +0 -0
  34. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment_text.py +0 -0
  35. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment_update.py +0 -0
  36. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/comment_update_text.py +0 -0
  37. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/cycle_mode.py +0 -0
  38. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/dartboard.py +0 -0
  39. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/dartboard_create.py +0 -0
  40. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/dartboard_kind.py +0 -0
  41. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/dartboard_update.py +0 -0
  42. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/discord_integration.py +0 -0
  43. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/doc.py +0 -0
  44. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/doc_create.py +0 -0
  45. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/doc_create_text.py +0 -0
  46. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/doc_source_type.py +0 -0
  47. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/doc_text.py +0 -0
  48. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/doc_update.py +0 -0
  49. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/doc_update_text.py +0 -0
  50. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event.py +0 -0
  51. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_adtl.py +0 -0
  52. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_create.py +0 -0
  53. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_create_adtl.py +0 -0
  54. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_kind.py +0 -0
  55. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_subscription.py +0 -0
  56. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_subscription_create.py +0 -0
  57. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_subscription_update.py +0 -0
  58. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_update.py +0 -0
  59. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/event_update_adtl.py +0 -0
  60. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/filter_connector.py +0 -0
  61. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/filter_group.py +0 -0
  62. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/filter_search.py +0 -0
  63. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form.py +0 -0
  64. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form_create.py +0 -0
  65. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form_field.py +0 -0
  66. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form_field_create.py +0 -0
  67. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form_field_create_default.py +0 -0
  68. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form_field_default.py +0 -0
  69. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form_field_update.py +0 -0
  70. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form_field_update_default.py +0 -0
  71. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/form_update.py +0 -0
  72. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/github_integration.py +0 -0
  73. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/github_integration_tenant_extension_status.py +0 -0
  74. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/google_data.py +0 -0
  75. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/icon_kind.py +0 -0
  76. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout.py +0 -0
  77. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_config.py +0 -0
  78. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_create.py +0 -0
  79. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_create_filter_group.py +0 -0
  80. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_create_kind_config_map.py +0 -0
  81. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_create_sorts.py +0 -0
  82. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_kind.py +0 -0
  83. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_kind_config_map.py +0 -0
  84. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_update.py +0 -0
  85. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_update_filter_group.py +0 -0
  86. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_update_kind_config_map.py +0 -0
  87. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/layout_update_sorts.py +0 -0
  88. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/models_response.py +0 -0
  89. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/notion_integration.py +0 -0
  90. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/notion_integration_tenant_extension_status.py +0 -0
  91. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/operation.py +0 -0
  92. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/operation_kind.py +0 -0
  93. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/operation_model_kind.py +0 -0
  94. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/option.py +0 -0
  95. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/option_create.py +0 -0
  96. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/option_update.py +0 -0
  97. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/priority.py +0 -0
  98. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/property_.py +0 -0
  99. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/property_adtl.py +0 -0
  100. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/property_create.py +0 -0
  101. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/property_create_adtl.py +0 -0
  102. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/property_kind.py +0 -0
  103. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/property_update.py +0 -0
  104. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/property_update_adtl.py +0 -0
  105. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/recommendation_status.py +0 -0
  106. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/relationship.py +0 -0
  107. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/relationship_create.py +0 -0
  108. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/relationship_kind.py +0 -0
  109. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/relationship_kind_create.py +0 -0
  110. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/relationship_kind_kind.py +0 -0
  111. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/relationship_kind_update.py +0 -0
  112. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/relationship_update.py +0 -0
  113. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/request_body.py +0 -0
  114. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/response_body.py +0 -0
  115. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/slack_integration.py +0 -0
  116. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/slack_integration_tenant_extension_status.py +0 -0
  117. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/sort.py +0 -0
  118. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/space.py +0 -0
  119. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/space_create.py +0 -0
  120. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/space_kind.py +0 -0
  121. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/space_update.py +0 -0
  122. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/status.py +0 -0
  123. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/status_create.py +0 -0
  124. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/status_kind.py +0 -0
  125. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/status_update.py +0 -0
  126. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/subscription.py +0 -0
  127. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/subtask_display_mode.py +0 -0
  128. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/summary_statistic_kind.py +0 -0
  129. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task.py +0 -0
  130. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_attachment.py +0 -0
  131. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_attachment_create.py +0 -0
  132. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_attachment_update.py +0 -0
  133. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_create.py +0 -0
  134. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_create_description.py +0 -0
  135. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_create_properties.py +0 -0
  136. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_create_recurrence.py +0 -0
  137. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_description.py +0 -0
  138. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_doc_relationship.py +0 -0
  139. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_doc_relationship_create.py +0 -0
  140. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_doc_relationship_update.py +0 -0
  141. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_link.py +0 -0
  142. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_link_adtl.py +0 -0
  143. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_link_create.py +0 -0
  144. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_link_kind.py +0 -0
  145. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_link_update.py +0 -0
  146. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_notion_document.py +0 -0
  147. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_notion_document_block_children_map.py +0 -0
  148. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_notion_document_block_map.py +0 -0
  149. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_notion_document_page_map.py +0 -0
  150. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_properties.py +0 -0
  151. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_recurrence.py +0 -0
  152. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_source_type.py +0 -0
  153. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_update.py +0 -0
  154. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_update_description.py +0 -0
  155. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_update_properties.py +0 -0
  156. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/task_update_recurrence.py +0 -0
  157. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/tenant.py +0 -0
  158. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/tenant_create.py +0 -0
  159. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/tenant_entitlement_overrides.py +0 -0
  160. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/tenant_update.py +0 -0
  161. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/theme.py +0 -0
  162. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/transaction.py +0 -0
  163. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/transaction_kind.py +0 -0
  164. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/transaction_response.py +0 -0
  165. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/user_create.py +0 -0
  166. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/user_dartboard_layout.py +0 -0
  167. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/user_dartboard_layout_create.py +0 -0
  168. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/user_dartboard_layout_update.py +0 -0
  169. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/user_role.py +0 -0
  170. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/user_status.py +0 -0
  171. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/user_update.py +0 -0
  172. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/validation_error_response.py +0 -0
  173. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/validation_error_response_items.py +0 -0
  174. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/view.py +0 -0
  175. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/view_create.py +0 -0
  176. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/view_kind.py +0 -0
  177. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/view_update.py +0 -0
  178. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/models/yc_integration.py +0 -0
  179. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/generated/types.py +0 -0
  180. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart/webhook.py +0 -0
  181. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart_tools.egg-info/SOURCES.txt +0 -0
  182. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart_tools.egg-info/dependency_links.txt +0 -0
  183. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart_tools.egg-info/dist/dart-tools-0.3.3.tar.gz +0 -0
  184. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart_tools.egg-info/entry_points.txt +0 -0
  185. {dart-tools-0.4.8 → dart-tools-0.5.0}/dart_tools.egg-info/top_level.txt +0 -0
  186. {dart-tools-0.4.8 → dart-tools-0.5.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dart-tools
3
- Version: 0.4.8
3
+ Version: 0.5.0
4
4
  Summary: The Dart CLI and Python Library
5
5
  Author-email: Dart Software Team <software@itsdart.com>
6
6
  License: MIT License
@@ -79,7 +79,7 @@ pip install dart-tools
79
79
 
80
80
  ## Using the CLI
81
81
 
82
- As an example, start off by logging in with
82
+ Start off by setting up authentication with
83
83
  ```bash
84
84
  dart login
85
85
  ```
@@ -101,14 +101,15 @@ This command will mark the referenced task 'Done'. Here `[DUID]` is meant to be
101
101
 
102
102
  ## Using the Python Library
103
103
 
104
- In Python, you can run something like
104
+ First, set up authentication. Run `dart login` in the terminal for an interactive process, or visit [your Dart profile](https://app.itsdart.com/?settings=profile) and then run `dart.login(token)` or save the token into the `DART_TOKEN` environment variable.
105
+
106
+ Then, you can run something like
105
107
  ```python
106
108
  import os
107
- from dart import is_logged_in, login, create_task, update_task
109
+ from dart import create_task, is_logged_in, update_task
108
110
 
109
- # Login based on information stored in environment variables, but only if needed
110
- if not is_logged_in():
111
- login(email=os.environ["DART_EMAIL"], password=os.environ["DART_PASSWORD"])
111
+ # Check that auth is set up and stop if not, can remove this once everything is set up
112
+ is_logged_in(should_raise=True)
112
113
 
113
114
  # Create a new task called 'Update the landing page'
114
115
  # With priority 'Critical' (i.e. p0) and with the 'marketing' tag
@@ -22,7 +22,7 @@ pip install dart-tools
22
22
 
23
23
  ## Using the CLI
24
24
 
25
- As an example, start off by logging in with
25
+ Start off by setting up authentication with
26
26
  ```bash
27
27
  dart login
28
28
  ```
@@ -44,14 +44,15 @@ This command will mark the referenced task 'Done'. Here `[DUID]` is meant to be
44
44
 
45
45
  ## Using the Python Library
46
46
 
47
- In Python, you can run something like
47
+ First, set up authentication. Run `dart login` in the terminal for an interactive process, or visit [your Dart profile](https://app.itsdart.com/?settings=profile) and then run `dart.login(token)` or save the token into the `DART_TOKEN` environment variable.
48
+
49
+ Then, you can run something like
48
50
  ```python
49
51
  import os
50
- from dart import is_logged_in, login, create_task, update_task
52
+ from dart import create_task, is_logged_in, update_task
51
53
 
52
- # Login based on information stored in environment variables, but only if needed
53
- if not is_logged_in():
54
- login(email=os.environ["DART_EMAIL"], password=os.environ["DART_PASSWORD"])
54
+ # Check that auth is set up and stop if not, can remove this once everything is set up
55
+ is_logged_in(should_raise=True)
55
56
 
56
57
  # Create a new task called 'Update the landing page'
57
58
  # With priority 'Critical' (i.e. p0) and with the 'marketing' tag
@@ -15,13 +15,14 @@ import subprocess
15
15
  import sys
16
16
  from collections import defaultdict
17
17
  from datetime import timezone
18
- from getpass import getpass
19
18
  from importlib.metadata import version
20
19
  from typing import Literal, NoReturn
20
+ from webbrowser import open_new_tab
21
21
 
22
22
  import dateparser
23
23
  from pick import pick
24
24
  import requests
25
+ import platformdirs
25
26
 
26
27
  from .exception import DartException
27
28
  from .generated import Client
@@ -46,6 +47,7 @@ from .generated.models import (
46
47
  from .generated.api.transactions import transactions_create
47
48
  from .order_manager import get_orders_between
48
49
 
50
+ _APP = "dart-tools"
49
51
  _PROG = "dart"
50
52
 
51
53
  _PROD_HOST = "https://app.itsdart.com"
@@ -59,21 +61,22 @@ _CREATE_TASK_CMD = "createtask"
59
61
  _UPDATE_TASK_CMD = "updatetask"
60
62
  _BEGIN_TASK_CMD = "begintask"
61
63
 
64
+ _PROFILE_SETTINGS_URL_FRAG = "/?settings=profile"
62
65
  _ROOT_API_URL_FRAG = "/api/v0"
63
66
  _CSRF_URL_FRAG = _ROOT_API_URL_FRAG + "/csrf-token"
64
- _LOGIN_URL_FRAG = _ROOT_API_URL_FRAG + "/login"
65
- _CURRENT_USER_URL_FRAG = _ROOT_API_URL_FRAG + "/user-data?mode=auto"
67
+ _USER_STATUS_URL_FRAG = _ROOT_API_URL_FRAG + "/user-status"
68
+ _USER_DATA_URL_FRAG = _ROOT_API_URL_FRAG + "/user-data?mode=auto"
66
69
  _COPY_BRANCH_URL_FRAG = _ROOT_API_URL_FRAG + "/vcs/copy-branch-link"
67
70
  _REPLICATE_SPACE_URL_FRAG_FMT = _ROOT_API_URL_FRAG + "/spaces/replicate/{duid}"
68
71
 
69
- _CONFIG_FPATH = os.path.expanduser("~/.dart-tools")
72
+ _AUTH_TOKEN_ENVVAR_KEY = "DART_TOKEN"
73
+ _CONFIG_FPATH = platformdirs.user_config_path(_APP, roaming=False, ensure_exists=False)
70
74
  _CSRF_TOKEN_COOKIE = "csrftoken"
71
- _SESSION_ID_COOKIE = "sessionid"
72
75
  _CLIENT_DUID_KEY = "clientDuid"
73
76
  _HOST_KEY = "host"
74
77
  _HOSTS_KEY = "hosts"
78
+ _AUTH_TOKEN_KEY = "authToken"
75
79
  _CSRF_TOKEN_KEY = "csrfToken"
76
- _SESSION_ID_KEY = "sessionId"
77
80
 
78
81
  _DUID_CHARS = string.ascii_lowercase + string.ascii_uppercase + string.digits
79
82
  _PRIORITY_MAP = {
@@ -85,7 +88,8 @@ _PRIORITY_MAP = {
85
88
  _SIZES = {1, 2, 3, 5, 8}
86
89
  _COMPLETED_STATUS_KINDS = {"Finished", "Canceled"}
87
90
 
88
- _VERSION = version("dart-tools")
91
+ _VERSION = version(_APP)
92
+ _AUTH_TOKEN_ENVVAR = os.environ.get(_AUTH_TOKEN_ENVVAR_KEY)
89
93
 
90
94
  _is_cli = False
91
95
 
@@ -179,8 +183,6 @@ class _Session:
179
183
  self._session = requests.Session()
180
184
  if (csrf_token := self._config.get(_CSRF_TOKEN_KEY)) is not None:
181
185
  self._session.cookies.set(_CSRF_TOKEN_COOKIE, csrf_token)
182
- if (session_id := self._config.get(_SESSION_ID_KEY)) is not None:
183
- self._session.cookies.set(_SESSION_ID_COOKIE, session_id)
184
186
 
185
187
  def get_base_url(self):
186
188
  return self._config.host
@@ -188,8 +190,11 @@ class _Session:
188
190
  def get_client_duid(self):
189
191
  return self._config.client_duid
190
192
 
191
- def get_is_logged_in(self):
192
- return self._config.get(_SESSION_ID_KEY) is not None
193
+ def get_auth_token(self):
194
+ result = self._config.get(_AUTH_TOKEN_KEY)
195
+ if result is not None:
196
+ return result
197
+ return _AUTH_TOKEN_ENVVAR
193
198
 
194
199
  def _refresh_csrf(self):
195
200
  response = self._session.get(self._config.host + _CSRF_URL_FRAG)
@@ -205,15 +210,17 @@ class _Session:
205
210
  return csrf_token
206
211
 
207
212
  def get_headers(self):
208
- return {
209
- "client-duid": self._config.client_duid,
213
+ result = {
210
214
  "Origin": self._config.host,
215
+ "client-duid": self.get_client_duid(),
211
216
  "x-csrftoken": self.get_csrf_token(),
212
217
  }
218
+ if (auth_token := self.get_auth_token()) is not None:
219
+ result["Authorization"] = f"Bearer {auth_token}"
220
+ return result
213
221
 
214
222
  def get_cookies(self):
215
223
  return {
216
- _SESSION_ID_COOKIE: self._config.get(_SESSION_ID_KEY),
217
224
  _CSRF_TOKEN_COOKIE: self.get_csrf_token(),
218
225
  }
219
226
 
@@ -260,7 +267,7 @@ class Dart(Client):
260
267
  class UserBundle:
261
268
  def __init__(self, session):
262
269
  _log("Loading active tasks")
263
- response = session.get(_CURRENT_USER_URL_FRAG)
270
+ response = session.get(_USER_DATA_URL_FRAG)
264
271
  _check_request_response_and_maybe_exit(response)
265
272
  self._raw = response.json()
266
273
  if not self.is_logged_in:
@@ -409,11 +416,11 @@ def set_host(host):
409
416
 
410
417
 
411
418
  def _auth_failure_exit():
412
- _dart_exit(f"Not logged in, run\n\n{_PROG} {_LOGIN_CMD}\n\nto log in.")
419
+ _dart_exit(f"Not logged in, run\n\n {_PROG} {_LOGIN_CMD}\n\nto log in.")
413
420
 
414
421
 
415
422
  def _unknown_failure_exit() -> NoReturn:
416
- _dart_exit(f"Not logged in, run\n\n{_PROG} {_LOGIN_CMD}\n\nto log in.")
423
+ _dart_exit("Unknown failure, email\n\n support@itsdart.com\n\nfor help.")
417
424
 
418
425
 
419
426
  def _check_request_response_and_maybe_exit(response):
@@ -467,32 +474,42 @@ def print_version_update_message_maybe():
467
474
  )
468
475
 
469
476
 
470
- def is_logged_in():
477
+ def _get_is_logged_in(session):
478
+ response = session.get(_USER_STATUS_URL_FRAG)
479
+ return response.json().get("isLoggedIn", False)
480
+
481
+
482
+ def is_logged_in(should_raise=False):
471
483
  config = _Config()
472
484
  session = _Session(config)
473
485
 
474
- result = session.get_is_logged_in()
486
+ result = _get_is_logged_in(session)
487
+
488
+ if not result and should_raise:
489
+ _auth_failure_exit()
475
490
  _log(f"You are {'' if result else 'not '}logged in")
476
491
  return result
477
492
 
478
493
 
479
- def login(*, email=None, password=None):
494
+ def login(token=None):
480
495
  config = _Config()
481
496
  session = _Session(config)
482
497
 
483
498
  _log("Log in to Dart")
484
- if email is None:
485
- email = input("Email: ")
486
- if password is None:
487
- password = getpass()
499
+ if token is None:
500
+ if not _is_cli:
501
+ _dart_exit("Login failed, token is required.")
502
+ _log(
503
+ "Dart is opening in your browser, log in if needed and copy your authentication token from the page"
504
+ )
505
+ open_new_tab(config.host + _PROFILE_SETTINGS_URL_FRAG)
506
+ token = input("Token: ")
488
507
 
489
- result = session.post(_LOGIN_URL_FRAG, json={"email": email, "password": password})
490
- if result.status_code in {401, 403}:
491
- _dart_exit("Invalid login information.")
492
- _check_request_response_and_maybe_exit(result)
508
+ config.set(_AUTH_TOKEN_KEY, token)
493
509
 
494
- cookies = result.cookies.get_dict()
495
- config.set(_SESSION_ID_KEY, cookies.get(_SESSION_ID_COOKIE))
510
+ worked = _get_is_logged_in(session)
511
+ if not worked:
512
+ _dart_exit("Invalid token.")
496
513
 
497
514
  _log("Logged in.")
498
515
  return True
@@ -837,7 +854,6 @@ def replicate_space(duid):
837
854
  session = _Session(config)
838
855
 
839
856
  response = session.post(_REPLICATE_SPACE_URL_FRAG_FMT.format(duid=duid))
840
- print()
841
857
  _check_request_response_and_maybe_exit(response)
842
858
 
843
859
  space = Space.from_dict(response.json()["item"])
@@ -908,10 +924,7 @@ def cli():
908
924
 
909
925
  login_parser = subparsers.add_parser(_LOGIN_CMD, aliases="l", help="login")
910
926
  login_parser.add_argument(
911
- "-e", "--email", dest="email", help="email to log in with"
912
- )
913
- login_parser.add_argument(
914
- "-p", "--password", dest="password", help="password to log in with"
927
+ "-t", "--token", dest="token", help="your authentication token"
915
928
  )
916
929
  login_parser.set_defaults(func=login)
917
930
 
@@ -13,8 +13,10 @@ class FilterApplicability(str, Enum):
13
13
  IS_AFTER = "is after"
14
14
  IS_BEFORE = "is before"
15
15
  IS_BETWEEN = "is between"
16
+ IS_CHECKED = "is checked"
16
17
  IS_NOT = "is not"
17
18
  IS_NOT_SET = "is not set"
19
+ IS_UNCHECKED = "is unchecked"
18
20
 
19
21
  def __str__(self) -> str:
20
22
  return str(self.value)
@@ -29,6 +29,8 @@ class FilterAssignee:
29
29
  * `is before` - IS_BEFORE
30
30
  * `is after` - IS_AFTER
31
31
  * `is between` - IS_BETWEEN
32
+ * `is checked` - IS_CHECKED
33
+ * `is unchecked` - IS_UNCHECKED
32
34
  connector (FilterConnector): * `or` - OR
33
35
  * `and` - AND
34
36
  values (List[Any]):
@@ -29,6 +29,8 @@ class FilterSet:
29
29
  * `is before` - IS_BEFORE
30
30
  * `is after` - IS_AFTER
31
31
  * `is between` - IS_BETWEEN
32
+ * `is checked` - IS_CHECKED
33
+ * `is unchecked` - IS_UNCHECKED
32
34
  connector (FilterConnector): * `or` - OR
33
35
  * `and` - AND
34
36
  values (List[Any]):
@@ -16,8 +16,10 @@ class Folder:
16
16
  """
17
17
  Attributes:
18
18
  duid (str):
19
+ space_duid (str):
19
20
  kind (FolderKind): * `Other` - OTHER
20
21
  * `Default` - DEFAULT
22
+ * `Reports` - REPORTS
21
23
  accessible_by_team (bool):
22
24
  accessible_by_user_duids (List[str]):
23
25
  order (str):
@@ -55,6 +57,7 @@ class Folder:
55
57
  """
56
58
 
57
59
  duid: str
60
+ space_duid: str
58
61
  kind: FolderKind
59
62
  accessible_by_team: bool
60
63
  accessible_by_user_duids: List[str]
@@ -69,6 +72,7 @@ class Folder:
69
72
 
70
73
  def to_dict(self) -> Dict[str, Any]:
71
74
  duid = self.duid
75
+ space_duid = self.space_duid
72
76
  kind = self.kind.value
73
77
 
74
78
  accessible_by_team = self.accessible_by_team
@@ -89,6 +93,7 @@ class Folder:
89
93
  field_dict.update(
90
94
  {
91
95
  "duid": duid,
96
+ "spaceDuid": space_duid,
92
97
  "kind": kind,
93
98
  "accessibleByTeam": accessible_by_team,
94
99
  "accessibleByUserDuids": accessible_by_user_duids,
@@ -110,6 +115,8 @@ class Folder:
110
115
  d = src_dict.copy()
111
116
  duid = d.pop("duid")
112
117
 
118
+ space_duid = d.pop("spaceDuid")
119
+
113
120
  kind = FolderKind(d.pop("kind"))
114
121
 
115
122
  accessible_by_team = d.pop("accessibleByTeam")
@@ -132,6 +139,7 @@ class Folder:
132
139
 
133
140
  folder = cls(
134
141
  duid=duid,
142
+ space_duid=space_duid,
135
143
  kind=kind,
136
144
  accessible_by_team=accessible_by_team,
137
145
  accessible_by_user_duids=accessible_by_user_duids,
@@ -4,6 +4,7 @@ from attrs import define as _attrs_define
4
4
  from attrs import field as _attrs_field
5
5
 
6
6
  from ..models.color_name import ColorName
7
+ from ..models.folder_kind import FolderKind
7
8
  from ..models.icon_kind import IconKind
8
9
  from ..types import UNSET, Unset
9
10
 
@@ -15,7 +16,11 @@ class FolderCreate:
15
16
  """
16
17
  Attributes:
17
18
  duid (str):
19
+ space_duid (str):
18
20
  order (str):
21
+ kind (Union[Unset, FolderKind]): * `Other` - OTHER
22
+ * `Default` - DEFAULT
23
+ * `Reports` - REPORTS
19
24
  accessible_by_team (Union[Unset, bool]):
20
25
  accessible_by_user_duids (Union[Unset, List[str]]):
21
26
  title (Union[Unset, str]):
@@ -51,7 +56,9 @@ class FolderCreate:
51
56
  """
52
57
 
53
58
  duid: str
59
+ space_duid: str
54
60
  order: str
61
+ kind: Union[Unset, FolderKind] = UNSET
55
62
  accessible_by_team: Union[Unset, bool] = UNSET
56
63
  accessible_by_user_duids: Union[Unset, List[str]] = UNSET
57
64
  title: Union[Unset, str] = UNSET
@@ -63,7 +70,12 @@ class FolderCreate:
63
70
 
64
71
  def to_dict(self) -> Dict[str, Any]:
65
72
  duid = self.duid
73
+ space_duid = self.space_duid
66
74
  order = self.order
75
+ kind: Union[Unset, str] = UNSET
76
+ if not isinstance(self.kind, Unset):
77
+ kind = self.kind.value
78
+
67
79
  accessible_by_team = self.accessible_by_team
68
80
  accessible_by_user_duids: Union[Unset, List[str]] = UNSET
69
81
  if not isinstance(self.accessible_by_user_duids, Unset):
@@ -85,9 +97,12 @@ class FolderCreate:
85
97
  field_dict.update(
86
98
  {
87
99
  "duid": duid,
100
+ "spaceDuid": space_duid,
88
101
  "order": order,
89
102
  }
90
103
  )
104
+ if kind is not UNSET:
105
+ field_dict["kind"] = kind
91
106
  if accessible_by_team is not UNSET:
92
107
  field_dict["accessibleByTeam"] = accessible_by_team
93
108
  if accessible_by_user_duids is not UNSET:
@@ -110,8 +125,17 @@ class FolderCreate:
110
125
  d = src_dict.copy()
111
126
  duid = d.pop("duid")
112
127
 
128
+ space_duid = d.pop("spaceDuid")
129
+
113
130
  order = d.pop("order")
114
131
 
132
+ _kind = d.pop("kind", UNSET)
133
+ kind: Union[Unset, FolderKind]
134
+ if isinstance(_kind, Unset):
135
+ kind = UNSET
136
+ else:
137
+ kind = FolderKind(_kind)
138
+
115
139
  accessible_by_team = d.pop("accessibleByTeam", UNSET)
116
140
 
117
141
  accessible_by_user_duids = cast(List[str], d.pop("accessibleByUserDuids", UNSET))
@@ -138,7 +162,9 @@ class FolderCreate:
138
162
 
139
163
  folder_create = cls(
140
164
  duid=duid,
165
+ space_duid=space_duid,
141
166
  order=order,
167
+ kind=kind,
142
168
  accessible_by_team=accessible_by_team,
143
169
  accessible_by_user_duids=accessible_by_user_duids,
144
170
  title=title,
@@ -4,6 +4,7 @@ from enum import Enum
4
4
  class FolderKind(str, Enum):
5
5
  DEFAULT = "Default"
6
6
  OTHER = "Other"
7
+ REPORTS = "Reports"
7
8
 
8
9
  def __str__(self) -> str:
9
10
  return str(self.value)
@@ -4,6 +4,7 @@ from attrs import define as _attrs_define
4
4
  from attrs import field as _attrs_field
5
5
 
6
6
  from ..models.color_name import ColorName
7
+ from ..models.folder_kind import FolderKind
7
8
  from ..models.icon_kind import IconKind
8
9
  from ..types import UNSET, Unset
9
10
 
@@ -15,6 +16,10 @@ class FolderUpdate:
15
16
  """
16
17
  Attributes:
17
18
  duid (str):
19
+ space_duid (Union[Unset, str]):
20
+ kind (Union[Unset, FolderKind]): * `Other` - OTHER
21
+ * `Default` - DEFAULT
22
+ * `Reports` - REPORTS
18
23
  accessible_by_team (Union[Unset, bool]):
19
24
  accessible_by_user_duids (Union[Unset, List[str]]):
20
25
  order (Union[Unset, str]):
@@ -51,6 +56,8 @@ class FolderUpdate:
51
56
  """
52
57
 
53
58
  duid: str
59
+ space_duid: Union[Unset, str] = UNSET
60
+ kind: Union[Unset, FolderKind] = UNSET
54
61
  accessible_by_team: Union[Unset, bool] = UNSET
55
62
  accessible_by_user_duids: Union[Unset, List[str]] = UNSET
56
63
  order: Union[Unset, str] = UNSET
@@ -63,6 +70,11 @@ class FolderUpdate:
63
70
 
64
71
  def to_dict(self) -> Dict[str, Any]:
65
72
  duid = self.duid
73
+ space_duid = self.space_duid
74
+ kind: Union[Unset, str] = UNSET
75
+ if not isinstance(self.kind, Unset):
76
+ kind = self.kind.value
77
+
66
78
  accessible_by_team = self.accessible_by_team
67
79
  accessible_by_user_duids: Union[Unset, List[str]] = UNSET
68
80
  if not isinstance(self.accessible_by_user_duids, Unset):
@@ -87,6 +99,10 @@ class FolderUpdate:
87
99
  "duid": duid,
88
100
  }
89
101
  )
102
+ if space_duid is not UNSET:
103
+ field_dict["spaceDuid"] = space_duid
104
+ if kind is not UNSET:
105
+ field_dict["kind"] = kind
90
106
  if accessible_by_team is not UNSET:
91
107
  field_dict["accessibleByTeam"] = accessible_by_team
92
108
  if accessible_by_user_duids is not UNSET:
@@ -111,6 +127,15 @@ class FolderUpdate:
111
127
  d = src_dict.copy()
112
128
  duid = d.pop("duid")
113
129
 
130
+ space_duid = d.pop("spaceDuid", UNSET)
131
+
132
+ _kind = d.pop("kind", UNSET)
133
+ kind: Union[Unset, FolderKind]
134
+ if isinstance(_kind, Unset):
135
+ kind = UNSET
136
+ else:
137
+ kind = FolderKind(_kind)
138
+
114
139
  accessible_by_team = d.pop("accessibleByTeam", UNSET)
115
140
 
116
141
  accessible_by_user_duids = cast(List[str], d.pop("accessibleByUserDuids", UNSET))
@@ -139,6 +164,8 @@ class FolderUpdate:
139
164
 
140
165
  folder_update = cls(
141
166
  duid=duid,
167
+ space_duid=space_duid,
168
+ kind=kind,
142
169
  accessible_by_team=accessible_by_team,
143
170
  accessible_by_user_duids=accessible_by_user_duids,
144
171
  order=order,
@@ -62,6 +62,7 @@ class User:
62
62
  is_admin (bool):
63
63
  updated_by_client_duid (Union[Unset, None, str]):
64
64
  image_url (Optional[str]):
65
+ auth_token (Optional[str]):
65
66
  google_data (Optional[GoogleData]):
66
67
  """
67
68
 
@@ -75,6 +76,7 @@ class User:
75
76
  color_name: ColorName
76
77
  is_admin: bool
77
78
  image_url: Optional[str]
79
+ auth_token: Optional[str]
78
80
  google_data: Optional["GoogleData"]
79
81
  updated_by_client_duid: Union[Unset, None, str] = UNSET
80
82
  additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -95,6 +97,7 @@ class User:
95
97
  is_admin = self.is_admin
96
98
  updated_by_client_duid = self.updated_by_client_duid
97
99
  image_url = self.image_url
100
+ auth_token = self.auth_token
98
101
  google_data = self.google_data.to_dict() if self.google_data else None
99
102
 
100
103
  field_dict: Dict[str, Any] = {}
@@ -111,6 +114,7 @@ class User:
111
114
  "colorName": color_name,
112
115
  "isAdmin": is_admin,
113
116
  "imageUrl": image_url,
117
+ "authToken": auth_token,
114
118
  "googleData": google_data,
115
119
  }
116
120
  )
@@ -146,6 +150,8 @@ class User:
146
150
 
147
151
  image_url = d.pop("imageUrl")
148
152
 
153
+ auth_token = d.pop("authToken")
154
+
149
155
  _google_data = d.pop("googleData")
150
156
  google_data: Optional[GoogleData]
151
157
  if _google_data is None:
@@ -165,6 +171,7 @@ class User:
165
171
  is_admin=is_admin,
166
172
  updated_by_client_duid=updated_by_client_duid,
167
173
  image_url=image_url,
174
+ auth_token=auth_token,
168
175
  google_data=google_data,
169
176
  )
170
177
 
@@ -48,9 +48,11 @@ def _get_orders_between_recursive(start: str, end: str, count: int):
48
48
 
49
49
 
50
50
  def get_orders_between(start: str | None, end: str | None, count: int = 1):
51
- if count <= 0 or (bool(start) and bool(end) and start >= end):
51
+ if count <= 0:
52
+ return []
53
+ if bool(start) and bool(end) and start >= end:
52
54
  print(f"invalid request for {count} values between {start} and {end}")
53
- return [start or ""] * count
55
+ return [start] * count
54
56
  return [
55
57
  e + _make_order_suffix()
56
58
  for e in _get_orders_between_recursive(start or "", end or "", count)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dart-tools
3
- Version: 0.4.8
3
+ Version: 0.5.0
4
4
  Summary: The Dart CLI and Python Library
5
5
  Author-email: Dart Software Team <software@itsdart.com>
6
6
  License: MIT License
@@ -79,7 +79,7 @@ pip install dart-tools
79
79
 
80
80
  ## Using the CLI
81
81
 
82
- As an example, start off by logging in with
82
+ Start off by setting up authentication with
83
83
  ```bash
84
84
  dart login
85
85
  ```
@@ -101,14 +101,15 @@ This command will mark the referenced task 'Done'. Here `[DUID]` is meant to be
101
101
 
102
102
  ## Using the Python Library
103
103
 
104
- In Python, you can run something like
104
+ First, set up authentication. Run `dart login` in the terminal for an interactive process, or visit [your Dart profile](https://app.itsdart.com/?settings=profile) and then run `dart.login(token)` or save the token into the `DART_TOKEN` environment variable.
105
+
106
+ Then, you can run something like
105
107
  ```python
106
108
  import os
107
- from dart import is_logged_in, login, create_task, update_task
109
+ from dart import create_task, is_logged_in, update_task
108
110
 
109
- # Login based on information stored in environment variables, but only if needed
110
- if not is_logged_in():
111
- login(email=os.environ["DART_EMAIL"], password=os.environ["DART_PASSWORD"])
111
+ # Check that auth is set up and stop if not, can remove this once everything is set up
112
+ is_logged_in(should_raise=True)
112
113
 
113
114
  # Create a new task called 'Update the landing page'
114
115
  # With priority 'Critical' (i.e. p0) and with the 'marketing' tag
@@ -1,3 +1,4 @@
1
1
  dateparser
2
2
  pick
3
3
  requests
4
+ platformdirs
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dart-tools"
3
- version = "0.4.8"
3
+ version = "0.5.0"
4
4
  description = "The Dart CLI and Python Library"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.8"
@@ -35,7 +35,8 @@ classifiers=[
35
35
  dependencies = [
36
36
  "dateparser",
37
37
  "pick",
38
- "requests"
38
+ "requests",
39
+ "platformdirs"
39
40
  ]
40
41
 
41
42
  [project.urls]
File without changes
File without changes
File without changes