|
46 | 46 | ScramCredentialInfo,
|
47 | 47 | ScramMechanism,
|
48 | 48 | UserScramCredentialsDescription)
|
| 49 | + |
49 | 50 | from ._topic import (TopicDescription) # noqa: F401
|
50 | 51 |
|
51 | 52 | from ._cluster import (DescribeClusterResult) # noqa: F401
|
52 | 53 |
|
| 54 | +from ._listoffsets import (OffsetSpec, # noqa: F401 |
| 55 | + ListOffsetsResultInfo) |
| 56 | + |
53 | 57 | from .._model import TopicCollection as _TopicCollection
|
54 | 58 |
|
55 | 59 | from ..cimpl import (KafkaException, # noqa: F401
|
|
71 | 75 | RESOURCE_BROKER,
|
72 | 76 | OFFSET_INVALID)
|
73 | 77 |
|
74 |
| -from confluent_kafka import ConsumerGroupTopicPartitions \ |
75 |
| - as _ConsumerGroupTopicPartitions |
76 |
| - |
77 |
| -from confluent_kafka import ConsumerGroupState \ |
78 |
| - as _ConsumerGroupState |
| 78 | +from confluent_kafka import \ |
| 79 | + ConsumerGroupTopicPartitions as _ConsumerGroupTopicPartitions, \ |
| 80 | + ConsumerGroupState as _ConsumerGroupState, \ |
| 81 | + IsolationLevel as _IsolationLevel |
79 | 82 |
|
80 | 83 |
|
81 | 84 | try:
|
@@ -295,6 +298,28 @@ def _make_user_scram_credentials_result(f, futmap):
|
295 | 298 | for _, fut in futmap.items():
|
296 | 299 | fut.set_exception(e)
|
297 | 300 |
|
| 301 | + @staticmethod |
| 302 | + def _make_futmap_result(f, futmap): |
| 303 | + try: |
| 304 | + results = f.result() |
| 305 | + len_results = len(results) |
| 306 | + len_futures = len(futmap) |
| 307 | + if len(results) != len_futures: |
| 308 | + raise RuntimeError( |
| 309 | + f"Results length {len_results} is different from future-map length {len_futures}") |
| 310 | + for key, value in results.items(): |
| 311 | + fut = futmap.get(key, None) |
| 312 | + if fut is None: |
| 313 | + raise RuntimeError( |
| 314 | + f"Key {key} not found in future-map: {futmap}") |
| 315 | + if isinstance(value, KafkaError): |
| 316 | + fut.set_exception(KafkaException(value)) |
| 317 | + else: |
| 318 | + fut.set_result(value) |
| 319 | + except Exception as e: |
| 320 | + for _, fut in futmap.items(): |
| 321 | + fut.set_exception(e) |
| 322 | + |
298 | 323 | @staticmethod
|
299 | 324 | def _create_future():
|
300 | 325 | f = concurrent.futures.Future()
|
@@ -384,7 +409,6 @@ def _check_list_consumer_group_offsets_request(request):
|
384 | 409 | if topic_partition.partition < 0:
|
385 | 410 | raise ValueError("Element of 'topic_partitions' must not have negative 'partition' value")
|
386 | 411 | if topic_partition.offset != OFFSET_INVALID:
|
387 |
| - print(topic_partition.offset) |
388 | 412 | raise ValueError("Element of 'topic_partitions' must not have 'offset' value")
|
389 | 413 |
|
390 | 414 | @staticmethod
|
@@ -479,6 +503,34 @@ def _check_alter_user_scram_credentials_request(alterations):
|
479 | 503 | "to be either a UserScramCredentialUpsertion or a " +
|
480 | 504 | "UserScramCredentialDeletion")
|
481 | 505 |
|
| 506 | + @staticmethod |
| 507 | + def _check_list_offsets_request(topic_partition_offsets, kwargs): |
| 508 | + if not isinstance(topic_partition_offsets, dict): |
| 509 | + raise TypeError("Expected topic_partition_offsets to be " + |
| 510 | + "dict of [TopicPartitions,OffsetSpec] for list offsets request") |
| 511 | + |
| 512 | + for topic_partition, offset_spec in topic_partition_offsets.items(): |
| 513 | + if topic_partition is None: |
| 514 | + raise TypeError("partition cannot be None") |
| 515 | + if not isinstance(topic_partition, _TopicPartition): |
| 516 | + raise TypeError("partition must be a TopicPartition") |
| 517 | + if topic_partition.topic is None: |
| 518 | + raise TypeError("partition topic name cannot be None") |
| 519 | + if not isinstance(topic_partition.topic, string_type): |
| 520 | + raise TypeError("partition topic name must be string") |
| 521 | + if not topic_partition.topic: |
| 522 | + raise ValueError("partition topic name cannot be empty") |
| 523 | + if topic_partition.partition < 0: |
| 524 | + raise ValueError("partition index must be non-negative") |
| 525 | + if offset_spec is None: |
| 526 | + raise TypeError("OffsetSpec cannot be None") |
| 527 | + if not isinstance(offset_spec, OffsetSpec): |
| 528 | + raise TypeError("Value must be a OffsetSpec") |
| 529 | + |
| 530 | + if 'isolation_level' in kwargs: |
| 531 | + if not isinstance(kwargs['isolation_level'], _IsolationLevel): |
| 532 | + raise TypeError("isolation_level argument should be an IsolationLevel") |
| 533 | + |
482 | 534 | def create_topics(self, new_topics, **kwargs):
|
483 | 535 | """
|
484 | 536 | Create one or more new topics.
|
@@ -1103,5 +1155,45 @@ def alter_user_scram_credentials(self, alterations, **kwargs):
|
1103 | 1155 | AdminClient._make_user_scram_credentials_result)
|
1104 | 1156 |
|
1105 | 1157 | super(AdminClient, self).alter_user_scram_credentials(alterations, f, **kwargs)
|
| 1158 | + return futmap |
| 1159 | + |
| 1160 | + def list_offsets(self, topic_partition_offsets, **kwargs): |
| 1161 | + """ |
| 1162 | + Enables to find the beginning offset, |
| 1163 | + end offset as well as the offset matching a timestamp |
| 1164 | + or the offset with max timestamp in partitions. |
| 1165 | +
|
| 1166 | + :param dict([TopicPartition, OffsetSpec]) topic_partition_offsets: Dictionary of |
| 1167 | + TopicPartition objects associated with the corresponding OffsetSpec to query for. |
| 1168 | + :param IsolationLevel isolation_level: The isolation level to use when |
| 1169 | + querying. |
| 1170 | + :param float request_timeout: The overall request timeout in seconds, |
| 1171 | + including broker lookup, request transmission, operation time |
| 1172 | + on broker, and response. Default: `socket.timeout.ms*1000.0` |
| 1173 | +
|
| 1174 | + :returns: A dict of futures keyed by TopicPartition. |
| 1175 | + The future result() method returns ListOffsetsResultInfo |
| 1176 | + raises KafkaException |
| 1177 | +
|
| 1178 | + :rtype: dict[TopicPartition, future] |
| 1179 | +
|
| 1180 | + :raises TypeError: Invalid input type. |
| 1181 | + :raises ValueError: Invalid input value. |
| 1182 | + """ |
| 1183 | + AdminClient._check_list_offsets_request(topic_partition_offsets, kwargs) |
| 1184 | + |
| 1185 | + if 'isolation_level' in kwargs: |
| 1186 | + kwargs['isolation_level_value'] = kwargs['isolation_level'].value |
| 1187 | + del kwargs['isolation_level'] |
| 1188 | + |
| 1189 | + topic_partition_offsets_list = [ |
| 1190 | + _TopicPartition(topic_partition.topic, int(topic_partition.partition), |
| 1191 | + int(offset_spec._value)) |
| 1192 | + for topic_partition, offset_spec in topic_partition_offsets.items()] |
| 1193 | + |
| 1194 | + f, futmap = AdminClient._make_futures_v2(topic_partition_offsets_list, |
| 1195 | + _TopicPartition, |
| 1196 | + AdminClient._make_futmap_result) |
1106 | 1197 |
|
| 1198 | + super(AdminClient, self).list_offsets(topic_partition_offsets_list, f, **kwargs) |
1107 | 1199 | return futmap
|
0 commit comments