Skip to content

Commit 8034bae

Browse files
authored
PYTHON-4834 Add __repr__ to IndexModel, SearchIndexModel (mongodb#1909)
1 parent fa263dc commit 8034bae

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

doc/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ PyMongo 4.11 brings a number of changes including:
1717
- :attr:`~pymongo.asynchronous.mongo_client.AsyncMongoClient.address` and
1818
:attr:`~pymongo.mongo_client.MongoClient.address` now correctly block when called on unconnected clients
1919
until either connection succeeds or a server selection timeout error is raised.
20+
- Added :func:`repr` support to :class:`pymongo.operations.IndexModel`.
21+
- Added :func:`repr` support to :class:`pymongo.operations.SearchIndexModel`.
2022

2123
Issues Resolved
2224
...............

pymongo/operations.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,13 @@ def document(self) -> dict[str, Any]:
773773
"""
774774
return self.__document
775775

776+
def __repr__(self) -> str:
777+
return "{}({}{})".format(
778+
self.__class__.__name__,
779+
self.document["key"],
780+
"".join([f", {key}={value!r}" for key, value in self.document.items() if key != "key"]),
781+
)
782+
776783

777784
class SearchIndexModel:
778785
"""Represents a search index to create."""
@@ -812,3 +819,9 @@ def __init__(
812819
def document(self) -> Mapping[str, Any]:
813820
"""The document for this index."""
814821
return self.__document
822+
823+
def __repr__(self) -> str:
824+
return "{}({})".format(
825+
self.__class__.__name__,
826+
", ".join([f"{key}={value!r}" for key, value in self.document.items()]),
827+
)

test/test_operations.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright 2024-present MongoDB, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Test the operations module."""
16+
from __future__ import annotations
17+
18+
from test import UnitTest, unittest
19+
20+
from pymongo import ASCENDING, DESCENDING
21+
from pymongo.collation import Collation
22+
from pymongo.errors import OperationFailure
23+
from pymongo.operations import IndexModel, SearchIndexModel
24+
25+
26+
class TestOperationsBase(UnitTest):
27+
"""Base class for testing operations module."""
28+
29+
def assertRepr(self, obj):
30+
new_obj = eval(repr(obj))
31+
self.assertEqual(type(new_obj), type(obj))
32+
self.assertEqual(repr(new_obj), repr(obj))
33+
34+
35+
class TestIndexModel(TestOperationsBase):
36+
"""Test IndexModel features."""
37+
38+
def test_repr(self):
39+
# Based on examples in test_collection.py
40+
self.assertRepr(IndexModel("hello"))
41+
self.assertRepr(IndexModel([("hello", DESCENDING), ("world", ASCENDING)]))
42+
self.assertRepr(
43+
IndexModel([("hello", DESCENDING), ("world", ASCENDING)], name="hello_world")
44+
)
45+
# Test all the kwargs
46+
self.assertRepr(IndexModel("name", name="name"))
47+
self.assertRepr(IndexModel("unique", unique=False))
48+
self.assertRepr(IndexModel("background", background=True))
49+
self.assertRepr(IndexModel("sparse", sparse=True))
50+
self.assertRepr(IndexModel("bucketSize", bucketSize=1))
51+
self.assertRepr(IndexModel("min", min=1))
52+
self.assertRepr(IndexModel("max", max=1))
53+
self.assertRepr(IndexModel("expireAfterSeconds", expireAfterSeconds=1))
54+
self.assertRepr(
55+
IndexModel("partialFilterExpression", partialFilterExpression={"hello": "world"})
56+
)
57+
self.assertRepr(IndexModel("collation", collation=Collation(locale="en_US")))
58+
self.assertRepr(IndexModel("wildcardProjection", wildcardProjection={"$**": 1}))
59+
self.assertRepr(IndexModel("hidden", hidden=False))
60+
# Test string literal
61+
self.assertEqual(repr(IndexModel("hello")), "IndexModel({'hello': 1}, name='hello_1')")
62+
self.assertEqual(
63+
repr(IndexModel({"hello": 1, "world": -1})),
64+
"IndexModel({'hello': 1, 'world': -1}, name='hello_1_world_-1')",
65+
)
66+
67+
68+
class TestSearchIndexModel(TestOperationsBase):
69+
"""Test SearchIndexModel features."""
70+
71+
def test_repr(self):
72+
self.assertRepr(SearchIndexModel({"hello": "hello"}, key=1))
73+
self.assertEqual(
74+
repr(SearchIndexModel({"hello": "hello"}, key=1)),
75+
"SearchIndexModel(definition={'hello': 'hello'}, key=1)",
76+
)
77+
78+
79+
if __name__ == "__main__":
80+
unittest.main()

0 commit comments

Comments
 (0)