Skip to content

Commit 5efdcb8

Browse files
committed
PYTHON-2185 Deprecate geoHaystack in create_index(es)
1 parent 6e39ae0 commit 5efdcb8

File tree

4 files changed

+50
-44
lines changed

4 files changed

+50
-44
lines changed

pymongo/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,15 @@
2626
"""
2727

2828
GEOHAYSTACK = "geoHaystack"
29-
"""Index specifier for a 2-dimensional `haystack index`_.
29+
"""**DEPRECATED** - Index specifier for a 2-dimensional `haystack index`_.
3030
31-
.. versionadded:: 2.1
31+
**DEPRECATED** - :attr:`GEOHAYSTACK` is deprecated and will be removed in
32+
PyMongo 4.0. geoHaystack indexes (and the geoSearch command) were deprecated
33+
in MongoDB 4.4. Instead, create a 2d index and use $geoNear or $geoWithin.
34+
See https://dochub.mongodb.org/core/4.4-deprecate-geoHaystack.
35+
36+
.. versionchanged:: 3.11
37+
Deprecated.
3238
3339
.. _haystack index: http://docs.mongodb.org/manual/core/geohaystack/
3440
"""

pymongo/collection.py

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@
5656

5757
_UJOIN = u"%s.%s"
5858
_FIND_AND_MODIFY_DOC_FIELDS = {'value': 1}
59+
_HAYSTACK_MSG = (
60+
"geoHaystack indexes are deprecated as of MongoDB 4.4."
61+
" Instead, create a 2d index and use $geoNear or $geoWithin."
62+
" See https://dochub.mongodb.org/core/4.4-deprecate-geoHaystack")
5963

6064

6165
class ReturnDocument(object):
@@ -1897,10 +1901,24 @@ def create_indexes(self, indexes, session=None, **kwargs):
18971901
.. _createIndexes: https://docs.mongodb.com/manual/reference/command/createIndexes/
18981902
"""
18991903
common.validate_list('indexes', indexes)
1904+
return self.__create_indexes(indexes, session, **kwargs)
1905+
1906+
def __create_indexes(self, indexes, session, **kwargs):
1907+
"""Internal createIndexes helper.
1908+
1909+
:Parameters:
1910+
- `indexes`: A list of :class:`~pymongo.operations.IndexModel`
1911+
instances.
1912+
- `session` (optional): a
1913+
:class:`~pymongo.client_session.ClientSession`.
1914+
- `**kwargs` (optional): optional arguments to the createIndexes
1915+
command (like maxTimeMS) can be passed as keyword arguments.
1916+
"""
19001917
names = []
19011918
with self._socket_for_writes(session) as sock_info:
19021919
supports_collations = sock_info.max_wire_version >= 5
19031920
supports_quorum = sock_info.max_wire_version >= 9
1921+
19041922
def gen_indexes():
19051923
for index in indexes:
19061924
if not isinstance(index, IndexModel):
@@ -1912,15 +1930,20 @@ def gen_indexes():
19121930
raise ConfigurationError(
19131931
"Must be connected to MongoDB "
19141932
"3.4+ to use collations.")
1933+
if 'bucketSize' in document:
1934+
# The bucketSize option is required by geoHaystack.
1935+
warnings.warn(
1936+
_HAYSTACK_MSG, DeprecationWarning, stacklevel=4)
19151937
names.append(document["name"])
19161938
yield document
1939+
19171940
cmd = SON([('createIndexes', self.name),
19181941
('indexes', list(gen_indexes()))])
19191942
cmd.update(kwargs)
19201943
if 'commitQuorum' in kwargs and not supports_quorum:
19211944
raise ConfigurationError(
1922-
"Must be connected to MongoDB 4.4+ to use the "
1923-
"commitQuorum option for createIndexes")
1945+
"Must be connected to MongoDB 4.4+ to use the "
1946+
"commitQuorum option for createIndexes")
19241947

19251948
self._command(
19261949
sock_info, cmd, read_preference=ReadPreference.PRIMARY,
@@ -1929,36 +1952,6 @@ def gen_indexes():
19291952
session=session)
19301953
return names
19311954

1932-
def __create_index(self, keys, index_options, session, **kwargs):
1933-
"""Internal create index helper.
1934-
1935-
:Parameters:
1936-
- `keys`: a list of tuples [(key, type), (key, type), ...]
1937-
- `index_options`: a dict of index options.
1938-
- `session` (optional): a
1939-
:class:`~pymongo.client_session.ClientSession`.
1940-
"""
1941-
index_doc = helpers._index_document(keys)
1942-
index = {"key": index_doc}
1943-
collation = validate_collation_or_none(
1944-
index_options.pop('collation', None))
1945-
index.update(index_options)
1946-
1947-
with self._socket_for_writes(session) as sock_info:
1948-
if collation is not None:
1949-
if sock_info.max_wire_version < 5:
1950-
raise ConfigurationError(
1951-
'Must be connected to MongoDB 3.4+ to use collations.')
1952-
else:
1953-
index['collation'] = collation
1954-
cmd = SON([('createIndexes', self.name), ('indexes', [index])])
1955-
cmd.update(kwargs)
1956-
self._command(
1957-
sock_info, cmd, read_preference=ReadPreference.PRIMARY,
1958-
codec_options=_UNICODE_REPLACE_CODEC_OPTIONS,
1959-
write_concern=self._write_concern_for(session),
1960-
session=session)
1961-
19621955
def create_index(self, keys, session=None, **kwargs):
19631956
"""Creates an index on this collection.
19641957
@@ -2053,13 +2046,11 @@ def create_index(self, keys, session=None, **kwargs):
20532046
20542047
.. _wildcard index: https://docs.mongodb.com/master/core/index-wildcard/#wildcard-index-core
20552048
"""
2056-
keys = helpers._index_list(keys)
2057-
name = kwargs.setdefault("name", helpers._gen_index_name(keys))
20582049
cmd_options = {}
20592050
if "maxTimeMS" in kwargs:
20602051
cmd_options["maxTimeMS"] = kwargs.pop("maxTimeMS")
2061-
self.__create_index(keys, kwargs, session, **cmd_options)
2062-
return name
2052+
index = IndexModel(keys, **kwargs)
2053+
return self.__create_indexes([index], session, **cmd_options)[0]
20632054

20642055
def ensure_index(self, key_or_list, cache_for=300, **kwargs):
20652056
"""**DEPRECATED** - Ensures that an index exists on this collection.
@@ -2080,8 +2071,8 @@ def ensure_index(self, key_or_list, cache_for=300, **kwargs):
20802071
if "bucket_size" in kwargs:
20812072
kwargs["bucketSize"] = kwargs.pop("bucket_size")
20822073

2083-
keys = helpers._index_list(key_or_list)
2084-
name = kwargs.setdefault("name", helpers._gen_index_name(keys))
2074+
index = IndexModel(key_or_list, **kwargs)
2075+
name = index.document["name"]
20852076

20862077
# Note that there is a race condition here. One thread could
20872078
# check if the index is cached and be preempted before creating
@@ -2091,7 +2082,7 @@ def ensure_index(self, key_or_list, cache_for=300, **kwargs):
20912082
# other than wasted round trips.
20922083
if not self.__database.client._cached(self.__database.name,
20932084
self.__name, name):
2094-
self.__create_index(keys, kwargs, session=None)
2085+
self.__create_indexes([index], session=None)
20952086
self.__database.client._cache_index(self.__database.name,
20962087
self.__name, name, cache_for)
20972088
return name

pymongo/helpers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ def _index_document(index_list):
9696
raise TypeError("first item in each key pair must be a string")
9797
if not isinstance(value, (string_type, int, abc.Mapping)):
9898
raise TypeError("second item in each key pair must be 1, -1, "
99-
"'2d', 'geoHaystack', or another valid MongoDB "
100-
"index specifier.")
99+
"'2d', or another valid MongoDB index specifier.")
101100
index[key] = value
102101
return index
103102

test/test_legacy_api.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from bson.objectid import ObjectId
3030
from bson.py3compat import string_type
3131
from bson.son import SON
32-
from pymongo import ASCENDING, DESCENDING
32+
from pymongo import ASCENDING, DESCENDING, GEOHAYSTACK
3333
from pymongo.database import Database
3434
from pymongo.common import partition_node
3535
from pymongo.errors import (BulkWriteError,
@@ -43,6 +43,7 @@
4343
WriteConcernError,
4444
WTimeoutError)
4545
from pymongo.message import _CursorAddress
46+
from pymongo.operations import IndexModel
4647
from pymongo.son_manipulator import (AutoReference,
4748
NamespaceInjector,
4849
ObjectIdShuffler,
@@ -108,6 +109,15 @@ def test_ensure_index_deprecation(self):
108109
def test_reindex_deprecation(self):
109110
self.assertRaises(DeprecationWarning, lambda: self.db.test.reindex())
110111

112+
def test_geoHaystack_deprecation(self):
113+
self.addCleanup(self.db.test.drop)
114+
keys = [("pos", GEOHAYSTACK), ("type", ASCENDING)]
115+
self.assertRaises(
116+
DeprecationWarning, self.db.test.create_index, keys, bucketSize=1)
117+
indexes = [IndexModel(keys, bucketSize=1)]
118+
self.assertRaises(
119+
DeprecationWarning, self.db.test.create_indexes, indexes)
120+
111121

112122
class TestLegacy(IntegrationTest):
113123

0 commit comments

Comments
 (0)