sensu-plugins-mongodb-mrtrotl 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE +22 -0
  4. data/README.md +27 -0
  5. data/bin/check-mongodb-metric.rb +144 -0
  6. data/bin/check-mongodb-query-count.rb +267 -0
  7. data/bin/check-mongodb.py +1644 -0
  8. data/bin/check-mongodb.rb +5 -0
  9. data/bin/metrics-mongodb-replication.rb +254 -0
  10. data/bin/metrics-mongodb.rb +133 -0
  11. data/lib/bson/__init__.py +1347 -0
  12. data/lib/bson/__pycache__/__init__.cpython-310.pyc +0 -0
  13. data/lib/bson/__pycache__/_helpers.cpython-310.pyc +0 -0
  14. data/lib/bson/__pycache__/binary.cpython-310.pyc +0 -0
  15. data/lib/bson/__pycache__/code.cpython-310.pyc +0 -0
  16. data/lib/bson/__pycache__/codec_options.cpython-310.pyc +0 -0
  17. data/lib/bson/__pycache__/dbref.cpython-310.pyc +0 -0
  18. data/lib/bson/__pycache__/decimal128.cpython-310.pyc +0 -0
  19. data/lib/bson/__pycache__/errors.cpython-310.pyc +0 -0
  20. data/lib/bson/__pycache__/int64.cpython-310.pyc +0 -0
  21. data/lib/bson/__pycache__/json_util.cpython-310.pyc +0 -0
  22. data/lib/bson/__pycache__/max_key.cpython-310.pyc +0 -0
  23. data/lib/bson/__pycache__/min_key.cpython-310.pyc +0 -0
  24. data/lib/bson/__pycache__/objectid.cpython-310.pyc +0 -0
  25. data/lib/bson/__pycache__/raw_bson.cpython-310.pyc +0 -0
  26. data/lib/bson/__pycache__/regex.cpython-310.pyc +0 -0
  27. data/lib/bson/__pycache__/son.cpython-310.pyc +0 -0
  28. data/lib/bson/__pycache__/timestamp.cpython-310.pyc +0 -0
  29. data/lib/bson/__pycache__/tz_util.cpython-310.pyc +0 -0
  30. data/lib/bson/_cbson.cpython-310-x86_64-linux-gnu.so +0 -0
  31. data/lib/bson/_helpers.py +41 -0
  32. data/lib/bson/binary.py +364 -0
  33. data/lib/bson/code.py +101 -0
  34. data/lib/bson/codec_options.py +414 -0
  35. data/lib/bson/codec_options.pyi +100 -0
  36. data/lib/bson/dbref.py +133 -0
  37. data/lib/bson/decimal128.py +314 -0
  38. data/lib/bson/errors.py +35 -0
  39. data/lib/bson/int64.py +39 -0
  40. data/lib/bson/json_util.py +874 -0
  41. data/lib/bson/max_key.py +55 -0
  42. data/lib/bson/min_key.py +55 -0
  43. data/lib/bson/objectid.py +286 -0
  44. data/lib/bson/py.typed +2 -0
  45. data/lib/bson/raw_bson.py +175 -0
  46. data/lib/bson/regex.py +135 -0
  47. data/lib/bson/son.py +208 -0
  48. data/lib/bson/timestamp.py +124 -0
  49. data/lib/bson/tz_util.py +52 -0
  50. data/lib/gridfs/__init__.py +1015 -0
  51. data/lib/gridfs/__pycache__/__init__.cpython-310.pyc +0 -0
  52. data/lib/gridfs/__pycache__/errors.cpython-310.pyc +0 -0
  53. data/lib/gridfs/__pycache__/grid_file.cpython-310.pyc +0 -0
  54. data/lib/gridfs/errors.py +33 -0
  55. data/lib/gridfs/grid_file.py +907 -0
  56. data/lib/gridfs/py.typed +2 -0
  57. data/lib/pymongo/__init__.py +185 -0
  58. data/lib/pymongo/__pycache__/__init__.cpython-310.pyc +0 -0
  59. data/lib/pymongo/__pycache__/_csot.cpython-310.pyc +0 -0
  60. data/lib/pymongo/__pycache__/aggregation.cpython-310.pyc +0 -0
  61. data/lib/pymongo/__pycache__/auth.cpython-310.pyc +0 -0
  62. data/lib/pymongo/__pycache__/auth_aws.cpython-310.pyc +0 -0
  63. data/lib/pymongo/__pycache__/bulk.cpython-310.pyc +0 -0
  64. data/lib/pymongo/__pycache__/change_stream.cpython-310.pyc +0 -0
  65. data/lib/pymongo/__pycache__/client_options.cpython-310.pyc +0 -0
  66. data/lib/pymongo/__pycache__/client_session.cpython-310.pyc +0 -0
  67. data/lib/pymongo/__pycache__/collation.cpython-310.pyc +0 -0
  68. data/lib/pymongo/__pycache__/collection.cpython-310.pyc +0 -0
  69. data/lib/pymongo/__pycache__/command_cursor.cpython-310.pyc +0 -0
  70. data/lib/pymongo/__pycache__/common.cpython-310.pyc +0 -0
  71. data/lib/pymongo/__pycache__/compression_support.cpython-310.pyc +0 -0
  72. data/lib/pymongo/__pycache__/cursor.cpython-310.pyc +0 -0
  73. data/lib/pymongo/__pycache__/daemon.cpython-310.pyc +0 -0
  74. data/lib/pymongo/__pycache__/database.cpython-310.pyc +0 -0
  75. data/lib/pymongo/__pycache__/driver_info.cpython-310.pyc +0 -0
  76. data/lib/pymongo/__pycache__/encryption.cpython-310.pyc +0 -0
  77. data/lib/pymongo/__pycache__/encryption_options.cpython-310.pyc +0 -0
  78. data/lib/pymongo/__pycache__/errors.cpython-310.pyc +0 -0
  79. data/lib/pymongo/__pycache__/event_loggers.cpython-310.pyc +0 -0
  80. data/lib/pymongo/__pycache__/hello.cpython-310.pyc +0 -0
  81. data/lib/pymongo/__pycache__/helpers.cpython-310.pyc +0 -0
  82. data/lib/pymongo/__pycache__/max_staleness_selectors.cpython-310.pyc +0 -0
  83. data/lib/pymongo/__pycache__/message.cpython-310.pyc +0 -0
  84. data/lib/pymongo/__pycache__/mongo_client.cpython-310.pyc +0 -0
  85. data/lib/pymongo/__pycache__/monitor.cpython-310.pyc +0 -0
  86. data/lib/pymongo/__pycache__/monitoring.cpython-310.pyc +0 -0
  87. data/lib/pymongo/__pycache__/network.cpython-310.pyc +0 -0
  88. data/lib/pymongo/__pycache__/ocsp_cache.cpython-310.pyc +0 -0
  89. data/lib/pymongo/__pycache__/ocsp_support.cpython-310.pyc +0 -0
  90. data/lib/pymongo/__pycache__/operations.cpython-310.pyc +0 -0
  91. data/lib/pymongo/__pycache__/periodic_executor.cpython-310.pyc +0 -0
  92. data/lib/pymongo/__pycache__/pool.cpython-310.pyc +0 -0
  93. data/lib/pymongo/__pycache__/pyopenssl_context.cpython-310.pyc +0 -0
  94. data/lib/pymongo/__pycache__/read_concern.cpython-310.pyc +0 -0
  95. data/lib/pymongo/__pycache__/read_preferences.cpython-310.pyc +0 -0
  96. data/lib/pymongo/__pycache__/response.cpython-310.pyc +0 -0
  97. data/lib/pymongo/__pycache__/results.cpython-310.pyc +0 -0
  98. data/lib/pymongo/__pycache__/saslprep.cpython-310.pyc +0 -0
  99. data/lib/pymongo/__pycache__/server.cpython-310.pyc +0 -0
  100. data/lib/pymongo/__pycache__/server_api.cpython-310.pyc +0 -0
  101. data/lib/pymongo/__pycache__/server_description.cpython-310.pyc +0 -0
  102. data/lib/pymongo/__pycache__/server_selectors.cpython-310.pyc +0 -0
  103. data/lib/pymongo/__pycache__/server_type.cpython-310.pyc +0 -0
  104. data/lib/pymongo/__pycache__/settings.cpython-310.pyc +0 -0
  105. data/lib/pymongo/__pycache__/socket_checker.cpython-310.pyc +0 -0
  106. data/lib/pymongo/__pycache__/srv_resolver.cpython-310.pyc +0 -0
  107. data/lib/pymongo/__pycache__/ssl_context.cpython-310.pyc +0 -0
  108. data/lib/pymongo/__pycache__/ssl_support.cpython-310.pyc +0 -0
  109. data/lib/pymongo/__pycache__/topology.cpython-310.pyc +0 -0
  110. data/lib/pymongo/__pycache__/topology_description.cpython-310.pyc +0 -0
  111. data/lib/pymongo/__pycache__/typings.cpython-310.pyc +0 -0
  112. data/lib/pymongo/__pycache__/uri_parser.cpython-310.pyc +0 -0
  113. data/lib/pymongo/__pycache__/write_concern.cpython-310.pyc +0 -0
  114. data/lib/pymongo/_cmessage.cpython-310-x86_64-linux-gnu.so +0 -0
  115. data/lib/pymongo/_csot.py +118 -0
  116. data/lib/pymongo/aggregation.py +229 -0
  117. data/lib/pymongo/auth.py +549 -0
  118. data/lib/pymongo/auth_aws.py +94 -0
  119. data/lib/pymongo/bulk.py +513 -0
  120. data/lib/pymongo/change_stream.py +457 -0
  121. data/lib/pymongo/client_options.py +302 -0
  122. data/lib/pymongo/client_session.py +1112 -0
  123. data/lib/pymongo/collation.py +224 -0
  124. data/lib/pymongo/collection.py +3204 -0
  125. data/lib/pymongo/command_cursor.py +353 -0
  126. data/lib/pymongo/common.py +984 -0
  127. data/lib/pymongo/compression_support.py +149 -0
  128. data/lib/pymongo/cursor.py +1345 -0
  129. data/lib/pymongo/daemon.py +141 -0
  130. data/lib/pymongo/database.py +1202 -0
  131. data/lib/pymongo/driver_info.py +42 -0
  132. data/lib/pymongo/encryption.py +884 -0
  133. data/lib/pymongo/encryption_options.py +221 -0
  134. data/lib/pymongo/errors.py +365 -0
  135. data/lib/pymongo/event_loggers.py +221 -0
  136. data/lib/pymongo/hello.py +219 -0
  137. data/lib/pymongo/helpers.py +259 -0
  138. data/lib/pymongo/max_staleness_selectors.py +114 -0
  139. data/lib/pymongo/message.py +1440 -0
  140. data/lib/pymongo/mongo_client.py +2144 -0
  141. data/lib/pymongo/monitor.py +440 -0
  142. data/lib/pymongo/monitoring.py +1801 -0
  143. data/lib/pymongo/network.py +311 -0
  144. data/lib/pymongo/ocsp_cache.py +87 -0
  145. data/lib/pymongo/ocsp_support.py +372 -0
  146. data/lib/pymongo/operations.py +507 -0
  147. data/lib/pymongo/periodic_executor.py +183 -0
  148. data/lib/pymongo/pool.py +1660 -0
  149. data/lib/pymongo/py.typed +2 -0
  150. data/lib/pymongo/pyopenssl_context.py +383 -0
  151. data/lib/pymongo/read_concern.py +75 -0
  152. data/lib/pymongo/read_preferences.py +609 -0
  153. data/lib/pymongo/response.py +109 -0
  154. data/lib/pymongo/results.py +217 -0
  155. data/lib/pymongo/saslprep.py +113 -0
  156. data/lib/pymongo/server.py +247 -0
  157. data/lib/pymongo/server_api.py +170 -0
  158. data/lib/pymongo/server_description.py +285 -0
  159. data/lib/pymongo/server_selectors.py +153 -0
  160. data/lib/pymongo/server_type.py +32 -0
  161. data/lib/pymongo/settings.py +159 -0
  162. data/lib/pymongo/socket_checker.py +104 -0
  163. data/lib/pymongo/srv_resolver.py +126 -0
  164. data/lib/pymongo/ssl_context.py +39 -0
  165. data/lib/pymongo/ssl_support.py +99 -0
  166. data/lib/pymongo/topology.py +890 -0
  167. data/lib/pymongo/topology_description.py +639 -0
  168. data/lib/pymongo/typings.py +39 -0
  169. data/lib/pymongo/uri_parser.py +624 -0
  170. data/lib/pymongo/write_concern.py +129 -0
  171. data/lib/pymongo-4.2.0.dist-info/INSTALLER +1 -0
  172. data/lib/pymongo-4.2.0.dist-info/LICENSE +201 -0
  173. data/lib/pymongo-4.2.0.dist-info/METADATA +250 -0
  174. data/lib/pymongo-4.2.0.dist-info/RECORD +167 -0
  175. data/lib/pymongo-4.2.0.dist-info/REQUESTED +0 -0
  176. data/lib/pymongo-4.2.0.dist-info/WHEEL +6 -0
  177. data/lib/pymongo-4.2.0.dist-info/top_level.txt +3 -0
  178. data/lib/sensu-plugins-mongodb/metrics.rb +391 -0
  179. data/lib/sensu-plugins-mongodb/version.rb +9 -0
  180. data/lib/sensu-plugins-mongodb.rb +1 -0
  181. metadata +407 -0
