Skip to content

PYTHON-5782 Coverage increase, remove old code in message.py#2772

Open
aclark4life wants to merge 12 commits into
mongodb:masterfrom
aclark4life:PYTHON-5782
Open

PYTHON-5782 Coverage increase, remove old code in message.py#2772
aclark4life wants to merge 12 commits into
mongodb:masterfrom
aclark4life:PYTHON-5782

Conversation

@aclark4life

@aclark4life aclark4life commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

PYTHON-5782

Changes in this PR

Adds test/test_message.py with unit tests for pymongo/message.py.

Also removes a dead code branch in _convert_write_result() — a legacy compatibility shim for MongoDB < 2.6 that manually reconstructed the upserted _id when it wasn't an ObjectId. MongoDB 2.6+ always returns the upserted field directly, so this branch was unreachable.

Tests cover:

Result / error conversion

  • _convert_exception() — converts an Exception into an errmsg/errtype failure document for event publishing
  • _convert_client_bulk_exception() — same as above but also captures the error code, used by the client-level bulk write API
  • _convert_write_result() — converts a legacy GLE (Get Last Error) write result into write-command format, handling insert/update/delete/upsert, wtimeout, and errInfo branches
  • _raise_document_too_large() — raises DocumentTooLarge with a size-aware message for inserts or a generic message for other operations

Wire-format message construction

  • _op_msg() — builds an OP_MSG wire message, injecting $db and $readPreference, and temporarily popping document-sequence fields before encoding

Command builders

  • _gen_find_command() — builds a find command document from a query spec, applying projections, skip/limit, batch size, read concern, collation, and cursor options
  • _gen_get_more_command() — builds a getMore command document, conditionally including batch size, maxTimeMS, and comment (gated on wire version ≥ 9)

Read preference

  • _maybe_add_read_preference() — injects $readPreference into a query spec for non-primary modes, skipping plain secondaryPreferred when no tags or maxStalenessSeconds are set

Test Plan

Added unit tests using a real ZlibContext for compression paths and a MagicMock connection for _gen_get_more_command. Focuses on the pure-Python code paths without requiring a live MongoDB server.

hatch run test:test test/test_message.py -v

Checklist

Checklist for Author

  • Did you update the changelog (if necessary)?
  • Is there test coverage?
  • Is any followup work tracked in a JIRA ticket? If so, add link(s).

Checklist for Reviewer

  • Does the title of the PR reference a JIRA Ticket?
  • Do you fully understand the implementation? (Would you be comfortable explaining how this code works to someone else?)
  • Is all relevant documentation (README or docstring) updated?

Copilot AI review requested due to automatic review settings April 23, 2026 21:42
@aclark4life aclark4life requested a review from a team as a code owner April 23, 2026 21:42
@aclark4life aclark4life requested a review from Jibola April 23, 2026 21:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new unit test module to increase coverage of pymongo/message.py by exercising message-building utilities and related pure-Python helper functions without requiring a live MongoDB server.

Changes:

  • Adds test/test_message.py with unit tests for message helpers (read preference wrapping, command generation, write-result conversion).
  • Adds tests covering OP_MSG / OP_QUERY / OP_GET_MORE message construction in both compressed and uncompressed paths.
  • Adds tests for error conversion and document-too-large error formatting.

@codecov-commenter

codecov-commenter commented Apr 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

Comment thread test/test_message.py
Comment thread test/test_message.py Outdated
Comment thread test/test_message.py Outdated
@aclark4life aclark4life force-pushed the PYTHON-5782 branch 2 times, most recently from a6c8f8e to a8d9f92 Compare May 6, 2026 20:34
@aclark4life aclark4life requested a review from Copilot May 6, 2026 20:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@aclark4life aclark4life force-pushed the PYTHON-5782 branch 3 times, most recently from 4baf2a6 to 7b31987 Compare May 6, 2026 20:53
@aclark4life aclark4life requested a review from Copilot May 7, 2026 02:02
@aclark4life aclark4life changed the title PYTHON-5782 Increase code coverage for message.py PYTHON-5782 Improve code coverage for message.py May 7, 2026
@aclark4life aclark4life changed the title PYTHON-5782 Improve code coverage for message.py PYTHON-5782 Improve coverage for message.py May 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@aclark4life aclark4life changed the title PYTHON-5782 Improve coverage for message.py PYTHON-5782 Improve coverage for message.py May 7, 2026
@aclark4life aclark4life changed the title PYTHON-5782 Improve coverage for message.py PYTHON-5782 Coverage improvements for message.py May 7, 2026
@aclark4life aclark4life changed the title PYTHON-5782 Coverage improvements for message.py PYTHON-5782 Coverage improvement for message.py May 7, 2026
@aclark4life aclark4life requested a review from Copilot May 7, 2026 02:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@aclark4life

Copy link
Copy Markdown
Contributor Author

Test failures flaky:

  Error response from daemon: No such image: quay.io/pypa/manylinux_2_28_aarch64:2026.03.20-1
  Error response from daemon: Get "https://quay.io/v2/": context deadline exceeded
(api/gridfs/asynchronous/grid_file: line   10) timeout   http://dochub.mongodb.org/core/gridfsspec - HTTPSConnectionPool(host='dochub.mongodb.org', port=443): Read timed out. (read timeout=60)

Comment thread test/test_message.py
Comment thread test/test_message.py Outdated
self.assertEqual(result["upserted"][0]["_id"], 42)

def test_update_legacy_upsert_id_from_update_doc(self):
# Pre-2.6 servers omit "upserted"; _id is extracted from the update doc (takes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't support servers <4.2, so no need to test them. Any code that still makes a distinction should be removed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread pymongo/message.py
Comment on lines 171 to 174
elif operation == "update":
if "upserted" in result:
res["upserted"] = [{"index": 0, "_id": result["upserted"]}]
# Versions of MongoDB before 2.6 don't return the _id for an
# upsert if _id is not an ObjectId.
elif result.get("updatedExisting") is False and affected == 1:
# If _id is in both the update document *and* the query spec
# the update document _id takes precedence.
update = command["updates"][0]
_id = update["u"].get("_id", update["q"].get("_id"))
res["upserted"] = [{"index": 0, "_id": _id}]
return res

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that the PR should be updated to reflect that there's this minor refactor here.

Comment thread test/test_message.py

# _gen_find_command

def test_find_basic(self):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the calls to _gen_find_command and _gen_get_more_command should use keyword args for readability.

Comment thread test/test_message.py Outdated
self.assertEqual(max_doc_size, 0)

def test_op_msg_max_doc_size_matches_largest_encoded_doc(self):
docs = [{"_id": 1, "x": 2}, {"_id": 3, "x": 4}]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These encode to the same size, so the assert would pass regardless of how max_doc_size is set. One of these should be larger than the other to ensure correctness.

Comment thread test/test_message.py Outdated
Comment on lines +202 to +204
with self.assertRaises(DocumentTooLarge) as ctx:
_raise_document_too_large("update", 2_000_000, 1_000_000)
self.assertIn("update", str(ctx.exception))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
with self.assertRaises(DocumentTooLarge) as ctx:
_raise_document_too_large("update", 2_000_000, 1_000_000)
self.assertIn("update", str(ctx.exception))
with self.assertRaisesRegex(DocumentTooLarge, "update command document too large"):
_raise_document_too_large("update", 2_000_000, 1_000_000)

@aclark4life aclark4life changed the title PYTHON-5782 Coverage increase for message.py PYTHON-5782 Coverage increase & remove old code in message.py Jun 11, 2026
@aclark4life aclark4life changed the title PYTHON-5782 Coverage increase & remove old code in message.py PYTHON-5782 Coverage increase, remove old code in message.py Jun 11, 2026
- Replace _MockCtx with real ZlibContext(-1) to satisfy the
  SnappyContext | ZlibContext | ZstdContext union type
- Annotate docs list as list to satisfy the Mapping invariance check
- Add # type: ignore[arg-type] on _MockConn call sites for
  _gen_get_more_command (mocking AsyncConnection | Connection fully
  would require a much heavier stub)
Address Copilot feedback: add tests for legacy upsert _id fallback in
_convert_write_result and for the zlib-compressed _op_msg path.
Guard zlib compression test with _have_zlib() skip condition.
- Use keyword args in all _gen_find_command and _gen_get_more_command calls
- Fix test_op_msg_max_doc_size_matches_largest_encoded_doc to use docs of different sizes so the max() assertion is meaningful
- Use assertRaisesRegex with the exact message in test_raise_document_too_large_update_generic_message
- Remove !r from the DocumentTooLarge message in _raise_document_too_large so it matches

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread pymongo/message.py
# There's nothing intelligent we can say
# about size for update and delete
raise DocumentTooLarge(f"{operation!r} command document too large")
raise DocumentTooLarge(f"{operation} command document too large")

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants