kafka-python 2.2.14__tar.gz → 2.2.16__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. {kafka_python-2.2.14 → kafka_python-2.2.16}/CHANGES.md +12 -0
  2. {kafka_python-2.2.14 → kafka_python-2.2.16}/PKG-INFO +1 -1
  3. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/conn.py +7 -0
  4. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/consumer/group.py +2 -2
  5. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/producer/record_accumulator.py +2 -2
  6. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/producer/transaction_manager.py +2 -2
  7. kafka_python-2.2.16/kafka/version.py +1 -0
  8. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka_python.egg-info/PKG-INFO +1 -1
  9. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_conn.py +55 -2
  10. kafka_python-2.2.14/kafka/version.py +0 -1
  11. {kafka_python-2.2.14 → kafka_python-2.2.16}/AUTHORS.md +0 -0
  12. {kafka_python-2.2.14 → kafka_python-2.2.16}/LICENSE +0 -0
  13. {kafka_python-2.2.14 → kafka_python-2.2.16}/MANIFEST.in +0 -0
  14. {kafka_python-2.2.14 → kafka_python-2.2.16}/README.rst +0 -0
  15. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/__init__.py +0 -0
  16. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/admin/__init__.py +0 -0
  17. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/admin/acl_resource.py +0 -0
  18. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/admin/client.py +0 -0
  19. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/admin/config_resource.py +0 -0
  20. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/admin/new_partitions.py +0 -0
  21. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/admin/new_topic.py +0 -0
  22. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/benchmarks/__init__.py +0 -0
  23. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/benchmarks/consumer_performance.py +0 -0
  24. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/benchmarks/load_example.py +0 -0
  25. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/benchmarks/producer_performance.py +0 -0
  26. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/benchmarks/record_batch_compose.py +0 -0
  27. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/benchmarks/record_batch_read.py +0 -0
  28. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/benchmarks/varint_speed.py +0 -0
  29. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/client_async.py +0 -0
  30. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/cluster.py +0 -0
  31. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/codec.py +0 -0
  32. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/consumer/__init__.py +0 -0
  33. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/consumer/fetcher.py +0 -0
  34. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/consumer/subscription_state.py +0 -0
  35. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/__init__.py +0 -0
  36. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/assignors/__init__.py +0 -0
  37. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/assignors/abstract.py +0 -0
  38. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/assignors/range.py +0 -0
  39. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/assignors/roundrobin.py +0 -0
  40. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/assignors/sticky/__init__.py +0 -0
  41. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/assignors/sticky/partition_movements.py +0 -0
  42. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/assignors/sticky/sorted_set.py +0 -0
  43. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/assignors/sticky/sticky_assignor.py +0 -0
  44. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/base.py +0 -0
  45. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/consumer.py +0 -0
  46. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/heartbeat.py +0 -0
  47. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/coordinator/protocol.py +0 -0
  48. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/errors.py +0 -0
  49. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/future.py +0 -0
  50. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/__init__.py +0 -0
  51. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/compound_stat.py +0 -0
  52. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/dict_reporter.py +0 -0
  53. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/kafka_metric.py +0 -0
  54. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/measurable.py +0 -0
  55. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/measurable_stat.py +0 -0
  56. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/metric_config.py +0 -0
  57. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/metric_name.py +0 -0
  58. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/metrics.py +0 -0
  59. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/metrics_reporter.py +0 -0
  60. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/quota.py +0 -0
  61. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stat.py +0 -0
  62. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/__init__.py +0 -0
  63. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/avg.py +0 -0
  64. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/count.py +0 -0
  65. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/histogram.py +0 -0
  66. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/max_stat.py +0 -0
  67. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/min_stat.py +0 -0
  68. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/percentile.py +0 -0
  69. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/percentiles.py +0 -0
  70. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/rate.py +0 -0
  71. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/sampled_stat.py +0 -0
  72. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/sensor.py +0 -0
  73. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/metrics/stats/total.py +0 -0
  74. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/partitioner/__init__.py +0 -0
  75. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/partitioner/default.py +0 -0
  76. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/producer/__init__.py +0 -0
  77. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/producer/future.py +0 -0
  78. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/producer/kafka.py +0 -0
  79. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/producer/sender.py +0 -0
  80. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/__init__.py +0 -0
  81. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/abstract.py +0 -0
  82. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/add_offsets_to_txn.py +0 -0
  83. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/add_partitions_to_txn.py +0 -0
  84. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/admin.py +0 -0
  85. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/api.py +0 -0
  86. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/api_versions.py +0 -0
  87. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/broker_api_versions.py +0 -0
  88. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/commit.py +0 -0
  89. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/end_txn.py +0 -0
  90. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/fetch.py +0 -0
  91. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/find_coordinator.py +0 -0
  92. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/frame.py +0 -0
  93. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/group.py +0 -0
  94. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/init_producer_id.py +0 -0
  95. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/list_offsets.py +0 -0
  96. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/message.py +0 -0
  97. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/metadata.py +0 -0
  98. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/offset_for_leader_epoch.py +0 -0
  99. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/parser.py +0 -0
  100. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/pickle.py +0 -0
  101. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/produce.py +0 -0
  102. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/sasl_authenticate.py +0 -0
  103. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/sasl_handshake.py +0 -0
  104. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/struct.py +0 -0
  105. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/txn_offset_commit.py +0 -0
  106. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/protocol/types.py +0 -0
  107. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/record/__init__.py +0 -0
  108. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/record/_crc32c.py +0 -0
  109. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/record/abc.py +0 -0
  110. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/record/default_records.py +0 -0
  111. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/record/legacy_records.py +0 -0
  112. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/record/memory_records.py +0 -0
  113. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/record/util.py +0 -0
  114. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/sasl/__init__.py +0 -0
  115. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/sasl/abc.py +0 -0
  116. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/sasl/gssapi.py +0 -0
  117. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/sasl/msk.py +0 -0
  118. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/sasl/oauth.py +0 -0
  119. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/sasl/plain.py +0 -0
  120. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/sasl/scram.py +0 -0
  121. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/sasl/sspi.py +0 -0
  122. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/serializer/__init__.py +0 -0
  123. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/serializer/abstract.py +0 -0
  124. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/socks5_wrapper.py +0 -0
  125. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/structs.py +0 -0
  126. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/util.py +0 -0
  127. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/vendor/__init__.py +0 -0
  128. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/vendor/enum34.py +0 -0
  129. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/vendor/selectors34.py +0 -0
  130. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/vendor/six.py +0 -0
  131. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka/vendor/socketpair.py +0 -0
  132. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka_python.egg-info/SOURCES.txt +0 -0
  133. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka_python.egg-info/dependency_links.txt +0 -0
  134. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka_python.egg-info/requires.txt +0 -0
  135. {kafka_python-2.2.14 → kafka_python-2.2.16}/kafka_python.egg-info/top_level.txt +0 -0
  136. {kafka_python-2.2.14 → kafka_python-2.2.16}/pyproject.toml +0 -0
  137. {kafka_python-2.2.14 → kafka_python-2.2.16}/setup.cfg +0 -0
  138. {kafka_python-2.2.14 → kafka_python-2.2.16}/setup.py +0 -0
  139. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/integration/__init__.py +0 -0
  140. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/integration/conftest.py +0 -0
  141. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/integration/fixtures.py +0 -0
  142. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/integration/test_admin_integration.py +0 -0
  143. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/integration/test_consumer_group.py +0 -0
  144. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/integration/test_consumer_integration.py +0 -0
  145. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/integration/test_producer_integration.py +0 -0
  146. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/integration/test_sasl_integration.py +0 -0
  147. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_acl_comparisons.py +0 -0
  148. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_admin.py +0 -0
  149. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_api_object_implementation.py +0 -0
  150. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_assignors.py +0 -0
  151. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_client_async.py +0 -0
  152. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_cluster.py +0 -0
  153. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_codec.py +0 -0
  154. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_consumer.py +0 -0
  155. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_coordinator.py +0 -0
  156. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_fetcher.py +0 -0
  157. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_metrics.py +0 -0
  158. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_object_conversion.py +0 -0
  159. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_package.py +0 -0
  160. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_partition_movements.py +0 -0
  161. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_partitioner.py +0 -0
  162. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_producer.py +0 -0
  163. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_protocol.py +0 -0
  164. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_record_accumulator.py +0 -0
  165. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_sender.py +0 -0
  166. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_subscription_state.py +0 -0
  167. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/test_util.py +0 -0
  168. {kafka_python-2.2.14 → kafka_python-2.2.16}/test/testutil.py +0 -0
