mcp-gee-sweet 0.7.0.dev63__tar.gz → 0.7.0.dev64__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 (129) hide show
  1. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/PKG-INFO +1 -1
  2. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/docs/content.py +10 -3
  3. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_docs_content.py +36 -19
  4. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.claude/commands/prep-for-pr.md +0 -0
  5. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.dockerignore +0 -0
  6. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  7. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  8. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  9. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.github/dependabot.yml +0 -0
  10. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.github/workflows/ci.yml +0 -0
  11. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.github/workflows/docs.yml +0 -0
  12. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.github/workflows/publish-dev.yml +0 -0
  13. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.github/workflows/release.yml +0 -0
  14. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.gitignore +0 -0
  15. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.pre-commit-config.yaml +0 -0
  16. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/.python-version +0 -0
  17. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/CHANGELOG.md +0 -0
  18. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/CLAUDE.md +0 -0
  19. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/CODE_OF_CONDUCT.md +0 -0
  20. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/CONTRIBUTING.md +0 -0
  21. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/Dockerfile +0 -0
  22. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/LICENSE +0 -0
  23. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/Makefile +0 -0
  24. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/README.md +0 -0
  25. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/SECURITY.md +0 -0
  26. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docker-compose.yml +0 -0
  27. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/auth.md +0 -0
  28. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/client-setup.md +0 -0
  29. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/configuration.md +0 -0
  30. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/decision-chart-theming.md +0 -0
  31. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/decision-composite-tools.md +0 -0
  32. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/decision-docs-formatting.md +0 -0
  33. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/decision-fork.md +0 -0
  34. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/decision-grid-data-size-cap.md +0 -0
  35. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/decision-publishing.md +0 -0
  36. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/decision-response-size-cap-generalization.md +0 -0
  37. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/decision-testing.md +0 -0
  38. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/decisions/index.md +0 -0
  39. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/design/docs-ast-pipeline.md +0 -0
  40. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/design/effectiveformat-spike.md +0 -0
  41. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/design/index.md +0 -0
  42. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/design/markdown-support.md +0 -0
  43. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/design/phase3-theme-system.md +0 -0
  44. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/design.md +0 -0
  45. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/index.md +0 -0
  46. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/known-limitations.md +0 -0
  47. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/notes-read.md +0 -0
  48. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/README.md +0 -0
  49. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/fixtures/tc-d195-create-doc.md +0 -0
  50. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/fixtures/tc-d196-create-doc.html +0 -0
  51. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/fixtures/tc-d213-dollar-escape.md +0 -0
  52. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/fixtures/tc-d226-heading-table.md +0 -0
  53. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/fixtures.template.md +0 -0
  54. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/operations.yaml +0 -0
  55. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/playwright_oauth.md +0 -0
  56. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/results/.gitkeep +0 -0
  57. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/results/2026-06-02.md +0 -0
  58. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/results/2026-06-14.md +0 -0
  59. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/results/2026-06-17.md +0 -0
  60. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/results/2026-06-18.md +0 -0
  61. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/results/2026-06-21-drive-discovery.md +0 -0
  62. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/results/2026-06-21-sheets-delete-clear.md +0 -0
  63. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/results/2026-06-28.md +0 -0
  64. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/retro-v0.8.0.md +0 -0
  65. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/run.md +0 -0
  66. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/runs/README.md +0 -0
  67. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/runs/v0.8.0.md +0 -0
  68. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/setup.md +0 -0
  69. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/tests/calendar.md +0 -0
  70. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/tests/docs.md +0 -0
  71. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/tests/drive.md +0 -0
  72. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/tests/infra.md +0 -0
  73. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/tests/sheets_charts.md +0 -0
  74. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/tests/sheets_mgmt.md +0 -0
  75. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/tests/sheets_read.md +0 -0
  76. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa/tests/sheets_write.md +0 -0
  77. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/qa-checklist.md +0 -0
  78. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/roadmap.md +0 -0
  79. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/docs/tools.md +0 -0
  80. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/mkdocs.yml +0 -0
  81. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/pyproject.toml +0 -0
  82. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/scripts/gen_tool_docs.py +0 -0
  83. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/scripts/oauth_setup.py +0 -0
  84. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/.env.template +0 -0
  85. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/__init__.py +0 -0
  86. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/auth.py +0 -0
  87. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/cache.py +0 -0
  88. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/server.py +0 -0
  89. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/__init__.py +0 -0
  90. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/cache.py +0 -0
  91. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/calendar.py +0 -0
  92. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/docs/__init__.py +0 -0
  93. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/docs/ast.py +0 -0
  94. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/docs/emitter.py +0 -0
  95. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/docs/html_parser.py +0 -0
  96. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/docs/layout.py +0 -0
  97. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/docs/style.py +0 -0
  98. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/docs/tables.py +0 -0
  99. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/drive/__init__.py +0 -0
  100. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/drive/activity.py +0 -0
  101. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/drive/files.py +0 -0
  102. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/drive/sharing.py +0 -0
  103. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/drive/transfer.py +0 -0
  104. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/response_limits.py +0 -0
  105. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/sheets/__init__.py +0 -0
  106. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/sheets/data.py +0 -0
  107. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/sheets/helpers.py +0 -0
  108. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/src/mcp_gee_sweet/tools/sheets/structure.py +0 -0
  109. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/__init__.py +0 -0
  110. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/drive/__init__.py +0 -0
  111. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/drive/test_activity.py +0 -0
  112. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/drive/test_files.py +0 -0
  113. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/drive/test_sharing.py +0 -0
  114. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/drive/test_transfer.py +0 -0
  115. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/sheets/__init__.py +0 -0
  116. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/sheets/test_data.py +0 -0
  117. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/sheets/test_helpers.py +0 -0
  118. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/sheets/test_structure.py +0 -0
  119. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_auth.py +0 -0
  120. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_cache.py +0 -0
  121. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_calendar.py +0 -0
  122. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_docs_core.py +0 -0
  123. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_docs_layout.py +0 -0
  124. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_docs_style.py +0 -0
  125. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_docs_tables.py +0 -0
  126. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_gen_tool_docs.py +0 -0
  127. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_response_limits.py +0 -0
  128. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/tests/test_server.py +0 -0
  129. {mcp_gee_sweet-0.7.0.dev63 → mcp_gee_sweet-0.7.0.dev64}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-gee-sweet