@@ -0,0 +1,353 @@
1
+ # Copyright 2014-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
+ """CommandCursor class to iterate over command results."""
16
+
17
+ from collections import deque
18
+ from typing import TYPE_CHECKING, Any, Generic, Iterator, Mapping, NoReturn, Optional
19
+
20
+ from bson import _convert_raw_document_lists_to_streams
21
+ from pymongo.cursor import _CURSOR_CLOSED_ERRORS, _SocketManager
22
+ from pymongo.errors import ConnectionFailure, InvalidOperation, OperationFailure
23
+ from pymongo.message import _CursorAddress, _GetMore, _RawBatchGetMore
24
+ from pymongo.response import PinnedResponse
25
+ from pymongo.typings import _Address, _DocumentType
26
+
27
+ if TYPE_CHECKING:
28
+ from pymongo.client_session import ClientSession
29
+ from pymongo.collection import Collection
30
+
31
+
32
+ class CommandCursor(Generic[_DocumentType]):
33
+ """A cursor / iterator over command cursors."""
34
+
35
+ _getmore_class = _GetMore
36
+
37
+ def __init__(
38
+ self,
39
+ collection: "Collection[_DocumentType]",
40
+ cursor_info: Mapping[str, Any],
41
+ address: Optional[_Address],
42
+ batch_size: int = 0,
43
+ max_await_time_ms: Optional[int] = None,
44
+ session: Optional["ClientSession"] = None,
45
+ explicit_session: bool = False,
46
+ comment: Any = None,
47
+ ) -> None:
48
+ """Create a new command cursor."""
49
+ self.__sock_mgr: Any = None
50
+ self.__collection: Collection[_DocumentType] = collection
51
+ self.__id = cursor_info["id"]
52
+ self.__data = deque(cursor_info["firstBatch"])
53
+ self.__postbatchresumetoken = cursor_info.get("postBatchResumeToken")
54
+ self.__address = address
55
+ self.__batch_size = batch_size
56
+ self.__max_await_time_ms = max_await_time_ms
57
+ self.__session = session
58
+ self.__explicit_session = explicit_session
59
+ self.__killed = self.__id == 0
60
+ self.__comment = comment
61
+ if self.__killed:
62
+ self.__end_session(True)
63
+
64
+ if "ns" in cursor_info:
65
+ self.__ns = cursor_info["ns"]
66
+ else:
67
+ self.__ns = collection.full_name
68
+
69
+ self.batch_size(batch_size)
70
+
71
+ if not isinstance(max_await_time_ms, int) and max_await_time_ms is not None:
72
+ raise TypeError("max_await_time_ms must be an integer or None")
73
+
74
+ def __del__(self) -> None:
75
+ self.__die()
76
+
77
+ def __die(self, synchronous=False):
78
+ """Closes this cursor."""
79
+ already_killed = self.__killed
80
+ self.__killed = True
81
+ if self.__id and not already_killed:
82
+ cursor_id = self.__id
83
+ address = _CursorAddress(self.__address, self.__ns)
84
+ else:
85
+ # Skip killCursors.
86
+ cursor_id = 0
87
+ address = None
88
+ self.__collection.database.client._cleanup_cursor(
89
+ synchronous,
90
+ cursor_id,
91
+ address,
92
+ self.__sock_mgr,
93
+ self.__session,
94
+ self.__explicit_session,
95
+ )
96
+ if not self.__explicit_session:
97
+ self.__session = None
98
+ self.__sock_mgr = None
99
+
100
+ def __end_session(self, synchronous):
101
+ if self.__session and not self.__explicit_session:
102
+ self.__session._end_session(lock=synchronous)
103
+ self.__session = None
104
+
105
+ def close(self) -> None:
106
+ """Explicitly close / kill this cursor."""
107
+ self.__die(True)
108
+
109
+ def batch_size(self, batch_size: int) -> "CommandCursor[_DocumentType]":
110
+ """Limits the number of documents returned in one batch. Each batch
111
+ requires a round trip to the server. It can be adjusted to optimize
112
+ performance and limit data transfer.
113
+
114
+ .. note:: batch_size can not override MongoDB's internal limits on the
115
+ amount of data it will return to the client in a single batch (i.e
116
+ if you set batch size to 1,000,000,000, MongoDB will currently only
117
+ return 4-16MB of results per batch).
118
+
119
+ Raises :exc:`TypeError` if `batch_size` is not an integer.
120
+ Raises :exc:`ValueError` if `batch_size` is less than ``0``.
121
+
122
+ :Parameters:
123
+ - `batch_size`: The size of each batch of results requested.
124
+ """
125
+ if not isinstance(batch_size, int):
126
+ raise TypeError("batch_size must be an integer")
127
+ if batch_size < 0:
128
+ raise ValueError("batch_size must be >= 0")
129
+
130
+ self.__batch_size = batch_size == 1 and 2 or batch_size
131
+ return self
132
+
133
+ def _has_next(self):
134
+ """Returns `True` if the cursor has documents remaining from the
135
+ previous batch."""
136
+ return len(self.__data) > 0
137
+
138
+ @property
139
+ def _post_batch_resume_token(self):
140
+ """Retrieve the postBatchResumeToken from the response to a
141
+ changeStream aggregate or getMore."""
142
+ return self.__postbatchresumetoken
143
+
144
+ def _maybe_pin_connection(self, sock_info):
145
+ client = self.__collection.database.client
146
+ if not client._should_pin_cursor(self.__session):
147
+ return
148
+ if not self.__sock_mgr:
149
+ sock_info.pin_cursor()
150
+ sock_mgr = _SocketManager(sock_info, False)
151
+ # Ensure the connection gets returned when the entire result is
152
+ # returned in the first batch.
153
+ if self.__id == 0:
154
+ sock_mgr.close()
155
+ else:
156
+ self.__sock_mgr = sock_mgr
157
+
158
+ def __send_message(self, operation):
159
+ """Send a getmore message and handle the response."""
160
+ client = self.__collection.database.client
161
+ try:
162
+ response = client._run_operation(
163
+ operation, self._unpack_response, address=self.__address
164
+ )
165
+ except OperationFailure as exc:
166
+ if exc.code in _CURSOR_CLOSED_ERRORS:
167
+ # Don't send killCursors because the cursor is already closed.
168
+ self.__killed = True
169
+ # Return the session and pinned connection, if necessary.
170
+ self.close()
171
+ raise
172
+ except ConnectionFailure:
173
+ # Don't send killCursors because the cursor is already closed.
174
+ self.__killed = True
175
+ # Return the session and pinned connection, if necessary.
176
+ self.close()
177
+ raise
178
+ except Exception:
179
+ self.close()
180
+ raise
181
+
182
+ if isinstance(response, PinnedResponse):
183
+ if not self.__sock_mgr:
184
+ self.__sock_mgr = _SocketManager(response.socket_info, response.more_to_come)
185
+ if response.from_command:
186
+ cursor = response.docs[0]["cursor"]
187
+ documents = cursor["nextBatch"]
188
+ self.__postbatchresumetoken = cursor.get("postBatchResumeToken")
189
+ self.__id = cursor["id"]
190
+ else:
191
+ documents = response.docs
192
+ self.__id = response.data.cursor_id
193
+
194
+ if self.__id == 0:
195
+ self.close()
196
+ self.__data = deque(documents)
197
+
198
+ def _unpack_response(
199
+ self, response, cursor_id, codec_options, user_fields=None, legacy_response=False
200
+ ):
201
+ return response.unpack_response(cursor_id, codec_options, user_fields, legacy_response)
202
+
203
+ def _refresh(self):
204
+ """Refreshes the cursor with more data from the server.
205
+
206
+ Returns the length of self.__data after refresh. Will exit early if
207
+ self.__data is already non-empty. Raises OperationFailure when the
208
+ cursor cannot be refreshed due to an error on the query.
209
+ """
210
+ if len(self.__data) or self.__killed:
211
+ return len(self.__data)
212
+
213
+ if self.__id: # Get More
214
+ dbname, collname = self.__ns.split(".", 1)
215
+ read_pref = self.__collection._read_preference_for(self.session)
216
+ self.__send_message(
217
+ self._getmore_class(
218
+ dbname,
219
+ collname,
220
+ self.__batch_size,
221
+ self.__id,
222
+ self.__collection.codec_options,
223
+ read_pref,
224
+ self.__session,
225
+ self.__collection.database.client,
226
+ self.__max_await_time_ms,
227
+ self.__sock_mgr,
228
+ False,
229
+ self.__comment,
230
+ )
231
+ )
232
+ else: # Cursor id is zero nothing else to return
233
+ self.__die(True)
234
+
235
+ return len(self.__data)
236
+
237
+ @property
238
+ def alive(self) -> bool:
239
+ """Does this cursor have the potential to return more data?
240
+
241
+ Even if :attr:`alive` is ``True``, :meth:`next` can raise
242
+ :exc:`StopIteration`. Best to use a for loop::
243
+
244
+ for doc in collection.aggregate(pipeline):
245
+ print(doc)
246
+
247
+ .. note:: :attr:`alive` can be True while iterating a cursor from
248
+ a failed server. In this case :attr:`alive` will return False after
249
+ :meth:`next` fails to retrieve the next batch of results from the
250
+ server.
251
+ """
252
+ return bool(len(self.__data) or (not self.__killed))
253
+
254
+ @property
255
+ def cursor_id(self) -> int:
256
+ """Returns the id of the cursor."""
257
+ return self.__id
258
+
259
+ @property
260
+ def address(self) -> Optional[_Address]:
261
+ """The (host, port) of the server used, or None.
262
+
263
+ .. versionadded:: 3.0
264
+ """
265
+ return self.__address
266
+
267
+ @property
268
+ def session(self) -> Optional["ClientSession"]:
269
+ """The cursor's :class:`~pymongo.client_session.ClientSession`, or None.
270
+
271
+ .. versionadded:: 3.6
272
+ """
273
+ if self.__explicit_session:
274
+ return self.__session
275
+ return None
276
+
277
+ def __iter__(self) -> Iterator[_DocumentType]:
278
+ return self
279
+
280
+ def next(self) -> _DocumentType:
281
+ """Advance the cursor."""
282
+ # Block until a document is returnable.
283
+ while self.alive:
284
+ doc = self._try_next(True)
285
+ if doc is not None:
286
+ return doc
287
+
288
+ raise StopIteration
289
+
290
+ __next__ = next
291
+
292
+ def _try_next(self, get_more_allowed):
293
+ """Advance the cursor blocking for at most one getMore command."""
294
+ if not len(self.__data) and not self.__killed and get_more_allowed:
295
+ self._refresh()
296
+ if len(self.__data):
297
+ return self.__data.popleft()
298
+ else:
299
+ return None
300
+
301
+ def __enter__(self) -> "CommandCursor[_DocumentType]":
302
+ return self
303
+
304
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
305
+ self.close()
306
+
307
+
308
+ class RawBatchCommandCursor(CommandCursor, Generic[_DocumentType]):
309
+ _getmore_class = _RawBatchGetMore
310
+
311
+ def __init__(
312
+ self,
313
+ collection: "Collection[_DocumentType]",
314
+ cursor_info: Mapping[str, Any],
315
+ address: Optional[_Address],
316
+ batch_size: int = 0,
317
+ max_await_time_ms: Optional[int] = None,
318
+ session: Optional["ClientSession"] = None,
319
+ explicit_session: bool = False,
320
+ comment: Any = None,
321
+ ) -> None:
322
+ """Create a new cursor / iterator over raw batches of BSON data.
323
+
324
+ Should not be called directly by application developers -
325
+ see :meth:`~pymongo.collection.Collection.aggregate_raw_batches`
326
+ instead.
327
+
328
+ .. seealso:: The MongoDB documentation on `cursors <https://dochub.mongodb.org/core/cursors>`_.
329
+ """
330
+ assert not cursor_info.get("firstBatch")
331
+ super(RawBatchCommandCursor, self).__init__(
332
+ collection,
333
+ cursor_info,
334
+ address,
335
+ batch_size,
336
+ max_await_time_ms,
337
+ session,
338
+ explicit_session,
339
+ comment,
340
+ )
341
+
342
+ def _unpack_response(
343
+ self, response, cursor_id, codec_options, user_fields=None, legacy_response=False
344
+ ):
345
+ raw_response = response.raw_response(cursor_id, user_fields=user_fields)
346
+ if not legacy_response:
347
+ # OP_MSG returns firstBatch/nextBatch documents as a BSON array
348
+ # Re-assemble the array of documents into a document stream
349
+ _convert_raw_document_lists_to_streams(raw_response[0])
350
+ return raw_response
351
+
352
+ def __getitem__(self, index: int) -> NoReturn:
353
+ raise InvalidOperation("Cannot call __getitem__ on RawBatchCursor")