devrev-Python-SDK 2.9.0__tar.gz → 2.10.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 (363) hide show
  1. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/PKG-INFO +11 -1
  2. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/README.md +10 -0
  3. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/articles.md +12 -0
  4. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/changelog.md +9 -0
  5. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/mcp/tools-reference.md +2 -0
  6. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/pyproject.toml +1 -1
  7. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/articles.py +34 -0
  8. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/articles.py +34 -0
  9. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_articles.py +150 -0
  10. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_articles_unified.py +163 -0
  11. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/bug-fixer.md +0 -0
  12. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/builder.md +0 -0
  13. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/documentation.md +0 -0
  14. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/foreman.md +0 -0
  15. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/pr-review-boss.md +0 -0
  16. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/release-manager.md +0 -0
  17. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/simplifier.md +0 -0
  18. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/tester.md +0 -0
  19. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/commands/foreman-work.md +0 -0
  20. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/commands/release-prepare.md +0 -0
  21. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/commands/review-start.md +0 -0
  22. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/commands/simplify-code.md +0 -0
  23. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/code-quality.md +0 -0
  24. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/data-modeling.md +0 -0
  25. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/devrev-sdk.md +0 -0
  26. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/git-workflow.md +0 -0
  27. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/pull-requests.md +0 -0
  28. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/python-development.md +0 -0
  29. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/security.md +0 -0
  30. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/testing.md +0 -0
  31. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.dockerignore +0 -0
  32. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.env.sample +0 -0
  33. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/article-artifact-simplification.md +0 -0
  34. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  35. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  36. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  37. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  38. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/dependabot.yml +0 -0
  39. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/pull_request_template.md +0 -0
  40. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/api-check.yml +0 -0
  41. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/ci.yml +0 -0
  42. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/claude-code-review.yml +0 -0
  43. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/claude.yml +0 -0
  44. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/deploy.yml +0 -0
  45. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/docs.yml +0 -0
  46. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/integration-tests.yml +0 -0
  47. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/release.yml +0 -0
  48. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/sync-openapi.yml +0 -0
  49. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.gitignore +0 -0
  50. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.pre-commit-config.yaml +0 -0
  51. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/CLAUDE.md +0 -0
  52. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/CODE_OF_CONDUCT.md +0 -0
  53. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/CONTRIBUTING.md +0 -0
  54. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/DEPRECATIONS.md +0 -0
  55. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/Dockerfile +0 -0
  56. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/KNOWN_ISSUES.md +0 -0
  57. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/OPENAPI_SPEC_DISCREPANCIES.md +0 -0
  58. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/SECURITY.md +0 -0
  59. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/augment-mcp-config-remote.json +0 -0
  60. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/augment-mcp-config.json +0 -0
  61. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/augment-settings.json +0 -0
  62. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/README.md +0 -0
  63. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/bench_http_client.py +0 -0
  64. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/bench_models.py +0 -0
  65. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/bench_pagination.py +0 -0
  66. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/conftest.py +0 -0
  67. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/context7.json +0 -0
  68. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/README.md +0 -0
  69. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/audit-logging-setup.sh +0 -0
  70. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/cloudbuild.yaml +0 -0
  71. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/monitoring/README.md +0 -0
  72. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/monitoring/alert-policies.yaml +0 -0
  73. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/monitoring/dashboard.json +0 -0
  74. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/monitoring/validate-config.sh +0 -0
  75. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/service.yaml +0 -0
  76. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docker-compose.yml +0 -0
  77. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/brands.md +0 -0
  78. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/engagements.md +0 -0
  79. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/incidents.md +0 -0
  80. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/index.md +0 -0
  81. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/question-answers.md +0 -0
  82. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/recommendations.md +0 -0
  83. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/search.md +0 -0
  84. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/uoms.md +0 -0
  85. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta-api-differences.md +0 -0
  86. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/client.md +0 -0
  87. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/config.md +0 -0
  88. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/exceptions.md +0 -0
  89. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/index.md +0 -0
  90. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/accounts.md +0 -0
  91. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/base.md +0 -0
  92. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/index.md +0 -0
  93. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/users.md +0 -0
  94. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/works.md +0 -0
  95. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/accounts.md +0 -0
  96. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/code-changes.md +0 -0
  97. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/conversations.md +0 -0
  98. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/dev-users.md +0 -0
  99. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/groups.md +0 -0
  100. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/index.md +0 -0
  101. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/links.md +0 -0
  102. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/parts.md +0 -0
  103. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/rev-users.md +0 -0
  104. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/slas.md +0 -0
  105. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/tags.md +0 -0
  106. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/timeline-entries.md +0 -0
  107. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/webhooks.md +0 -0
  108. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/works.md +0 -0
  109. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/advanced.md +0 -0
  110. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/basic.md +0 -0
  111. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/beta-features.md +0 -0
  112. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/index.md +0 -0
  113. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/integrations.md +0 -0
  114. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/getting-started/authentication.md +0 -0
  115. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/getting-started/index.md +0 -0
  116. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/getting-started/installation.md +0 -0
  117. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/getting-started/quickstart.md +0 -0
  118. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/beta-api.md +0 -0
  119. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/compatibility.md +0 -0
  120. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/configuration.md +0 -0
  121. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/error-handling.md +0 -0
  122. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/github-actions-setup.md +0 -0
  123. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/index.md +0 -0
  124. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/logging.md +0 -0
  125. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/pagination.md +0 -0
  126. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/sync-vs-async.md +0 -0
  127. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/testing.md +0 -0
  128. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/version-support.md +0 -0
  129. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/write-integration-testing-strategy.md +0 -0
  130. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/hooks/copy_llms.py +0 -0
  131. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/index.md +0 -0
  132. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/mcp/deployment.md +0 -0
  133. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/mcp/index.md +0 -0
  134. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/mcp/quickstart.md +0 -0
  135. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/stylesheets/extra.css +0 -0
  136. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/README.md +0 -0
  137. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/README.md +0 -0
  138. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/async_example.py +0 -0
  139. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/create_work.py +0 -0
  140. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/error_handling.py +0 -0
  141. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/list_accounts.py +0 -0
  142. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/pagination.py +0 -0
  143. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/search_users.py +0 -0
  144. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/README.md +0 -0
  145. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/main.py +0 -0
  146. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/requirements.txt +0 -0
  147. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/README.md +0 -0
  148. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/main.py +0 -0
  149. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/requirements.txt +0 -0
  150. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/flask/README.md +0 -0
  151. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/flask/app.py +0 -0
  152. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/flask/requirements.txt +0 -0
  153. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/llms-ctx-full.txt +0 -0
  154. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/llms-ctx.txt +0 -0
  155. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/llms-mcp.txt +0 -0
  156. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/llms.txt +0 -0
  157. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/mkdocs.yml +0 -0
  158. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/openapi-beta.yaml +0 -0
  159. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/openapi-public.yaml +0 -0
  160. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/openapi-spec-corrections.yaml +0 -0
  161. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/scripts/build_ai_docs.py +0 -0
  162. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/scripts/setup-github-secrets.sh +0 -0
  163. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/__init__.py +0 -0
  164. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/client.py +0 -0
  165. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/config.py +0 -0
  166. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/exceptions.py +0 -0
  167. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/__init__.py +0 -0
  168. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/accounts.py +0 -0
  169. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/articles.py +0 -0
  170. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/artifacts.py +0 -0
  171. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/base.py +0 -0
  172. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/brands.py +0 -0
  173. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/code_changes.py +0 -0
  174. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/conversations.py +0 -0
  175. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/dev_users.py +0 -0
  176. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/engagements.py +0 -0
  177. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/groups.py +0 -0
  178. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/incidents.py +0 -0
  179. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/links.py +0 -0
  180. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/notifications.py +0 -0
  181. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/parts.py +0 -0
  182. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/preferences.py +0 -0
  183. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/question_answers.py +0 -0
  184. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/recommendations.py +0 -0
  185. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/rev_users.py +0 -0
  186. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/search.py +0 -0
  187. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/slas.py +0 -0
  188. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/sync.py +0 -0
  189. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/tags.py +0 -0
  190. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/tasks.py +0 -0
  191. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/timeline_entries.py +0 -0
  192. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/timeline_events.py +0 -0
  193. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/track_events.py +0 -0
  194. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/uoms.py +0 -0
  195. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/webhooks.py +0 -0
  196. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/widgets.py +0 -0
  197. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/works.py +0 -0
  198. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/py.typed +0 -0
  199. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/__init__.py +0 -0
  200. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/accounts.py +0 -0
  201. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/artifacts.py +0 -0
  202. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/base.py +0 -0
  203. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/brands.py +0 -0
  204. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/code_changes.py +0 -0
  205. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/conversations.py +0 -0
  206. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/dev_users.py +0 -0
  207. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/engagements.py +0 -0
  208. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/groups.py +0 -0
  209. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/incidents.py +0 -0
  210. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/links.py +0 -0
  211. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/notifications.py +0 -0
  212. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/parts.py +0 -0
  213. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/preferences.py +0 -0
  214. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/question_answers.py +0 -0
  215. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/recommendations.py +0 -0
  216. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/rev_users.py +0 -0
  217. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/search.py +0 -0
  218. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/slas.py +0 -0
  219. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/tags.py +0 -0
  220. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/timeline_entries.py +0 -0
  221. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/track_events.py +0 -0
  222. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/uoms.py +0 -0
  223. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/webhooks.py +0 -0
  224. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/works.py +0 -0
  225. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/__init__.py +0 -0
  226. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/content_converter.py +0 -0
  227. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/deprecation.py +0 -0
  228. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/http.py +0 -0
  229. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/logging.py +0 -0
  230. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/pagination.py +0 -0
  231. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/__init__.py +0 -0
  232. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/__main__.py +0 -0
  233. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/config.py +0 -0
  234. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/__init__.py +0 -0
  235. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/audit.py +0 -0
  236. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/auth.py +0 -0
  237. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/health.py +0 -0
  238. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/rate_limit.py +0 -0
  239. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/__init__.py +0 -0
  240. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/escalation.py +0 -0
  241. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/investigate.py +0 -0
  242. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/response.py +0 -0
  243. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/summarize.py +0 -0
  244. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/triage.py +0 -0
  245. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/__init__.py +0 -0
  246. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/account.py +0 -0
  247. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/article.py +0 -0
  248. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/conversation.py +0 -0
  249. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/part.py +0 -0
  250. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/server_info.py +0 -0
  251. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/ticket.py +0 -0
  252. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/user.py +0 -0
  253. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/server.py +0 -0
  254. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/__init__.py +0 -0
  255. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/accounts.py +0 -0
  256. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/conversations.py +0 -0
  257. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/engagements.py +0 -0
  258. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/groups.py +0 -0
  259. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/incidents.py +0 -0
  260. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/links.py +0 -0
  261. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/parts.py +0 -0
  262. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/recommendations.py +0 -0
  263. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/search.py +0 -0
  264. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/server_info.py +0 -0
  265. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/slas.py +0 -0
  266. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/tags.py +0 -0
  267. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/timeline.py +0 -0
  268. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/users.py +0 -0
  269. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/works.py +0 -0
  270. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/__init__.py +0 -0
  271. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/errors.py +0 -0
  272. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/formatting.py +0 -0
  273. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/pagination.py +0 -0
  274. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/__init__.py +0 -0
  275. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/conftest.py +0 -0
  276. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/__init__.py +0 -0
  277. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/conftest.py +0 -0
  278. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_accounts_e2e.py +0 -0
  279. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_all_readonly_endpoints.py +0 -0
  280. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_articles_lifecycle.py +0 -0
  281. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_backwards_compatibility.py +0 -0
  282. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_contacts_e2e.py +0 -0
  283. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_core_services_phase1.py +0 -0
  284. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_extended_services_phase2.py +0 -0
  285. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_get_endpoints.py +0 -0
  286. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_issues_e2e.py +0 -0
  287. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_kb_articles_e2e.py +0 -0
  288. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_mcp_articles.py +0 -0
  289. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_ping.py +0 -0
  290. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_question_answers_e2e.py +0 -0
  291. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_readonly_endpoints.py +0 -0
  292. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_specialized_services_phase3.py +0 -0
  293. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_tickets_e2e.py +0 -0
  294. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_write_operations.py +0 -0
  295. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/utils/__init__.py +0 -0
  296. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/utils/cleanup.py +0 -0
  297. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/utils/constants.py +0 -0
  298. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/utils/data_manager.py +0 -0
  299. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/performance/__init__.py +0 -0
  300. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/performance/test_articles_performance.py +0 -0
  301. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/__init__.py +0 -0
  302. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/__init__.py +0 -0
  303. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/conftest.py +0 -0
  304. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_audit.py +0 -0
  305. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_config.py +0 -0
  306. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_phase4_transport.py +0 -0
  307. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_prompts.py +0 -0
  308. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_resources.py +0 -0
  309. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_server_info.py +0 -0
  310. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_accounts.py +0 -0
  311. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_conversations.py +0 -0
  312. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_engagements.py +0 -0
  313. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_groups.py +0 -0
  314. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_incidents.py +0 -0
  315. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_links.py +0 -0
  316. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_parts.py +0 -0
  317. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_recommendations.py +0 -0
  318. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_search.py +0 -0
  319. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_slas.py +0 -0
  320. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_tags.py +0 -0
  321. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_timeline.py +0 -0
  322. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_users.py +0 -0
  323. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_works.py +0 -0
  324. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_utils.py +0 -0
  325. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/models/__init__.py +0 -0
  326. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/models/test_user_state_regression.py +0 -0
  327. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/__init__.py +0 -0
  328. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/conftest.py +0 -0
  329. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_articles.py +0 -0
  330. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_async_services.py +0 -0
  331. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_brands.py +0 -0
  332. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_code_changes.py +0 -0
  333. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_conversations.py +0 -0
  334. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_engagements.py +0 -0
  335. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_groups.py +0 -0
  336. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_incidents.py +0 -0
  337. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_links.py +0 -0
  338. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_notifications.py +0 -0
  339. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_parts.py +0 -0
  340. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_preferences.py +0 -0
  341. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_question_answers.py +0 -0
  342. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_recommendations.py +0 -0
  343. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_search.py +0 -0
  344. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_slas.py +0 -0
  345. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_tags.py +0 -0
  346. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_timeline_entries.py +0 -0
  347. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_track_events.py +0 -0
  348. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_uoms.py +0 -0
  349. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_webhooks.py +0 -0
  350. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_works.py +0 -0
  351. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_artifacts.py +0 -0
  352. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_backward_compatibility.py +0 -0
  353. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_base_service.py +0 -0
  354. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_client.py +0 -0
  355. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_config.py +0 -0
  356. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_content_converter.py +0 -0
  357. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_deprecation.py +0 -0
  358. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_error_handling.py +0 -0
  359. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_exceptions.py +0 -0
  360. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_http.py +0 -0
  361. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_logging.py +0 -0
  362. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_pagination.py +0 -0
  363. {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devrev-Python-SDK
3
- Version: 2.9.0
3
+ Version: 2.10.0
4
4
  Summary: A modern, type-safe Python SDK for the DevRev API
5
5
  Project-URL: Homepage, https://github.com/mgmonteleone/py-dev-rev
6
6
  Project-URL: Documentation, https://github.com/mgmonteleone/py-dev-rev
@@ -545,6 +545,16 @@ client.articles.update_with_content(
545
545
  applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123", "don:core:dvrv-us-1:devo/1:part/456"],
546
546
  )
547
547
 
548
+ # Update access level and tags
549
+ from devrev.models.articles import ArticleAccessLevel
550
+ from devrev.models.base import SetTagWithValue
551
+
552
+ client.articles.update_with_content(
553
+ id=article.id,
554
+ access_level=ArticleAccessLevel.INTERNAL, # internal, external, private, public
555
+ tags=[SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/123")],
556
+ )
557
+
548
558
  # List published articles (metadata only)
549
559
  published = client.articles.list(limit=20)
550
560
  for article in published:
@@ -470,6 +470,16 @@ client.articles.update_with_content(
470
470
  applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123", "don:core:dvrv-us-1:devo/1:part/456"],
471
471
  )
472
472
 
473
+ # Update access level and tags
474
+ from devrev.models.articles import ArticleAccessLevel
475
+ from devrev.models.base import SetTagWithValue
476
+
477
+ client.articles.update_with_content(
478
+ id=article.id,
479
+ access_level=ArticleAccessLevel.INTERNAL, # internal, external, private, public
480
+ tags=[SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/123")],
481
+ )
482
+
473
483
  # List published articles (metadata only)
474
484
  published = client.articles.list(limit=20)
475
485
  for article in published:
@@ -94,6 +94,8 @@ article = client.articles.create_with_content(
94
94
  status=ArticleStatus.PUBLISHED, # Optional: draft, published, archived
95
95
  content_format="text/html", # Optional: default is text/html
96
96
  applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123"], # Optional: associate with parts
97
+ scope=1, # Optional: 1=internal, 2=external (API default is external)
98
+ tags=[SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/123")], # Optional: apply tags
97
99
  )
98
100
  print(f"Created article with content: {article.id}")
99
101
  ```
@@ -188,6 +190,16 @@ updated_article = client.articles.update_with_content(
188
190
  id="don:core:dvrv-us-1:devo/1:article/123",
189
191
  applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123", "don:core:dvrv-us-1:devo/1:part/456"],
190
192
  )
193
+
194
+ # Update access level and tags
195
+ from devrev.models.articles import ArticleAccessLevel
196
+ from devrev.models.base import SetTagWithValue
197
+
198
+ updated_article = client.articles.update_with_content(
199
+ id="don:core:dvrv-us-1:devo/1:article/123",
200
+ access_level=ArticleAccessLevel.INTERNAL, # Change to internal visibility
201
+ tags=[SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/123")], # Apply tags
202
+ )
191
203
  ```
192
204
 
193
205
  ### Async Usage
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.10.0] - 2026-03-09
11
+
12
+ ### Added
13
+
14
+ - **Article Scope and Tags** (#173) — Added visibility and tagging parameters to MCP article tools:
15
+ - `devrev_articles_create`: Added `scope` (1=internal, 2=external) and `tags` (list of tag IDs) parameters
16
+ - `devrev_articles_update`: Added `access_level` (internal, external, private, public) and `tags` parameters
17
+ - SDK `update_with_content`: Added `access_level` and `tags` parameters for both sync and async methods
18
+
10
19
  ## [2.9.0] - 2026-03-09
11
20
 
12
21
  ### Added
@@ -57,6 +57,8 @@ Tools are the primary way AI assistants interact with DevRev. Each tool maps to
57
57
  - **Optional Content Loading**: Use `include_content=true` in `get` to fetch article body
58
58
  - **Clear Parameters**: `content` for article body, `description` for metadata summary
59
59
  - **Part Association**: Use `applies_to_parts` to natively associate articles with products, capabilities, features, or enhancements
60
+ - **Visibility Control**: Use `scope` (1=internal, 2=external) on create or `access_level` (internal, external, private, public) on update
61
+ - **Tagging**: Apply tags using the `tags` parameter (list of tag IDs)
60
62
 
61
63
  ### Conversations
62
64
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "devrev-Python-SDK"
7
- version = "2.9.0"
7
+ version = "2.10.0"
8
8
  description = "A modern, type-safe Python SDK for the DevRev API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -9,6 +9,7 @@ from collections.abc import Sequence
9
9
  from devrev.exceptions import DevRevError
10
10
  from devrev.models.articles import (
11
11
  Article,
12
+ ArticleAccessLevel,
12
13
  ArticlesCountRequest,
13
14
  ArticlesCountResponse,
14
15
  ArticlesCreateRequest,
@@ -22,6 +23,7 @@ from devrev.models.articles import (
22
23
  ArticleStatus,
23
24
  ArticlesUpdateRequest,
24
25
  ArticlesUpdateRequestAppliesToParts,
26
+ ArticlesUpdateRequestTags,
25
27
  ArticlesUpdateResponse,
26
28
  ArticleType,
27
29
  ArticleWithContent,
@@ -439,6 +441,8 @@ class ArticlesService(BaseService):
439
441
  description: str | None = None,
440
442
  status: ArticleStatus | None = None,
441
443
  applies_to_parts: builtins.list[str] | None = None,
444
+ access_level: ArticleAccessLevel | None = None,
445
+ tags: builtins.list[SetTagWithValue] | None = None,
442
446
  ) -> Article:
443
447
  """Update article metadata and/or content.
444
448
 
@@ -454,6 +458,8 @@ class ArticlesService(BaseService):
454
458
  description: Optional new metadata description
455
459
  status: Optional new status
456
460
  applies_to_parts: Optional list of part IDs to associate with
461
+ access_level: Optional access level (internal, external, private, public)
462
+ tags: Optional list of tags to apply (list of SetTagWithValue objects)
457
463
 
458
464
  Returns:
459
465
  Updated article
@@ -487,6 +493,12 @@ class ArticlesService(BaseService):
487
493
  ... "ART-123",
488
494
  ... applies_to_parts=["don:core:...:capability/6"]
489
495
  ... )
496
+ >>>
497
+ >>> # Update access level to internal
498
+ >>> article = client.articles.update_with_content(
499
+ ... "ART-123",
500
+ ... access_level=ArticleAccessLevel.INTERNAL
501
+ ... )
490
502
  """
491
503
  if not self._parent_client:
492
504
  raise DevRevError(
@@ -503,12 +515,19 @@ class ArticlesService(BaseService):
503
515
  if applies_to_parts is not None:
504
516
  applies_to_parts_req = ArticlesUpdateRequestAppliesToParts(set=applies_to_parts)
505
517
 
518
+ # Build tags wrapper if provided
519
+ tags_req = None
520
+ if tags is not None:
521
+ tags_req = ArticlesUpdateRequestTags(set=tags)
522
+
506
523
  # Update metadata if any metadata fields provided
507
524
  has_metadata = (
508
525
  title is not None
509
526
  or description is not None
510
527
  or status is not None
511
528
  or applies_to_parts is not None
529
+ or access_level is not None
530
+ or tags is not None
512
531
  )
513
532
  if has_metadata:
514
533
  update_req = ArticlesUpdateRequest(
@@ -517,6 +536,8 @@ class ArticlesService(BaseService):
517
536
  description=description,
518
537
  status=status,
519
538
  applies_to_parts=applies_to_parts_req,
539
+ access_level=access_level,
540
+ tags=tags_req,
520
541
  )
521
542
  return self.update(update_req)
522
543
 
@@ -844,6 +865,8 @@ class AsyncArticlesService(AsyncBaseService):
844
865
  description: str | None = None,
845
866
  status: ArticleStatus | None = None,
846
867
  applies_to_parts: builtins.list[str] | None = None,
868
+ access_level: ArticleAccessLevel | None = None,
869
+ tags: builtins.list[SetTagWithValue] | None = None,
847
870
  ) -> Article:
848
871
  """Update article metadata and/or content (async).
849
872
 
@@ -859,6 +882,8 @@ class AsyncArticlesService(AsyncBaseService):
859
882
  description: Optional new metadata description
860
883
  status: Optional new status
861
884
  applies_to_parts: Optional list of part IDs to associate with
885
+ access_level: Optional access level (internal, external, private, public)
886
+ tags: Optional list of tags to apply (list of SetTagWithValue objects)
862
887
 
863
888
  Returns:
864
889
  Updated article
@@ -881,12 +906,19 @@ class AsyncArticlesService(AsyncBaseService):
881
906
  if applies_to_parts is not None:
882
907
  applies_to_parts_req = ArticlesUpdateRequestAppliesToParts(set=applies_to_parts)
883
908
 
909
+ # Build tags wrapper if provided
910
+ tags_req = None
911
+ if tags is not None:
912
+ tags_req = ArticlesUpdateRequestTags(set=tags)
913
+
884
914
  # Update metadata if any metadata fields provided
885
915
  has_metadata = (
886
916
  title is not None
887
917
  or description is not None
888
918
  or status is not None
889
919
  or applies_to_parts is not None
920
+ or access_level is not None
921
+ or tags is not None
890
922
  )
891
923
  if has_metadata:
892
924
  update_req = ArticlesUpdateRequest(
@@ -895,6 +927,8 @@ class AsyncArticlesService(AsyncBaseService):
895
927
  description=description,
896
928
  status=status,
897
929
  applies_to_parts=applies_to_parts_req,
930
+ access_level=access_level,
931
+ tags=tags_req,
898
932
  )
899
933
  return await self.update(update_req)
900
934
 
@@ -12,11 +12,13 @@ from mcp.server.fastmcp import Context
12
12
 
13
13
  from devrev.exceptions import DevRevError
14
14
  from devrev.models.articles import (
15
+ ArticleAccessLevel,
15
16
  ArticlesDeleteRequest,
16
17
  ArticlesGetRequest,
17
18
  ArticlesListRequest,
18
19
  ArticleStatus,
19
20
  )
21
+ from devrev.models.base import SetTagWithValue
20
22
  from devrev_mcp.server import _config, mcp
21
23
  from devrev_mcp.utils.errors import format_devrev_error
22
24
  from devrev_mcp.utils.formatting import serialize_model, serialize_models
@@ -103,6 +105,8 @@ if _config.enable_destructive_tools:
103
105
  status: str | None = None,
104
106
  content_format: str = "text/html",
105
107
  applies_to_parts: list[str] | None = None,
108
+ scope: int | None = None,
109
+ tags: list[str] | None = None,
106
110
  ) -> dict[str, Any]:
107
111
  """Create a new article with content.
108
112
 
@@ -116,6 +120,8 @@ if _config.enable_destructive_tools:
116
120
  content_format: Content MIME type (default: text/html).
117
121
  applies_to_parts: Optional list of part IDs (products, capabilities,
118
122
  features, enhancements) to associate the article with.
123
+ scope: Optional visibility scope (1=internal, 2=external).
124
+ tags: Optional list of tag IDs to apply to the article.
119
125
 
120
126
  Returns:
121
127
  Dictionary containing the created article details.
@@ -135,6 +141,9 @@ if _config.enable_destructive_tools:
135
141
  f"Valid statuses: {', '.join(s.name for s in ArticleStatus)}"
136
142
  ) from e
137
143
 
144
+ # Convert tag IDs to SetTagWithValue objects
145
+ tags_list = [SetTagWithValue(id=tag_id) for tag_id in tags] if tags is not None else None
146
+
138
147
  article = await app.get_client().articles.create_with_content(
139
148
  title=title,
140
149
  content=content,
@@ -143,6 +152,8 @@ if _config.enable_destructive_tools:
143
152
  status=article_status,
144
153
  content_format=content_format,
145
154
  applies_to_parts=applies_to_parts,
155
+ scope=scope,
156
+ tags=tags_list,
146
157
  )
147
158
  return serialize_model(article)
148
159
  except DevRevError as e:
@@ -157,6 +168,8 @@ if _config.enable_destructive_tools:
157
168
  description: str | None = None,
158
169
  status: str | None = None,
159
170
  applies_to_parts: list[str] | None = None,
171
+ access_level: str | None = None,
172
+ tags: list[str] | None = None,
160
173
  ) -> dict[str, Any]:
161
174
  """Update an existing article in DevRev.
162
175
 
@@ -170,6 +183,11 @@ if _config.enable_destructive_tools:
170
183
  applies_to_parts: Optional list of part IDs (products, capabilities,
171
184
  features, enhancements) to associate the article with.
172
185
  Pass an empty list to remove all associations.
186
+ access_level: Optional access level (internal, external, private, public).
187
+ Note: For updates, use ``access_level`` (string enum). For creation,
188
+ use the ``scope`` parameter (integer: 1=internal, 2=external).
189
+ tags: Optional list of tag IDs to apply to the article.
190
+ Pass an empty list to remove all tags.
173
191
 
174
192
  Returns:
175
193
  Dictionary containing the updated article details.
@@ -189,6 +207,20 @@ if _config.enable_destructive_tools:
189
207
  f"Valid statuses: {', '.join(s.name for s in ArticleStatus)}"
190
208
  ) from e
191
209
 
210
+ # Convert access_level string to ArticleAccessLevel enum
211
+ article_access_level = None
212
+ if access_level:
213
+ try:
214
+ article_access_level = ArticleAccessLevel[access_level.upper()]
215
+ except KeyError as e:
216
+ raise RuntimeError(
217
+ f"Invalid access level: {e.args[0]}. "
218
+ f"Valid levels: {', '.join(a.name for a in ArticleAccessLevel)}"
219
+ ) from e
220
+
221
+ # Convert tag IDs to SetTagWithValue objects
222
+ tags_list = [SetTagWithValue(id=tag_id) for tag_id in tags] if tags is not None else None
223
+
192
224
  article = await app.get_client().articles.update_with_content(
193
225
  id=id,
194
226
  title=title,
@@ -196,6 +228,8 @@ if _config.enable_destructive_tools:
196
228
  description=description,
197
229
  status=article_status,
198
230
  applies_to_parts=applies_to_parts,
231
+ access_level=article_access_level,
232
+ tags=tags_list,
199
233
  )
200
234
  return serialize_model(article)
201
235
  except DevRevError as e:
@@ -182,6 +182,53 @@ class TestArticlesCreateTool:
182
182
  "don:core:dvrv-us-1:devo/1:capability/2",
183
183
  ]
184
184
 
185
+ @pytest.mark.asyncio
186
+ async def test_create_with_scope(self, mock_ctx, mock_client):
187
+ """Test creating an article with scope (internal)."""
188
+ mock_article = _make_mock_article(
189
+ title="Internal Article",
190
+ description="Internal content",
191
+ )
192
+ mock_client.articles.create_with_content.return_value = mock_article
193
+
194
+ result = await devrev_articles_create(
195
+ mock_ctx,
196
+ title="Internal Article",
197
+ content="Internal content",
198
+ owned_by=["don:identity:dvrv-us-1:devo/test:devu/1"],
199
+ scope=1, # 1 = internal
200
+ )
201
+
202
+ assert result["title"] == "Internal Article"
203
+ # Verify scope was passed to SDK
204
+ call_args = mock_client.articles.create_with_content.call_args
205
+ assert call_args[1]["scope"] == 1
206
+
207
+ @pytest.mark.asyncio
208
+ async def test_create_with_tags(self, mock_ctx, mock_client):
209
+ """Test creating an article with tags."""
210
+ mock_article = _make_mock_article(
211
+ title="Tagged Article",
212
+ description="Content with tags",
213
+ )
214
+ mock_client.articles.create_with_content.return_value = mock_article
215
+
216
+ result = await devrev_articles_create(
217
+ mock_ctx,
218
+ title="Tagged Article",
219
+ content="Content with tags",
220
+ owned_by=["don:identity:dvrv-us-1:devo/test:devu/1"],
221
+ tags=["don:core:dvrv-us-1:devo/1:tag/1", "don:core:dvrv-us-1:devo/1:tag/2"],
222
+ )
223
+
224
+ assert result["title"] == "Tagged Article"
225
+ # Verify tags were converted to SetTagWithValue and passed to SDK
226
+ call_args = mock_client.articles.create_with_content.call_args
227
+ tags_arg = call_args[1]["tags"]
228
+ assert len(tags_arg) == 2
229
+ assert tags_arg[0].id == "don:core:dvrv-us-1:devo/1:tag/1"
230
+ assert tags_arg[1].id == "don:core:dvrv-us-1:devo/1:tag/2"
231
+
185
232
 
186
233
  class TestArticlesUpdateTool:
187
234
  """Tests for devrev_articles_update tool."""
@@ -236,6 +283,109 @@ class TestArticlesUpdateTool:
236
283
  call_args = mock_client.articles.update_with_content.call_args
237
284
  assert call_args[1]["applies_to_parts"] == ["don:core:dvrv-us-1:devo/1:feature/3"]
238
285
 
286
+ @pytest.mark.asyncio
287
+ async def test_update_with_access_level(self, mock_ctx, mock_client):
288
+ """Test updating an article with access_level."""
289
+ from devrev.models.articles import ArticleAccessLevel
290
+
291
+ mock_article = _make_mock_article(
292
+ id="article-1",
293
+ title="Internal Article",
294
+ status="published",
295
+ )
296
+ mock_client.articles.update_with_content.return_value = mock_article
297
+
298
+ result = await devrev_articles_update(
299
+ mock_ctx,
300
+ id="article-1",
301
+ access_level="internal",
302
+ )
303
+
304
+ assert result["title"] == "Internal Article"
305
+ # Verify access_level was converted to enum and passed to SDK
306
+ call_args = mock_client.articles.update_with_content.call_args
307
+ assert call_args[1]["access_level"] == ArticleAccessLevel.INTERNAL
308
+
309
+ @pytest.mark.asyncio
310
+ async def test_update_with_tags(self, mock_ctx, mock_client):
311
+ """Test updating an article with tags."""
312
+ mock_article = _make_mock_article(
313
+ id="article-1",
314
+ title="Tagged Article",
315
+ status="published",
316
+ )
317
+ mock_client.articles.update_with_content.return_value = mock_article
318
+
319
+ result = await devrev_articles_update(
320
+ mock_ctx,
321
+ id="article-1",
322
+ tags=["don:core:dvrv-us-1:devo/1:tag/1"],
323
+ )
324
+
325
+ assert result["title"] == "Tagged Article"
326
+ # Verify tags were converted to SetTagWithValue and passed to SDK
327
+ call_args = mock_client.articles.update_with_content.call_args
328
+ tags_arg = call_args[1]["tags"]
329
+ assert len(tags_arg) == 1
330
+ assert tags_arg[0].id == "don:core:dvrv-us-1:devo/1:tag/1"
331
+
332
+ @pytest.mark.asyncio
333
+ async def test_update_with_invalid_access_level(self, mock_ctx, mock_client):
334
+ """Test updating an article with invalid access_level raises error."""
335
+ with pytest.raises(RuntimeError, match="Invalid access level"):
336
+ await devrev_articles_update(
337
+ mock_ctx,
338
+ id="article-1",
339
+ access_level="invalid_level",
340
+ )
341
+
342
+ @pytest.mark.asyncio
343
+ async def test_update_with_empty_tags_removes_all(self, mock_ctx, mock_client):
344
+ """Test updating with empty tags list removes all tags."""
345
+ mock_article = _make_mock_article(
346
+ id="article-1",
347
+ title="No Tags Article",
348
+ status="published",
349
+ )
350
+ mock_client.articles.update_with_content.return_value = mock_article
351
+
352
+ result = await devrev_articles_update(
353
+ mock_ctx,
354
+ id="article-1",
355
+ tags=[],
356
+ )
357
+
358
+ assert result["title"] == "No Tags Article"
359
+ # Verify empty list is passed (not None) to clear tags
360
+ call_args = mock_client.articles.update_with_content.call_args
361
+ tags_arg = call_args[1]["tags"]
362
+ assert tags_arg is not None
363
+ assert tags_arg == []
364
+
365
+ @pytest.mark.asyncio
366
+ async def test_create_with_empty_tags(self, mock_ctx, mock_client):
367
+ """Test creating with empty tags list passes empty list (not None)."""
368
+ mock_article = _make_mock_article(
369
+ title="No Tags Article",
370
+ description="Content without tags",
371
+ )
372
+ mock_client.articles.create_with_content.return_value = mock_article
373
+
374
+ result = await devrev_articles_create(
375
+ mock_ctx,
376
+ title="No Tags Article",
377
+ content="Content without tags",
378
+ owned_by=["don:identity:dvrv-us-1:devo/test:devu/1"],
379
+ tags=[],
380
+ )
381
+
382
+ assert result["title"] == "No Tags Article"
383
+ # Verify empty list is passed (not None)
384
+ call_args = mock_client.articles.create_with_content.call_args
385
+ tags_arg = call_args[1]["tags"]
386
+ assert tags_arg is not None
387
+ assert tags_arg == []
388
+
239
389
 
240
390
  class TestArticlesDeleteTool:
241
391
  """Tests for devrev_articles_delete tool."""
@@ -856,6 +856,87 @@ class TestUpdateWithContent:
856
856
  assert "applies_to_parts" in data
857
857
  assert data["applies_to_parts"]["set"] == []
858
858
 
859
+ def test_update_with_content_access_level_only(
860
+ self,
861
+ articles_service: ArticlesService,
862
+ mock_article: Article,
863
+ mock_http_client: MagicMock,
864
+ ) -> None:
865
+ """Test updating only access_level."""
866
+ from devrev.models.articles import ArticleAccessLevel
867
+
868
+ mock_response = MagicMock()
869
+ mock_response.json.return_value = {"article": mock_article.model_dump(mode="json")}
870
+ mock_http_client.post.return_value = mock_response
871
+
872
+ result = articles_service.update_with_content(
873
+ "article-123",
874
+ access_level=ArticleAccessLevel.INTERNAL,
875
+ )
876
+
877
+ assert result.id == "article-123"
878
+ # Verify update was called with access_level
879
+ post_call = mock_http_client.post.call_args
880
+ assert "articles.update" in post_call[0][0]
881
+ data = post_call[1]["data"]
882
+ assert data["access_level"] == "internal"
883
+
884
+ def test_update_with_content_tags_only(
885
+ self,
886
+ articles_service: ArticlesService,
887
+ mock_article: Article,
888
+ mock_http_client: MagicMock,
889
+ ) -> None:
890
+ """Test updating only tags."""
891
+ from devrev.models.base import SetTagWithValue
892
+
893
+ mock_response = MagicMock()
894
+ mock_response.json.return_value = {"article": mock_article.model_dump(mode="json")}
895
+ mock_http_client.post.return_value = mock_response
896
+
897
+ result = articles_service.update_with_content(
898
+ "article-123",
899
+ tags=[SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/1")],
900
+ )
901
+
902
+ assert result.id == "article-123"
903
+ # Verify update was called with tags wrapped in set
904
+ post_call = mock_http_client.post.call_args
905
+ assert "articles.update" in post_call[0][0]
906
+ data = post_call[1]["data"]
907
+ assert "tags" in data
908
+ assert data["tags"]["set"] == [{"id": "don:core:dvrv-us-1:devo/1:tag/1"}]
909
+
910
+ def test_update_with_content_access_level_and_tags(
911
+ self,
912
+ articles_service: ArticlesService,
913
+ mock_article: Article,
914
+ mock_http_client: MagicMock,
915
+ ) -> None:
916
+ """Test updating access_level and tags together."""
917
+ from devrev.models.articles import ArticleAccessLevel
918
+ from devrev.models.base import SetTagWithValue
919
+
920
+ mock_response = MagicMock()
921
+ mock_response.json.return_value = {"article": mock_article.model_dump(mode="json")}
922
+ mock_http_client.post.return_value = mock_response
923
+
924
+ result = articles_service.update_with_content(
925
+ "article-123",
926
+ access_level=ArticleAccessLevel.EXTERNAL,
927
+ tags=[
928
+ SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/1"),
929
+ SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/2"),
930
+ ],
931
+ )
932
+
933
+ assert result.id == "article-123"
934
+ post_call = mock_http_client.post.call_args
935
+ data = post_call[1]["data"]
936
+ assert data["access_level"] == "external"
937
+ assert "tags" in data
938
+ assert len(data["tags"]["set"]) == 2
939
+
859
940
 
860
941
  # ============================================================================
861
942
  # Async Tests
@@ -1526,3 +1607,85 @@ class TestUpdateWithContentAsync:
1526
1607
  data = post_call[1]["data"]
1527
1608
  assert "applies_to_parts" in data
1528
1609
  assert data["applies_to_parts"]["set"] == []
1610
+
1611
+ @pytest.mark.asyncio
1612
+ async def test_async_update_with_content_access_level_only(
1613
+ self,
1614
+ async_articles_service: AsyncArticlesService,
1615
+ mock_article: Article,
1616
+ mock_async_http_client: MagicMock,
1617
+ ) -> None:
1618
+ """Test async updating only access_level."""
1619
+ from devrev.models.articles import ArticleAccessLevel
1620
+
1621
+ mock_response = MagicMock()
1622
+ mock_response.json.return_value = {"article": mock_article.model_dump(mode="json")}
1623
+ mock_async_http_client.post.return_value = mock_response
1624
+
1625
+ result = await async_articles_service.update_with_content(
1626
+ "article-123",
1627
+ access_level=ArticleAccessLevel.INTERNAL,
1628
+ )
1629
+
1630
+ assert result.id == "article-123"
1631
+ post_call = mock_async_http_client.post.call_args
1632
+ assert "articles.update" in post_call[0][0]
1633
+ data = post_call[1]["data"]
1634
+ assert data["access_level"] == "internal"
1635
+
1636
+ @pytest.mark.asyncio
1637
+ async def test_async_update_with_content_tags_only(
1638
+ self,
1639
+ async_articles_service: AsyncArticlesService,
1640
+ mock_article: Article,
1641
+ mock_async_http_client: MagicMock,
1642
+ ) -> None:
1643
+ """Test async updating only tags."""
1644
+ from devrev.models.base import SetTagWithValue
1645
+
1646
+ mock_response = MagicMock()
1647
+ mock_response.json.return_value = {"article": mock_article.model_dump(mode="json")}
1648
+ mock_async_http_client.post.return_value = mock_response
1649
+
1650
+ result = await async_articles_service.update_with_content(
1651
+ "article-123",
1652
+ tags=[SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/1")],
1653
+ )
1654
+
1655
+ assert result.id == "article-123"
1656
+ post_call = mock_async_http_client.post.call_args
1657
+ assert "articles.update" in post_call[0][0]
1658
+ data = post_call[1]["data"]
1659
+ assert "tags" in data
1660
+ assert data["tags"]["set"] == [{"id": "don:core:dvrv-us-1:devo/1:tag/1"}]
1661
+
1662
+ @pytest.mark.asyncio
1663
+ async def test_async_update_with_content_access_level_and_tags(
1664
+ self,
1665
+ async_articles_service: AsyncArticlesService,
1666
+ mock_article: Article,
1667
+ mock_async_http_client: MagicMock,
1668
+ ) -> None:
1669
+ """Test async updating access_level and tags together."""
1670
+ from devrev.models.articles import ArticleAccessLevel
1671
+ from devrev.models.base import SetTagWithValue
1672
+
1673
+ mock_response = MagicMock()
1674
+ mock_response.json.return_value = {"article": mock_article.model_dump(mode="json")}
1675
+ mock_async_http_client.post.return_value = mock_response
1676
+
1677
+ result = await async_articles_service.update_with_content(
1678
+ "article-123",
1679
+ access_level=ArticleAccessLevel.EXTERNAL,
1680
+ tags=[
1681
+ SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/1"),
1682
+ SetTagWithValue(id="don:core:dvrv-us-1:devo/1:tag/2"),
1683
+ ],
1684
+ )
1685
+
1686
+ assert result.id == "article-123"
1687
+ post_call = mock_async_http_client.post.call_args
1688
+ data = post_call[1]["data"]
1689
+ assert data["access_level"] == "external"
1690
+ assert "tags" in data
1691
+ assert len(data["tags"]["set"]) == 2