3
- Version: 0.7.0.dev63
3
+ Version: 0.7.0.dev64
4
4
  Summary: MCP server for Google Workspace — Sheets, Drive, Docs, and Calendar. 60+ tools for AI clients.
5
5
  Project-URL: Homepage, https://github.com/khuisman/mcp-gee-sweet
6
6
  Project-URL: Bug Tracker, https://github.com/khuisman/mcp-gee-sweet/issues
@@ -377,12 +377,19 @@ def register(tool):
377
377
  clear_requests.append(
378
378
  {"deleteContentRange": {"range": {"startIndex": 1, "endIndex": end_index - 1}}}
379
379
  )
380
+ # Sent as its own batchUpdate, not combined with the insert below: live testing
381
+ # showed the Docs API resolves a same-batch insertText's inherited formatting
382
+ # from a pre-batch snapshot, so contamination survived even after the clear
383
+ # request above ran earlier in that same batch. A separate call forces the
384
+ # insert to see the already-cleared document state.
385
+ docs_service.documents().batchUpdate(
386
+ documentId=doc_id, body={"requests": clear_requests}
387
+ ).execute()
380
388
 
381
389
  content_requests, tables = _to_doc_requests(content, content_format, start_index=1)
382
- all_requests = clear_requests + content_requests
383
- if all_requests:
390
+ if content_requests:
384
391
  docs_service.documents().batchUpdate(
385
- documentId=doc_id, body={"requests": all_requests}
392
+ documentId=doc_id, body={"requests": content_requests}
386
393
  ).execute()
387
394
  fill_tables(docs_service, doc_id, tables)
388
395
 
@@ -688,7 +688,15 @@ class TestGetDocContent:
688
688
  class TestWriteDocContent:
689
689
  """Bug (#255): clear+reinsert left a stale textStyle override on the document's
690
690
  trailing paragraph mark (which the Docs API won't let deleteContentRange remove),
691
- letting it leak into newly-inserted content on the next write_doc_content call."""
691
+ letting it leak into newly-inserted content on the next write_doc_content call.
692
+
693
+ The clear (updateTextStyle + deleteContentRange) and the new content's insertText
694
+ must be sent as two SEPARATE batchUpdate calls, not combined into one: live testing
695
+ against the real Docs API showed a same-batch insertText resolves its inherited
696
+ formatting from a pre-batch snapshot, so contamination survived even after the
697
+ clear request ran earlier in that same batch. See content.py's write_doc_content
698
+ for the full account.
699
+ """
692
700
 
693
701
  def _make_services(self, end_index=50):
694
702
  drive_svc = MagicMock()
@@ -708,38 +716,47 @@ class TestWriteDocContent:
708
716
  doc_cache=MagicMock(),
709
717
  )
710
718
 
711
- def _batchupdate_requests(self, docs_svc):
712
- return docs_svc.documents.return_value.batchUpdate.call_args.kwargs["body"]["requests"]
719
+ def _batchupdate_calls(self, docs_svc):
720
+ return [
721
+ c.kwargs["body"]["requests"]
722
+ for c in docs_svc.documents.return_value.batchUpdate.call_args_list
723
+ ]
713
724
 
714
- def test_clears_trailing_mark_style_before_deleting(self):
725
+ def test_clears_trailing_mark_style_before_deleting_in_its_own_batch(self):
715
726
  drive_svc, docs_svc = self._make_services(end_index=50)
716
727
  ctx = self._ctx(drive_svc, docs_svc)
717
728
  _docs_tools["write_doc_content"](doc_id="doc1", content="<p>New content</p>", ctx=ctx)
718
- requests = self._batchupdate_requests(docs_svc)
729
+ calls = self._batchupdate_calls(docs_svc)
719
730
 
720
- clear_style_idx = next(
721
- i
722
- for i, r in enumerate(requests)
723
- if "updateTextStyle" in r and r["updateTextStyle"]["fields"] == "*"
724
- )
725
- delete_idx = next(i for i, r in enumerate(requests) if "deleteContentRange" in r)
726
-
727
- clear_style = requests[clear_style_idx]["updateTextStyle"]
731
+ # First batchUpdate call: clear + delete, nothing else.
732
+ clear_requests = calls[0]
733
+ assert len(clear_requests) == 2
734
+ clear_style = clear_requests[0]["updateTextStyle"]
728
735
  assert clear_style["range"] == {"startIndex": 49, "endIndex": 50}
729
736
  assert clear_style["textStyle"] == {}
730
- # Must run before deleteContentRange, while the original indices are still valid.
731
- assert clear_style_idx < delete_idx
732
- assert requests[delete_idx]["deleteContentRange"]["range"] == {
737
+ assert clear_style["fields"] == "*"
738
+ assert clear_requests[1]["deleteContentRange"]["range"] == {
733
739
  "startIndex": 1,
734
740
  "endIndex": 49,
735
741
  }
736
742
 
743
+ # Second batchUpdate call: the new content, sent separately.
744
+ content_requests = calls[1]
745
+ assert not any(
746
+ "updateTextStyle" in r and r["updateTextStyle"].get("fields") == "*"
747
+ for r in content_requests
748
+ )
749
+ assert not any("deleteContentRange" in r for r in content_requests)
750
+ assert any("insertText" in r for r in content_requests)
751
+
737
752
  def test_empty_doc_skips_clear_requests(self):
738
753
  drive_svc, docs_svc = self._make_services(end_index=2)
739
754
  ctx = self._ctx(drive_svc, docs_svc)
740
755
  _docs_tools["write_doc_content"](doc_id="doc1", content="<p>New content</p>", ctx=ctx)
741
- requests = self._batchupdate_requests(docs_svc)
756
+ calls = self._batchupdate_calls(docs_svc)
757
+ # Only one batchUpdate call (the content) — no separate clear/delete call.
758
+ assert len(calls) == 1
742
759
  assert not any(
743
- "updateTextStyle" in r and r["updateTextStyle"]["fields"] == "*" for r in requests
760
+ "updateTextStyle" in r and r["updateTextStyle"].get("fields") == "*" for r in calls[0]
744
761
  )
745
- assert not any("deleteContentRange" in r for r in requests)
762
+ assert not any("deleteContentRange" in r for r in calls[0])