targetprocess-py 0.1.0__tar.gz → 0.2.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 (231) hide show
  1. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.coderabbit.yaml +8 -5
  2. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.env.example +4 -0
  3. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/dependabot.yml +10 -2
  4. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/workflows/ci.yml +4 -4
  5. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/workflows/commit-message.yml +1 -1
  6. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/workflows/release.yml +1 -1
  7. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.pre-commit-config.yaml +1 -1
  8. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/CHANGELOG.md +67 -1
  9. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/CONTRIBUTING.md +108 -16
  10. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/PKG-INFO +30 -12
  11. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/README.md +28 -10
  12. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/SECURITY.md +2 -1
  13. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/SPEC.md +134 -90
  14. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/docs/USAGE.md +338 -4
  15. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/docs/testing.md +16 -5
  16. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/examples/README.md +11 -10
  17. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/examples/bulk_updates.py +25 -15
  18. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/examples/create_bug.py +25 -16
  19. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/pyproject.toml +1 -1
  20. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/scripts/check_internal_refs.py +8 -32
  21. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/scripts/live_smoke.py +1 -1
  22. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/__init__.py +10 -2
  23. targetprocess_py-0.2.0/src/targetprocess/exceptions.py +272 -0
  24. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/request_handler.py +92 -6
  25. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/__init__.py +2 -0
  26. targetprocess_py-0.2.0/src/targetprocess/resources/_verify.py +209 -0
  27. targetprocess_py-0.2.0/src/targetprocess/resources/assignables.py +351 -0
  28. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/base.py +378 -10
  29. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/bugs.py +6 -2
  30. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/entities.py +42 -2
  31. targetprocess_py-0.2.0/src/targetprocess/resources/entity_states.py +129 -0
  32. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/epics.py +6 -2
  33. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/features.py +6 -2
  34. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/relation_types.py +1 -1
  35. targetprocess_py-0.2.0/src/targetprocess/resources/relations.py +36 -0
  36. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/requests.py +6 -2
  37. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/tasks.py +6 -2
  38. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/user_stories.py +6 -2
  39. targetprocess_py-0.2.0/src/targetprocess/resources/users.py +81 -0
  40. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/types.py +37 -0
  41. targetprocess_py-0.2.0/tests/integration/cassettes/test_live_readonly/test_entity_states_scoped_to_a_workflow.yaml +373 -0
  42. targetprocess_py-0.2.0/tests/integration/cassettes/test_live_readonly/test_logged_user_resolves_the_acting_user.yaml +89 -0
  43. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite/test_bulk_create_and_update_tasks_under_a_story.yaml +3 -3
  44. targetprocess_py-0.2.0/tests/integration/cassettes/test_live_readwrite/test_custom_field_set_and_clear_round_trip.yaml +641 -0
  45. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite/test_request_create_update_delete_round_trip.yaml +2 -2
  46. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite/test_user_story_create_update_delete_round_trip.yaml +2 -2
  47. targetprocess_py-0.2.0/tests/integration/cassettes/test_live_readwrite/test_verified_update_returns_the_re_read.yaml +533 -0
  48. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite_surfaces/test_assignment_create_and_delete.yaml +1 -1
  49. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite_surfaces/test_attachment_upload_list_download_and_delete.yaml +3 -3
  50. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite_surfaces/test_comment_create_update_delete_round_trip.yaml +3 -3
  51. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite_surfaces/test_relation_create_and_delete.yaml +2 -2
  52. targetprocess_py-0.2.0/tests/integration/cassettes/test_live_readwrite_surfaces/test_relation_inbound_outbound_create_and_filter.yaml +895 -0
  53. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite_surfaces/test_role_effort_create_update_delete_round_trip.yaml +1 -1
  54. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readwrite_surfaces/test_team_assignment_create_and_delete.yaml +1 -1
  55. targetprocess_py-0.2.0/tests/integration/cassettes/test_live_readwrite_surfaces/test_two_level_advance_moves_both_levels.yaml +2060 -0
  56. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/conftest.py +87 -11
  57. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/test_live_readonly.py +47 -0
  58. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/test_live_readwrite.py +126 -9
  59. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/test_live_readwrite_surfaces.py +170 -8
  60. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_cassette_guard.py +56 -0
  61. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_cassette_sanitiser.py +222 -1
  62. targetprocess_py-0.2.0/tests/test_exceptions.py +297 -0
  63. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_internal_refs.py +13 -11
  64. targetprocess_py-0.2.0/tests/test_query_parameters.py +120 -0
  65. targetprocess_py-0.2.0/tests/test_request_handler_logged_user.py +59 -0
  66. targetprocess_py-0.2.0/tests/test_resources/test_assignable_state.py +468 -0
  67. targetprocess_py-0.2.0/tests/test_resources/test_custom_field_writes.py +152 -0
  68. targetprocess_py-0.2.0/tests/test_resources/test_entity_states.py +201 -0
  69. targetprocess_py-0.2.0/tests/test_resources/test_ignored_filter_paths.py +257 -0
  70. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_relations.py +32 -0
  71. targetprocess_py-0.2.0/tests/test_resources/test_users.py +165 -0
  72. targetprocess_py-0.2.0/tests/test_resources/test_verified_writes.py +606 -0
  73. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/uv.lock +21 -21
  74. targetprocess_py-0.1.0/src/targetprocess/exceptions.py +0 -147
  75. targetprocess_py-0.1.0/src/targetprocess/resources/entity_states.py +0 -20
  76. targetprocess_py-0.1.0/src/targetprocess/resources/relations.py +0 -34
  77. targetprocess_py-0.1.0/src/targetprocess/resources/users.py +0 -20
  78. targetprocess_py-0.1.0/tests/test_exceptions.py +0 -124
  79. targetprocess_py-0.1.0/tests/test_resources/test_entity_states.py +0 -39
  80. targetprocess_py-0.1.0/tests/test_resources/test_users.py +0 -39
  81. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.commitlintrc.json +0 -0
  82. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  83. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  84. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  85. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/labels.yml +0 -0
  86. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.github/pull_request_template.md +0 -0
  87. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.gitignore +0 -0
  88. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.jscpd.json +0 -0
  89. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.python-version +0 -0
  90. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/.tool-versions +0 -0
  91. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/CODEOWNERS +0 -0
  92. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/CODE_OF_CONDUCT.md +0 -0
  93. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/LICENSE +0 -0
  94. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/examples/list_user_stories.py +0 -0
  95. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/examples/readonly_reporting.py +0 -0
  96. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/scripts/apply_labels.sh +0 -0
  97. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/scripts/check_commit_message.py +0 -0
  98. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/scripts/check_large_files.py +0 -0
  99. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/scripts/check_model_coverage.py +0 -0
  100. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/scripts/check_todos.py +0 -0
  101. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_assignables.py +0 -0
  102. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_base.py +0 -0
  103. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_content.py +0 -0
  104. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_dates.py +0 -0
  105. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_entity_types.py +0 -0
  106. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_generals.py +0 -0
  107. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_joins.py +0 -0
  108. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_lookups.py +0 -0
  109. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_nested.py +0 -0
  110. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/_observability.py +0 -0
  111. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/client.py +0 -0
  112. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/models.py +0 -0
  113. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/py.typed +0 -0
  114. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/assignments.py +0 -0
  115. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/attachments.py +0 -0
  116. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/comments.py +0 -0
  117. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/custom_activities.py +0 -0
  118. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/custom_fields.py +0 -0
  119. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/custom_rules.py +0 -0
  120. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/entity_types.py +0 -0
  121. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/iterations.py +0 -0
  122. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/priorities.py +0 -0
  123. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/processes.py +0 -0
  124. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/projects.py +0 -0
  125. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/releases.py +0 -0
  126. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/role_efforts.py +0 -0
  127. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/roles.py +0 -0
  128. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/severities.py +0 -0
  129. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/team_assignments.py +0 -0
  130. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/team_iterations.py +0 -0
  131. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/teams.py +0 -0
  132. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/terms.py +0 -0
  133. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/test_cases.py +0 -0
  134. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/times.py +0 -0
  135. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/resources/workflows.py +0 -0
  136. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/response_parser.py +0 -0
  137. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/src/targetprocess/transport.py +0 -0
  138. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/__init__.py +0 -0
  139. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/_support/__init__.py +0 -0
  140. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/_support/request_handler.py +0 -0
  141. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/conftest.py +0 -0
  142. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/__init__.py +0 -0
  143. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readonly/test_entity_types_catalogue_parses.yaml +0 -0
  144. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readonly/test_find_for_day_matches_a_real_entry.yaml +0 -0
  145. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readonly/test_generic_entities_comment.yaml +0 -0
  146. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readonly/test_get_single_with_include.yaml +0 -0
  147. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readonly/test_list_user_stories_parses.yaml +0 -0
  148. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readonly/test_pagination_crosses_page_boundary.yaml +0 -0
  149. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readonly/test_priorities_scoped_to_an_entity_type.yaml +0 -0
  150. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/integration/cassettes/test_live_readonly/test_severities_rank_the_bug_set.yaml +0 -0
  151. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/live_payloads.py +0 -0
  152. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_assignment.py +0 -0
  153. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_attachment.py +0 -0
  154. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_bug.py +0 -0
  155. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_client.py +0 -0
  156. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_comment.py +0 -0
  157. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_commit_message.py +0 -0
  158. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_custom_activity.py +0 -0
  159. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_custom_field.py +0 -0
  160. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_custom_field_value.py +0 -0
  161. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_custom_rule.py +0 -0
  162. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_entity_extras.py +0 -0
  163. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_entity_ref.py +0 -0
  164. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_entity_state.py +0 -0
  165. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_entity_type.py +0 -0
  166. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_epic.py +0 -0
  167. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_feature.py +0 -0
  168. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_integration_request_response.py +0 -0
  169. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_iteration.py +0 -0
  170. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_model_field_coverage.py +0 -0
  171. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_models.py +0 -0
  172. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_observability.py +0 -0
  173. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_priority.py +0 -0
  174. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_process.py +0 -0
  175. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_project.py +0 -0
  176. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_relation.py +0 -0
  177. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_relation_type.py +0 -0
  178. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_release.py +0 -0
  179. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_request.py +0 -0
  180. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_request_handler.py +0 -0
  181. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_request_handler_bulk.py +0 -0
  182. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_assignments.py +0 -0
  183. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_attachments.py +0 -0
  184. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_base_resource.py +0 -0
  185. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_bugs.py +0 -0
  186. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_comments.py +0 -0
  187. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_custom_activities.py +0 -0
  188. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_custom_fields.py +0 -0
  189. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_custom_rules.py +0 -0
  190. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_entities.py +0 -0
  191. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_entity_types.py +0 -0
  192. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_epics.py +0 -0
  193. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_features.py +0 -0
  194. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_iterations.py +0 -0
  195. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_lookup_resolvers.py +0 -0
  196. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_priorities.py +0 -0
  197. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_processes.py +0 -0
  198. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_projects.py +0 -0
  199. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_relation_types.py +0 -0
  200. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_releases.py +0 -0
  201. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_requests.py +0 -0
  202. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_role_efforts.py +0 -0
  203. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_roles.py +0 -0
  204. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_server_capability.py +0 -0
  205. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_severities.py +0 -0
  206. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_tasks.py +0 -0
  207. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_team_assignments.py +0 -0
  208. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_team_iterations.py +0 -0
  209. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_teams.py +0 -0
  210. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_terms.py +0 -0
  211. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_test_cases.py +0 -0
  212. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_times.py +0 -0
  213. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_user_stories.py +0 -0
  214. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_resources/test_workflows.py +0 -0
  215. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_response_parser.py +0 -0
  216. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_role.py +0 -0
  217. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_role_effort.py +0 -0
  218. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_severity.py +0 -0
  219. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_task.py +0 -0
  220. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_team.py +0 -0
  221. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_team_assignment.py +0 -0
  222. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_team_iteration.py +0 -0
  223. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_term.py +0 -0
  224. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_test_case.py +0 -0
  225. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_time.py +0 -0
  226. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_transport.py +0 -0
  227. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_types.py +0 -0
  228. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_uploaded_attachment.py +0 -0
  229. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_user.py +0 -0
  230. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_user_story.py +0 -0
  231. {targetprocess_py-0.1.0 → targetprocess_py-0.2.0}/tests/test_workflow.py +0 -0