@@ -1,3 +1,15 @@
1
+ # 2.2.16 (Nov 18, 2025)
2
+
3
+ Fixes
4
+ * Fix thread not waking up when there is still data to be sent (gqmelo / #2670)
5
+ * Ensure timeout is checked after each fetch position update in `Consumer.position()` (k61n / #2668)
6
+
7
+ # 2.2.15 (July 1, 2025)
8
+
9
+ Fixes
10
+ * Fix KafkaProducer broken method names (llk89 / #2660)
11
+ * Fix spelling mistake in KafkaConsumer docs (Xeus-CC / #2659)
12
+
1
13
  # 2.2.14 (June 27, 2025)
2
14
 
3
15
  Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kafka-python
3
- Version: 2.2.14
3
+ Version: 2.2.16
4
4
  Summary: Pure Python client for Apache Kafka
5
5
  Author-email: Dana Powers <dana.powers@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/dpkp/kafka-python
@@ -1075,6 +1075,13 @@ class BrokerConnection(object):
1075
1075
  total_bytes = self._send_bytes(self._send_buffer)
1076
1076
  self._send_buffer = self._send_buffer[total_bytes:]
1077
1077
 
1078
+ # If all data was sent, we need to get the new data from the protocol now, otherwise
1079
+ # this function would return True, indicating that there are no more pending
1080
+ # requests. This could cause the calling thread to wait indefinitely as it won't
1081
+ # know that there is still buffered data to send.
1082
+ if not self._send_buffer:
1083
+ self._send_buffer = self._protocol.send_bytes()
1084
+
1078
1085
  if self._sensors:
1079
1086
  self._sensors.bytes_sent.record(total_bytes)
1080
1087
  # Return True iff send buffer is empty
@@ -123,7 +123,7 @@ class KafkaConsumer(six.Iterator):
123
123
  be disabled in cases seeking extreme performance. Default: True
124
124
  isolation_level (str): Configure KIP-98 transactional consumer by
125
125
  setting to 'read_committed'. This will cause the consumer to
126
- skip records from aborted tranactions. Default: 'read_uncommitted'
126
+ skip records from aborted transactions. Default: 'read_uncommitted'
127
127
  allow_auto_create_topics (bool): Enable/disable auto topic creation
128
128
  on metadata request. Only available with api_version >= (0, 11).
129
129
  Default: True
@@ -757,7 +757,7 @@ class KafkaConsumer(six.Iterator):
757
757
  # batch update fetch positions for any partitions without a valid position
758
758
  if self._update_fetch_positions(timeout_ms=timer.timeout_ms):
759
759
  position = self._subscription.assignment[partition].position
760
- elif timer.expired:
760
+ if timer.expired:
761
761
  return None
762
762
  else:
763
763
  return position.offset
@@ -430,7 +430,7 @@ class RecordAccumulator(object):
430
430
  expired = bool(waited_time >= time_to_wait)
431
431
 
432
432
  sendable = (full or expired or self._closed or
433
- self._flush_in_progress())
433
+ self.flush_in_progress())
434
434
 
435
435
  if sendable and not backing_off:
436
436
  ready_nodes.add(leader)
@@ -563,7 +563,7 @@ class RecordAccumulator(object):
563
563
  """Deallocate the record batch."""
564
564
  self._incomplete.remove(batch)
565
565
 
566
- def _flush_in_progress(self):
566
+ def flush_in_progress(self):
567
567
  """Are there any threads currently waiting on a flush?"""
568
568
  return self._flushes_in_progress.get() > 0
569
569
 
@@ -553,11 +553,11 @@ class TxnRequestHandler(object):
553
553
  return self.transaction_manager.producer_id_and_epoch.epoch
554
554
 
555
555
  def fatal_error(self, exc):
556
- self.transaction_manager._transition_to_fatal_error(exc)
556
+ self.transaction_manager.transition_to_fatal_error(exc)
557
557
  self._result.done(error=exc)
558
558
 
559
559
  def abortable_error(self, exc):
560
- self.transaction_manager._transition_to_abortable_error(exc)
560
+ self.transaction_manager.transition_to_abortable_error(exc)
561
561
  self._result.done(error=exc)
562
562
 
563
563
  def fail(self, exc):
@@ -0,0 +1 @@
1
+ __version__ = '2.2.16'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kafka-python
3
- Version: 2.2.14
3
+ Version: 2.2.16
4
4
  Summary: Pure Python client for Apache Kafka
5
5
  Author-email: Dana Powers <dana.powers@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/dpkp/kafka-python
@@ -12,6 +12,9 @@ import pytest
12
12
 
13
13
  from kafka.conn import BrokerConnection, ConnectionStates
14
14
  from kafka.future import Future
15
+ from kafka.conn import BrokerConnection, ConnectionStates, SSLWantWriteError
16
+ from kafka.metrics.metrics import Metrics
17
+ from kafka.metrics.stats.sensor import Sensor
15
18
  from kafka.protocol.api import RequestHeader
16
19
  from kafka.protocol.group import HeartbeatResponse
17
20
  from kafka.protocol.metadata import MetadataRequest
@@ -43,10 +46,20 @@ def _socket(mocker):
43
46
  mocker.patch('socket.socket', return_value=socket)
44
47
  return socket
45
48
 
49
+ @pytest.fixture
50
+ def metrics(mocker):
51
+ metrics = mocker.MagicMock(Metrics)
52
+ metrics.mocked_sensors = {}
53
+ def sensor(name, **kwargs):
54
+ if name not in metrics.mocked_sensors:
55
+ metrics.mocked_sensors[name] = mocker.MagicMock(Sensor)
56
+ return metrics.mocked_sensors[name]
57
+ metrics.sensor.side_effect = sensor
58
+ return metrics
46
59
 
47
60
  @pytest.fixture
48
- def conn(_socket, dns_lookup, mocker):
49
- conn = BrokerConnection('localhost', 9092, socket.AF_INET)
61
+ def conn(_socket, dns_lookup, metrics, mocker):
62
+ conn = BrokerConnection('localhost', 9092, socket.AF_INET, metrics=metrics)
50
63
  mocker.patch.object(conn, '_try_api_versions_check', return_value=True)
51
64
  return conn
52
65
 
@@ -228,6 +241,46 @@ def test_send_response(_socket, conn):
228
241
  assert len(conn.in_flight_requests) == 1
229
242
 
230
243
 
244
+ def test_send_async_request_while_other_request_is_already_in_buffer(_socket, conn, metrics):
245
+ conn.connect()
246
+ assert conn.state is ConnectionStates.CONNECTED
247
+ assert 'node-0.bytes-sent' in metrics.mocked_sensors
248
+ bytes_sent_sensor = metrics.mocked_sensors['node-0.bytes-sent']
249
+
250
+ req1 = MetadataRequest[0](topics='foo')
251
+ header1 = RequestHeader(req1, client_id=conn.config['client_id'])
252
+ payload_bytes1 = len(header1.encode()) + len(req1.encode())
253
+ req2 = MetadataRequest[0]([])
254
+ header2 = RequestHeader(req2, client_id=conn.config['client_id'])
255
+ payload_bytes2 = len(header2.encode()) + len(req2.encode())
256
+
257
+ # The first call to the socket will raise a transient SSL exception. This will make the first
258
+ # request to be kept in the internal buffer to be sent in the next call of
259
+ # send_pending_requests_v2.
260
+ _socket.send.side_effect = [SSLWantWriteError, 4 + payload_bytes1, 4 + payload_bytes2]
261
+
262
+ conn.send(req1, blocking=False)
263
+ # This won't send any bytes because of the SSL exception and the request bytes will be kept in
264
+ # the buffer.
265
+ assert conn.send_pending_requests_v2() is False
266
+ assert bytes_sent_sensor.record.call_args_list[0].args == (0,)
267
+
268
+ conn.send(req2, blocking=False)
269
+ # This will send the remaining bytes in the buffer from the first request, but should notice
270
+ # that the second request was queued, therefore it should return False.
271
+ bytes_sent_sensor.record.reset_mock()
272
+ assert conn.send_pending_requests_v2() is False
273
+ bytes_sent_sensor.record.assert_called_once_with(4 + payload_bytes1)
274
+
275
+ bytes_sent_sensor.record.reset_mock()
276
+ assert conn.send_pending_requests_v2() is True
277
+ bytes_sent_sensor.record.assert_called_once_with(4 + payload_bytes2)
278
+
279
+ bytes_sent_sensor.record.reset_mock()
280
+ assert conn.send_pending_requests_v2() is True
281
+ bytes_sent_sensor.record.assert_called_once_with(0)
282
+
283
+
231
284
  def test_send_error(_socket, conn):
232
285
  conn.connect()
233
286
  assert conn.state is ConnectionStates.CONNECTED
@@ -1 +0,0 @@
1
- __version__ = '2.2.14'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes