Skip to content

PYTHON-5429 Server command is case sensitive #2421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ PyMongo 4.14 brings a number of changes including:
- Added :meth:`pymongo.asynchronous.mongo_client.AsyncMongoClient.append_metadata` and
:meth:`pymongo.mongo_client.MongoClient.append_metadata` to allow instantiated MongoClients to send client metadata
on-demand

- Introduces a minor breaking change. When encoding :class:`bson.binary.BinaryVector`, a ``ValueError`` will be raised
if the 'padding' metadata field is < 0 or > 7, or non-zero for any type other than PACKED_BIT.
- Fixed a bug that raised ``EncryptionError`` when using :meth:`pymongo.mongo_client.MongoClient.server_info` with an
encrypted connection. :meth:`pymongo.mongo_client.MongoClient.server_info` now runs the camel cased ``buildInfo`` command
instead of the lower cased ``buildinfo`` command which may cause a breaking change in applications that rely on matching the
lower cased ``buildinfo`` command.

Changes in Version 4.13.2 (2025/06/17)
--------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions pymongo/asynchronous/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -834,12 +834,12 @@ async def command(
Any additional keyword arguments will be added to the final
command document before it is sent.

For example, a command like ``{buildinfo: 1}`` can be sent
For example, a command like ``{buildInfo: 1}`` can be sent
using:

>>> await db.command("buildinfo")
>>> await db.command("buildInfo")
OR
>>> await db.command({"buildinfo": 1})
>>> await db.command({"buildInfo": 1})

For a command where the value matters, like ``{count:
collection_name}`` we can do:
Expand Down
2 changes: 1 addition & 1 deletion pymongo/asynchronous/mongo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2311,7 +2311,7 @@ async def server_info(
return cast(
dict,
await self.admin.command(
"buildinfo", read_preference=ReadPreference.PRIMARY, session=session
"buildInfo", read_preference=ReadPreference.PRIMARY, session=session
),
)

Expand Down
6 changes: 3 additions & 3 deletions pymongo/synchronous/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -834,12 +834,12 @@ def command(
Any additional keyword arguments will be added to the final
command document before it is sent.

For example, a command like ``{buildinfo: 1}`` can be sent
For example, a command like ``{buildInfo: 1}`` can be sent
using:

>>> db.command("buildinfo")
>>> db.command("buildInfo")
OR
>>> db.command({"buildinfo": 1})
>>> db.command({"buildInfo": 1})

For a command where the value matters, like ``{count:
collection_name}`` we can do:
Expand Down
2 changes: 1 addition & 1 deletion pymongo/synchronous/mongo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2303,7 +2303,7 @@ def server_info(self, session: Optional[client_session.ClientSession] = None) ->
return cast(
dict,
self.admin.command(
"buildinfo", read_preference=ReadPreference.PRIMARY, session=session
"buildInfo", read_preference=ReadPreference.PRIMARY, session=session
),
)

Expand Down
6 changes: 3 additions & 3 deletions test/asynchronous/test_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,9 @@ async def test_validate_collection_background(self):
async def test_command(self):
self.maxDiff = None
db = self.client.admin
first = await db.command("buildinfo")
second = await db.command({"buildinfo": 1})
third = await db.command("buildinfo", 1)
first = await db.command("buildInfo")
second = await db.command({"buildInfo": 1})
third = await db.command("buildInfo", 1)
self.assertEqualReply(first, second)
self.assertEqualReply(second, third)

Expand Down
12 changes: 6 additions & 6 deletions test/mockupdb/test_network_disconnect_primary.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,17 @@ def test_network_disconnect_primary(self):
self.assertEqual(TOPOLOGY_TYPE.ReplicaSetWithPrimary, topology.description.topology_type)

# Open a socket in the application pool (calls ismaster).
with going(client.db.command, "buildinfo"):
primary.receives("buildinfo").ok()
with going(client.db.command, "buildInfo"):
primary.receives("buildInfo").ok()

# The primary hangs replying to ismaster.
ismaster_future = Future()
primary.autoresponds("ismaster", lambda r: r.ok(ismaster_future.result()))

# Network error on application operation.
with self.assertRaises(ConnectionFailure):
with going(client.db.command, "buildinfo"):
primary.receives("buildinfo").hangup()
with going(client.db.command, "buildInfo"):
primary.receives("buildInfo").hangup()

# Topology type is updated.
self.assertEqual(TOPOLOGY_TYPE.ReplicaSetNoPrimary, topology.description.topology_type)
Expand All @@ -89,9 +89,9 @@ def test_network_disconnect_primary(self):
ismaster_future.set_result(primary_response)

# Demand a primary.
with going(client.db.command, "buildinfo"):
with going(client.db.command, "buildInfo"):
wait_until(lambda: client.primary == primary.address, "rediscover primary")
primary.receives("buildinfo").ok()
primary.receives("buildInfo").ok()

self.assertEqual(TOPOLOGY_TYPE.ReplicaSetWithPrimary, topology.description.topology_type)

Expand Down
4 changes: 2 additions & 2 deletions test/mockupdb/test_reset_and_request_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ def _test_disconnect(self, operation):
after = time.time()

# Demand a reconnect.
with going(self.client.db.command, "buildinfo"):
self.server.receives("buildinfo").ok()
with going(self.client.db.command, "buildInfo"):
self.server.receives("buildInfo").ok()

last = self.ismaster_time
self.assertGreaterEqual(last, after, "called ismaster before needed")
Expand Down
6 changes: 3 additions & 3 deletions test/test_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,9 @@ def test_validate_collection_background(self):
def test_command(self):
self.maxDiff = None
db = self.client.admin
first = db.command("buildinfo")
second = db.command({"buildinfo": 1})
third = db.command("buildinfo", 1)
first = db.command("buildInfo")
second = db.command({"buildInfo": 1})
third = db.command("buildInfo", 1)
self.assertEqualReply(first, second)
self.assertEqualReply(second, third)

Expand Down
Loading