From 6d7817b5b93f4eba7ea38267c767dd9c92800c8b Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Tue, 17 Mar 2026 14:40:54 -0400 Subject: [PATCH 1/2] PYTHON-5757 Deprecate Python 2 methods in SON bson/son.py contains three methods that were added for Python 2 compatibility but are no longer needed --- bson/son.py | 16 ++++++++++++++++ doc/changelog.rst | 5 +++++ test/test_son.py | 6 +++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/bson/son.py b/bson/son.py index 8fd4f95cd2..ccb6bdb273 100644 --- a/bson/son.py +++ b/bson/son.py @@ -22,6 +22,7 @@ import copy import re +import warnings from collections.abc import Mapping as _Mapping from typing import ( Any, @@ -99,13 +100,28 @@ def __iter__(self) -> Iterator[_Key]: yield from self.__keys def has_key(self, key: _Key) -> bool: + warnings.warn( + "SON.has_key() is deprecated, use the in operator instead", + DeprecationWarning, + stacklevel=2, + ) return key in self.__keys def iterkeys(self) -> Iterator[_Key]: + warnings.warn( + "SON.iterkeys() is deprecated, use the keys() method instead", + DeprecationWarning, + stacklevel=2, + ) return self.__iter__() # fourth level uses definitions from lower levels def itervalues(self) -> Iterator[_Value]: + warnings.warn( + "SON.itervalues() is deprecated, use the values() method instead", + DeprecationWarning, + stacklevel=2, + ) for _, v in self.items(): yield v diff --git a/doc/changelog.rst b/doc/changelog.rst index f38709203c..9e6e680d49 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -6,6 +6,11 @@ Changes in Version 4.17.0 (2026/XX/XX) PyMongo 4.17 brings a number of changes including: +- ``has_key``, ``iterkeys`` and ``itervalues`` in :class:`bson.son.SON` have + been deprecated and will be removed in PyMongo 5.0. These methods were + deprecated in favor of the standard dictionary methods ``in``, ``keys``, and + ``values`` respectively. + - Added the :meth:`~pymongo.asynchronous.client_session.AsyncClientSession.bind` and :meth:`~pymongo.client_session.ClientSession.bind` methods that allow users to bind a session to all database operations within the scope of a context manager instead of having to explicitly pass the session to each individual operation. See for examples and more information. diff --git a/test/test_son.py b/test/test_son.py index 36a6834889..02f069c3fe 100644 --- a/test/test_son.py +++ b/test/test_son.py @@ -145,13 +145,13 @@ def test_iteration(self): self.assertEqual(ele * 100, test_son[ele]) def test_contains_has(self): - """has_key and __contains__""" + """key in SON and __contains__""" test_son = SON([(1, 100), (2, 200), (3, 300)]) self.assertIn(1, test_son) self.assertIn(2, test_son, "in failed") self.assertNotIn(22, test_son, "in succeeded when it shouldn't") - self.assertTrue(test_son.has_key(2), "has_key failed") - self.assertFalse(test_son.has_key(22), "has_key succeeded when it shouldn't") + self.assertTrue(2 in test_son, "'in' operator failed for key 2") + self.assertFalse(22 in test_son, "'in' operator succeeded when it shouldn't") def test_clears(self): """Test clear()""" From 554904deef547d78163acd9b5cbc9d6dab4ec2a3 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Tue, 17 Mar 2026 15:08:50 -0400 Subject: [PATCH 2/2] Address review feedback --- doc/changelog.rst | 4 ++-- test/test_son.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/doc/changelog.rst b/doc/changelog.rst index 9e6e680d49..23d5b2fc9e 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -8,8 +8,8 @@ PyMongo 4.17 brings a number of changes including: - ``has_key``, ``iterkeys`` and ``itervalues`` in :class:`bson.son.SON` have been deprecated and will be removed in PyMongo 5.0. These methods were - deprecated in favor of the standard dictionary methods ``in``, ``keys``, and - ``values`` respectively. + deprecated in favor of the standard dictionary containment operator ``in`` + and the ``keys()`` and ``values()`` methods, respectively. - Added the :meth:`~pymongo.asynchronous.client_session.AsyncClientSession.bind` and :meth:`~pymongo.client_session.ClientSession.bind` methods that allow users to bind a session to all database operations within the scope of a context manager instead of having to explicitly pass the session to each individual operation. diff --git a/test/test_son.py b/test/test_son.py index 02f069c3fe..3d2069a4c2 100644 --- a/test/test_son.py +++ b/test/test_son.py @@ -145,13 +145,11 @@ def test_iteration(self): self.assertEqual(ele * 100, test_son[ele]) def test_contains_has(self): - """key in SON and __contains__""" + """Test key membership via 'in' and __contains__.""" test_son = SON([(1, 100), (2, 200), (3, 300)]) self.assertIn(1, test_son) self.assertIn(2, test_son, "in failed") self.assertNotIn(22, test_son, "in succeeded when it shouldn't") - self.assertTrue(2 in test_son, "'in' operator failed for key 2") - self.assertFalse(22 in test_son, "'in' operator succeeded when it shouldn't") def test_clears(self): """Test clear()"""