@@ -124,11 +124,14 @@ reviews:
124
124
  Items/Next/Prev envelope — are kept as recorded so a cassette still
125
125
  exercises real parsing, pagination and filter behaviour
126
126
  (docs/testing.md). On a write-path cassette the REQUEST body is
127
- recorded as sent and is deliberately not field-scrubbed: its
128
- Name/Description values are synthetic strings the test invented,
129
- carrying the recording ticket's reference as a prefix, and must NOT
130
- be flagged. Do flag a request body carrying text that reads as
131
- having come off the live instance rather than being invented.
127
+ recorded as sent and is deliberately not field-scrubbed, save the Name
128
+ of each CustomFields entry (in one entity, or every item of a bulk
129
+ array), which is the tenant's configuration and is scrubbed to the
130
+ "Sanitised Name" placeholder as every Name in a response body is: its
131
+ other Name/Description values are synthetic strings the test invented,
132
+ carrying the module's recording prefix, and must NOT be flagged. Do
133
+ flag a request body carrying text that reads as having come off the
134
+ live instance rather than being invented.
132
135
  - path: ".github/workflows/**"
133
136
  instructions: |
134
137
  GitHub Actions CI — high blast radius. Validation jobs run on pull
@@ -11,6 +11,10 @@ TP_DOMAIN=example.tpondemand.com
11
11
  # Fetch it from your TP instance's account settings; never share or commit it.
12
12
  TP_TOKEN=your-api-token
13
13
 
14
+ # The project the write examples target when --project-id is not given. Set it
15
+ # to a throwaway/sandbox project on your own instance; never production.
16
+ TP_SANDBOX_PROJECT_ID=
17
+
14
18
  # Comma-separated allow-list of project ids the write examples may modify.
15
19
  # Only set this for a throwaway/sandbox project; never production.
16
20
  # Required by examples/create_bug.py and examples/bulk_updates.py.
@@ -17,6 +17,14 @@
17
17
  # mypy --strict, pytest with --cov-fail-under=90, the pre-commit hook suite,
18
18
  # duplication detection, CodeQL, CodeRabbit review) decide whether a bump is safe
19
19
  # before it reaches main.
20
+ #
21
+ # Every commit-message prefix below (prefix and prefix-development alike) must
22
+ # be a type the commit-msg hooks accept — the type-enum in .commitlintrc.json,
23
+ # enforced by conventional-pre-commit — because CI lints each pull request's
24
+ # title as a commit message and squash merge makes that title the commit on
25
+ # main, so a prefix outside that set leaves every update from that ecosystem
26
+ # unmergeable. The uv ecosystem uses build; pre-commit and github-actions both
27
+ # use ci.
20
28
  version: 2
21
29
 
22
30
  updates:
@@ -42,8 +50,8 @@ updates:
42
50
  labels:
43
51
  - "dependencies"
44
52
  commit-message:
45
- prefix: "deps"
46
- prefix-development: "deps-dev"
53
+ prefix: "build"
54
+ prefix-development: "build"
47
55
  include: "scope"
