Skip to content

Commit 7716de0

Browse files
committed
PYTHON-5488 - MongoClient.append_metadata should not add duplicates
1 parent 4e9b52b commit 7716de0

File tree

4 files changed

+64
-20
lines changed

4 files changed

+64
-20
lines changed

pymongo/asynchronous/mongo_client.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,7 @@ async def target() -> bool:
10431043

10441044
def append_metadata(self, driver_info: DriverInfo) -> None:
10451045
"""Appends the given metadata to existing driver metadata.
1046+
If given driver_info.name is already present in the metadata, no append is done.
10461047
10471048
:param driver_info: a :class:`~pymongo.driver_info.DriverInfo`
10481049
@@ -1053,7 +1054,11 @@ def append_metadata(self, driver_info: DriverInfo) -> None:
10531054
raise TypeError(
10541055
f"driver_info must be an instance of DriverInfo, not {type(driver_info)}"
10551056
)
1056-
self._options.pool_options._update_metadata(driver_info)
1057+
if (
1058+
driver_info.name
1059+
and driver_info.name not in self._options.pool_options.metadata["driver"]["name"]
1060+
):
1061+
self._options.pool_options._update_metadata(driver_info)
10571062

10581063
def _should_pin_cursor(self, session: Optional[AsyncClientSession]) -> Optional[bool]:
10591064
return self._options.load_balanced and not (session and session.in_transaction)

pymongo/synchronous/mongo_client.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,7 @@ def target() -> bool:
10431043

10441044
def append_metadata(self, driver_info: DriverInfo) -> None:
10451045
"""Appends the given metadata to existing driver metadata.
1046+
If given driver_info.name is already present in the metadata, no append is done.
10461047
10471048
:param driver_info: a :class:`~pymongo.driver_info.DriverInfo`
10481049
@@ -1053,7 +1054,11 @@ def append_metadata(self, driver_info: DriverInfo) -> None:
10531054
raise TypeError(
10541055
f"driver_info must be an instance of DriverInfo, not {type(driver_info)}"
10551056
)
1056-
self._options.pool_options._update_metadata(driver_info)
1057+
if (
1058+
driver_info.name
1059+
and driver_info.name not in self._options.pool_options.metadata["driver"]["name"]
1060+
):
1061+
self._options.pool_options._update_metadata(driver_info)
10571062

10581063
def _should_pin_cursor(self, session: Optional[ClientSession]) -> Optional[bool]:
10591064
return self._options.load_balanced and not (session and session.in_transaction)

test/asynchronous/test_client_metadata.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ async def check_metadata_added(
9696
add_name: str,
9797
add_version: Optional[str],
9898
add_platform: Optional[str],
99+
is_duplicate: bool = False,
99100
) -> None:
100101
# send initial metadata
101102
name, version, platform, metadata = await self.send_ping_and_get_metadata(client, True)
@@ -107,15 +108,22 @@ async def check_metadata_added(
107108
new_name, new_version, new_platform, new_metadata = await self.send_ping_and_get_metadata(
108109
client, True
109110
)
110-
self.assertEqual(new_name, f"{name}|{add_name}" if add_name is not None else name)
111-
self.assertEqual(
112-
new_version,
113-
f"{version}|{add_version}" if add_version is not None else version,
114-
)
115-
self.assertEqual(
116-
new_platform,
117-
f"{platform}|{add_platform}" if add_platform is not None else platform,
118-
)
111+
112+
if not is_duplicate:
113+
self.assertEqual(new_name, f"{name}|{add_name}" if add_name is not None else name)
114+
self.assertEqual(
115+
new_version,
116+
f"{version}|{add_version}" if add_version is not None else version,
117+
)
118+
self.assertEqual(
119+
new_platform,
120+
f"{platform}|{add_platform}" if add_platform is not None else platform,
121+
)
122+
# Metadata should be unchanged if the new name was already present
123+
else:
124+
self.assertEqual(new_name, name)
125+
self.assertEqual(new_version, version)
126+
self.assertEqual(new_platform, platform)
119127

120128
metadata.pop("driver")
121129
metadata.pop("platform")
@@ -210,6 +218,16 @@ async def test_doesnt_update_established_connections(self):
210218
self.assertIsNone(self.handshake_req)
211219
self.assertEqual(listener.event_count(ConnectionClosedEvent), 0)
212220

221+
async def test_append_metadata_duplicate_name(self):
222+
client = await self.async_rs_or_single_client(
223+
"mongodb://" + self.server.address_string,
224+
maxIdleTimeMS=1,
225+
driver=DriverInfo("library", "1.2", "Library Platform"),
226+
)
227+
await self.check_metadata_added(
228+
client, "library", "2.0", "Framework Platform", is_duplicate=True
229+
)
230+
213231

214232
if __name__ == "__main__":
215233
unittest.main()

test/test_client_metadata.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def check_metadata_added(
9696
add_name: str,
9797
add_version: Optional[str],
9898
add_platform: Optional[str],
99+
is_duplicate: bool = False,
99100
) -> None:
100101
# send initial metadata
101102
name, version, platform, metadata = self.send_ping_and_get_metadata(client, True)
@@ -107,15 +108,22 @@ def check_metadata_added(
107108
new_name, new_version, new_platform, new_metadata = self.send_ping_and_get_metadata(
108109
client, True
109110
)
110-
self.assertEqual(new_name, f"{name}|{add_name}" if add_name is not None else name)
111-
self.assertEqual(
112-
new_version,
113-
f"{version}|{add_version}" if add_version is not None else version,
114-
)
115-
self.assertEqual(
116-
new_platform,
117-
f"{platform}|{add_platform}" if add_platform is not None else platform,
118-
)
111+
112+
if not is_duplicate:
113+
self.assertEqual(new_name, f"{name}|{add_name}" if add_name is not None else name)
114+
self.assertEqual(
115+
new_version,
116+
f"{version}|{add_version}" if add_version is not None else version,
117+
)
118+
self.assertEqual(
119+
new_platform,
120+
f"{platform}|{add_platform}" if add_platform is not None else platform,
121+
)
122+
# Metadata should be unchanged if the new name was already present
123+
else:
124+
self.assertEqual(new_name, name)
125+
self.assertEqual(new_version, version)
126+
self.assertEqual(new_platform, platform)
119127

120128
metadata.pop("driver")
121129
metadata.pop("platform")
@@ -210,6 +218,14 @@ def test_doesnt_update_established_connections(self):
210218
self.assertIsNone(self.handshake_req)
211219
self.assertEqual(listener.event_count(ConnectionClosedEvent), 0)
212220

221+
def test_append_metadata_duplicate_name(self):
222+
client = self.rs_or_single_client(
223+
"mongodb://" + self.server.address_string,
224+
maxIdleTimeMS=1,
225+
driver=DriverInfo("library", "1.2", "Library Platform"),
226+
)
227+
self.check_metadata_added(client, "library", "2.0", "Framework Platform", is_duplicate=True)
228+
213229

214230
if __name__ == "__main__":
215231
unittest.main()

0 commit comments

Comments
 (0)