kafka-python 3.0.0__tar.gz → 3.0.1__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.
- {kafka_python-3.0.0 → kafka_python-3.0.1}/CHANGES.md +19 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/PKG-INFO +1 -1
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/client.py +2 -2
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/consumer/fetcher.py +30 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/consumer/group.py +26 -6
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/base.py +8 -10
- kafka_python-3.0.1/kafka/partitioner/abc.py +52 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/producer/future.py +38 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/producer/kafka.py +2 -2
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/structs.py +22 -8
- kafka_python-3.0.1/kafka/version.py +1 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka_python.egg-info/PKG-INFO +1 -1
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/integration/conftest.py +122 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/integration/test_admin_integration.py +22 -87
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/integration/test_consumer_integration.py +35 -111
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/test_mock_broker.py +258 -1
- kafka_python-3.0.0/kafka/partitioner/abc.py +0 -8
- kafka_python-3.0.0/kafka/version.py +0 -1
- {kafka_python-3.0.0 → kafka_python-3.0.1}/AUTHORS.md +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/LICENSE +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/MANIFEST.in +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/README.rst +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/__main__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/__main__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/_acls.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/_cluster.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/_configs.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/_groups.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/_partitions.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/_topics.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/_transactions.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/admin/_users.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/consumer_performance.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/load_example.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/producer_encode_path.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/producer_performance.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/profile_protocol.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/protocol_old_vs_new.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/record_batch_compose.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/record_batch_read.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/benchmarks/varint_speed.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/acls/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/acls/common.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/acls/create.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/acls/delete.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/acls/describe.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/cluster/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/cluster/describe.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/cluster/describe_quorum.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/cluster/features.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/cluster/log_dirs.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/cluster/versions.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/configs/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/configs/alter.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/configs/common.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/configs/describe.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/configs/list.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/configs/reset.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/alter_offsets.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/delete.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/delete_offsets.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/describe.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/list.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/list_offsets.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/remove_members.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/groups/reset_offsets.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/partitions/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/partitions/alter_reassignments.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/partitions/create.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/partitions/delete_records.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/partitions/describe.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/partitions/elect_leaders.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/partitions/list_offsets.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/partitions/list_reassignments.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/topics/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/topics/create.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/topics/delete.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/topics/describe.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/topics/list.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/transactions/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/transactions/abort.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/transactions/describe.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/transactions/describe_producers.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/transactions/find_hanging.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/transactions/list.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/users/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/users/alter_user_scram_credentials.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/admin/users/describe_user_scram_credentials.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/common.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/consumer/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cli/producer/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/cluster.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/codec.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/consumer/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/consumer/__main__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/consumer/subscription_state.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/abstract.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/cooperative_sticky.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/range.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/roundrobin.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/sticky/StickyAssignorUserData.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/sticky/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/sticky/partition_movements.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/sticky/sorted_set.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/sticky/sticky_assignor.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/assignors/sticky/user_data.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/consumer.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/heartbeat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/coordinator/subscription.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/errors.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/future.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/compound_stat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/dict_reporter.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/kafka_metric.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/measurable.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/measurable_stat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/metric_config.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/metric_name.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/metrics.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/metrics_reporter.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/quota.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/avg.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/count.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/histogram.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/max_stat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/min_stat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/percentile.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/percentiles.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/rate.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/sampled_stat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/sensor.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/metrics/stats/total.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/compat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/connection.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/http_connect.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/inet.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/manager.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/metrics.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/sasl/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/sasl/abc.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/sasl/gssapi.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/sasl/msk.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/sasl/oauth.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/sasl/plain.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/sasl/scram.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/sasl/sspi.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/selector.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/socks5.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/transport.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/net/wakeup_notifier.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/partitioner/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/partitioner/default.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/partitioner/sticky.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/producer/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/producer/__main__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/producer/producer_batch.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/producer/record_accumulator.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/producer/sender.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/producer/transaction_manager.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/acl.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/acl.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/client_quotas.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/client_quotas.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/cluster.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/cluster.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/configs.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/configs.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/groups.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/groups.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/topics.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/topics.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/transactions.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/transactions.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/users.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/admin/users.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/api_data.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/api_header.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/api_key.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/api_message.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/broker_version_data.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/fetch.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/fetch.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/group.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/group.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/metadata.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/metadata.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/offsets.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/consumer/offsets.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/data_container.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/frame.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/generate_stubs.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/metadata/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/metadata/api_versions.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/metadata/api_versions.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/metadata/find_coordinator.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/metadata/find_coordinator.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/metadata/metadata.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/metadata/metadata.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/abstract.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/add_offsets_to_txn.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/add_partitions_to_txn.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/admin.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/api.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/api_versions.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/commit.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/consumer_protocol.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/end_txn.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/fetch.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/find_coordinator.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/group.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/init_producer_id.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/list_offsets.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/metadata.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/offset_for_leader_epoch.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/produce.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/sasl_authenticate.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/sasl_handshake.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/struct.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/txn_offset_commit.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/old/types.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/parser.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/producer/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/producer/produce.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/producer/produce.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/producer/transaction.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/producer/transaction.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/sasl.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/sasl.pyi +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/array.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/base.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/codecs/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/codecs/encode_buffer.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/codecs/tagged_fields.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/codecs/types.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/codegen.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/simple.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/struct.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/fields/struct_array.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/load_json.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AddOffsetsToTxnRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AddOffsetsToTxnResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AddPartitionsToTxnRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AddPartitionsToTxnResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterClientQuotasRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterClientQuotasResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterConfigsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterConfigsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterPartitionReassignmentsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterPartitionReassignmentsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterReplicaLogDirsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterReplicaLogDirsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterUserScramCredentialsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/AlterUserScramCredentialsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ApiVersionsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ApiVersionsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ConsumerProtocolAssignment.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ConsumerProtocolSubscription.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/CreateAclsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/CreateAclsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/CreatePartitionsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/CreatePartitionsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/CreateTopicsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/CreateTopicsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DeleteAclsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DeleteAclsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DeleteGroupsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DeleteGroupsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DeleteRecordsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DeleteRecordsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DeleteTopicsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DeleteTopicsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeAclsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeAclsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeClientQuotasRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeClientQuotasResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeClusterRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeClusterResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeConfigsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeConfigsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeGroupsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeGroupsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeLogDirsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeLogDirsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeProducersRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeProducersResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeQuorumRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeQuorumResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeTopicPartitionsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeTopicPartitionsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeTransactionsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeTransactionsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeUserScramCredentialsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/DescribeUserScramCredentialsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ElectLeadersRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ElectLeadersResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/EndTxnRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/EndTxnResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/FetchRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/FetchResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/FindCoordinatorRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/FindCoordinatorResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/HeartbeatRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/HeartbeatResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/IncrementalAlterConfigsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/IncrementalAlterConfigsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/InitProducerIdRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/InitProducerIdResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/JoinGroupRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/JoinGroupResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/LeaveGroupRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/LeaveGroupResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListConfigResourcesRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListConfigResourcesResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListGroupsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListGroupsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListOffsetsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListOffsetsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListPartitionReassignmentsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListPartitionReassignmentsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListTransactionsRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ListTransactionsResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/MetadataRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/MetadataResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/OffsetCommitRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/OffsetCommitResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/OffsetDeleteRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/OffsetDeleteResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/OffsetFetchRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/OffsetFetchResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/OffsetForLeaderEpochRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/OffsetForLeaderEpochResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ProduceRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ProduceResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/RequestHeader.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/ResponseHeader.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/SaslAuthenticateRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/SaslAuthenticateResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/SaslHandshakeRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/SaslHandshakeResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/SyncGroupRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/SyncGroupResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/TxnOffsetCommitRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/TxnOffsetCommitResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/UpdateFeaturesRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/UpdateFeaturesResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/WriteTxnMarkersRequest.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/WriteTxnMarkersResponse.json +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/protocol/schemas/resources/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/record/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/record/_crc32c.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/record/abc.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/record/default_records.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/record/legacy_records.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/record/memory_records.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/record/util.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/serializer/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/serializer/abstract.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/serializer/default.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/serializer/json.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/serializer/wrapper.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/util.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka/vendor/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka_python.egg-info/SOURCES.txt +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka_python.egg-info/dependency_links.txt +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka_python.egg-info/entry_points.txt +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka_python.egg-info/requires.txt +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/kafka_python.egg-info/top_level.txt +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/pyproject.toml +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/setup.cfg +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/integration/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/integration/fixtures.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/integration/test_producer_integration.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/integration/test_sasl_integration.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/integration/test_ssl_integration.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/__init__.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_compat.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_connection.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_http_connect.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_inet.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_manager.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_sasl_reauthentication.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_selector.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_transport.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/net/test_wakeup_notifier.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/test_cluster.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/test_codec.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/test_future.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/test_metrics.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/test_package.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/test_util.py +0 -0
- {kafka_python-3.0.0 → kafka_python-3.0.1}/test/testutil.py +0 -0
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# 3.0.1 (Jun 17, 2026)
|
|
2
|
+
|
|
3
|
+
### Fixes
|
|
4
|
+
* receive_message_max_bytes default 100MiB (consumer/producer/admin); check against fetch_max_bytes and max_partition_fetch_bytes in Consumer (#3075)
|
|
5
|
+
|
|
6
|
+
### Consumer
|
|
7
|
+
* Add MemberState to ConsumerGroupMetadata / consumer.group_metadata() (#3071)
|
|
8
|
+
|
|
9
|
+
### Tests
|
|
10
|
+
* Add ConsumerGroupRunner fixture to manage multi-consumer group integration tests (#3072)
|
|
11
|
+
* Add MockGroup and test coordinator rebalance / metadata snapshot changes (#3069)
|
|
12
|
+
* Use 4.3 api_version for producer tests; fixup inadvertent sender thread leak in test (#3068)
|
|
13
|
+
* Add test coverage for producer acks (#3067)
|
|
14
|
+
* Fill-in empty sender tests (#3066)
|
|
15
|
+
* Add MockCluster; test failover on CoordinatorNotAvailableError (#3065)
|
|
16
|
+
|
|
17
|
+
### Documentation
|
|
18
|
+
* Add ConsumerRecord, RecordMetadata, and FutureRecordMetadata to docs (#3070)
|
|
19
|
+
|
|
1
20
|
# 3.0.0 (Jun 11, 2026)
|
|
2
21
|
|
|
3
22
|
This is a major release with significant changes to kafka-python internals to simplify networking and feature development. It introduces a new networking layer (`kafka.net`) and a dynamic protocol system that uses JSON schema files imported from Apache Kafka. It substantially refactors and expands the Admin client, including breaking changes to some API signatures, and it lands a long list of KIP features/changes across the producer, consumer, admin, and networking/metadata clients. Protocol support across kafka-python is now at or beyond the apache kafka 3.0 baseline.
|
|
@@ -75,7 +75,7 @@ class KafkaAdminClient(
|
|
|
75
75
|
broker connection. Default: 5.
|
|
76
76
|
receive_message_max_bytes (int): Maximum allowed network frame size.
|
|
77
77
|
Used to avoid OOM when decoding malformed network message header.
|
|
78
|
-
Default:
|
|
78
|
+
Default: 100_000_000.
|
|
79
79
|
receive_buffer_bytes (int): The size of the TCP receive buffer
|
|
80
80
|
(SO_RCVBUF) to use when reading data. Default: None (relies on
|
|
81
81
|
system defaults). Java client defaults to 32768.
|
|
@@ -177,7 +177,7 @@ class KafkaAdminClient(
|
|
|
177
177
|
'reconnect_backoff_ms': 50,
|
|
178
178
|
'reconnect_backoff_max_ms': 30000,
|
|
179
179
|
'max_in_flight_requests_per_connection': 5,
|
|
180
|
-
'receive_message_max_bytes':
|
|
180
|
+
'receive_message_max_bytes': 100_000_000,
|
|
181
181
|
'receive_buffer_bytes': None,
|
|
182
182
|
'send_buffer_bytes': None,
|
|
183
183
|
'socket_options': [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)],
|
|
@@ -26,6 +26,36 @@ _LOGGED_DESERIALIZE_WARNING = False
|
|
|
26
26
|
ConsumerRecord = collections.namedtuple("ConsumerRecord",
|
|
27
27
|
["topic", "partition", "leader_epoch", "offset", "timestamp", "timestamp_type",
|
|
28
28
|
"key", "value", "headers", "checksum", "serialized_key_size", "serialized_value_size", "serialized_header_size"])
|
|
29
|
+
ConsumerRecord.__doc__ = """A single record (message) consumed from a topic partition.
|
|
30
|
+
|
|
31
|
+
Yielded by :meth:`~kafka.KafkaConsumer.poll` (inside the returned
|
|
32
|
+
``{TopicPartition: [ConsumerRecord, ...]}`` mapping) and by iterating
|
|
33
|
+
over a :class:`~kafka.KafkaConsumer`. ``key`` and ``value`` are decoded
|
|
34
|
+
by the consumer's configured deserializers.
|
|
35
|
+
|
|
36
|
+
Keyword Arguments:
|
|
37
|
+
topic (str): The topic this record was received from.
|
|
38
|
+
partition (int): The partition this record was received from.
|
|
39
|
+
leader_epoch (int): The partition leader epoch for this record, or -1
|
|
40
|
+
if unknown.
|
|
41
|
+
offset (int): The position of this record in the topic partition.
|
|
42
|
+
timestamp (int): The timestamp of this record, in milliseconds since
|
|
43
|
+
the epoch (UTC), or -1 if unknown.
|
|
44
|
+
timestamp_type (int): The type of the timestamp: 0 for CreateTime (set
|
|
45
|
+
by the producer) or 1 for LogAppendTime (set by the broker).
|
|
46
|
+
key: The (deserialized) key of the record, or None.
|
|
47
|
+
value: The (deserialized) value of the record, or None.
|
|
48
|
+
headers (list): A list of ``(key, value)`` header tuples, where key is
|
|
49
|
+
a str and value is bytes.
|
|
50
|
+
checksum (int): Deprecated. The CRC32 checksum of the record, or None.
|
|
51
|
+
Removed in message format v2 (Kafka 0.11+).
|
|
52
|
+
serialized_key_size (int): The size of the serialized, uncompressed key
|
|
53
|
+
in bytes, or -1 if the key is None.
|
|
54
|
+
serialized_value_size (int): The size of the serialized, uncompressed
|
|
55
|
+
value in bytes, or -1 if the value is None.
|
|
56
|
+
serialized_header_size (int): The size of the serialized, uncompressed
|
|
57
|
+
headers in bytes, or -1 if there are no headers.
|
|
58
|
+
"""
|
|
29
59
|
|
|
30
60
|
|
|
31
61
|
CompletedFetch = collections.namedtuple("CompletedFetch",
|
|
@@ -180,7 +180,9 @@ class KafkaConsumer:
|
|
|
180
180
|
rebalances. Default: 3000
|
|
181
181
|
receive_message_max_bytes (int): Maximum allowed network frame size.
|
|
182
182
|
Used to avoid OOM when decoding malformed network message header.
|
|
183
|
-
|
|
183
|
+
Automatically raised to ``fetch_max_bytes + max_partition_fetch_bytes``
|
|
184
|
+
if configured lower, since a FetchResponse frame may be that large.
|
|
185
|
+
Default: 100_000_000.
|
|
184
186
|
receive_buffer_bytes (int): The size of the TCP receive buffer
|
|
185
187
|
(SO_RCVBUF) to use when reading data. Default: None (relies on
|
|
186
188
|
system defaults). The java client defaults to 32768.
|
|
@@ -328,7 +330,7 @@ class KafkaConsumer:
|
|
|
328
330
|
'heartbeat_interval_ms': 3000,
|
|
329
331
|
'receive_buffer_bytes': None,
|
|
330
332
|
'send_buffer_bytes': None,
|
|
331
|
-
'receive_message_max_bytes':
|
|
333
|
+
'receive_message_max_bytes': 100_000_000,
|
|
332
334
|
'socket_options': [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)],
|
|
333
335
|
'consumer_timeout_ms': float('inf'),
|
|
334
336
|
'security_protocol': 'PLAINTEXT',
|
|
@@ -389,6 +391,20 @@ class KafkaConsumer:
|
|
|
389
391
|
"fetch_max_wait_ms ({})."
|
|
390
392
|
.format(connections_max_idle_ms, request_timeout_ms, fetch_max_wait_ms))
|
|
391
393
|
|
|
394
|
+
# fetch_max_bytes (KIP-74) is a soft cap the broker applies to the
|
|
395
|
+
# *record data* in a FetchResponse body, not to the whole frame. The
|
|
396
|
+
# frame also carries the response header + per-topic/per-partition
|
|
397
|
+
# metadata, and the broker returns at least the first record batch even
|
|
398
|
+
# when it alone exceeds fetch_max_bytes. So a FetchResponse frame can be
|
|
399
|
+
# somewhat larger than fetch_max_bytes; give the frame-size guard
|
|
400
|
+
# max_partition_fetch_bytes of headroom over it so legitimate responses
|
|
401
|
+
# aren't rejected as InvalidReceiveError. Auto-raise so the guard tracks
|
|
402
|
+
# the fetch sizing unless the user explicitly configured a larger value.
|
|
403
|
+
fetch_response_max_bytes = (
|
|
404
|
+
self.config['fetch_max_bytes'] + self.config['max_partition_fetch_bytes'])
|
|
405
|
+
if self.config['receive_message_max_bytes'] < fetch_response_max_bytes:
|
|
406
|
+
self.config['receive_message_max_bytes'] = fetch_response_max_bytes
|
|
407
|
+
|
|
392
408
|
if self.config['metrics_enabled']:
|
|
393
409
|
metrics_tags = {'client-id': self.config['client_id']}
|
|
394
410
|
metric_config = MetricConfig(samples=self.config['metrics_num_samples'],
|
|
@@ -662,13 +678,17 @@ class KafkaConsumer:
|
|
|
662
678
|
self._coordinator.commit_offsets_sync(offsets, timeout_ms=timeout_ms)
|
|
663
679
|
|
|
664
680
|
def group_metadata(self):
|
|
665
|
-
"""Return a snapshot of this consumer's group membership
|
|
681
|
+
"""Return a snapshot of this consumer's group membership.
|
|
666
682
|
|
|
667
683
|
Pass the result to KafkaProducer.send_offsets_to_transaction() so the
|
|
668
684
|
broker can fence stale instances of this consumer when committing
|
|
669
|
-
offsets inside a transaction. The snapshot
|
|
670
|
-
|
|
671
|
-
|
|
685
|
+
offsets inside a transaction (KIP-447). The snapshot also exposes the
|
|
686
|
+
current MemberState (``state``), so callers can observe whether the
|
|
687
|
+
consumer has converged on a stable assignment.
|
|
688
|
+
|
|
689
|
+
The snapshot is always safe to call: if no group_id is configured
|
|
690
|
+
(manual assignment) the returned ConsumerGroupMetadata has
|
|
691
|
+
group_id=None and is permanently unjoined.
|
|
672
692
|
|
|
673
693
|
Returns:
|
|
674
694
|
ConsumerGroupMetadata
|
|
@@ -16,19 +16,13 @@ from kafka.protocol.consumer import (
|
|
|
16
16
|
HeartbeatRequest, JoinGroupRequest, LeaveGroupRequest, SyncGroupRequest,
|
|
17
17
|
DEFAULT_GENERATION_ID, UNKNOWN_MEMBER_ID,
|
|
18
18
|
)
|
|
19
|
-
from kafka.structs import ConsumerGroupMetadata
|
|
19
|
+
from kafka.structs import ConsumerGroupMetadata, MemberState
|
|
20
20
|
from kafka.util import Timer
|
|
21
21
|
|
|
22
22
|
log = logging.getLogger('kafka.coordinator')
|
|
23
23
|
heartbeat_log = logging.getLogger('kafka.coordinator.heartbeat')
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
class MemberState:
|
|
27
|
-
UNJOINED = '<unjoined>' # the client is not part of a group
|
|
28
|
-
REBALANCING = '<rebalancing>' # the client has begun rebalancing
|
|
29
|
-
STABLE = '<stable>' # the client has joined and is sending heartbeats
|
|
30
|
-
|
|
31
|
-
|
|
32
26
|
class Generation:
|
|
33
27
|
def __init__(self, generation_id, member_id, protocol):
|
|
34
28
|
self.generation_id = generation_id
|
|
@@ -891,13 +885,16 @@ class BaseCoordinator(ABC):
|
|
|
891
885
|
return self._generation
|
|
892
886
|
|
|
893
887
|
def group_metadata(self):
|
|
894
|
-
"""Return a snapshot of this member's group
|
|
888
|
+
"""Return a snapshot of this member's group membership.
|
|
895
889
|
|
|
896
890
|
Returns the current generation_id / member_id / group_instance_id even
|
|
897
891
|
when the group is not stable; the caller (typically
|
|
898
892
|
KafkaProducer.send_offsets_to_transaction) needs whatever is current
|
|
899
|
-
so the broker can fence stale instances. If the consumer has
|
|
900
|
-
joined, the snapshot has the no-generation defaults.
|
|
893
|
+
so the broker can fence stale instances (KIP-447). If the consumer has
|
|
894
|
+
never joined, the snapshot has the no-generation defaults.
|
|
895
|
+
|
|
896
|
+
Also carries the live MemberState (``state``) so callers can observe
|
|
897
|
+
whether the group has converged (it is ignored by the fencing path).
|
|
901
898
|
"""
|
|
902
899
|
with self._lock:
|
|
903
900
|
return ConsumerGroupMetadata(
|
|
@@ -905,6 +902,7 @@ class BaseCoordinator(ABC):
|
|
|
905
902
|
generation_id=self._generation.generation_id,
|
|
906
903
|
member_id=self._generation.member_id,
|
|
907
904
|
group_instance_id=self.group_instance_id,
|
|
905
|
+
state=self.state,
|
|
908
906
|
)
|
|
909
907
|
|
|
910
908
|
# deprecated
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Partitioner(ABC):
|
|
5
|
+
"""Base class for pluggable partition selection strategies.
|
|
6
|
+
|
|
7
|
+
A :class:`~kafka.KafkaProducer` consults its configured partitioner to
|
|
8
|
+
choose a partition for each record whose ``partition`` was not supplied
|
|
9
|
+
explicitly to :meth:`~kafka.KafkaProducer.send`. Subclass this and
|
|
10
|
+
implement :meth:`partition`, then pass an instance via the
|
|
11
|
+
``partitioner`` config argument.
|
|
12
|
+
|
|
13
|
+
Two built-in implementations are provided: ``DefaultPartitioner``
|
|
14
|
+
(murmur2-hash keyed records, random partition for null keys) and
|
|
15
|
+
``StickyPartitioner`` (KIP-480; null-key records stick to one partition
|
|
16
|
+
per topic until a new batch is started, then rotate).
|
|
17
|
+
|
|
18
|
+
Sticky-style partitioners may additionally implement an optional
|
|
19
|
+
``on_new_batch(self, topic, cluster, prev_partition)`` hook, which the
|
|
20
|
+
producer calls when a null-key record would have triggered a fresh
|
|
21
|
+
batch, giving the partitioner a chance to rotate off its current sticky
|
|
22
|
+
choice. The hook is looked up with ``getattr``, so it is entirely
|
|
23
|
+
optional.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def partition(self, topic, key, serialized_key, value, serialized_value, cluster):
|
|
28
|
+
"""Choose a partition for a record.
|
|
29
|
+
|
|
30
|
+
Arguments:
|
|
31
|
+
topic (str): The topic the record is destined for.
|
|
32
|
+
key: The user-supplied key, before serialization. May be None.
|
|
33
|
+
serialized_key (bytes): The post-serializer key bytes, or None
|
|
34
|
+
when the caller passed ``key=None``.
|
|
35
|
+
value: The user-supplied value, before serialization.
|
|
36
|
+
serialized_value (bytes): The post-serializer value bytes, or
|
|
37
|
+
None when the caller passed ``value=None``.
|
|
38
|
+
cluster (ClusterMetadata): A live cluster snapshot. Use
|
|
39
|
+
``cluster.partitions_for_topic(topic)`` for all partitions
|
|
40
|
+
and ``cluster.available_partitions_for_topic(topic)`` for
|
|
41
|
+
those whose leader is currently known.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
int: The partition id to assign the record to.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
ValueError: If the topic is not present in cluster metadata.
|
|
48
|
+
Partitioner exceptions surface to the caller via the
|
|
49
|
+
returned :class:`~kafka.producer.future.FutureRecordMetadata`.
|
|
50
|
+
"""
|
|
51
|
+
pass
|
|
52
|
+
|
|
@@ -30,6 +30,19 @@ class FutureProduceResult(Future):
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class FutureRecordMetadata(Future):
|
|
33
|
+
"""An asynchronous handle to the result of a single :meth:`~kafka.KafkaProducer.send`.
|
|
34
|
+
|
|
35
|
+
:meth:`~kafka.KafkaProducer.send` returns one of these immediately,
|
|
36
|
+
before the record has been transmitted to the broker. Call :meth:`get`
|
|
37
|
+
to block until the record is acknowledged and obtain its
|
|
38
|
+
:class:`RecordMetadata`, or register callbacks via
|
|
39
|
+
:meth:`~kafka.future.Future.add_callback` /
|
|
40
|
+
:meth:`~kafka.future.Future.add_errback` to be notified without
|
|
41
|
+
blocking. The future resolves successfully once the containing batch is
|
|
42
|
+
acknowledged according to the producer's ``acks`` configuration, or
|
|
43
|
+
fails with the relevant exception (for example
|
|
44
|
+
:class:`~kafka.errors.KafkaTimeoutError`).
|
|
45
|
+
"""
|
|
33
46
|
__slots__ = ('_produce_future', 'args')
|
|
34
47
|
def __init__(self, produce_future, batch_index, timestamp_ms, checksum, serialized_key_size, serialized_value_size, serialized_header_size):
|
|
35
48
|
super().__init__()
|
|
@@ -99,3 +112,28 @@ class FutureRecordMetadata(Future):
|
|
|
99
112
|
RecordMetadata = collections.namedtuple(
|
|
100
113
|
'RecordMetadata', ['topic', 'partition', 'topic_partition', 'offset', 'timestamp',
|
|
101
114
|
'checksum', 'serialized_key_size', 'serialized_value_size', 'serialized_header_size'])
|
|
115
|
+
RecordMetadata.__doc__ = """Metadata about a record that has been acknowledged by the broker.
|
|
116
|
+
|
|
117
|
+
Returned by :meth:`FutureRecordMetadata.get`, which resolves once the
|
|
118
|
+
batch containing the record has been acknowledged according to the
|
|
119
|
+
producer's ``acks`` configuration.
|
|
120
|
+
|
|
121
|
+
Keyword Arguments:
|
|
122
|
+
topic (str): The topic the record was appended to.
|
|
123
|
+
partition (int): The partition the record was appended to.
|
|
124
|
+
topic_partition (TopicPartition): The ``(topic, partition)`` the record
|
|
125
|
+
was appended to.
|
|
126
|
+
offset (int): The offset of the record in the topic partition, or -1 if
|
|
127
|
+
the broker did not assign one (e.g. ``acks=0``).
|
|
128
|
+
timestamp (int): The timestamp of the record, in milliseconds since the
|
|
129
|
+
epoch (UTC). For CreateTime this is the producer-supplied timestamp;
|
|
130
|
+
for LogAppendTime it is the broker-assigned timestamp.
|
|
131
|
+
checksum (int): Deprecated. The CRC32 checksum of the record, or None.
|
|
132
|
+
Removed in message format v2 (Kafka 0.11+).
|
|
133
|
+
serialized_key_size (int): The size of the serialized, uncompressed key
|
|
134
|
+
in bytes, or -1 if the key is None.
|
|
135
|
+
serialized_value_size (int): The size of the serialized, uncompressed
|
|
136
|
+
value in bytes, or -1 if the value is None.
|
|
137
|
+
serialized_header_size (int): The size of the serialized, uncompressed
|
|
138
|
+
headers in bytes, or -1 if there are no headers.
|
|
139
|
+
"""
|
|
@@ -282,7 +282,7 @@ class KafkaProducer:
|
|
|
282
282
|
Default: 30000.
|
|
283
283
|
receive_message_max_bytes (int): Maximum allowed network frame size.
|
|
284
284
|
Used to avoid OOM when decoding malformed network message header.
|
|
285
|
-
Default:
|
|
285
|
+
Default: 100_000_000.
|
|
286
286
|
receive_buffer_bytes (int): The size of the TCP receive buffer
|
|
287
287
|
(SO_RCVBUF) to use when reading data. Default: None (relies on
|
|
288
288
|
system defaults). Java client defaults to 32768.
|
|
@@ -425,7 +425,7 @@ class KafkaProducer:
|
|
|
425
425
|
'client_dns_lookup': 'use_all_dns_ips',
|
|
426
426
|
'retry_backoff_ms': 100,
|
|
427
427
|
'request_timeout_ms': 30000,
|
|
428
|
-
'receive_message_max_bytes':
|
|
428
|
+
'receive_message_max_bytes': 100_000_000,
|
|
429
429
|
'receive_buffer_bytes': None,
|
|
430
430
|
'send_buffer_bytes': None,
|
|
431
431
|
'socket_options': [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)],
|
|
@@ -51,19 +51,33 @@ Keyword Arguments:
|
|
|
51
51
|
"""
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
class MemberState:
|
|
55
|
+
UNJOINED = '<unjoined>' # the client is not part of a group
|
|
56
|
+
REBALANCING = '<rebalancing>' # the client has begun rebalancing
|
|
57
|
+
STABLE = '<stable>' # the client has joined and is sending heartbeats
|
|
58
|
+
|
|
59
|
+
|
|
54
60
|
ConsumerGroupMetadata = namedtuple("ConsumerGroupMetadata",
|
|
55
|
-
["group_id", "generation_id", "member_id", "group_instance_id"],
|
|
56
|
-
defaults=[-1, '', None])
|
|
57
|
-
ConsumerGroupMetadata.__doc__ = """A snapshot of a consumer's group membership
|
|
61
|
+
["group_id", "generation_id", "member_id", "group_instance_id", "state"],
|
|
62
|
+
defaults=[None, -1, '', None, MemberState.UNJOINED])
|
|
63
|
+
ConsumerGroupMetadata.__doc__ = """A snapshot of a consumer's group membership.
|
|
64
|
+
|
|
65
|
+
The first four fields are the KIP-447 fencing identity: pass the snapshot to
|
|
66
|
+
KafkaProducer.send_offsets_to_transaction() so the broker can fence stale
|
|
67
|
+
consumer instances when committing offsets inside a transaction. The broker
|
|
68
|
+
uses member_id + generation_id + group_instance_id to verify the producer is
|
|
69
|
+
acting on behalf of the current group generation.
|
|
58
70
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
The ``state`` field exposes the live MemberState (it is ignored by the
|
|
72
|
+
producer/fencing path). It lets callers observe whether the consumer has
|
|
73
|
+
converged on a stable assignment - useful for monitoring and for tests that
|
|
74
|
+
wait for a group to finish rebalancing.
|
|
63
75
|
|
|
64
76
|
Keyword Arguments:
|
|
65
|
-
group_id (str): The consumer group id.
|
|
77
|
+
group_id (str): The consumer group id, or None for manual assignment.
|
|
66
78
|
generation_id (int): The current generation id (-1 if unjoined).
|
|
67
79
|
member_id (str): The current member id ('' if unjoined).
|
|
68
80
|
group_instance_id (str): The static membership instance id, or None.
|
|
81
|
+
state (str): The current MemberState (one of MemberState.UNJOINED,
|
|
82
|
+
MemberState.REBALANCING, MemberState.STABLE).
|
|
69
83
|
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '3.0.1'
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import collections
|
|
1
2
|
import contextlib
|
|
2
3
|
import os
|
|
4
|
+
import threading
|
|
5
|
+
import time
|
|
3
6
|
from urllib.parse import urlparse
|
|
4
7
|
import uuid
|
|
5
8
|
|
|
@@ -7,6 +10,7 @@ import pytest
|
|
|
7
10
|
|
|
8
11
|
from kafka import KafkaAdminClient, KafkaConsumer, KafkaProducer
|
|
9
12
|
from kafka.net.compat import KafkaNetClient
|
|
13
|
+
from kafka.structs import MemberState
|
|
10
14
|
from kafka.util import TOPIC_LEGAL_CHARS, TOPIC_MAX_LENGTH, ensure_valid_topic_name
|
|
11
15
|
from test.testutil import env_kafka_version, random_string
|
|
12
16
|
from test.integration.fixtures import KafkaFixture, ZookeeperFixture, create_topics, client_params
|
|
@@ -248,3 +252,121 @@ def send_messages(topic, producer, request):
|
|
|
248
252
|
return [msg for (msg, f) in messages_and_futures]
|
|
249
253
|
|
|
250
254
|
return _send_messages
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class ConsumerGroupRunner:
|
|
258
|
+
"""Manage pools of group-consuming threads for integration tests.
|
|
259
|
+
|
|
260
|
+
Each spawned consumer runs ``poll()`` in its own background thread until
|
|
261
|
+
the runner is torn down. Use :meth:`wait_for_stable` to block until every
|
|
262
|
+
member has joined and the group has finished rebalancing. Threads are
|
|
263
|
+
stopped and joined automatically when the ``consumer_group`` fixture tears
|
|
264
|
+
down, so tests don't need their own ``try/finally`` bookkeeping.
|
|
265
|
+
|
|
266
|
+
consumers = consumer_group.spawn(group_id='g', count=4)
|
|
267
|
+
consumer_group.wait_for_stable()
|
|
268
|
+
# ... assert on consumers[i].assignment() ...
|
|
269
|
+
|
|
270
|
+
``wait_for_stable`` reads ``consumer.group_metadata()`` / ``assignment()``
|
|
271
|
+
from the test thread while each consumer polls on its own thread. Both
|
|
272
|
+
reads are lock-protected snapshots, so this cross-thread observation is
|
|
273
|
+
safe even though KafkaConsumer is otherwise single-threaded.
|
|
274
|
+
"""
|
|
275
|
+
def __init__(self, consumer_factory):
|
|
276
|
+
self._factory = consumer_factory
|
|
277
|
+
self._members = [] # [{thread, stop, ready, consumer, error}, ...]
|
|
278
|
+
|
|
279
|
+
@property
|
|
280
|
+
def consumers(self):
|
|
281
|
+
"""Live consumers in spawn order (across all groups)."""
|
|
282
|
+
return [m['consumer'] for m in self._members]
|
|
283
|
+
|
|
284
|
+
def spawn(self, group_id, count=1, client_id_prefix='consumer', **consumer_params):
|
|
285
|
+
"""Start ``count`` consumer threads in ``group_id``; return their consumers.
|
|
286
|
+
|
|
287
|
+
Blocks until each consumer has been constructed (or re-raises whatever
|
|
288
|
+
the consumer thread failed with during startup). Extra keyword args are
|
|
289
|
+
passed through to ``kafka_consumer_factory``.
|
|
290
|
+
"""
|
|
291
|
+
started = []
|
|
292
|
+
for _ in range(count):
|
|
293
|
+
member = {
|
|
294
|
+
'stop': threading.Event(),
|
|
295
|
+
'ready': threading.Event(),
|
|
296
|
+
'consumer': None,
|
|
297
|
+
'error': None,
|
|
298
|
+
}
|
|
299
|
+
client_id = '%s-%d' % (client_id_prefix, len(self._members))
|
|
300
|
+
|
|
301
|
+
def run(member=member, client_id=client_id):
|
|
302
|
+
try:
|
|
303
|
+
with self._factory(group_id=group_id, client_id=client_id,
|
|
304
|
+
**consumer_params) as c:
|
|
305
|
+
member['consumer'] = c
|
|
306
|
+
member['ready'].set()
|
|
307
|
+
while not member['stop'].is_set():
|
|
308
|
+
c.poll(timeout_ms=200)
|
|
309
|
+
except Exception as e: # surfaced via spawn() / stop()
|
|
310
|
+
member['error'] = e
|
|
311
|
+
finally:
|
|
312
|
+
member['ready'].set()
|
|
313
|
+
|
|
314
|
+
member['thread'] = threading.Thread(target=run, name=client_id, daemon=True)
|
|
315
|
+
self._members.append(member)
|
|
316
|
+
member['thread'].start()
|
|
317
|
+
assert member['ready'].wait(timeout=15), \
|
|
318
|
+
'consumer %s failed to start within 15s' % client_id
|
|
319
|
+
if member['error'] is not None:
|
|
320
|
+
raise member['error'] # pylint: disable=raising-bad-type
|
|
321
|
+
started.append(member['consumer'])
|
|
322
|
+
return started
|
|
323
|
+
|
|
324
|
+
def wait_for_stable(self, timeout=30, poll_interval=1):
|
|
325
|
+
"""Block until every member is STABLE, assigned, and on one generation.
|
|
326
|
+
|
|
327
|
+
"One generation" is checked per group_id: a fully converged group has
|
|
328
|
+
all of its members reporting the same generation_id, which means the
|
|
329
|
+
most recent rebalance has propagated to everyone.
|
|
330
|
+
"""
|
|
331
|
+
deadline = time.monotonic() + timeout
|
|
332
|
+
while True:
|
|
333
|
+
generations = collections.defaultdict(set)
|
|
334
|
+
converged = True
|
|
335
|
+
for c in self.consumers:
|
|
336
|
+
meta = c.group_metadata()
|
|
337
|
+
if meta.state != MemberState.STABLE or not c.assignment():
|
|
338
|
+
converged = False
|
|
339
|
+
break
|
|
340
|
+
generations[meta.group_id].add(meta.generation_id)
|
|
341
|
+
if converged and all(len(g) == 1 for g in generations.values()):
|
|
342
|
+
return
|
|
343
|
+
assert time.monotonic() < deadline, 'timeout waiting for stable group'
|
|
344
|
+
time.sleep(poll_interval)
|
|
345
|
+
|
|
346
|
+
def stop(self):
|
|
347
|
+
"""Signal all threads to stop, then join them (called at teardown)."""
|
|
348
|
+
for member in self._members:
|
|
349
|
+
member['stop'].set()
|
|
350
|
+
for member in self._members:
|
|
351
|
+
member['thread'].join(timeout=5)
|
|
352
|
+
assert not member['thread'].is_alive(), \
|
|
353
|
+
'consumer thread %s did not exit' % member['thread'].name
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
@pytest.fixture
|
|
357
|
+
def consumer_group(kafka_consumer_factory):
|
|
358
|
+
"""Return a ConsumerGroupRunner for multi-threaded consumer group tests.
|
|
359
|
+
|
|
360
|
+
Spawns group-consuming threads on demand and tears them all down (stop +
|
|
361
|
+
join) when the test finishes::
|
|
362
|
+
|
|
363
|
+
def test_something(consumer_group, topic):
|
|
364
|
+
consumer_group.spawn(group_id='g', count=3)
|
|
365
|
+
consumer_group.wait_for_stable()
|
|
366
|
+
...
|
|
367
|
+
"""
|
|
368
|
+
runner = ConsumerGroupRunner(kafka_consumer_factory)
|
|
369
|
+
try:
|
|
370
|
+
yield runner
|
|
371
|
+
finally:
|
|
372
|
+
runner.stop()
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from logging import info
|
|
2
|
-
from threading import Event, Thread
|
|
3
2
|
from time import monotonic as time, sleep
|
|
4
3
|
|
|
5
4
|
import pytest
|
|
@@ -170,95 +169,31 @@ def test_describe_configs_invalid_broker_id_raises(kafka_admin_client):
|
|
|
170
169
|
|
|
171
170
|
|
|
172
171
|
@pytest.mark.skipif(env_kafka_version() < (0, 11), reason='Describe consumer group requires broker >=0.11')
|
|
173
|
-
def test_describe_group_exists(kafka_admin_client,
|
|
174
|
-
"""Tests that the describe consumer group call returns valid consumer group information
|
|
175
|
-
This test takes inspiration from the test 'test_group' in test_consumer_group.py.
|
|
176
|
-
"""
|
|
177
|
-
consumers = {}
|
|
178
|
-
stop = {}
|
|
179
|
-
threads = {}
|
|
172
|
+
def test_describe_group_exists(kafka_admin_client, consumer_group, topic):
|
|
173
|
+
"""Tests that the describe consumer group call returns valid consumer group information"""
|
|
180
174
|
random_group_id = 'test-group-' + random_string(6)
|
|
181
175
|
group_id_list = [random_group_id, random_group_id + '_2']
|
|
182
|
-
generations = {group_id_list[0]: set(), group_id_list[1]: set()}
|
|
183
|
-
def consumer_thread(i, group_id):
|
|
184
|
-
assert i not in consumers
|
|
185
|
-
assert i not in stop
|
|
186
|
-
stop[i] = Event()
|
|
187
|
-
with kafka_consumer_factory(group_id=group_id) as c:
|
|
188
|
-
consumers[i] = c
|
|
189
|
-
while not stop[i].is_set():
|
|
190
|
-
consumers[i].poll(timeout_ms=200)
|
|
191
|
-
consumers[i] = None
|
|
192
|
-
stop[i] = None
|
|
193
|
-
|
|
194
|
-
num_consumers = 3
|
|
195
|
-
for i in range(num_consumers):
|
|
196
|
-
group_id = group_id_list[i % 2]
|
|
197
|
-
t = Thread(target=consumer_thread, args=(i, group_id,))
|
|
198
|
-
t.start()
|
|
199
|
-
threads[i] = t
|
|
200
|
-
|
|
201
|
-
try:
|
|
202
|
-
timeout = time() + 35
|
|
203
|
-
while True:
|
|
204
|
-
info('Checking consumers...')
|
|
205
|
-
for c in range(num_consumers):
|
|
206
|
-
|
|
207
|
-
# Verify all consumers have been created
|
|
208
|
-
if c not in consumers:
|
|
209
|
-
break
|
|
210
|
-
|
|
211
|
-
# Verify all consumers have an assignment
|
|
212
|
-
elif not consumers[c].assignment():
|
|
213
|
-
break
|
|
214
|
-
|
|
215
|
-
# If all consumers exist and have an assignment
|
|
216
|
-
else:
|
|
217
|
-
|
|
218
|
-
info('All consumers have assignment... checking for stable group')
|
|
219
|
-
# Verify all consumers are in the same generation
|
|
220
|
-
# then log state and break while loop
|
|
221
|
-
|
|
222
|
-
for consumer in consumers.values():
|
|
223
|
-
generations[consumer.config['group_id']].add(consumer._coordinator._generation.generation_id)
|
|
224
|
-
|
|
225
|
-
is_same_generation = any([len(consumer_generation) == 1 for consumer_generation in generations.values()])
|
|
226
|
-
|
|
227
|
-
# New generation assignment is not complete until
|
|
228
|
-
# coordinator.rejoining = False
|
|
229
|
-
rejoining = any([consumer._coordinator.rejoining
|
|
230
|
-
for consumer in list(consumers.values())])
|
|
231
|
-
|
|
232
|
-
if not rejoining and is_same_generation:
|
|
233
|
-
break
|
|
234
|
-
assert time() < timeout, "timeout waiting for assignments"
|
|
235
|
-
info('sleeping...')
|
|
236
|
-
sleep(1)
|
|
237
176
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
for c in range(num_consumers):
|
|
259
|
-
info('Waiting for consumer thread %s', c)
|
|
260
|
-
threads[c].join()
|
|
261
|
-
threads[c] = None
|
|
177
|
+
# Two members in the first group, one in the second.
|
|
178
|
+
consumer_group.spawn(group_id=group_id_list[0], count=2)
|
|
179
|
+
consumer_group.spawn(group_id=group_id_list[1], count=1)
|
|
180
|
+
consumer_group.wait_for_stable(timeout=35)
|
|
181
|
+
|
|
182
|
+
info('Group stabilized; verifying assignment')
|
|
183
|
+
output = kafka_admin_client.describe_groups(group_id_list)
|
|
184
|
+
assert len(output) == 2
|
|
185
|
+
groups = set()
|
|
186
|
+
for group in output.values():
|
|
187
|
+
assert(group['group_id'] in group_id_list)
|
|
188
|
+
if group['group_id'] == group_id_list[0]:
|
|
189
|
+
assert(len(group['members']) == 2)
|
|
190
|
+
else:
|
|
191
|
+
assert(len(group['members']) == 1)
|
|
192
|
+
for member in group['members']:
|
|
193
|
+
assert(member['member_metadata']['topics'] == [topic])
|
|
194
|
+
assert(member['member_assignment']['assigned_partitions'][0]['topic'] == topic)
|
|
195
|
+
groups.add(group['group_id'])
|
|
196
|
+
assert(sorted(list(groups)) == group_id_list)
|
|
262
197
|
|
|
263
198
|
|
|
264
199
|
@pytest.mark.skipif(env_kafka_version() < (1, 1), reason="Delete consumer groups requires broker >=1.1")
|