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.
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/PKG-INFO +11 -1
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/README.md +10 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/articles.md +12 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/changelog.md +9 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/mcp/tools-reference.md +2 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/pyproject.toml +1 -1
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/articles.py +34 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/articles.py +34 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_articles.py +150 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_articles_unified.py +163 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/bug-fixer.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/builder.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/documentation.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/foreman.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/pr-review-boss.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/release-manager.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/simplifier.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/agents/tester.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/commands/foreman-work.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/commands/release-prepare.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/commands/review-start.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/commands/simplify-code.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/code-quality.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/data-modeling.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/devrev-sdk.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/git-workflow.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/pull-requests.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/python-development.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/security.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.augment/rules/testing.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.dockerignore +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.env.sample +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/article-artifact-simplification.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/ISSUE_TEMPLATE/question.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/dependabot.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/pull_request_template.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/api-check.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/ci.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/claude-code-review.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/claude.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/deploy.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/docs.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/integration-tests.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/release.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.github/workflows/sync-openapi.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.gitignore +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/.pre-commit-config.yaml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/CLAUDE.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/CODE_OF_CONDUCT.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/CONTRIBUTING.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/DEPRECATIONS.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/Dockerfile +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/KNOWN_ISSUES.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/OPENAPI_SPEC_DISCREPANCIES.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/SECURITY.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/augment-mcp-config-remote.json +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/augment-mcp-config.json +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/augment-settings.json +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/README.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/bench_http_client.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/bench_models.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/bench_pagination.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/benchmarks/conftest.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/context7.json +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/README.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/audit-logging-setup.sh +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/cloudbuild.yaml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/monitoring/README.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/monitoring/alert-policies.yaml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/monitoring/dashboard.json +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/monitoring/validate-config.sh +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/deploy/service.yaml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docker-compose.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/brands.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/engagements.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/incidents.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/question-answers.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/recommendations.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/search.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta/uoms.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/beta-api-differences.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/client.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/config.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/exceptions.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/accounts.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/base.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/users.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/models/works.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/accounts.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/code-changes.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/conversations.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/dev-users.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/groups.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/links.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/parts.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/rev-users.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/slas.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/tags.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/timeline-entries.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/webhooks.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/api/services/works.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/advanced.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/basic.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/beta-features.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/examples/integrations.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/getting-started/authentication.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/getting-started/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/getting-started/installation.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/getting-started/quickstart.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/beta-api.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/compatibility.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/configuration.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/error-handling.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/github-actions-setup.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/logging.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/pagination.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/sync-vs-async.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/testing.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/version-support.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/guides/write-integration-testing-strategy.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/hooks/copy_llms.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/mcp/deployment.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/mcp/index.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/mcp/quickstart.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/docs/stylesheets/extra.css +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/README.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/README.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/async_example.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/create_work.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/error_handling.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/list_accounts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/pagination.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/basic/search_users.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/README.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/main.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/cloud_functions/requirements.txt +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/README.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/main.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/fastapi/requirements.txt +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/flask/README.md +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/flask/app.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/examples/integrations/flask/requirements.txt +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/llms-ctx-full.txt +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/llms-ctx.txt +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/llms-mcp.txt +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/llms.txt +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/mkdocs.yml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/openapi-beta.yaml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/openapi-public.yaml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/openapi-spec-corrections.yaml +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/scripts/build_ai_docs.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/scripts/setup-github-secrets.sh +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/client.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/config.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/exceptions.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/accounts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/articles.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/artifacts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/base.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/brands.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/code_changes.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/conversations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/dev_users.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/engagements.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/groups.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/incidents.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/links.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/notifications.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/parts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/preferences.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/question_answers.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/recommendations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/rev_users.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/search.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/slas.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/sync.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/tags.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/tasks.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/timeline_entries.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/timeline_events.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/track_events.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/uoms.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/webhooks.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/widgets.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/models/works.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/py.typed +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/accounts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/artifacts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/base.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/brands.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/code_changes.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/conversations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/dev_users.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/engagements.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/groups.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/incidents.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/links.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/notifications.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/parts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/preferences.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/question_answers.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/recommendations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/rev_users.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/search.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/slas.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/tags.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/timeline_entries.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/track_events.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/uoms.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/webhooks.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/services/works.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/content_converter.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/deprecation.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/http.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/logging.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev/utils/pagination.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/__main__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/config.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/audit.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/auth.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/health.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/middleware/rate_limit.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/escalation.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/investigate.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/response.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/summarize.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/prompts/triage.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/account.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/article.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/conversation.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/part.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/server_info.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/ticket.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/resources/user.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/server.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/accounts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/conversations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/engagements.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/groups.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/incidents.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/links.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/parts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/recommendations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/search.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/server_info.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/slas.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/tags.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/timeline.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/users.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/tools/works.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/errors.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/formatting.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/src/devrev_mcp/utils/pagination.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/conftest.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/conftest.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_accounts_e2e.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_all_readonly_endpoints.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_articles_lifecycle.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_backwards_compatibility.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_contacts_e2e.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_core_services_phase1.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_extended_services_phase2.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_get_endpoints.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_issues_e2e.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_kb_articles_e2e.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_mcp_articles.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_ping.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_question_answers_e2e.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_readonly_endpoints.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_specialized_services_phase3.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_tickets_e2e.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/test_write_operations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/utils/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/utils/cleanup.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/utils/constants.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/integration/utils/data_manager.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/performance/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/performance/test_articles_performance.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/conftest.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_audit.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_config.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_phase4_transport.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_prompts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_resources.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_server_info.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_accounts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_conversations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_engagements.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_groups.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_incidents.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_links.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_parts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_recommendations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_search.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_slas.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_tags.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_timeline.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_users.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_tools_works.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/mcp/test_utils.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/models/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/models/test_user_state_regression.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/__init__.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/conftest.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_articles.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_async_services.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_brands.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_code_changes.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_conversations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_engagements.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_groups.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_incidents.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_links.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_notifications.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_parts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_preferences.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_question_answers.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_recommendations.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_search.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_slas.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_tags.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_timeline_entries.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_track_events.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_uoms.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_webhooks.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/services/test_works.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_artifacts.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_backward_compatibility.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_base_service.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_client.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_config.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_content_converter.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_deprecation.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_error_handling.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_exceptions.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_http.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_logging.py +0 -0
- {devrev_python_sdk-2.9.0 → devrev_python_sdk-2.10.0}/tests/unit/test_pagination.py +0 -0
- {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.
|
|
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
|
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|