48
56
  groups:
49
57
  # Test/lint/type tooling moves together: a mypy or ruff bump is judged by
@@ -22,7 +22,7 @@ jobs:
22
22
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
23
  with:
24
24
  persist-credentials: false
25
- - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
25
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
26
26
  with:
27
27
  python-version: ${{ matrix.python-version }}
28
28
  - run: uv sync --all-extras
@@ -45,7 +45,7 @@ jobs:
45
45
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
46
46
  with:
47
47
  persist-credentials: false
48
- - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
48
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
49
49
  - run: uv sync --all-extras
50
50
  - run: uv run pre-commit run --all-files --hook-stage pre-commit --show-diff-on-failure
51
51
  - run: uv run pre-commit run --all-files --hook-stage pre-push --show-diff-on-failure
@@ -80,7 +80,7 @@ jobs:
80
80
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
81
81
  with:
82
82
  persist-credentials: false
83
- - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
83
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
84
84
  - run: uv export --all-extras --no-emit-project --format requirements-txt --quiet -o requirements-audit.txt
85
85
  - run: uvx pip-audit --strict --no-deps --disable-pip --progress-spinner off -r requirements-audit.txt
86
86
 
@@ -95,7 +95,7 @@ jobs:
95
95
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
96
96
  with:
97
97
  persist-credentials: false
98
- - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
98
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
99
99
  - run: uv build
