kafka-python 3.0.0__py3-none-any.whl
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/__init__.py +34 -0
- kafka/__main__.py +5 -0
- kafka/admin/__init__.py +29 -0
- kafka/admin/__main__.py +5 -0
- kafka/admin/_acls.py +355 -0
- kafka/admin/_cluster.py +359 -0
- kafka/admin/_configs.py +479 -0
- kafka/admin/_groups.py +754 -0
- kafka/admin/_partitions.py +595 -0
- kafka/admin/_topics.py +281 -0
- kafka/admin/_transactions.py +450 -0
- kafka/admin/_users.py +194 -0
- kafka/admin/client.py +373 -0
- kafka/benchmarks/__init__.py +0 -0
- kafka/benchmarks/consumer_performance.py +138 -0
- kafka/benchmarks/load_example.py +109 -0
- kafka/benchmarks/producer_encode_path.py +201 -0
- kafka/benchmarks/producer_performance.py +161 -0
- kafka/benchmarks/profile_protocol.py +138 -0
- kafka/benchmarks/protocol_old_vs_new.py +447 -0
- kafka/benchmarks/record_batch_compose.py +77 -0
- kafka/benchmarks/record_batch_read.py +82 -0
- kafka/benchmarks/varint_speed.py +426 -0
- kafka/cli/__init__.py +36 -0
- kafka/cli/admin/__init__.py +117 -0
- kafka/cli/admin/acls/__init__.py +9 -0
- kafka/cli/admin/acls/common.py +76 -0
- kafka/cli/admin/acls/create.py +19 -0
- kafka/cli/admin/acls/delete.py +23 -0
- kafka/cli/admin/acls/describe.py +16 -0
- kafka/cli/admin/cluster/__init__.py +14 -0
- kafka/cli/admin/cluster/describe.py +11 -0
- kafka/cli/admin/cluster/describe_quorum.py +11 -0
- kafka/cli/admin/cluster/features.py +52 -0
- kafka/cli/admin/cluster/log_dirs.py +43 -0
- kafka/cli/admin/cluster/versions.py +33 -0
- kafka/cli/admin/configs/__init__.py +10 -0
- kafka/cli/admin/configs/alter.py +43 -0
- kafka/cli/admin/configs/common.py +17 -0
- kafka/cli/admin/configs/describe.py +30 -0
- kafka/cli/admin/configs/list.py +16 -0
- kafka/cli/admin/configs/reset.py +20 -0
- kafka/cli/admin/groups/__init__.py +16 -0
- kafka/cli/admin/groups/alter_offsets.py +30 -0
- kafka/cli/admin/groups/delete.py +11 -0
- kafka/cli/admin/groups/delete_offsets.py +29 -0
- kafka/cli/admin/groups/describe.py +11 -0
- kafka/cli/admin/groups/list.py +28 -0
- kafka/cli/admin/groups/list_offsets.py +29 -0
- kafka/cli/admin/groups/remove_members.py +40 -0
- kafka/cli/admin/groups/reset_offsets.py +139 -0
- kafka/cli/admin/partitions/__init__.py +21 -0
- kafka/cli/admin/partitions/alter_reassignments.py +37 -0
- kafka/cli/admin/partitions/create.py +27 -0
- kafka/cli/admin/partitions/delete_records.py +31 -0
- kafka/cli/admin/partitions/describe.py +36 -0
- kafka/cli/admin/partitions/elect_leaders.py +53 -0
- kafka/cli/admin/partitions/list_offsets.py +88 -0
- kafka/cli/admin/partitions/list_reassignments.py +35 -0
- kafka/cli/admin/topics/__init__.py +10 -0
- kafka/cli/admin/topics/create.py +13 -0
- kafka/cli/admin/topics/delete.py +19 -0
- kafka/cli/admin/topics/describe.py +18 -0
- kafka/cli/admin/topics/list.py +11 -0
- kafka/cli/admin/transactions/__init__.py +17 -0
- kafka/cli/admin/transactions/abort.py +38 -0
- kafka/cli/admin/transactions/describe.py +24 -0
- kafka/cli/admin/transactions/describe_producers.py +29 -0
- kafka/cli/admin/transactions/find_hanging.py +26 -0
- kafka/cli/admin/transactions/list.py +37 -0
- kafka/cli/admin/users/__init__.py +8 -0
- kafka/cli/admin/users/alter_user_scram_credentials.py +34 -0
- kafka/cli/admin/users/describe_user_scram_credentials.py +15 -0
- kafka/cli/common.py +95 -0
- kafka/cli/consumer/__init__.py +63 -0
- kafka/cli/producer/__init__.py +57 -0
- kafka/cluster.py +824 -0
- kafka/codec.py +325 -0
- kafka/consumer/__init__.py +5 -0
- kafka/consumer/__main__.py +5 -0
- kafka/consumer/fetcher.py +2012 -0
- kafka/consumer/group.py +1347 -0
- kafka/consumer/subscription_state.py +897 -0
- kafka/coordinator/__init__.py +0 -0
- kafka/coordinator/assignors/__init__.py +0 -0
- kafka/coordinator/assignors/abstract.py +90 -0
- kafka/coordinator/assignors/cooperative_sticky.py +167 -0
- kafka/coordinator/assignors/range.py +81 -0
- kafka/coordinator/assignors/roundrobin.py +101 -0
- kafka/coordinator/assignors/sticky/StickyAssignorUserData.json +37 -0
- kafka/coordinator/assignors/sticky/__init__.py +0 -0
- kafka/coordinator/assignors/sticky/partition_movements.py +149 -0
- kafka/coordinator/assignors/sticky/sorted_set.py +63 -0
- kafka/coordinator/assignors/sticky/sticky_assignor.py +665 -0
- kafka/coordinator/assignors/sticky/user_data.py +8 -0
- kafka/coordinator/base.py +1215 -0
- kafka/coordinator/consumer.py +1224 -0
- kafka/coordinator/heartbeat.py +82 -0
- kafka/coordinator/subscription.py +34 -0
- kafka/errors.py +1004 -0
- kafka/future.py +166 -0
- kafka/metrics/__init__.py +13 -0
- kafka/metrics/compound_stat.py +33 -0
- kafka/metrics/dict_reporter.py +81 -0
- kafka/metrics/kafka_metric.py +36 -0
- kafka/metrics/measurable.py +27 -0
- kafka/metrics/measurable_stat.py +13 -0
- kafka/metrics/metric_config.py +33 -0
- kafka/metrics/metric_name.py +105 -0
- kafka/metrics/metrics.py +261 -0
- kafka/metrics/metrics_reporter.py +53 -0
- kafka/metrics/quota.py +41 -0
- kafka/metrics/stat.py +19 -0
- kafka/metrics/stats/__init__.py +15 -0
- kafka/metrics/stats/avg.py +24 -0
- kafka/metrics/stats/count.py +17 -0
- kafka/metrics/stats/histogram.py +99 -0
- kafka/metrics/stats/max_stat.py +17 -0
- kafka/metrics/stats/min_stat.py +19 -0
- kafka/metrics/stats/percentile.py +14 -0
- kafka/metrics/stats/percentiles.py +75 -0
- kafka/metrics/stats/rate.py +118 -0
- kafka/metrics/stats/sampled_stat.py +99 -0
- kafka/metrics/stats/sensor.py +136 -0
- kafka/metrics/stats/total.py +15 -0
- kafka/net/__init__.py +19 -0
- kafka/net/compat.py +165 -0
- kafka/net/connection.py +593 -0
- kafka/net/http_connect.py +144 -0
- kafka/net/inet.py +122 -0
- kafka/net/manager.py +451 -0
- kafka/net/metrics.py +149 -0
- kafka/net/sasl/__init__.py +32 -0
- kafka/net/sasl/abc.py +28 -0
- kafka/net/sasl/gssapi.py +95 -0
- kafka/net/sasl/msk.py +245 -0
- kafka/net/sasl/oauth.py +98 -0
- kafka/net/sasl/plain.py +42 -0
- kafka/net/sasl/scram.py +135 -0
- kafka/net/sasl/sspi.py +111 -0
- kafka/net/selector.py +644 -0
- kafka/net/socks5.py +262 -0
- kafka/net/transport.py +415 -0
- kafka/net/wakeup_notifier.py +72 -0
- kafka/partitioner/__init__.py +8 -0
- kafka/partitioner/abc.py +8 -0
- kafka/partitioner/default.py +89 -0
- kafka/partitioner/sticky.py +109 -0
- kafka/producer/__init__.py +5 -0
- kafka/producer/__main__.py +5 -0
- kafka/producer/future.py +101 -0
- kafka/producer/kafka.py +1123 -0
- kafka/producer/producer_batch.py +192 -0
- kafka/producer/record_accumulator.py +647 -0
- kafka/producer/sender.py +884 -0
- kafka/producer/transaction_manager.py +1326 -0
- kafka/protocol/__init__.py +0 -0
- kafka/protocol/admin/__init__.py +29 -0
- kafka/protocol/admin/acl.py +83 -0
- kafka/protocol/admin/acl.pyi +375 -0
- kafka/protocol/admin/client_quotas.py +14 -0
- kafka/protocol/admin/client_quotas.pyi +265 -0
- kafka/protocol/admin/cluster.py +31 -0
- kafka/protocol/admin/cluster.pyi +620 -0
- kafka/protocol/admin/configs.py +22 -0
- kafka/protocol/admin/configs.pyi +437 -0
- kafka/protocol/admin/groups.py +24 -0
- kafka/protocol/admin/groups.pyi +261 -0
- kafka/protocol/admin/topics.py +53 -0
- kafka/protocol/admin/topics.pyi +982 -0
- kafka/protocol/admin/transactions.py +18 -0
- kafka/protocol/admin/transactions.pyi +311 -0
- kafka/protocol/admin/users.py +14 -0
- kafka/protocol/admin/users.pyi +223 -0
- kafka/protocol/api_data.py +125 -0
- kafka/protocol/api_header.py +55 -0
- kafka/protocol/api_key.py +97 -0
- kafka/protocol/api_message.py +277 -0
- kafka/protocol/broker_version_data.py +246 -0
- kafka/protocol/consumer/__init__.py +13 -0
- kafka/protocol/consumer/fetch.py +16 -0
- kafka/protocol/consumer/fetch.pyi +298 -0
- kafka/protocol/consumer/group.py +38 -0
- kafka/protocol/consumer/group.pyi +824 -0
- kafka/protocol/consumer/metadata.py +30 -0
- kafka/protocol/consumer/metadata.pyi +89 -0
- kafka/protocol/consumer/offsets.py +75 -0
- kafka/protocol/consumer/offsets.pyi +288 -0
- kafka/protocol/data_container.py +166 -0
- kafka/protocol/frame.py +30 -0
- kafka/protocol/generate_stubs.py +468 -0
- kafka/protocol/metadata/__init__.py +10 -0
- kafka/protocol/metadata/api_versions.py +41 -0
- kafka/protocol/metadata/api_versions.pyi +128 -0
- kafka/protocol/metadata/find_coordinator.py +19 -0
- kafka/protocol/metadata/find_coordinator.pyi +105 -0
- kafka/protocol/metadata/metadata.py +34 -0
- kafka/protocol/metadata/metadata.pyi +160 -0
- kafka/protocol/old/__init__.py +0 -0
- kafka/protocol/old/abstract.py +17 -0
- kafka/protocol/old/add_offsets_to_txn.py +54 -0
- kafka/protocol/old/add_partitions_to_txn.py +71 -0
- kafka/protocol/old/admin.py +1086 -0
- kafka/protocol/old/api.py +205 -0
- kafka/protocol/old/api_versions.py +133 -0
- kafka/protocol/old/commit.py +355 -0
- kafka/protocol/old/consumer_protocol.py +36 -0
- kafka/protocol/old/end_txn.py +53 -0
- kafka/protocol/old/fetch.py +408 -0
- kafka/protocol/old/find_coordinator.py +72 -0
- kafka/protocol/old/group.py +451 -0
- kafka/protocol/old/init_producer_id.py +42 -0
- kafka/protocol/old/list_offsets.py +186 -0
- kafka/protocol/old/metadata.py +290 -0
- kafka/protocol/old/offset_for_leader_epoch.py +133 -0
- kafka/protocol/old/produce.py +247 -0
- kafka/protocol/old/sasl_authenticate.py +38 -0
- kafka/protocol/old/sasl_handshake.py +39 -0
- kafka/protocol/old/struct.py +87 -0
- kafka/protocol/old/txn_offset_commit.py +73 -0
- kafka/protocol/old/types.py +440 -0
- kafka/protocol/parser.py +191 -0
- kafka/protocol/producer/__init__.py +7 -0
- kafka/protocol/producer/produce.py +17 -0
- kafka/protocol/producer/produce.pyi +197 -0
- kafka/protocol/producer/transaction.py +30 -0
- kafka/protocol/producer/transaction.pyi +663 -0
- kafka/protocol/sasl.py +52 -0
- kafka/protocol/sasl.pyi +126 -0
- kafka/protocol/schemas/__init__.py +7 -0
- kafka/protocol/schemas/fields/__init__.py +7 -0
- kafka/protocol/schemas/fields/array.py +127 -0
- kafka/protocol/schemas/fields/base.py +156 -0
- kafka/protocol/schemas/fields/codecs/__init__.py +12 -0
- kafka/protocol/schemas/fields/codecs/encode_buffer.py +82 -0
- kafka/protocol/schemas/fields/codecs/tagged_fields.py +109 -0
- kafka/protocol/schemas/fields/codecs/types.py +505 -0
- kafka/protocol/schemas/fields/codegen.py +40 -0
- kafka/protocol/schemas/fields/simple.py +127 -0
- kafka/protocol/schemas/fields/struct.py +357 -0
- kafka/protocol/schemas/fields/struct_array.py +142 -0
- kafka/protocol/schemas/load_json.py +42 -0
- kafka/protocol/schemas/resources/AddOffsetsToTxnRequest.json +40 -0
- kafka/protocol/schemas/resources/AddOffsetsToTxnResponse.json +35 -0
- kafka/protocol/schemas/resources/AddPartitionsToTxnRequest.json +65 -0
- kafka/protocol/schemas/resources/AddPartitionsToTxnResponse.json +60 -0
- kafka/protocol/schemas/resources/AlterClientQuotasRequest.json +47 -0
- kafka/protocol/schemas/resources/AlterClientQuotasResponse.json +41 -0
- kafka/protocol/schemas/resources/AlterConfigsRequest.json +43 -0
- kafka/protocol/schemas/resources/AlterConfigsResponse.json +39 -0
- kafka/protocol/schemas/resources/AlterPartitionReassignmentsRequest.json +42 -0
- kafka/protocol/schemas/resources/AlterPartitionReassignmentsResponse.json +47 -0
- kafka/protocol/schemas/resources/AlterReplicaLogDirsRequest.json +41 -0
- kafka/protocol/schemas/resources/AlterReplicaLogDirsResponse.json +41 -0
- kafka/protocol/schemas/resources/AlterUserScramCredentialsRequest.json +45 -0
- kafka/protocol/schemas/resources/AlterUserScramCredentialsResponse.json +35 -0
- kafka/protocol/schemas/resources/ApiVersionsRequest.json +34 -0
- kafka/protocol/schemas/resources/ApiVersionsResponse.json +79 -0
- kafka/protocol/schemas/resources/ConsumerProtocolAssignment.json +42 -0
- kafka/protocol/schemas/resources/ConsumerProtocolSubscription.json +49 -0
- kafka/protocol/schemas/resources/CreateAclsRequest.json +46 -0
- kafka/protocol/schemas/resources/CreateAclsResponse.json +37 -0
- kafka/protocol/schemas/resources/CreatePartitionsRequest.json +47 -0
- kafka/protocol/schemas/resources/CreatePartitionsResponse.json +41 -0
- kafka/protocol/schemas/resources/CreateTopicsRequest.json +65 -0
- kafka/protocol/schemas/resources/CreateTopicsResponse.json +72 -0
- kafka/protocol/schemas/resources/DeleteAclsRequest.json +46 -0
- kafka/protocol/schemas/resources/DeleteAclsResponse.json +59 -0
- kafka/protocol/schemas/resources/DeleteGroupsRequest.json +30 -0
- kafka/protocol/schemas/resources/DeleteGroupsResponse.json +36 -0
- kafka/protocol/schemas/resources/DeleteRecordsRequest.json +42 -0
- kafka/protocol/schemas/resources/DeleteRecordsResponse.json +43 -0
- kafka/protocol/schemas/resources/DeleteTopicsRequest.json +43 -0
- kafka/protocol/schemas/resources/DeleteTopicsResponse.json +52 -0
- kafka/protocol/schemas/resources/DescribeAclsRequest.json +43 -0
- kafka/protocol/schemas/resources/DescribeAclsResponse.json +55 -0
- kafka/protocol/schemas/resources/DescribeClientQuotasRequest.json +37 -0
- kafka/protocol/schemas/resources/DescribeClientQuotasResponse.json +47 -0
- kafka/protocol/schemas/resources/DescribeClusterRequest.json +35 -0
- kafka/protocol/schemas/resources/DescribeClusterResponse.json +56 -0
- kafka/protocol/schemas/resources/DescribeConfigsRequest.json +42 -0
- kafka/protocol/schemas/resources/DescribeConfigsResponse.json +69 -0
- kafka/protocol/schemas/resources/DescribeGroupsRequest.json +38 -0
- kafka/protocol/schemas/resources/DescribeGroupsResponse.json +74 -0
- kafka/protocol/schemas/resources/DescribeLogDirsRequest.json +38 -0
- kafka/protocol/schemas/resources/DescribeLogDirsResponse.json +65 -0
- kafka/protocol/schemas/resources/DescribeProducersRequest.json +32 -0
- kafka/protocol/schemas/resources/DescribeProducersResponse.json +55 -0
- kafka/protocol/schemas/resources/DescribeQuorumRequest.json +39 -0
- kafka/protocol/schemas/resources/DescribeQuorumResponse.json +82 -0
- kafka/protocol/schemas/resources/DescribeTopicPartitionsRequest.json +40 -0
- kafka/protocol/schemas/resources/DescribeTopicPartitionsResponse.json +66 -0
- kafka/protocol/schemas/resources/DescribeTransactionsRequest.json +27 -0
- kafka/protocol/schemas/resources/DescribeTransactionsResponse.json +52 -0
- kafka/protocol/schemas/resources/DescribeUserScramCredentialsRequest.json +30 -0
- kafka/protocol/schemas/resources/DescribeUserScramCredentialsResponse.json +45 -0
- kafka/protocol/schemas/resources/ElectLeadersRequest.json +41 -0
- kafka/protocol/schemas/resources/ElectLeadersResponse.json +45 -0
- kafka/protocol/schemas/resources/EndTxnRequest.json +43 -0
- kafka/protocol/schemas/resources/EndTxnResponse.json +41 -0
- kafka/protocol/schemas/resources/FetchRequest.json +125 -0
- kafka/protocol/schemas/resources/FetchResponse.json +124 -0
- kafka/protocol/schemas/resources/FindCoordinatorRequest.json +43 -0
- kafka/protocol/schemas/resources/FindCoordinatorResponse.json +58 -0
- kafka/protocol/schemas/resources/HeartbeatRequest.json +39 -0
- kafka/protocol/schemas/resources/HeartbeatResponse.json +35 -0
- kafka/protocol/schemas/resources/IncrementalAlterConfigsRequest.json +44 -0
- kafka/protocol/schemas/resources/IncrementalAlterConfigsResponse.json +38 -0
- kafka/protocol/schemas/resources/InitProducerIdRequest.json +50 -0
- kafka/protocol/schemas/resources/InitProducerIdResponse.json +47 -0
- kafka/protocol/schemas/resources/JoinGroupRequest.json +63 -0
- kafka/protocol/schemas/resources/JoinGroupResponse.json +69 -0
- kafka/protocol/schemas/resources/LeaveGroupRequest.json +47 -0
- kafka/protocol/schemas/resources/LeaveGroupResponse.json +47 -0
- kafka/protocol/schemas/resources/ListConfigResourcesRequest.json +31 -0
- kafka/protocol/schemas/resources/ListConfigResourcesResponse.json +37 -0
- kafka/protocol/schemas/resources/ListGroupsRequest.json +36 -0
- kafka/protocol/schemas/resources/ListGroupsResponse.json +49 -0
- kafka/protocol/schemas/resources/ListOffsetsRequest.json +72 -0
- kafka/protocol/schemas/resources/ListOffsetsResponse.json +71 -0
- kafka/protocol/schemas/resources/ListPartitionReassignmentsRequest.json +34 -0
- kafka/protocol/schemas/resources/ListPartitionReassignmentsResponse.json +46 -0
- kafka/protocol/schemas/resources/ListTransactionsRequest.json +40 -0
- kafka/protocol/schemas/resources/ListTransactionsResponse.json +42 -0
- kafka/protocol/schemas/resources/MetadataRequest.json +56 -0
- kafka/protocol/schemas/resources/MetadataResponse.json +101 -0
- kafka/protocol/schemas/resources/OffsetCommitRequest.json +76 -0
- kafka/protocol/schemas/resources/OffsetCommitResponse.json +71 -0
- kafka/protocol/schemas/resources/OffsetDeleteRequest.json +39 -0
- kafka/protocol/schemas/resources/OffsetDeleteResponse.json +42 -0
- kafka/protocol/schemas/resources/OffsetFetchRequest.json +76 -0
- kafka/protocol/schemas/resources/OffsetFetchResponse.json +107 -0
- kafka/protocol/schemas/resources/OffsetForLeaderEpochRequest.json +52 -0
- kafka/protocol/schemas/resources/OffsetForLeaderEpochResponse.json +51 -0
- kafka/protocol/schemas/resources/ProduceRequest.json +73 -0
- kafka/protocol/schemas/resources/ProduceResponse.json +96 -0
- kafka/protocol/schemas/resources/RequestHeader.json +44 -0
- kafka/protocol/schemas/resources/ResponseHeader.json +26 -0
- kafka/protocol/schemas/resources/SaslAuthenticateRequest.json +29 -0
- kafka/protocol/schemas/resources/SaslAuthenticateResponse.json +34 -0
- kafka/protocol/schemas/resources/SaslHandshakeRequest.json +31 -0
- kafka/protocol/schemas/resources/SaslHandshakeResponse.json +32 -0
- kafka/protocol/schemas/resources/SyncGroupRequest.json +56 -0
- kafka/protocol/schemas/resources/SyncGroupResponse.json +46 -0
- kafka/protocol/schemas/resources/TxnOffsetCommitRequest.json +68 -0
- kafka/protocol/schemas/resources/TxnOffsetCommitResponse.json +47 -0
- kafka/protocol/schemas/resources/UpdateFeaturesRequest.json +43 -0
- kafka/protocol/schemas/resources/UpdateFeaturesResponse.json +39 -0
- kafka/protocol/schemas/resources/WriteTxnMarkersRequest.json +49 -0
- kafka/protocol/schemas/resources/WriteTxnMarkersResponse.json +45 -0
- kafka/protocol/schemas/resources/__init__.py +0 -0
- kafka/record/__init__.py +3 -0
- kafka/record/_crc32c.py +161 -0
- kafka/record/abc.py +144 -0
- kafka/record/default_records.py +782 -0
- kafka/record/legacy_records.py +587 -0
- kafka/record/memory_records.py +255 -0
- kafka/record/util.py +135 -0
- kafka/serializer/__init__.py +4 -0
- kafka/serializer/abstract.py +20 -0
- kafka/serializer/default.py +16 -0
- kafka/serializer/json.py +17 -0
- kafka/serializer/wrapper.py +21 -0
- kafka/structs.py +69 -0
- kafka/util.py +159 -0
- kafka/vendor/__init__.py +0 -0
- kafka/version.py +1 -0
- kafka_python-3.0.0.dist-info/METADATA +319 -0
- kafka_python-3.0.0.dist-info/RECORD +373 -0
- kafka_python-3.0.0.dist-info/WHEEL +5 -0
- kafka_python-3.0.0.dist-info/entry_points.txt +2 -0
- kafka_python-3.0.0.dist-info/licenses/LICENSE +202 -0
- kafka_python-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
"""Generate .pyi type stub files for dynamically created protocol classes.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
python -m kafka.protocol.generate_stubs # generate stubs
|
|
5
|
+
python -m kafka.protocol.generate_stubs --check # exit 1 if stubs are out of date
|
|
6
|
+
python -m kafka.protocol.generate_stubs --dry-run # print to stdout
|
|
7
|
+
"""
|
|
8
|
+
import importlib
|
|
9
|
+
import inspect
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
from .api_data import ApiData
|
|
14
|
+
from .api_message import ApiMessage
|
|
15
|
+
from .data_container import DataContainer
|
|
16
|
+
from .schemas.fields.simple import SimpleField
|
|
17
|
+
from .schemas.fields.array import ArrayField
|
|
18
|
+
from .schemas.fields.struct import StructField
|
|
19
|
+
from .schemas.fields.struct_array import StructArrayField
|
|
20
|
+
from kafka.util import classproperty
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# JSON schema type string -> Python type annotation
|
|
24
|
+
SIMPLE_TYPE_MAP = {
|
|
25
|
+
'int8': 'int',
|
|
26
|
+
'int16': 'int',
|
|
27
|
+
'uint16': 'int',
|
|
28
|
+
'int32': 'int',
|
|
29
|
+
'int64': 'int',
|
|
30
|
+
'float64': 'float',
|
|
31
|
+
'bool': 'bool',
|
|
32
|
+
'string': 'str',
|
|
33
|
+
'bytes': 'bytes',
|
|
34
|
+
'records': 'bytes',
|
|
35
|
+
'uuid': 'uuid.UUID',
|
|
36
|
+
'bitfield': 'set[int]',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Modules containing protocol classes, relative to kafka.protocol
|
|
40
|
+
MESSAGE_MODULES = [
|
|
41
|
+
'kafka.protocol.admin.acl',
|
|
42
|
+
'kafka.protocol.admin.client_quotas',
|
|
43
|
+
'kafka.protocol.admin.cluster',
|
|
44
|
+
'kafka.protocol.admin.configs',
|
|
45
|
+
'kafka.protocol.admin.groups',
|
|
46
|
+
'kafka.protocol.admin.topics',
|
|
47
|
+
'kafka.protocol.admin.transactions',
|
|
48
|
+
'kafka.protocol.admin.users',
|
|
49
|
+
'kafka.protocol.consumer.fetch',
|
|
50
|
+
'kafka.protocol.consumer.group',
|
|
51
|
+
'kafka.protocol.consumer.metadata',
|
|
52
|
+
'kafka.protocol.consumer.offsets',
|
|
53
|
+
'kafka.protocol.metadata.api_versions',
|
|
54
|
+
'kafka.protocol.metadata.find_coordinator',
|
|
55
|
+
'kafka.protocol.metadata.metadata',
|
|
56
|
+
'kafka.protocol.producer.produce',
|
|
57
|
+
'kafka.protocol.producer.transaction',
|
|
58
|
+
'kafka.protocol.sasl',
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _all_fields_recursive(cls):
|
|
63
|
+
"""Yield all fields from cls and its nested structs."""
|
|
64
|
+
if cls._struct is None:
|
|
65
|
+
return
|
|
66
|
+
for field in cls._struct._fields:
|
|
67
|
+
yield field
|
|
68
|
+
if field.is_struct() or field.is_struct_array():
|
|
69
|
+
dc = getattr(cls, field.type_str, None)
|
|
70
|
+
if dc is not None:
|
|
71
|
+
yield from _all_fields_recursive(dc)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def resolve_type(field):
|
|
75
|
+
"""Convert a field object to a Python type annotation string."""
|
|
76
|
+
if isinstance(field, StructArrayField):
|
|
77
|
+
base = 'list[%s]' % field.type_str
|
|
78
|
+
elif isinstance(field, ArrayField):
|
|
79
|
+
# Simple array (e.g., []int32, []string)
|
|
80
|
+
inner = SIMPLE_TYPE_MAP.get(field.array_of._type_str, 'Any')
|
|
81
|
+
base = 'list[%s]' % inner
|
|
82
|
+
elif isinstance(field, StructField):
|
|
83
|
+
base = field.type_str
|
|
84
|
+
elif isinstance(field, SimpleField):
|
|
85
|
+
base = SIMPLE_TYPE_MAP.get(field._type_str, 'Any')
|
|
86
|
+
# bytes fields accept ApiData objects (encoded automatically via .encode())
|
|
87
|
+
if field._type_str in ('bytes', 'records'):
|
|
88
|
+
base = 'bytes | ApiData'
|
|
89
|
+
else:
|
|
90
|
+
base = 'Any'
|
|
91
|
+
|
|
92
|
+
if field._nullable_versions is not None:
|
|
93
|
+
return '%s | None' % base
|
|
94
|
+
return base
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _collect_nested_classes(cls):
|
|
98
|
+
"""Yield (field, data_class) pairs for nested struct types on cls."""
|
|
99
|
+
if cls._struct is None:
|
|
100
|
+
return
|
|
101
|
+
seen = set()
|
|
102
|
+
for field in cls._struct._fields:
|
|
103
|
+
if field.is_struct() or field.is_struct_array():
|
|
104
|
+
dc = getattr(cls, field.type_str, None)
|
|
105
|
+
if dc is not None and dc not in seen:
|
|
106
|
+
seen.add(dc)
|
|
107
|
+
yield field, dc
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def emit_class(cls, indent=0, base_name=None):
|
|
111
|
+
"""Generate stub lines for a single protocol class."""
|
|
112
|
+
pad = ' ' * indent
|
|
113
|
+
lines = []
|
|
114
|
+
|
|
115
|
+
# Determine base class name for the stub
|
|
116
|
+
if base_name is None:
|
|
117
|
+
if issubclass(cls, ApiMessage):
|
|
118
|
+
base_name = 'ApiMessage'
|
|
119
|
+
elif issubclass(cls, ApiData):
|
|
120
|
+
base_name = 'ApiData'
|
|
121
|
+
else:
|
|
122
|
+
base_name = 'DataContainer'
|
|
123
|
+
|
|
124
|
+
lines.append('%sclass %s(%s):' % (pad, cls.__name__, base_name))
|
|
125
|
+
|
|
126
|
+
inner_pad = pad + ' '
|
|
127
|
+
|
|
128
|
+
# Nested inner classes first
|
|
129
|
+
for field, dc in _collect_nested_classes(cls):
|
|
130
|
+
lines.extend(emit_class(dc, indent=indent + 4, base_name='DataContainer'))
|
|
131
|
+
lines.append('')
|
|
132
|
+
|
|
133
|
+
# Field annotations
|
|
134
|
+
if cls._struct is not None:
|
|
135
|
+
for field in cls._struct._fields:
|
|
136
|
+
type_ann = resolve_type(field)
|
|
137
|
+
lines.append('%s%s: %s' % (inner_pad, field.name, type_ann))
|
|
138
|
+
|
|
139
|
+
# __init__ signature
|
|
140
|
+
init_params = ['self', '*args: Any']
|
|
141
|
+
if cls._struct is not None:
|
|
142
|
+
for field in cls._struct._fields:
|
|
143
|
+
type_ann = resolve_type(field)
|
|
144
|
+
init_params.append('%s: %s = ...' % (field.name, type_ann))
|
|
145
|
+
init_params.append('version: int | None = None')
|
|
146
|
+
init_params.append('**kwargs: Any')
|
|
147
|
+
|
|
148
|
+
if len(init_params) <= 4:
|
|
149
|
+
lines.append('%sdef __init__(%s) -> None: ...' % (inner_pad, ', '.join(init_params)))
|
|
150
|
+
else:
|
|
151
|
+
lines.append('%sdef __init__(' % inner_pad)
|
|
152
|
+
for i, param in enumerate(init_params):
|
|
153
|
+
comma = ',' if i < len(init_params) - 1 else ','
|
|
154
|
+
lines.append('%s %s%s' % (inner_pad, param, comma))
|
|
155
|
+
lines.append('%s) -> None: ...' % inner_pad)
|
|
156
|
+
|
|
157
|
+
# Common DataContainer methods/properties
|
|
158
|
+
lines.append('%s@property' % inner_pad)
|
|
159
|
+
lines.append('%sdef version(self) -> int | None: ...' % inner_pad)
|
|
160
|
+
lines.append('%sdef to_dict(self, meta: bool = False, json: bool = True) -> dict: ...' % inner_pad)
|
|
161
|
+
|
|
162
|
+
if base_name == 'DataContainer':
|
|
163
|
+
pass # encode/decode inherited from DataContainer
|
|
164
|
+
elif base_name == 'ApiData':
|
|
165
|
+
_emit_api_data_methods(lines, inner_pad, cls)
|
|
166
|
+
elif base_name == 'ApiMessage':
|
|
167
|
+
_emit_api_message_methods(lines, inner_pad, cls)
|
|
168
|
+
|
|
169
|
+
# Detect custom members defined on the class itself (not inherited)
|
|
170
|
+
_emit_custom_members(lines, inner_pad, cls, base_name)
|
|
171
|
+
|
|
172
|
+
return lines
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _emit_api_data_methods(lines, pad, cls):
|
|
176
|
+
"""Emit method stubs for ApiData subclasses."""
|
|
177
|
+
lines.append('%sname: str' % pad)
|
|
178
|
+
lines.append('%stype: str' % pad)
|
|
179
|
+
lines.append('%svalid_versions: tuple[int, int]' % pad)
|
|
180
|
+
lines.append('%smin_version: int' % pad)
|
|
181
|
+
lines.append('%smax_version: int' % pad)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _emit_api_message_methods(lines, pad, cls):
|
|
185
|
+
"""Emit method stubs for ApiMessage subclasses."""
|
|
186
|
+
lines.append('%sname: str' % pad)
|
|
187
|
+
lines.append('%stype: str' % pad)
|
|
188
|
+
lines.append('%sAPI_KEY: int' % pad)
|
|
189
|
+
lines.append('%sAPI_VERSION: int' % pad)
|
|
190
|
+
lines.append('%svalid_versions: tuple[int, int]' % pad)
|
|
191
|
+
lines.append('%smin_version: int' % pad)
|
|
192
|
+
lines.append('%smax_version: int' % pad)
|
|
193
|
+
lines.append('%s@property' % pad)
|
|
194
|
+
lines.append('%sdef header(self) -> Any: ...' % pad)
|
|
195
|
+
lines.append('%s@classmethod' % pad)
|
|
196
|
+
lines.append('%sdef is_request(cls) -> bool: ...' % pad)
|
|
197
|
+
lines.append('%sdef expect_response(self) -> bool: ...' % pad)
|
|
198
|
+
lines.append('%sdef with_header(self, correlation_id: int = 0, client_id: str = "kafka-python") -> None: ...' % pad)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _format_annotation(ann):
|
|
202
|
+
"""Format a type annotation as a clean string, using short class names."""
|
|
203
|
+
if isinstance(ann, str):
|
|
204
|
+
return ann
|
|
205
|
+
if isinstance(ann, type):
|
|
206
|
+
return ann.__name__
|
|
207
|
+
# For generic aliases like list[TopicPartition], use repr and clean up module paths
|
|
208
|
+
s = str(ann)
|
|
209
|
+
# Remove module prefixes (e.g., kafka.structs.TopicPartition -> TopicPartition)
|
|
210
|
+
import re
|
|
211
|
+
s = re.sub(r'[a-zA-Z_][a-zA-Z0-9_.]*\.([A-Z][a-zA-Z0-9_]*)', r'\1', s)
|
|
212
|
+
return s
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _get_return_annotation(obj):
|
|
216
|
+
"""Extract the return type annotation string from a callable, property, or classproperty."""
|
|
217
|
+
func = None
|
|
218
|
+
if isinstance(obj, classproperty):
|
|
219
|
+
func = obj.f
|
|
220
|
+
elif isinstance(obj, property):
|
|
221
|
+
func = obj.fget
|
|
222
|
+
elif isinstance(obj, classmethod):
|
|
223
|
+
func = obj.__func__
|
|
224
|
+
elif isinstance(obj, staticmethod):
|
|
225
|
+
func = obj.__func__
|
|
226
|
+
elif callable(obj):
|
|
227
|
+
func = obj
|
|
228
|
+
|
|
229
|
+
if func is not None:
|
|
230
|
+
hints = getattr(func, '__annotations__', {})
|
|
231
|
+
ret = hints.get('return')
|
|
232
|
+
if ret is not None:
|
|
233
|
+
return _format_annotation(ret)
|
|
234
|
+
return None
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _get_param_annotations(obj):
|
|
238
|
+
"""Extract parameter annotations from a callable, returning (params_str, has_annotations)."""
|
|
239
|
+
func = None
|
|
240
|
+
if isinstance(obj, classmethod):
|
|
241
|
+
func = obj.__func__
|
|
242
|
+
elif isinstance(obj, staticmethod):
|
|
243
|
+
func = obj.__func__
|
|
244
|
+
elif callable(obj):
|
|
245
|
+
func = obj
|
|
246
|
+
|
|
247
|
+
if func is None:
|
|
248
|
+
return None
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
sig = inspect.signature(func)
|
|
252
|
+
except (ValueError, TypeError):
|
|
253
|
+
return None
|
|
254
|
+
|
|
255
|
+
parts = []
|
|
256
|
+
for pname, param in sig.parameters.items():
|
|
257
|
+
if pname == 'self' or pname == 'cls':
|
|
258
|
+
parts.append(pname)
|
|
259
|
+
continue
|
|
260
|
+
ann = param.annotation
|
|
261
|
+
if ann is inspect.Parameter.empty:
|
|
262
|
+
ann_str = 'Any'
|
|
263
|
+
else:
|
|
264
|
+
ann_str = _format_annotation(ann)
|
|
265
|
+
if param.default is not inspect.Parameter.empty:
|
|
266
|
+
parts.append('%s: %s = ...' % (pname, ann_str))
|
|
267
|
+
elif param.kind == inspect.Parameter.VAR_POSITIONAL:
|
|
268
|
+
parts.append('*%s: %s' % (pname, ann_str))
|
|
269
|
+
elif param.kind == inspect.Parameter.VAR_KEYWORD:
|
|
270
|
+
parts.append('**%s: %s' % (pname, ann_str))
|
|
271
|
+
else:
|
|
272
|
+
parts.append('%s: %s' % (pname, ann_str))
|
|
273
|
+
return ', '.join(parts)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _emit_custom_members(lines, pad, cls, base_name):
|
|
277
|
+
"""Emit stubs for custom members defined directly on the class.
|
|
278
|
+
|
|
279
|
+
Reads type annotations from the source when available.
|
|
280
|
+
"""
|
|
281
|
+
skip = {
|
|
282
|
+
'_json', '_struct', '_class_version', '_VERSIONS', '_flexible_versions',
|
|
283
|
+
'_valid_versions', '__module__', '__qualname__', '__doc__', '__dict__',
|
|
284
|
+
'__weakref__', '__license__', 'json_patch', '__init_subclass__',
|
|
285
|
+
}
|
|
286
|
+
if base_name == 'ApiMessage':
|
|
287
|
+
base = ApiMessage
|
|
288
|
+
elif base_name == 'ApiData':
|
|
289
|
+
base = ApiData
|
|
290
|
+
else:
|
|
291
|
+
base = DataContainer
|
|
292
|
+
|
|
293
|
+
for name, obj in cls.__dict__.items():
|
|
294
|
+
if name.startswith('_') or name in skip:
|
|
295
|
+
continue
|
|
296
|
+
# Skip encode/decode overrides to avoid LSP violations in stubs
|
|
297
|
+
if name in ('encode', 'decode', 'encode_into') and hasattr(base, name):
|
|
298
|
+
continue
|
|
299
|
+
# Skip slot descriptors and nested classes (already handled)
|
|
300
|
+
if isinstance(obj, type):
|
|
301
|
+
continue
|
|
302
|
+
if type(obj).__name__ == 'member_descriptor':
|
|
303
|
+
continue
|
|
304
|
+
|
|
305
|
+
ret = _get_return_annotation(obj) or 'Any'
|
|
306
|
+
|
|
307
|
+
if isinstance(obj, classproperty):
|
|
308
|
+
lines.append('%s@property' % pad)
|
|
309
|
+
lines.append('%sdef %s(self) -> %s: ...' % (pad, name, ret))
|
|
310
|
+
elif isinstance(obj, property):
|
|
311
|
+
lines.append('%s@property' % pad)
|
|
312
|
+
lines.append('%sdef %s(self) -> %s: ...' % (pad, name, ret))
|
|
313
|
+
elif isinstance(obj, classmethod):
|
|
314
|
+
params = _get_param_annotations(obj) or 'cls, *args: Any, **kwargs: Any'
|
|
315
|
+
lines.append('%s@classmethod' % pad)
|
|
316
|
+
lines.append('%sdef %s(%s) -> %s: ...' % (pad, name, params, ret))
|
|
317
|
+
elif isinstance(obj, staticmethod):
|
|
318
|
+
params = _get_param_annotations(obj) or '*args: Any, **kwargs: Any'
|
|
319
|
+
lines.append('%s@staticmethod' % pad)
|
|
320
|
+
lines.append('%sdef %s(%s) -> %s: ...' % (pad, name, params, ret))
|
|
321
|
+
elif callable(obj) and not isinstance(obj, type):
|
|
322
|
+
params = _get_param_annotations(obj) or 'self, *args: Any, **kwargs: Any'
|
|
323
|
+
lines.append('%sdef %s(%s) -> %s: ...' % (pad, name, params, ret))
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def discover_modules():
|
|
327
|
+
"""Import all message modules and collect their exports.
|
|
328
|
+
|
|
329
|
+
Returns dict mapping module file path to list of (name, obj) pairs.
|
|
330
|
+
"""
|
|
331
|
+
result = {}
|
|
332
|
+
for mod_name in MESSAGE_MODULES:
|
|
333
|
+
mod = importlib.import_module(mod_name)
|
|
334
|
+
mod_file = inspect.getfile(mod)
|
|
335
|
+
all_names = getattr(mod, '__all__', [])
|
|
336
|
+
exports = []
|
|
337
|
+
for name in all_names:
|
|
338
|
+
obj = getattr(mod, name)
|
|
339
|
+
exports.append((name, obj))
|
|
340
|
+
result[mod_file] = (mod, exports)
|
|
341
|
+
return result
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def generate_module(mod, exports):
|
|
345
|
+
"""Generate the complete .pyi file content for a module."""
|
|
346
|
+
lines = []
|
|
347
|
+
lines.append('# Generated by generate_stubs.py (Python %d.%d)' % sys.version_info[:2])
|
|
348
|
+
lines.append('import uuid')
|
|
349
|
+
lines.append('from typing import Any, Self')
|
|
350
|
+
lines.append('')
|
|
351
|
+
|
|
352
|
+
# Determine needed imports based on base classes
|
|
353
|
+
from enum import IntEnum as _IntEnum
|
|
354
|
+
needs_api_message = False
|
|
355
|
+
needs_api_data = False
|
|
356
|
+
needs_data_container = False
|
|
357
|
+
needs_int_enum = False
|
|
358
|
+
for name, obj in exports:
|
|
359
|
+
if isinstance(obj, type):
|
|
360
|
+
if issubclass(obj, ApiMessage):
|
|
361
|
+
needs_api_message = True
|
|
362
|
+
elif issubclass(obj, ApiData):
|
|
363
|
+
needs_api_data = True
|
|
364
|
+
if issubclass(obj, _IntEnum):
|
|
365
|
+
needs_int_enum = True
|
|
366
|
+
|
|
367
|
+
# Check fields for nested classes (DataContainer) and bytes fields (ApiData)
|
|
368
|
+
for name, obj in exports:
|
|
369
|
+
if isinstance(obj, type) and hasattr(obj, '_struct') and obj._struct is not None:
|
|
370
|
+
for field in _all_fields_recursive(obj):
|
|
371
|
+
if field.is_struct() or field.is_struct_array():
|
|
372
|
+
needs_data_container = True
|
|
373
|
+
if isinstance(field, SimpleField) and field._type_str in ('bytes', 'records'):
|
|
374
|
+
needs_api_data = True
|
|
375
|
+
|
|
376
|
+
if needs_int_enum:
|
|
377
|
+
lines.append('from enum import IntEnum')
|
|
378
|
+
if needs_api_message:
|
|
379
|
+
lines.append('from kafka.protocol.api_message import ApiMessage')
|
|
380
|
+
if needs_api_data:
|
|
381
|
+
lines.append('from kafka.protocol.api_data import ApiData')
|
|
382
|
+
if needs_data_container:
|
|
383
|
+
lines.append('from kafka.protocol.data_container import DataContainer')
|
|
384
|
+
if needs_api_message or needs_api_data or needs_data_container or needs_int_enum:
|
|
385
|
+
lines.append('')
|
|
386
|
+
|
|
387
|
+
# Export __all__ so __init__.py can import it
|
|
388
|
+
all_names = [name for name, obj in exports]
|
|
389
|
+
lines.append('__all__ = [%s]' % ', '.join("'%s'" % n for n in all_names))
|
|
390
|
+
lines.append('')
|
|
391
|
+
|
|
392
|
+
for name, obj in exports:
|
|
393
|
+
if isinstance(obj, type) and issubclass(obj, DataContainer) and obj._struct is not None:
|
|
394
|
+
lines.extend(emit_class(obj))
|
|
395
|
+
lines.append('')
|
|
396
|
+
elif isinstance(obj, type):
|
|
397
|
+
# Non-protocol class (IntEnum, OffsetResetStrategy, etc.)
|
|
398
|
+
# Reproduce class with its attributes so the stub doesn't shadow the real definition
|
|
399
|
+
from enum import IntEnum as _IntEnum
|
|
400
|
+
bases = [b.__name__ for b in obj.__bases__ if b is not object]
|
|
401
|
+
base_str = '(%s)' % ', '.join(bases) if bases else ''
|
|
402
|
+
lines.append('class %s%s:' % (name, base_str))
|
|
403
|
+
members = {k: v for k, v in obj.__dict__.items()
|
|
404
|
+
if not k.startswith('_') and not callable(v)}
|
|
405
|
+
if members:
|
|
406
|
+
for k, v in members.items():
|
|
407
|
+
# IntEnum members have the enum class as type; use int instead
|
|
408
|
+
if issubclass(obj, _IntEnum):
|
|
409
|
+
lines.append(' %s: int' % k)
|
|
410
|
+
else:
|
|
411
|
+
lines.append(' %s: %s' % (k, type(v).__name__))
|
|
412
|
+
else:
|
|
413
|
+
lines.append(' ...')
|
|
414
|
+
lines.append('')
|
|
415
|
+
else:
|
|
416
|
+
# Constants
|
|
417
|
+
type_name = type(obj).__name__
|
|
418
|
+
lines.append('%s: %s' % (name, type_name))
|
|
419
|
+
lines.append('')
|
|
420
|
+
|
|
421
|
+
return '\n'.join(lines)
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def generate_all(dry_run=False, check=False):
|
|
425
|
+
"""Generate all stub files. Returns True if all stubs are up to date."""
|
|
426
|
+
modules = discover_modules()
|
|
427
|
+
all_up_to_date = True
|
|
428
|
+
|
|
429
|
+
for mod_file, (mod, exports) in sorted(modules.items()):
|
|
430
|
+
content = generate_module(mod, exports)
|
|
431
|
+
pyi_path = mod_file.replace('.py', '.pyi')
|
|
432
|
+
|
|
433
|
+
if dry_run:
|
|
434
|
+
print('# %s' % pyi_path)
|
|
435
|
+
print(content)
|
|
436
|
+
print()
|
|
437
|
+
elif check:
|
|
438
|
+
if os.path.exists(pyi_path):
|
|
439
|
+
with open(pyi_path, 'r') as f:
|
|
440
|
+
existing = f.read()
|
|
441
|
+
if existing != content:
|
|
442
|
+
print('OUTDATED: %s' % pyi_path)
|
|
443
|
+
all_up_to_date = False
|
|
444
|
+
else:
|
|
445
|
+
print('MISSING: %s' % pyi_path)
|
|
446
|
+
all_up_to_date = False
|
|
447
|
+
else:
|
|
448
|
+
with open(pyi_path, 'w') as f:
|
|
449
|
+
f.write(content)
|
|
450
|
+
print('Generated: %s' % pyi_path)
|
|
451
|
+
|
|
452
|
+
return all_up_to_date
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
if __name__ == '__main__':
|
|
456
|
+
import argparse
|
|
457
|
+
parser = argparse.ArgumentParser(description='Generate .pyi stubs for protocol classes')
|
|
458
|
+
parser.add_argument('--check', action='store_true',
|
|
459
|
+
help='Check if stubs are up to date (exit 1 if not)')
|
|
460
|
+
parser.add_argument('--dry-run', action='store_true',
|
|
461
|
+
help='Print to stdout instead of writing files')
|
|
462
|
+
args = parser.parse_args()
|
|
463
|
+
|
|
464
|
+
if args.check:
|
|
465
|
+
up_to_date = generate_all(check=True)
|
|
466
|
+
sys.exit(0 if up_to_date else 1)
|
|
467
|
+
else:
|
|
468
|
+
generate_all(dry_run=args.dry_run)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .api_versions import *
|
|
2
|
+
from .api_versions import __all__ as api_versions_all
|
|
3
|
+
|
|
4
|
+
from .find_coordinator import *
|
|
5
|
+
from .find_coordinator import __all__ as find_coordinator_all
|
|
6
|
+
|
|
7
|
+
from .metadata import *
|
|
8
|
+
from .metadata import __all__ as metadata_all
|
|
9
|
+
|
|
10
|
+
__all__ = api_versions_all + find_coordinator_all + metadata_all
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import io
|
|
2
|
+
|
|
3
|
+
from ..api_message import ApiMessage
|
|
4
|
+
from ..schemas.fields.codecs import Int16, Int32
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ApiVersionsRequest(ApiMessage): pass
|
|
8
|
+
class ApiVersionsResponse(ApiMessage):
|
|
9
|
+
# ApiVersionsResponse header never uses flexible formats, even if body does
|
|
10
|
+
@classmethod
|
|
11
|
+
def parse_header(cls, data, version=None):
|
|
12
|
+
return cls.header_class.decode(data, flexible=False) # pylint: disable=E1101
|
|
13
|
+
|
|
14
|
+
def encode_header(self, flexible=False):
|
|
15
|
+
return super().encode_header(flexible=False)
|
|
16
|
+
|
|
17
|
+
# ApiVersionsResponse body always decodes as version 0 when error is present
|
|
18
|
+
@classmethod
|
|
19
|
+
def decode(cls, data, version=None, header=False, framed=False):
|
|
20
|
+
if not hasattr(data, 'tell'):
|
|
21
|
+
data = io.BytesIO(data)
|
|
22
|
+
if framed:
|
|
23
|
+
size = Int32.decode(data)
|
|
24
|
+
if header:
|
|
25
|
+
hdr = cls.parse_header(data)
|
|
26
|
+
else:
|
|
27
|
+
hdr = None
|
|
28
|
+
curr = data.tell()
|
|
29
|
+
err = Int16.decode(data)
|
|
30
|
+
data.seek(curr)
|
|
31
|
+
if err != 0:
|
|
32
|
+
version = 0
|
|
33
|
+
ret = super().decode(data, version=version, header=False, framed=False)
|
|
34
|
+
if hdr is not None:
|
|
35
|
+
ret._header = hdr
|
|
36
|
+
return ret
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
'ApiVersionsRequest', 'ApiVersionsResponse',
|
|
41
|
+
]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Generated by generate_stubs.py (Python 3.14)
|
|
2
|
+
import uuid
|
|
3
|
+
from typing import Any, Self
|
|
4
|
+
|
|
5
|
+
from kafka.protocol.api_message import ApiMessage
|
|
6
|
+
from kafka.protocol.data_container import DataContainer
|
|
7
|
+
|
|
8
|
+
__all__ = ['ApiVersionsRequest', 'ApiVersionsResponse']
|
|
9
|
+
|
|
10
|
+
class ApiVersionsRequest(ApiMessage):
|
|
11
|
+
client_software_name: str
|
|
12
|
+
client_software_version: str
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
*args: Any,
|
|
16
|
+
client_software_name: str = ...,
|
|
17
|
+
client_software_version: str = ...,
|
|
18
|
+
version: int | None = None,
|
|
19
|
+
**kwargs: Any,
|
|
20
|
+
) -> None: ...
|
|
21
|
+
@property
|
|
22
|
+
def version(self) -> int | None: ...
|
|
23
|
+
def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
|
|
24
|
+
name: str
|
|
25
|
+
type: str
|
|
26
|
+
API_KEY: int
|
|
27
|
+
API_VERSION: int
|
|
28
|
+
valid_versions: tuple[int, int]
|
|
29
|
+
min_version: int
|
|
30
|
+
max_version: int
|
|
31
|
+
@property
|
|
32
|
+
def header(self) -> Any: ...
|
|
33
|
+
@classmethod
|
|
34
|
+
def is_request(cls) -> bool: ...
|
|
35
|
+
def expect_response(self) -> bool: ...
|
|
36
|
+
def with_header(self, correlation_id: int = 0, client_id: str = "kafka-python") -> None: ...
|
|
37
|
+
|
|
38
|
+
class ApiVersionsResponse(ApiMessage):
|
|
39
|
+
class ApiVersion(DataContainer):
|
|
40
|
+
api_key: int
|
|
41
|
+
min_version: int
|
|
42
|
+
max_version: int
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
*args: Any,
|
|
46
|
+
api_key: int = ...,
|
|
47
|
+
min_version: int = ...,
|
|
48
|
+
max_version: int = ...,
|
|
49
|
+
version: int | None = None,
|
|
50
|
+
**kwargs: Any,
|
|
51
|
+
) -> None: ...
|
|
52
|
+
@property
|
|
53
|
+
def version(self) -> int | None: ...
|
|
54
|
+
def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
|
|
55
|
+
|
|
56
|
+
class SupportedFeatureKey(DataContainer):
|
|
57
|
+
name: str
|
|
58
|
+
min_version: int
|
|
59
|
+
max_version: int
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
*args: Any,
|
|
63
|
+
name: str = ...,
|
|
64
|
+
min_version: int = ...,
|
|
65
|
+
max_version: int = ...,
|
|
66
|
+
version: int | None = None,
|
|
67
|
+
**kwargs: Any,
|
|
68
|
+
) -> None: ...
|
|
69
|
+
@property
|
|
70
|
+
def version(self) -> int | None: ...
|
|
71
|
+
def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
|
|
72
|
+
|
|
73
|
+
class FinalizedFeatureKey(DataContainer):
|
|
74
|
+
name: str
|
|
75
|
+
max_version_level: int
|
|
76
|
+
min_version_level: int
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
*args: Any,
|
|
80
|
+
name: str = ...,
|
|
81
|
+
max_version_level: int = ...,
|
|
82
|
+
min_version_level: int = ...,
|
|
83
|
+
version: int | None = None,
|
|
84
|
+
**kwargs: Any,
|
|
85
|
+
) -> None: ...
|
|
86
|
+
@property
|
|
87
|
+
def version(self) -> int | None: ...
|
|
88
|
+
def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
|
|
89
|
+
|
|
90
|
+
error_code: int
|
|
91
|
+
api_keys: list[ApiVersion]
|
|
92
|
+
throttle_time_ms: int
|
|
93
|
+
supported_features: list[SupportedFeatureKey]
|
|
94
|
+
finalized_features_epoch: int
|
|
95
|
+
finalized_features: list[FinalizedFeatureKey]
|
|
96
|
+
zk_migration_ready: bool
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
*args: Any,
|
|
100
|
+
error_code: int = ...,
|
|
101
|
+
api_keys: list[ApiVersion] = ...,
|
|
102
|
+
throttle_time_ms: int = ...,
|
|
103
|
+
supported_features: list[SupportedFeatureKey] = ...,
|
|
104
|
+
finalized_features_epoch: int = ...,
|
|
105
|
+
finalized_features: list[FinalizedFeatureKey] = ...,
|
|
106
|
+
zk_migration_ready: bool = ...,
|
|
107
|
+
version: int | None = None,
|
|
108
|
+
**kwargs: Any,
|
|
109
|
+
) -> None: ...
|
|
110
|
+
@property
|
|
111
|
+
def version(self) -> int | None: ...
|
|
112
|
+
def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
|
|
113
|
+
name: str
|
|
114
|
+
type: str
|
|
115
|
+
API_KEY: int
|
|
116
|
+
API_VERSION: int
|
|
117
|
+
valid_versions: tuple[int, int]
|
|
118
|
+
min_version: int
|
|
119
|
+
max_version: int
|
|
120
|
+
@property
|
|
121
|
+
def header(self) -> Any: ...
|
|
122
|
+
@classmethod
|
|
123
|
+
def is_request(cls) -> bool: ...
|
|
124
|
+
def expect_response(self) -> bool: ...
|
|
125
|
+
def with_header(self, correlation_id: int = 0, client_id: str = "kafka-python") -> None: ...
|
|
126
|
+
@classmethod
|
|
127
|
+
def parse_header(cls, data: Any, version: Any = ...) -> Any: ...
|
|
128
|
+
def encode_header(self, flexible: Any = ...) -> Any: ...
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from enum import IntEnum
|
|
2
|
+
|
|
3
|
+
from ..api_message import ApiMessage
|
|
4
|
+
from kafka.util import EnumHelper
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CoordinatorType(EnumHelper, IntEnum):
|
|
8
|
+
GROUP = 0
|
|
9
|
+
TRANSACTION = 1
|
|
10
|
+
SHARE = 2
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FindCoordinatorRequest(ApiMessage): pass
|
|
14
|
+
class FindCoordinatorResponse(ApiMessage): pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
'CoordinatorType', 'FindCoordinatorRequest', 'FindCoordinatorResponse',
|
|
19
|
+
]
|