devrev-Python-SDK 2.8.1__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.8.1 → devrev_python_sdk-2.10.0}/PKG-INFO +18 -1
  2. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/README.md +17 -0
  3. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/articles.md +19 -0
  4. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/changelog.md +15 -0
  5. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/mcp/tools-reference.md +3 -0
  6. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/pyproject.toml +1 -1
  7. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/articles.py +71 -2
  8. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/articles.py +43 -0
  9. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/conftest.py +2 -0
  10. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_articles.py +200 -0
  11. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_articles_unified.py +326 -0
  12. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/agents/bug-fixer.md +0 -0
  13. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/agents/builder.md +0 -0
  14. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/agents/documentation.md +0 -0
  15. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/agents/foreman.md +0 -0
  16. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/agents/pr-review-boss.md +0 -0
  17. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/agents/release-manager.md +0 -0
  18. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/agents/simplifier.md +0 -0
  19. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/agents/tester.md +0 -0
  20. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/commands/foreman-work.md +0 -0
  21. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/commands/release-prepare.md +0 -0
  22. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/commands/review-start.md +0 -0
  23. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/commands/simplify-code.md +0 -0
  24. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/rules/code-quality.md +0 -0
  25. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/rules/data-modeling.md +0 -0
  26. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/rules/devrev-sdk.md +0 -0
  27. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/rules/git-workflow.md +0 -0
  28. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/rules/pull-requests.md +0 -0
  29. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/rules/python-development.md +0 -0
  30. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/rules/security.md +0 -0
  31. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.augment/rules/testing.md +0 -0
  32. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.dockerignore +0 -0
  33. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.env.sample +0 -0
  34. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/article-artifact-simplification.md +0 -0
  35. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  36. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  37. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  38. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  39. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/dependabot.yml +0 -0
  40. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/pull_request_template.md +0 -0
  41. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/api-check.yml +0 -0
  42. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/ci.yml +0 -0
  43. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/claude-code-review.yml +0 -0
  44. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/claude.yml +0 -0
  45. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/deploy.yml +0 -0
  46. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/docs.yml +0 -0
  47. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/integration-tests.yml +0 -0
  48. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/release.yml +0 -0
  49. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.github/workflows/sync-openapi.yml +0 -0
  50. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.gitignore +0 -0
  51. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/.pre-commit-config.yaml +0 -0
  52. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/CLAUDE.md +0 -0
  53. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/CODE_OF_CONDUCT.md +0 -0
  54. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/CONTRIBUTING.md +0 -0
  55. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/DEPRECATIONS.md +0 -0
  56. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/Dockerfile +0 -0
  57. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/KNOWN_ISSUES.md +0 -0
  58. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/OPENAPI_SPEC_DISCREPANCIES.md +0 -0
  59. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/SECURITY.md +0 -0
  60. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/augment-mcp-config-remote.json +0 -0
  61. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/augment-mcp-config.json +0 -0
  62. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/augment-settings.json +0 -0
  63. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/benchmarks/README.md +0 -0
  64. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/benchmarks/bench_http_client.py +0 -0
  65. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/benchmarks/bench_models.py +0 -0
  66. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/benchmarks/bench_pagination.py +0 -0
  67. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/benchmarks/conftest.py +0 -0
  68. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/context7.json +0 -0
  69. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/deploy/README.md +0 -0
  70. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/deploy/audit-logging-setup.sh +0 -0
  71. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/deploy/cloudbuild.yaml +0 -0
  72. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/deploy/monitoring/README.md +0 -0
  73. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/deploy/monitoring/alert-policies.yaml +0 -0
  74. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/deploy/monitoring/dashboard.json +0 -0
  75. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/deploy/monitoring/validate-config.sh +0 -0
  76. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/deploy/service.yaml +0 -0
  77. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docker-compose.yml +0 -0
  78. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta/brands.md +0 -0
  79. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta/engagements.md +0 -0
  80. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta/incidents.md +0 -0
  81. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta/index.md +0 -0
  82. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta/question-answers.md +0 -0
  83. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta/recommendations.md +0 -0
  84. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta/search.md +0 -0
  85. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta/uoms.md +0 -0
  86. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/beta-api-differences.md +0 -0
  87. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/client.md +0 -0
  88. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/config.md +0 -0
  89. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/exceptions.md +0 -0
  90. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/index.md +0 -0
  91. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/models/accounts.md +0 -0
  92. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/models/base.md +0 -0
  93. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/models/index.md +0 -0
  94. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/models/users.md +0 -0
  95. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/models/works.md +0 -0
  96. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/accounts.md +0 -0
  97. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/code-changes.md +0 -0
  98. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/conversations.md +0 -0
  99. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/dev-users.md +0 -0
  100. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/groups.md +0 -0
  101. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/index.md +0 -0
  102. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/links.md +0 -0
  103. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/parts.md +0 -0
  104. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/rev-users.md +0 -0
  105. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/slas.md +0 -0
  106. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/tags.md +0 -0
  107. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/timeline-entries.md +0 -0
  108. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/webhooks.md +0 -0
  109. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/api/services/works.md +0 -0
  110. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/examples/advanced.md +0 -0
  111. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/examples/basic.md +0 -0
  112. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/examples/beta-features.md +0 -0
  113. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/examples/index.md +0 -0
  114. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/examples/integrations.md +0 -0
  115. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/getting-started/authentication.md +0 -0
  116. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/getting-started/index.md +0 -0
  117. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/getting-started/installation.md +0 -0
  118. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/getting-started/quickstart.md +0 -0
  119. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/beta-api.md +0 -0
  120. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/compatibility.md +0 -0
  121. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/configuration.md +0 -0
  122. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/error-handling.md +0 -0
  123. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/github-actions-setup.md +0 -0
  124. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/index.md +0 -0
  125. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/logging.md +0 -0
  126. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/pagination.md +0 -0
  127. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/sync-vs-async.md +0 -0
  128. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/testing.md +0 -0
  129. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/version-support.md +0 -0
  130. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/guides/write-integration-testing-strategy.md +0 -0
  131. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/hooks/copy_llms.py +0 -0
  132. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/index.md +0 -0
  133. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/mcp/deployment.md +0 -0
  134. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/mcp/index.md +0 -0
  135. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/mcp/quickstart.md +0 -0
  136. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/docs/stylesheets/extra.css +0 -0
  137. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/README.md +0 -0
  138. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/basic/README.md +0 -0
  139. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/basic/async_example.py +0 -0
  140. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/basic/create_work.py +0 -0
  141. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/basic/error_handling.py +0 -0
  142. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/basic/list_accounts.py +0 -0
  143. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/basic/pagination.py +0 -0
  144. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/basic/search_users.py +0 -0
  145. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/README.md +0 -0
  146. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/main.py +0 -0
  147. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/requirements.txt +0 -0
  148. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/README.md +0 -0
  149. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/main.py +0 -0
  150. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/requirements.txt +0 -0
  151. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/flask/README.md +0 -0
  152. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/flask/app.py +0 -0
  153. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/examples/integrations/flask/requirements.txt +0 -0
  154. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/llms-ctx-full.txt +0 -0
  155. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/llms-ctx.txt +0 -0
  156. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/llms-mcp.txt +0 -0
  157. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/llms.txt +0 -0
  158. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/mkdocs.yml +0 -0
  159. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/openapi-beta.yaml +0 -0
  160. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/openapi-public.yaml +0 -0
  161. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/openapi-spec-corrections.yaml +0 -0
  162. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/scripts/build_ai_docs.py +0 -0
  163. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/scripts/setup-github-secrets.sh +0 -0
  164. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/__init__.py +0 -0
  165. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/client.py +0 -0
  166. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/config.py +0 -0
  167. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/exceptions.py +0 -0
  168. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/__init__.py +0 -0
  169. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/accounts.py +0 -0
  170. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/articles.py +0 -0
  171. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/artifacts.py +0 -0
  172. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/base.py +0 -0
  173. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/brands.py +0 -0
  174. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/code_changes.py +0 -0
  175. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/conversations.py +0 -0
  176. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/dev_users.py +0 -0
  177. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/engagements.py +0 -0
  178. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/groups.py +0 -0
  179. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/incidents.py +0 -0
  180. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/links.py +0 -0
  181. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/notifications.py +0 -0
  182. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/parts.py +0 -0
  183. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/preferences.py +0 -0
  184. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/question_answers.py +0 -0
  185. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/recommendations.py +0 -0
  186. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/rev_users.py +0 -0
  187. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/search.py +0 -0
  188. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/slas.py +0 -0
  189. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/sync.py +0 -0
  190. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/tags.py +0 -0
  191. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/tasks.py +0 -0
  192. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/timeline_entries.py +0 -0
  193. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/timeline_events.py +0 -0
  194. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/track_events.py +0 -0
  195. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/uoms.py +0 -0
  196. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/webhooks.py +0 -0
  197. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/widgets.py +0 -0
  198. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/models/works.py +0 -0
  199. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/py.typed +0 -0
  200. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/__init__.py +0 -0
  201. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/accounts.py +0 -0
  202. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/artifacts.py +0 -0
  203. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/base.py +0 -0
  204. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/brands.py +0 -0
  205. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/code_changes.py +0 -0
  206. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/conversations.py +0 -0
  207. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/dev_users.py +0 -0
  208. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/engagements.py +0 -0
  209. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/groups.py +0 -0
  210. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/incidents.py +0 -0
  211. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/links.py +0 -0
  212. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/notifications.py +0 -0
  213. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/parts.py +0 -0
  214. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/preferences.py +0 -0
  215. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/question_answers.py +0 -0
  216. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/recommendations.py +0 -0
  217. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/rev_users.py +0 -0
  218. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/search.py +0 -0
  219. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/slas.py +0 -0
  220. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/tags.py +0 -0
  221. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/timeline_entries.py +0 -0
  222. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/track_events.py +0 -0
  223. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/uoms.py +0 -0
  224. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/webhooks.py +0 -0
  225. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/services/works.py +0 -0
  226. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/utils/__init__.py +0 -0
  227. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/utils/content_converter.py +0 -0
  228. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/utils/deprecation.py +0 -0
  229. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/utils/http.py +0 -0
  230. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/utils/logging.py +0 -0
  231. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev/utils/pagination.py +0 -0
  232. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/__init__.py +0 -0
  233. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/__main__.py +0 -0
  234. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/config.py +0 -0
  235. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/__init__.py +0 -0
  236. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/audit.py +0 -0
  237. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/auth.py +0 -0
  238. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/health.py +0 -0
  239. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/rate_limit.py +0 -0
  240. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/__init__.py +0 -0
  241. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/escalation.py +0 -0
  242. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/investigate.py +0 -0
  243. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/response.py +0 -0
  244. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/summarize.py +0 -0
  245. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/triage.py +0 -0
  246. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/__init__.py +0 -0
  247. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/account.py +0 -0
  248. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/article.py +0 -0
  249. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/conversation.py +0 -0
  250. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/part.py +0 -0
  251. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/server_info.py +0 -0
  252. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/ticket.py +0 -0
  253. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/user.py +0 -0
  254. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/server.py +0 -0
  255. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/__init__.py +0 -0
  256. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/accounts.py +0 -0
  257. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/conversations.py +0 -0
  258. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/engagements.py +0 -0
  259. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/groups.py +0 -0
  260. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/incidents.py +0 -0
  261. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/links.py +0 -0
  262. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/parts.py +0 -0
  263. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/recommendations.py +0 -0
  264. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/search.py +0 -0
  265. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/server_info.py +0 -0
  266. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/slas.py +0 -0
  267. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/tags.py +0 -0
  268. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/timeline.py +0 -0
  269. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/users.py +0 -0
  270. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/works.py +0 -0
  271. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/__init__.py +0 -0
  272. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/errors.py +0 -0
  273. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/formatting.py +0 -0
  274. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/pagination.py +0 -0
  275. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/__init__.py +0 -0
  276. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/conftest.py +0 -0
  277. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/__init__.py +0 -0
  278. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/conftest.py +0 -0
  279. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_accounts_e2e.py +0 -0
  280. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_all_readonly_endpoints.py +0 -0
  281. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_articles_lifecycle.py +0 -0
  282. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_backwards_compatibility.py +0 -0
  283. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_contacts_e2e.py +0 -0
  284. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_core_services_phase1.py +0 -0
  285. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_extended_services_phase2.py +0 -0
  286. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_get_endpoints.py +0 -0
  287. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_issues_e2e.py +0 -0
  288. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_kb_articles_e2e.py +0 -0
  289. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_mcp_articles.py +0 -0
  290. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_ping.py +0 -0
  291. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_question_answers_e2e.py +0 -0
  292. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_readonly_endpoints.py +0 -0
  293. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_specialized_services_phase3.py +0 -0
  294. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_tickets_e2e.py +0 -0
  295. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/test_write_operations.py +0 -0
  296. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/utils/__init__.py +0 -0
  297. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/utils/cleanup.py +0 -0
  298. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/utils/constants.py +0 -0
  299. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/integration/utils/data_manager.py +0 -0
  300. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/performance/__init__.py +0 -0
  301. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/performance/test_articles_performance.py +0 -0
  302. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/__init__.py +0 -0
  303. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/__init__.py +0 -0
  304. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_audit.py +0 -0
  305. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_config.py +0 -0
  306. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_phase4_transport.py +0 -0
  307. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_prompts.py +0 -0
  308. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_resources.py +0 -0
  309. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_server_info.py +0 -0
  310. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_accounts.py +0 -0
  311. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_conversations.py +0 -0
  312. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_engagements.py +0 -0
  313. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_groups.py +0 -0
  314. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_incidents.py +0 -0
  315. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_links.py +0 -0
  316. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_parts.py +0 -0
  317. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_recommendations.py +0 -0
  318. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_search.py +0 -0
  319. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_slas.py +0 -0
  320. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_tags.py +0 -0
  321. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_timeline.py +0 -0
  322. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_users.py +0 -0
  323. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_works.py +0 -0
  324. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_utils.py +0 -0
  325. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/models/__init__.py +0 -0
  326. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/models/test_user_state_regression.py +0 -0
  327. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/__init__.py +0 -0
  328. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/conftest.py +0 -0
  329. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_articles.py +0 -0
  330. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_async_services.py +0 -0
  331. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_brands.py +0 -0
  332. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_code_changes.py +0 -0
  333. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_conversations.py +0 -0
  334. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_engagements.py +0 -0
  335. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_groups.py +0 -0
  336. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_incidents.py +0 -0
  337. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_links.py +0 -0
  338. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_notifications.py +0 -0
  339. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_parts.py +0 -0
  340. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_preferences.py +0 -0
  341. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_question_answers.py +0 -0
  342. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_recommendations.py +0 -0
  343. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_search.py +0 -0
  344. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_slas.py +0 -0
  345. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_tags.py +0 -0
  346. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_timeline_entries.py +0 -0
  347. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_track_events.py +0 -0
  348. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_uoms.py +0 -0
  349. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_webhooks.py +0 -0
  350. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/services/test_works.py +0 -0
  351. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_artifacts.py +0 -0
  352. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_backward_compatibility.py +0 -0
  353. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_base_service.py +0 -0
  354. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_client.py +0 -0
  355. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_config.py +0 -0
  356. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_content_converter.py +0 -0
  357. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_deprecation.py +0 -0
  358. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_error_handling.py +0 -0
  359. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_exceptions.py +0 -0
  360. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_http.py +0 -0
  361. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_logging.py +0 -0
  362. {devrev_python_sdk-2.8.1 → devrev_python_sdk-2.10.0}/tests/unit/test_pagination.py +0 -0
  363. {devrev_python_sdk-2.8.1 → 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.8.1
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
@@ -517,6 +517,7 @@ article = client.articles.create_with_content(
517
517
  owned_by=["don:identity:dvrv-us-1:devo/1:devu/1"],
518
518
  description="Quick start guide for new users", # Optional metadata
519
519
  status=ArticleStatus.PUBLISHED,
520
+ applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123"], # Optional: associate with parts
520
521
  )
521
522
 
522
523
  # Get article with content
@@ -538,6 +539,22 @@ client.articles.update_with_content(
538
539
  status=ArticleStatus.ARCHIVED,
539
540
  )
540
541
 
542
+ # Update with part associations
543
+ client.articles.update_with_content(
544
+ id=article.id,
545
+ applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123", "don:core:dvrv-us-1:devo/1:part/456"],
546
+ )
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
+
541
558
  # List published articles (metadata only)
542
559
  published = client.articles.list(limit=20)
543
560
  for article in published:
@@ -442,6 +442,7 @@ article = client.articles.create_with_content(
442
442
  owned_by=["don:identity:dvrv-us-1:devo/1:devu/1"],
443
443
  description="Quick start guide for new users", # Optional metadata
444
444
  status=ArticleStatus.PUBLISHED,
445
+ applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123"], # Optional: associate with parts
445
446
  )
446
447
 
447
448
  # Get article with content
@@ -463,6 +464,22 @@ client.articles.update_with_content(
463
464
  status=ArticleStatus.ARCHIVED,
464
465
  )
465
466
 
467
+ # Update with part associations
468
+ client.articles.update_with_content(
469
+ id=article.id,
470
+ applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123", "don:core:dvrv-us-1:devo/1:part/456"],
471
+ )
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
+
466
483
  # List published articles (metadata only)
467
484
  published = client.articles.list(limit=20)
468
485
  for article in published:
@@ -93,6 +93,9 @@ article = client.articles.create_with_content(
93
93
  description="Short summary for search/listing", # Optional metadata
94
94
  status=ArticleStatus.PUBLISHED, # Optional: draft, published, archived
95
95
  content_format="text/html", # Optional: default is text/html
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
96
99
  )
97
100
  print(f"Created article with content: {article.id}")
98
101
  ```
@@ -181,6 +184,22 @@ updated_article = client.articles.update_with_content(
181
184
  id="don:core:dvrv-us-1:devo/1:article/123",
182
185
  content="<h1>New Content</h1>",
183
186
  )
187
+
188
+ # Update with part associations
189
+ updated_article = client.articles.update_with_content(
190
+ id="don:core:dvrv-us-1:devo/1:article/123",
191
+ applies_to_parts=["don:core:dvrv-us-1:devo/1:part/123", "don:core:dvrv-us-1:devo/1:part/456"],
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
+ )
184
203
  ```
185
204
 
186
205
  ### Async Usage
@@ -7,6 +7,21 @@ 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
+
19
+ ## [2.9.0] - 2026-03-09
20
+
21
+ ### Added
22
+
23
+ - **Article Part Association** (#171) — Added `applies_to_parts` parameter to MCP `articles_create` and `articles_update` tools, and SDK `update_with_content` method for native article-to-part association
24
+
10
25
  ## [2.8.1] - 2026-03-06
11
26
 
12
27
  ### Fixed
@@ -56,6 +56,9 @@ Tools are the primary way AI assistants interact with DevRev. Each tool maps to
56
56
  - **Unified Content Management**: Create and update articles with automatic artifact handling
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
+ - **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)
59
62
 
60
63
  ### Conversations
61
64
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "devrev-Python-SDK"
7
- version = "2.8.1"
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,
@@ -21,6 +22,8 @@ from devrev.models.articles import (
21
22
  ArticlesListResponse,
22
23
  ArticleStatus,
23
24
  ArticlesUpdateRequest,
25
+ ArticlesUpdateRequestAppliesToParts,
26
+ ArticlesUpdateRequestTags,
24
27
  ArticlesUpdateResponse,
25
28
  ArticleType,
26
29
  ArticleWithContent,
@@ -437,6 +440,9 @@ class ArticlesService(BaseService):
437
440
  content: str | None = None,
438
441
  description: str | None = None,
439
442
  status: ArticleStatus | None = None,
443
+ applies_to_parts: builtins.list[str] | None = None,
444
+ access_level: ArticleAccessLevel | None = None,
445
+ tags: builtins.list[SetTagWithValue] | None = None,
440
446
  ) -> Article:
441
447
  """Update article metadata and/or content.
442
448
 
@@ -451,6 +457,9 @@ class ArticlesService(BaseService):
451
457
  content: Optional new article body content
452
458
  description: Optional new metadata description
453
459
  status: Optional new status
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)
454
463
 
455
464
  Returns:
456
465
  Updated article
@@ -478,6 +487,18 @@ class ArticlesService(BaseService):
478
487
  ... title="New Title",
479
488
  ... content="<html>New content...</html>"
480
489
  ... )
490
+ >>>
491
+ >>> # Update applies_to_parts
492
+ >>> article = client.articles.update_with_content(
493
+ ... "ART-123",
494
+ ... applies_to_parts=["don:core:...:capability/6"]
495
+ ... )
496
+ >>>
497
+ >>> # Update access level to internal
498
+ >>> article = client.articles.update_with_content(
499
+ ... "ART-123",
500
+ ... access_level=ArticleAccessLevel.INTERNAL
501
+ ... )
481
502
  """
482
503
  if not self._parent_client:
483
504
  raise DevRevError(
@@ -489,13 +510,34 @@ class ArticlesService(BaseService):
489
510
  if content is not None:
490
511
  self.update_content(id, content)
491
512
 
513
+ # Build applies_to_parts wrapper if provided
514
+ applies_to_parts_req = None
515
+ if applies_to_parts is not None:
516
+ applies_to_parts_req = ArticlesUpdateRequestAppliesToParts(set=applies_to_parts)
517
+
518
+ # Build tags wrapper if provided
519
+ tags_req = None
520
+ if tags is not None:
521
+ tags_req = ArticlesUpdateRequestTags(set=tags)
522
+
492
523
  # Update metadata if any metadata fields provided
493
- if title is not None or description is not None or status is not None:
524
+ has_metadata = (
525
+ title is not None
526
+ or description is not None
527
+ or status is not None
528
+ or applies_to_parts is not None
529
+ or access_level is not None
530
+ or tags is not None
531
+ )
532
+ if has_metadata:
494
533
  update_req = ArticlesUpdateRequest(
495
534
  id=id,
496
535
  title=title,
497
536
  description=description,
498
537
  status=status,
538
+ applies_to_parts=applies_to_parts_req,
539
+ access_level=access_level,
540
+ tags=tags_req,
499
541
  )
500
542
  return self.update(update_req)
501
543
 
@@ -822,6 +864,9 @@ class AsyncArticlesService(AsyncBaseService):
822
864
  content: str | None = None,
823
865
  description: str | None = None,
824
866
  status: ArticleStatus | None = None,
867
+ applies_to_parts: builtins.list[str] | None = None,
868
+ access_level: ArticleAccessLevel | None = None,
869
+ tags: builtins.list[SetTagWithValue] | None = None,
825
870
  ) -> Article:
826
871
  """Update article metadata and/or content (async).
827
872
 
@@ -836,6 +881,9 @@ class AsyncArticlesService(AsyncBaseService):
836
881
  content: Optional new article body content
837
882
  description: Optional new metadata description
838
883
  status: Optional new status
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)
839
887
 
840
888
  Returns:
841
889
  Updated article
@@ -853,13 +901,34 @@ class AsyncArticlesService(AsyncBaseService):
853
901
  if content is not None:
854
902
  await self.update_content(id, content)
855
903
 
904
+ # Build applies_to_parts wrapper if provided
905
+ applies_to_parts_req = None
906
+ if applies_to_parts is not None:
907
+ applies_to_parts_req = ArticlesUpdateRequestAppliesToParts(set=applies_to_parts)
908
+
909
+ # Build tags wrapper if provided
910
+ tags_req = None
911
+ if tags is not None:
912
+ tags_req = ArticlesUpdateRequestTags(set=tags)
913
+
856
914
  # Update metadata if any metadata fields provided
857
- if title is not None or description is not None or status is not None:
915
+ has_metadata = (
916
+ title is not None
917
+ or description is not None
918
+ or status is not None
919
+ or applies_to_parts is not None
920
+ or access_level is not None
921
+ or tags is not None
922
+ )
923
+ if has_metadata:
858
924
  update_req = ArticlesUpdateRequest(
859
925
  id=id,
860
926
  title=title,
861
927
  description=description,
862
928
  status=status,
929
+ applies_to_parts=applies_to_parts_req,
930
+ access_level=access_level,
931
+ tags=tags_req,
863
932
  )
864
933
  return await self.update(update_req)
865
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
@@ -102,6 +104,9 @@ if _config.enable_destructive_tools:
102
104
  description: str | None = None,
103
105
  status: str | None = None,
104
106
  content_format: str = "text/html",
107
+ applies_to_parts: list[str] | None = None,
108
+ scope: int | None = None,
109
+ tags: list[str] | None = None,
105
110
  ) -> dict[str, Any]:
106
111
  """Create a new article with content.
107
112
 
@@ -113,6 +118,10 @@ if _config.enable_destructive_tools:
113
118
  description: Optional short metadata description (NOT the article body).
114
119
  status: Optional article status (draft, published, archived).
115
120
  content_format: Content MIME type (default: text/html).
121
+ applies_to_parts: Optional list of part IDs (products, capabilities,
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.
116
125
 
117
126
  Returns:
118
127
  Dictionary containing the created article details.
@@ -132,6 +141,9 @@ if _config.enable_destructive_tools:
132
141
  f"Valid statuses: {', '.join(s.name for s in ArticleStatus)}"
133
142
  ) from e
134
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
+
135
147
  article = await app.get_client().articles.create_with_content(
136
148
  title=title,
137
149
  content=content,
@@ -139,6 +151,9 @@ if _config.enable_destructive_tools:
139
151
  description=description,
140
152
  status=article_status,
141
153
  content_format=content_format,
154
+ applies_to_parts=applies_to_parts,
155
+ scope=scope,
156
+ tags=tags_list,
142
157
  )
143
158
  return serialize_model(article)
144
159
  except DevRevError as e:
@@ -152,6 +167,9 @@ if _config.enable_destructive_tools:
152
167
  content: str | None = None,
153
168
  description: str | None = None,
154
169
  status: str | None = None,
170
+ applies_to_parts: list[str] | None = None,
171
+ access_level: str | None = None,
172
+ tags: list[str] | None = None,
155
173
  ) -> dict[str, Any]:
156
174
  """Update an existing article in DevRev.
157
175
 
@@ -162,6 +180,14 @@ if _config.enable_destructive_tools:
162
180
  content: Optional new article body content.
163
181
  description: Optional new metadata description (NOT the article body).
164
182
  status: Optional new status (draft, published, archived).
183
+ applies_to_parts: Optional list of part IDs (products, capabilities,
184
+ features, enhancements) to associate the article with.
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.
165
191
 
166
192
  Returns:
167
193
  Dictionary containing the updated article details.
@@ -181,12 +207,29 @@ if _config.enable_destructive_tools:
181
207
  f"Valid statuses: {', '.join(s.name for s in ArticleStatus)}"
182
208
  ) from e
183
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
+
184
224
  article = await app.get_client().articles.update_with_content(
185
225
  id=id,
186
226
  title=title,
187
227
  content=content,
188
228
  description=description,
189
229
  status=article_status,
230
+ applies_to_parts=applies_to_parts,
231
+ access_level=article_access_level,
232
+ tags=tags_list,
190
233
  )
191
234
  return serialize_model(article)
192
235
  except DevRevError as e:
@@ -110,7 +110,9 @@ def mock_client():
110
110
  client.articles.list = AsyncMock()
111
111
  client.articles.get = AsyncMock()
112
112
  client.articles.create = AsyncMock()
113
+ client.articles.create_with_content = AsyncMock()
113
114
  client.articles.update = AsyncMock()
115
+ client.articles.update_with_content = AsyncMock()
114
116
  client.articles.delete = AsyncMock()
115
117
  client.articles.count = AsyncMock()
116
118
 
@@ -154,6 +154,81 @@ class TestArticlesCreateTool:
154
154
  owned_by=["don:identity:dvrv-us-1:devo/test:devu/1"],
155
155
  )
156
156
 
157
+ @pytest.mark.asyncio
158
+ async def test_create_with_applies_to_parts(self, mock_ctx, mock_client):
159
+ """Test creating an article with applies_to_parts."""
160
+ mock_article = _make_mock_article(
161
+ title="Article with Parts",
162
+ description="Content with parts",
163
+ )
164
+ mock_client.articles.create_with_content.return_value = mock_article
165
+
166
+ result = await devrev_articles_create(
167
+ mock_ctx,
168
+ title="Article with Parts",
169
+ content="Content with parts",
170
+ owned_by=["don:identity:dvrv-us-1:devo/test:devu/1"],
171
+ applies_to_parts=[
172
+ "don:core:dvrv-us-1:devo/1:product/1",
173
+ "don:core:dvrv-us-1:devo/1:capability/2",
174
+ ],
175
+ )
176
+
177
+ assert result["title"] == "Article with Parts"
178
+ # Verify applies_to_parts was passed to SDK
179
+ call_args = mock_client.articles.create_with_content.call_args
180
+ assert call_args[1]["applies_to_parts"] == [
181
+ "don:core:dvrv-us-1:devo/1:product/1",
182
+ "don:core:dvrv-us-1:devo/1:capability/2",
183
+ ]
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
+
157
232
 
158
233
  class TestArticlesUpdateTool:
159
234
  """Tests for devrev_articles_update tool."""
@@ -186,6 +261,131 @@ class TestArticlesUpdateTool:
186
261
  with pytest.raises(RuntimeError, match="Article not found"):
187
262
  await devrev_articles_update(mock_ctx, id="nonexistent", title="New")
188
263
 
264
+ @pytest.mark.asyncio
265
+ async def test_update_with_applies_to_parts(self, mock_ctx, mock_client):
266
+ """Test updating an article with applies_to_parts."""
267
+ mock_article = _make_mock_article(
268
+ id="article-1",
269
+ title="Updated Article",
270
+ status="published",
271
+ )
272
+ mock_client.articles.update_with_content.return_value = mock_article
273
+
274
+ result = await devrev_articles_update(
275
+ mock_ctx,
276
+ id="article-1",
277
+ title="Updated Article",
278
+ applies_to_parts=["don:core:dvrv-us-1:devo/1:feature/3"],
279
+ )
280
+
281
+ assert result["title"] == "Updated Article"
282
+ # Verify applies_to_parts was passed to SDK
283
+ call_args = mock_client.articles.update_with_content.call_args
284
+ assert call_args[1]["applies_to_parts"] == ["don:core:dvrv-us-1:devo/1:feature/3"]
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
+
189
389
 
190
390
  class TestArticlesDeleteTool:
191
391
  """Tests for devrev_articles_delete tool."""