100
100
  - run: uvx twine==7.0.0 check --strict dist/*
101
101
  - name: Smoke-test the built wheel in a clean environment
@@ -22,7 +22,7 @@ jobs:
22
22
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
23
  with:
24
24
  persist-credentials: false
25
- - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
25
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
26
26
  - run: uv sync --all-extras
27
27
  - name: Check the pull request title as a commit message
28
28
  run: |
@@ -42,7 +42,7 @@ jobs:
42
42
  # before building it.
43
43
  - name: Assert the tagged commit is on main
44
44
  run: git merge-base --is-ancestor "$GITHUB_SHA" origin/main
45
- - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
45
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
46
46
  - run: uv build
47
47
  - run: uvx twine==7.0.0 check --strict dist/*
48
48
  # The version is read from the package, not the tag (see
@@ -82,7 +82,7 @@ repos:
82
82
  # line above sets up; CI runs the same two over a pull request's title,
83
83
  # since squash merge makes the title the commit on main.
84
84
  - repo: https://github.com/compilerla/conventional-pre-commit
85
- rev: v4.3.0
85
+ rev: v4.4.0
86
86
  hooks:
87
87
  - id: conventional-pre-commit
88
88
  name: commit message follows Conventional Commits
@@ -7,6 +7,71 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2026-09-17
11
+
12
+ The first beta release.
13
+
14
+ ### Added
15
+
16
+ - `users.logged_user()`: resolves the user the client's credential
17
+ authenticates as with one `GET /api/v1/Users/LoggedUser`, returning the
18
+ `User` model, cached per client instance. `RequestHandler.logged_user()` is
19
+ the fixed-path read beneath it.
20
+ - `update()` and `update_many()` take an opt-in, keyword-only `verify=True`:
21
+ after the write each entity is re-read with one independent GET narrowed to
22
+ the requested keys, the re-read model is returned instead of TargetProcess's
23
+ own echo, and a requested field that is not observed raises the new
24
+ `VerificationError`, which carries every mismatch and survives a pickle
25
+ round trip. A verified write refuses, before sending, a `CustomFields` entry
26
+ that is not a mapping with a string `Name`. The default path is unchanged.
27
+ - `set_custom_field(id, name, value)` on every typed manager sets a
28
+ custom-field value by name, or clears it when `value` is `None`, sending
29
+ `{"CustomFields": [{"Name": ..., "Value": ...}]}`. It re-reads the entity by
30
+ default and raises `VerificationError` when the value, or the clear, did not
31
+ land, or no field of that name came back.
32
+ - `entity_states.for_workflow(workflow_id)`, `entity_states.resolve(name, *,
33
+ workflow_id)` and `entity_states.final_states(workflow_id)`: the states of
34
+ one workflow, a state name resolved within that workflow (raising
35
+ `NotFoundError` or `AmbiguousMatchError` rather than guessing), and the
36
+ workflow's final states.
37
+ - `entity_state_levels(id)` and `advance_state(id, *, to, team_to=None,
38
+ verify=True)` on the six work-item managers, through their new shared base
39
+ `AssignableResource`: a work item's project-workflow and team-workflow
40
+ entity states read together as `StateLevels` (of two `LevelState`s), and
41
+ moved as one transition - each target resolved within its own level's
42
+ workflow, one write where both levels share a workflow, and the new
43
+ `SplitTransitionError`, which survives a pickle round trip, raised before
44
+ any write when a distinct team level would be left behind.
45
+
46
+ ### Changed
47
+
48
+ - Development status moves from Alpha to Beta (the
49
+ `Development Status :: 4 - Beta` classifier), and the README states what
50
+ 1.0.0 requires.
51
+ - `list()` refuses, before any request is sent, a `where=` filter naming a
52
+ nested collection path TargetProcess accepts and silently ignores -
53
+ currently `Assignments.*` on the assignable collections (`UserStory`,
54
+ `Bug`, `Task`, `Feature`, `Epic`, `Request`, and `Assignable` through
55
+ `entities`), which answer HTTP 200 with the unfiltered rows. The
56
+ `ValueError` names the join-entity route: query `assignments` by
57
+ `GeneralUser.Id`.
58
+ - Every query-parameter name the request handler puts on an entity-API
59
+ request is declared in one allowlist (`QUERY_PARAMETERS`), and a name
60
+ outside it is refused before the request is built rather than sent for
61
+ TargetProcess to ignore. The `access_token` the transport merges in at
62
+ send time is not part of the allowlist.
63
+ - The relation examples in the `relations` and `relation_types` docstrings,
64
+ and the relations read in `scripts/live_smoke.py`, use the current
65
+ `Inbound`/`Outbound` names in place of the deprecated `Master`/`Slave`: the
66
+ create, the `Outbound.Id` filter and the include.
67
+
68
+ ### Fixed
69
+
70
+ - `ReadOnlyViolation` raised with an operation and a resource now survives a
71
+ pickle round trip with its message and attributes; it used to come back
72
+ with the generic readonly-mode message. Every library exception now pickles
73
+ through one mechanism on `TargetProcessError`.
74
+
10
75
  ## [0.1.0] - 2026-09-08
11
76
 
12
77
  The first public release.
@@ -97,5 +162,6 @@ The first public release.
97
162
  - Log scrubbing redacts the `access_token` query parameter and `Authorization`
98
163
  header values from the library's own log records.
99
164
 
100
- [Unreleased]: https://github.com/man8/targetprocess-py/compare/v0.1.0...HEAD
165
+ [Unreleased]: https://github.com/man8/targetprocess-py/compare/v0.2.0...HEAD
166
+ [0.2.0]: https://github.com/man8/targetprocess-py/compare/v0.1.0...v0.2.0
101
167
  [0.1.0]: https://github.com/man8/targetprocess-py/releases/tag/v0.1.0
@@ -22,15 +22,16 @@ unacceptable behaviour to louis@man8.com.
22
22
 
23
23
  ## Development setup
24
24
 
25
- Requires [uv](https://docs.astral.sh/uv/). `.python-version` pins the
26
- development interpreter (3.13); the library itself supports 3.12 and 3.13, and
27
- CI runs the test suite on both.
25
+ Requires [uv](https://docs.astral.sh/uv/). `.python-version` and
26
+ `.tool-versions` both pin the development interpreter (3.13); the library
27
+ itself supports 3.12 and 3.13 (`requires-python >=3.12` in `pyproject.toml`),
28
+ and CI runs the test suite on both.
28
29
 
29
30
  ```bash
30
31
  git clone https://github.com/man8/targetprocess-py.git
31
32
  cd targetprocess-py
32
33
  uv sync --all-extras
33
- uv run pre-commit install # installs both the pre-commit and pre-push hooks
34
+ uv run pre-commit install # installs the pre-commit, commit-msg and pre-push hooks
34
35
  ```
35
36
 
36
37
  ## Quality gates
@@ -52,17 +53,83 @@ package build run in CI.
52
53
  | Dependency vulnerabilities | `pip-audit` over the locked environment (CI) |
53
54
  | Package build | `uv build` and `twine check` (CI) |
54
55
 
55
- Also enforced: a 1000-line / 256 KiB ceiling per tracked file
56
- (`scripts/check_large_files.py`), issue references on debt markers
57
- (`scripts/check_todos.py`), no internal references in tracked files
58
- (`scripts/check_internal_refs.py`) or in commit messages
59
- (`scripts/check_commit_message.py`), a cyclomatic-complexity ceiling of 10 (ruff
60
- `C901`), and copy-paste detection above 3% (`.jscpd.json`, CI only).
56
+ Every hook that names no stage — `ruff-check`, `ruff-format`, the three
57
+ repository checks (file size, debt markers, internal references) and the
58
+ upstream `pre-commit-hooks` set (large added files, YAML and TOML validity,
59
+ merge-conflict markers, private keys, end-of-file and trailing whitespace) —
60
+ runs at both the commit and the push stage. `mypy --strict src` is pinned to
61
+ the push stage alone, being too slow to gate every commit and meaningful only
62
+ over the whole package. Ruff and mypy run through `uv run`, so the hook
63
+ versions are exactly the ones pinned in `uv.lock`, with no second pin to
64
+ drift.
65
+
66
+ Also enforced:
67
+
68
+ - A 1000-line / 256 KiB ceiling per tracked file
69
+ (`scripts/check_large_files.py`). `uv.lock` and the integration cassettes
70
+ are exempt, as generated artefacts whose size is not a design decision.
71
+ - An issue reference on every debt marker (`scripts/check_todos.py`): a
72
+ `TODO`, `FIXME`, `HACK` or `XXX` with no reference is debt nobody owns,
73
+ since it never reaches a board. Markdown is not scanned — a marker in
74
+ prose is documentation about markers, not debt in a code path.
75
+ - No internal references in tracked files (`scripts/check_internal_refs.py`)
76
+ or in commit messages (`scripts/check_commit_message.py`).
77
+ - A cyclomatic-complexity ceiling of 10 (ruff `C901`).
78
+ - Copy-paste detection above 3% duplication over Python sources
79
+ (`.jscpd.json`). Node-only tooling, so it runs in CI rather than requiring
80
+ a Node toolchain on every dev machine.
81
+
82
+ The internal-references check matches a generic shape — an upper-case key of
83
+ two to six characters, a dash, and up to six digits — rather than a list of
84
+ keys, since publishing that list would leak the very thing the check exists to
85
+ keep out. Matching is case-sensitive: lower-cased, the same shape also matches
86
+ a locked dependency version and a GUID fragment. `EXCLUDED_PREFIXES` excuses
87
+ the public standards designations that share the shape. Prose is scanned
88
+ here, unlike the debt-marker check above, because the hook runs over every
89
+ tracked text file. `ALLOWED_PATHS` permits a file by path alone — an entry
90
+ exempts references only, so a session URL or trailer is refused there too —
91
+ and it lapses as soon as the file stops carrying a reference, which
92
+ `tests/test_internal_refs.py` asserts. The commit-message hook refuses the
93
+ same shape with the same exclusions.
61
94
 
62
95
  Coverage is branch coverage over `src/`, gated at 90%. A change that drops
63
96
  coverage below the gate is not mergeable; add tests with the change rather than
64
97
  after it.
65
98
 
99
+ `.github/workflows/ci.yml` runs five job definitions — six job runs, since
100
+ `test` is a two-value matrix — on every push to `main` and every pull
101
+ request: `test` (`uv sync`, `ruff check`, `ruff format --check`,
102
+ `mypy --strict`, `pytest` with the coverage gate, over a Python 3.12/3.13
103
+ matrix with `UV_PYTHON` overriding the `.python-version` pin per leg);
104
+ `quality` (`pre-commit run --all-files` at both the `pre-commit` and
105
+ `pre-push` stages, which also proves the hook configuration itself still
106
+ works); `duplication` (jscpd); `audit` (`pip-audit` over `uv.lock` exported
107
+ with every extra and its hashes, failing the job on any known
108
+ vulnerability); and `build` (`uv build`, `twine check --strict`, and an
109
+ import of the built wheel from a clean environment).
110
+
111
+ `.github/workflows/release.yml` builds the distributions on a `v*` tag,
112
+ refuses a tag whose commit is not on `main` or whose name disagrees with the
113
+ wheel's version, and publishes to PyPI by trusted publishing (OIDC) under the
114
+ `pypi` GitHub environment. No token is stored; the environment's protection
115
+ rules are the manual gate on a publish.
116
+
117
+ One check runs outside CI, since it needs a live instance and a real token
118
+ that CI has neither of: `scripts/check_model_coverage.py` diffs each model's
119
+ declared aliases against its type's `/api/v1/{collection}/meta` and reports
120
+ coverage per model in both directions — a field TP declares that the model
121
+ does not, and a field the model declares that TP does not. It is GET-only;
122
+ `--fail-under` turns it into a gate for a caller who does have both a live
123
+ instance and a token. Three further conditions fail a run besides a coverage
124
+ shortfall: a declared field absent from `/meta`; a dead `EXCLUDED` or
125
+ `KNOWN_DEVIATIONS` entry — recorded to keep a decision visible, and stale as
126
+ soon as that decision changes; and a `/meta` body reporting no properties at
127
+ all, which is a failed measurement rather than full coverage. `--validate`
128
+ additionally fetches real records and parses them through each model — the
129
+ check `/meta` alone cannot make, since it says which properties exist and
130
+ not what TP puts in them — and a model whose sample cannot be fetched is
131
+ reported as not checked and fails the run.
132
+
66
133
  ## Tests
67
134
 
68
135
  - Unit tests live in `tests/` (one file per model, resource or component) and
@@ -104,9 +171,12 @@ after it.
104
171
  body rather than a fixture teardown a later refactor could move outside the
105
172
  cassette.
106
173
  - **Everything sent is synthetic.** `_scrub_request` neutralises the host and
107
- the token but nothing field-level, so a request body is recorded as sent:
108
- a write-path test may only send text it invented, never a value copied off
109
- the live instance.
174
+ the token but nothing field-level, save the name of each custom field in a
175
+ JSON request body (one entity, or every item of a bulk array), which is the
176
+ tenant's configuration and is scrubbed to the placeholder as every `Name` in
177
+ a response body is. So a request body is otherwise recorded as sent: a
178
+ write-path test may only send text it invented, never a value copied off the
179
+ live instance.
110
180
  - **Org-level state is read, never written.** Where a surface needs an
111
181
  existing Role, Team, RelationType or project membership, the test reads it
112
182
  live and uses it. Creating one would be a write outside the sandbox.
@@ -160,9 +230,10 @@ after it.
160
230
 
161
231
  - Ruff enforces PEP 8, pep8-naming, Google-convention docstrings on the public
162
232
  API, and the complexity ceiling. There are two documented naming exceptions:
163
- the PascalCase accessors in `models.py` (a per-file ignore in
164
- `pyproject.toml`) and the `ReadOnlyViolation` name (a `noqa` at its
165
- declaration). Add a third only with the same kind of justification.
233
+ the PascalCase accessors in `_base.py` (a per-file ignore in
234
+ `pyproject.toml`; `models.py` is the re-export surface) and the
235
+ `ReadOnlyViolation` name (a `noqa` at its declaration). Add a third only
236
+ with the same kind of justification.
166
237
  - Prose (docs, comments, docstrings) uses British English, and identifiers
167
238
  follow suit where a spelling choice exists. Field names that mirror the
168
239
  TargetProcess wire format keep TP's spelling and casing.
@@ -222,6 +293,27 @@ feat!: require an explicit mode on the client
222
293
  session that produced the change, are welcome: they say how the change was
223
294
  made.
224
295
 
296
+ ## Releasing
297
+
298
+ A release is a pull request followed by a tag.
299
+
300
+ 1. In a pull request, set `__version__` in `src/targetprocess/__init__.py`
301
+ (the only version string; the build reads it). Move the `[Unreleased]`
302
+ entries in `CHANGELOG.md` under a `## [X.Y.Z] - YYYY-MM-DD` heading dated
303
+ the release day, and update the link references at its foot. When the minor
304
+ version changes, update the supported-versions table in `SECURITY.md`. When
305
+ the development status changes, update the classifier in `pyproject.toml`
306
+ and the README's Development Status section.
307
+ 2. Once it has merged, a maintainer creates a signed, annotated tag on that
308
+ commit on `main` and pushes it:
309
+ `git tag -s vX.Y.Z -m "targetprocess-py X.Y.Z" <commit>`, then
310
+ `git push origin vX.Y.Z`.
311
+ 3. `.github/workflows/release.yml` builds and checks the distributions, then
312
+ waits for a maintainer to approve the `pypi` environment deployment. Once
313
+ approved it publishes to PyPI and creates the GitHub Release from the
314
+ version's CHANGELOG section.
315
+ 4. Confirm the new version on PyPI and its GitHub Release.
316
+
225
317
  ## Reporting a vulnerability
226
318
 
227
319
  See [SECURITY.md](SECURITY.md). Do not open a public issue for a suspected
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: targetprocess-py
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: A Python library for the TargetProcess v1 REST API
5
5
  Project-URL: Homepage, https://github.com/man8/targetprocess-py
6
6
  Project-URL: Repository, https://github.com/man8/targetprocess-py
@@ -11,7 +11,7 @@ Author-email: Louis Mandelstam <louis@man8.com>
11
11
  License: MIT
12
12
  License-File: LICENSE
13
13
  Keywords: api,async,asyncio,client,httpx,pydantic,rest,sdk,targetprocess
14
- Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Development Status :: 4 - Beta
15
15
  Classifier: Framework :: AsyncIO
16
16
  Classifier: Framework :: Pydantic :: 2
17
17
  Classifier: Intended Audience :: Developers
@@ -326,16 +326,33 @@ See [SPEC.md](SPEC.md) for the full specification, including detailed architectu
326
326
 
327
327
  ## Development Status
328
328
 
329
- **Current Status**: Alpha - core library complete
330
-
331
- - ✅ Project structure and configuration
332
- - ✅ Exception hierarchy
333
- - ✅ Client safety modes (handler-layer + resource-layer enforcement)
334
- - ✅ HTTP transport layer (access_token / Basic auth)
335
- - ✅ API request/response handling (RequestHandler + ResponseParser), retry/backoff, rate limiting
336
- - ✅ Entity models (42 model classes: the `Entity`/`NamedEntity`/`GeneralEntity`/`AssignableEntity` base chain, 6 nested shapes (`EntityRef`, `EntityTypeRef`, `UserRef`, `RefWithImportance`, `CustomFieldValue`, `CustomFieldConfig`), and 32 concrete entity types across the assignable, planning, organisational, workflow and configuration, join, supporting, and custom-field groups), each declaring its type's full `/meta` field surface
337
- - ✅ Resource managers (typed + generic)
338
- - ✅ Recorded integration test suite against a real TargetProcess instance
329
+ **Current status**: Beta. The core library is complete and tested against a
330
+ real TargetProcess instance. The public surface may still change between 0.x
331
+ minor releases; every change is recorded in [CHANGELOG.md](CHANGELOG.md).
332
+
333
+ ### What 1.0.0 requires
334
+
335
+ 1.0.0 will be released once all of the following hold:
336
+
337
+ 1. At least one comprehensive production integration is built on the library
338
+ and has been stable through the beta period.
339
+ 2. No open issue labelled `bug` remains unless explicitly deferred past 1.0.0,
340
+ and every known case where TargetProcess silently ignores all or part of a
341
+ request has been resolved: the library refuses it before sending, verifies it
342
+ after the write, or SPEC.md documents it as a limitation.
343
+ 3. The public surface is frozen: SPEC.md's Public API Surface matches
344
+ `targetprocess.__all__`, a Semantic Versioning promise for that surface is
345
+ stated, and a deprecation policy is written.
346
+ 4. Documentation and the recorded test cassettes are current: every public
347
+ resource manager is documented in [docs/USAGE.md](docs/USAGE.md), the
348
+ `KNOWN_DEVIATIONS` table in `scripts/check_model_coverage.py` has been
349
+ re-checked against a live instance, and the recorded test cassettes have no
350
+ open hygiene issues.
351
+ 5. CI tests every Python version `pyproject.toml` claims.
352
+ 6. The last beta release needed no breaking change to the public surface.
353
+ 7. The release carries the `Development Status :: 5 - Production/Stable`
354
+ classifier, a CHANGELOG section for 1.0.0, a `v1.0.0` tag on `main`, and is
355
+ published to PyPI through the release workflow.
339
356
 
340
357
  ## Requirements
341
358
 
@@ -359,6 +376,7 @@ in [`.env.example`](.env.example) (the committed template) and the
359
376
  | --- | --- |
360
377
  | `TP_DOMAIN` | TargetProcess instance domain |
361
378
  | `TP_TOKEN` | API token (sent as the `access_token` query parameter) |
379
+ | `TP_SANDBOX_PROJECT_ID` | Default target project for the write examples |
362
380
  | `TP_WRITE_ALLOWED_PROJECT_IDS` | Project id allow-list for the write examples |
363
381
 
364
382
  For local development, copy the template to `.env` (which is gitignored) and
@@ -287,16 +287,33 @@ See [SPEC.md](SPEC.md) for the full specification, including detailed architectu
287
287
 
288
288
  ## Development Status
289
289
 
290
- **Current Status**: Alpha - core library complete
291
-
292
- - ✅ Project structure and configuration
293
- - ✅ Exception hierarchy
294
- - ✅ Client safety modes (handler-layer + resource-layer enforcement)
295
- - ✅ HTTP transport layer (access_token / Basic auth)
296
- - ✅ API request/response handling (RequestHandler + ResponseParser), retry/backoff, rate limiting
297
- - ✅ Entity models (42 model classes: the `Entity`/`NamedEntity`/`GeneralEntity`/`AssignableEntity` base chain, 6 nested shapes (`EntityRef`, `EntityTypeRef`, `UserRef`, `RefWithImportance`, `CustomFieldValue`, `CustomFieldConfig`), and 32 concrete entity types across the assignable, planning, organisational, workflow and configuration, join, supporting, and custom-field groups), each declaring its type's full `/meta` field surface
298
- - ✅ Resource managers (typed + generic)
299
- - ✅ Recorded integration test suite against a real TargetProcess instance
290
+ **Current status**: Beta. The core library is complete and tested against a
291
+ real TargetProcess instance. The public surface may still change between 0.x
292
+ minor releases; every change is recorded in [CHANGELOG.md](CHANGELOG.md).
293
+
294
+ ### What 1.0.0 requires
295
+
296
+ 1.0.0 will be released once all of the following hold:
297
+
298
+ 1. At least one comprehensive production integration is built on the library
299
+ and has been stable through the beta period.
300
+ 2. No open issue labelled `bug` remains unless explicitly deferred past 1.0.0,
301
+ and every known case where TargetProcess silently ignores all or part of a
302
+ request has been resolved: the library refuses it before sending, verifies it
303
+ after the write, or SPEC.md documents it as a limitation.
304
+ 3. The public surface is frozen: SPEC.md's Public API Surface matches
305
+ `targetprocess.__all__`, a Semantic Versioning promise for that surface is
306
+ stated, and a deprecation policy is written.
307
+ 4. Documentation and the recorded test cassettes are current: every public
308
+ resource manager is documented in [docs/USAGE.md](docs/USAGE.md), the
309
+ `KNOWN_DEVIATIONS` table in `scripts/check_model_coverage.py` has been
310
+ re-checked against a live instance, and the recorded test cassettes have no
311
+ open hygiene issues.
312
+ 5. CI tests every Python version `pyproject.toml` claims.
313
+ 6. The last beta release needed no breaking change to the public surface.
314
+ 7. The release carries the `Development Status :: 5 - Production/Stable`
315
+ classifier, a CHANGELOG section for 1.0.0, a `v1.0.0` tag on `main`, and is
316
+ published to PyPI through the release workflow.
300
317
 
301
318
  ## Requirements
302
319
 
@@ -320,6 +337,7 @@ in [`.env.example`](.env.example) (the committed template) and the
320
337
  | --- | --- |
321
338
  | `TP_DOMAIN` | TargetProcess instance domain |
322
339
  | `TP_TOKEN` | API token (sent as the `access_token` query parameter) |
340
+ | `TP_SANDBOX_PROJECT_ID` | Default target project for the write examples |
323
341
  | `TP_WRITE_ALLOWED_PROJECT_IDS` | Project id allow-list for the write examples |
324
342
 
325
343
  For local development, copy the template to `.env` (which is gitignored) and
@@ -4,7 +4,8 @@
4
4
 
5
5
  | Version | Supported |
6
6
  | --- | --- |
7
- | 0.1.x | Yes |
7
+ | 0.2.x | Yes |
8
+ | 0.1.x | No |
8
9
  | Pre-release commits before 0.1.0 | No |
9
10
 
10
11
  Security fixes are released as a patch on the latest minor version. Once a new