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.
Files changed (373) hide show
  1. kafka/__init__.py +34 -0
  2. kafka/__main__.py +5 -0
  3. kafka/admin/__init__.py +29 -0
  4. kafka/admin/__main__.py +5 -0
  5. kafka/admin/_acls.py +355 -0
  6. kafka/admin/_cluster.py +359 -0
  7. kafka/admin/_configs.py +479 -0
  8. kafka/admin/_groups.py +754 -0
  9. kafka/admin/_partitions.py +595 -0
  10. kafka/admin/_topics.py +281 -0
  11. kafka/admin/_transactions.py +450 -0
  12. kafka/admin/_users.py +194 -0
  13. kafka/admin/client.py +373 -0
  14. kafka/benchmarks/__init__.py +0 -0
  15. kafka/benchmarks/consumer_performance.py +138 -0
  16. kafka/benchmarks/load_example.py +109 -0
  17. kafka/benchmarks/producer_encode_path.py +201 -0
  18. kafka/benchmarks/producer_performance.py +161 -0
  19. kafka/benchmarks/profile_protocol.py +138 -0
  20. kafka/benchmarks/protocol_old_vs_new.py +447 -0
  21. kafka/benchmarks/record_batch_compose.py +77 -0
  22. kafka/benchmarks/record_batch_read.py +82 -0
  23. kafka/benchmarks/varint_speed.py +426 -0
  24. kafka/cli/__init__.py +36 -0
  25. kafka/cli/admin/__init__.py +117 -0
  26. kafka/cli/admin/acls/__init__.py +9 -0
  27. kafka/cli/admin/acls/common.py +76 -0
  28. kafka/cli/admin/acls/create.py +19 -0
  29. kafka/cli/admin/acls/delete.py +23 -0
  30. kafka/cli/admin/acls/describe.py +16 -0
  31. kafka/cli/admin/cluster/__init__.py +14 -0
  32. kafka/cli/admin/cluster/describe.py +11 -0
  33. kafka/cli/admin/cluster/describe_quorum.py +11 -0
  34. kafka/cli/admin/cluster/features.py +52 -0
  35. kafka/cli/admin/cluster/log_dirs.py +43 -0
  36. kafka/cli/admin/cluster/versions.py +33 -0
  37. kafka/cli/admin/configs/__init__.py +10 -0
  38. kafka/cli/admin/configs/alter.py +43 -0
  39. kafka/cli/admin/configs/common.py +17 -0
  40. kafka/cli/admin/configs/describe.py +30 -0
  41. kafka/cli/admin/configs/list.py +16 -0
  42. kafka/cli/admin/configs/reset.py +20 -0
  43. kafka/cli/admin/groups/__init__.py +16 -0
  44. kafka/cli/admin/groups/alter_offsets.py +30 -0
  45. kafka/cli/admin/groups/delete.py +11 -0
  46. kafka/cli/admin/groups/delete_offsets.py +29 -0
  47. kafka/cli/admin/groups/describe.py +11 -0
  48. kafka/cli/admin/groups/list.py +28 -0
  49. kafka/cli/admin/groups/list_offsets.py +29 -0
  50. kafka/cli/admin/groups/remove_members.py +40 -0
  51. kafka/cli/admin/groups/reset_offsets.py +139 -0
  52. kafka/cli/admin/partitions/__init__.py +21 -0
  53. kafka/cli/admin/partitions/alter_reassignments.py +37 -0
  54. kafka/cli/admin/partitions/create.py +27 -0
  55. kafka/cli/admin/partitions/delete_records.py +31 -0
  56. kafka/cli/admin/partitions/describe.py +36 -0
  57. kafka/cli/admin/partitions/elect_leaders.py +53 -0
  58. kafka/cli/admin/partitions/list_offsets.py +88 -0
  59. kafka/cli/admin/partitions/list_reassignments.py +35 -0
  60. kafka/cli/admin/topics/__init__.py +10 -0
  61. kafka/cli/admin/topics/create.py +13 -0
  62. kafka/cli/admin/topics/delete.py +19 -0
  63. kafka/cli/admin/topics/describe.py +18 -0
  64. kafka/cli/admin/topics/list.py +11 -0
  65. kafka/cli/admin/transactions/__init__.py +17 -0
  66. kafka/cli/admin/transactions/abort.py +38 -0
  67. kafka/cli/admin/transactions/describe.py +24 -0
  68. kafka/cli/admin/transactions/describe_producers.py +29 -0
  69. kafka/cli/admin/transactions/find_hanging.py +26 -0
  70. kafka/cli/admin/transactions/list.py +37 -0
  71. kafka/cli/admin/users/__init__.py +8 -0
  72. kafka/cli/admin/users/alter_user_scram_credentials.py +34 -0
  73. kafka/cli/admin/users/describe_user_scram_credentials.py +15 -0
  74. kafka/cli/common.py +95 -0
  75. kafka/cli/consumer/__init__.py +63 -0
  76. kafka/cli/producer/__init__.py +57 -0
  77. kafka/cluster.py +824 -0
  78. kafka/codec.py +325 -0
  79. kafka/consumer/__init__.py +5 -0
  80. kafka/consumer/__main__.py +5 -0
  81. kafka/consumer/fetcher.py +2012 -0
  82. kafka/consumer/group.py +1347 -0
  83. kafka/consumer/subscription_state.py +897 -0
  84. kafka/coordinator/__init__.py +0 -0
  85. kafka/coordinator/assignors/__init__.py +0 -0
  86. kafka/coordinator/assignors/abstract.py +90 -0
  87. kafka/coordinator/assignors/cooperative_sticky.py +167 -0
  88. kafka/coordinator/assignors/range.py +81 -0
  89. kafka/coordinator/assignors/roundrobin.py +101 -0
  90. kafka/coordinator/assignors/sticky/StickyAssignorUserData.json +37 -0
  91. kafka/coordinator/assignors/sticky/__init__.py +0 -0
  92. kafka/coordinator/assignors/sticky/partition_movements.py +149 -0
  93. kafka/coordinator/assignors/sticky/sorted_set.py +63 -0
  94. kafka/coordinator/assignors/sticky/sticky_assignor.py +665 -0
  95. kafka/coordinator/assignors/sticky/user_data.py +8 -0
  96. kafka/coordinator/base.py +1215 -0
  97. kafka/coordinator/consumer.py +1224 -0
  98. kafka/coordinator/heartbeat.py +82 -0
  99. kafka/coordinator/subscription.py +34 -0
  100. kafka/errors.py +1004 -0
  101. kafka/future.py +166 -0
  102. kafka/metrics/__init__.py +13 -0
  103. kafka/metrics/compound_stat.py +33 -0
  104. kafka/metrics/dict_reporter.py +81 -0
  105. kafka/metrics/kafka_metric.py +36 -0
  106. kafka/metrics/measurable.py +27 -0
  107. kafka/metrics/measurable_stat.py +13 -0
  108. kafka/metrics/metric_config.py +33 -0
  109. kafka/metrics/metric_name.py +105 -0
  110. kafka/metrics/metrics.py +261 -0
  111. kafka/metrics/metrics_reporter.py +53 -0
  112. kafka/metrics/quota.py +41 -0
  113. kafka/metrics/stat.py +19 -0
  114. kafka/metrics/stats/__init__.py +15 -0
  115. kafka/metrics/stats/avg.py +24 -0
  116. kafka/metrics/stats/count.py +17 -0
  117. kafka/metrics/stats/histogram.py +99 -0
  118. kafka/metrics/stats/max_stat.py +17 -0
  119. kafka/metrics/stats/min_stat.py +19 -0
  120. kafka/metrics/stats/percentile.py +14 -0
  121. kafka/metrics/stats/percentiles.py +75 -0
  122. kafka/metrics/stats/rate.py +118 -0
  123. kafka/metrics/stats/sampled_stat.py +99 -0
  124. kafka/metrics/stats/sensor.py +136 -0
  125. kafka/metrics/stats/total.py +15 -0
  126. kafka/net/__init__.py +19 -0
  127. kafka/net/compat.py +165 -0
  128. kafka/net/connection.py +593 -0
  129. kafka/net/http_connect.py +144 -0
  130. kafka/net/inet.py +122 -0
  131. kafka/net/manager.py +451 -0
  132. kafka/net/metrics.py +149 -0
  133. kafka/net/sasl/__init__.py +32 -0
  134. kafka/net/sasl/abc.py +28 -0
  135. kafka/net/sasl/gssapi.py +95 -0
  136. kafka/net/sasl/msk.py +245 -0
  137. kafka/net/sasl/oauth.py +98 -0
  138. kafka/net/sasl/plain.py +42 -0
  139. kafka/net/sasl/scram.py +135 -0
  140. kafka/net/sasl/sspi.py +111 -0
  141. kafka/net/selector.py +644 -0
  142. kafka/net/socks5.py +262 -0
  143. kafka/net/transport.py +415 -0
  144. kafka/net/wakeup_notifier.py +72 -0
  145. kafka/partitioner/__init__.py +8 -0
  146. kafka/partitioner/abc.py +8 -0
  147. kafka/partitioner/default.py +89 -0
  148. kafka/partitioner/sticky.py +109 -0
  149. kafka/producer/__init__.py +5 -0
  150. kafka/producer/__main__.py +5 -0
  151. kafka/producer/future.py +101 -0
  152. kafka/producer/kafka.py +1123 -0
  153. kafka/producer/producer_batch.py +192 -0
  154. kafka/producer/record_accumulator.py +647 -0
  155. kafka/producer/sender.py +884 -0
  156. kafka/producer/transaction_manager.py +1326 -0
  157. kafka/protocol/__init__.py +0 -0
  158. kafka/protocol/admin/__init__.py +29 -0
  159. kafka/protocol/admin/acl.py +83 -0
  160. kafka/protocol/admin/acl.pyi +375 -0
  161. kafka/protocol/admin/client_quotas.py +14 -0
  162. kafka/protocol/admin/client_quotas.pyi +265 -0
  163. kafka/protocol/admin/cluster.py +31 -0
  164. kafka/protocol/admin/cluster.pyi +620 -0
  165. kafka/protocol/admin/configs.py +22 -0
  166. kafka/protocol/admin/configs.pyi +437 -0
  167. kafka/protocol/admin/groups.py +24 -0
  168. kafka/protocol/admin/groups.pyi +261 -0
  169. kafka/protocol/admin/topics.py +53 -0
  170. kafka/protocol/admin/topics.pyi +982 -0
  171. kafka/protocol/admin/transactions.py +18 -0
  172. kafka/protocol/admin/transactions.pyi +311 -0
  173. kafka/protocol/admin/users.py +14 -0
  174. kafka/protocol/admin/users.pyi +223 -0
  175. kafka/protocol/api_data.py +125 -0
  176. kafka/protocol/api_header.py +55 -0
  177. kafka/protocol/api_key.py +97 -0
  178. kafka/protocol/api_message.py +277 -0
  179. kafka/protocol/broker_version_data.py +246 -0
  180. kafka/protocol/consumer/__init__.py +13 -0
  181. kafka/protocol/consumer/fetch.py +16 -0
  182. kafka/protocol/consumer/fetch.pyi +298 -0
  183. kafka/protocol/consumer/group.py +38 -0
  184. kafka/protocol/consumer/group.pyi +824 -0
  185. kafka/protocol/consumer/metadata.py +30 -0
  186. kafka/protocol/consumer/metadata.pyi +89 -0
  187. kafka/protocol/consumer/offsets.py +75 -0
  188. kafka/protocol/consumer/offsets.pyi +288 -0
  189. kafka/protocol/data_container.py +166 -0
  190. kafka/protocol/frame.py +30 -0
  191. kafka/protocol/generate_stubs.py +468 -0
  192. kafka/protocol/metadata/__init__.py +10 -0
  193. kafka/protocol/metadata/api_versions.py +41 -0
  194. kafka/protocol/metadata/api_versions.pyi +128 -0
  195. kafka/protocol/metadata/find_coordinator.py +19 -0
  196. kafka/protocol/metadata/find_coordinator.pyi +105 -0
  197. kafka/protocol/metadata/metadata.py +34 -0
  198. kafka/protocol/metadata/metadata.pyi +160 -0
  199. kafka/protocol/old/__init__.py +0 -0
  200. kafka/protocol/old/abstract.py +17 -0
  201. kafka/protocol/old/add_offsets_to_txn.py +54 -0
  202. kafka/protocol/old/add_partitions_to_txn.py +71 -0
  203. kafka/protocol/old/admin.py +1086 -0
  204. kafka/protocol/old/api.py +205 -0
  205. kafka/protocol/old/api_versions.py +133 -0
  206. kafka/protocol/old/commit.py +355 -0
  207. kafka/protocol/old/consumer_protocol.py +36 -0
  208. kafka/protocol/old/end_txn.py +53 -0
  209. kafka/protocol/old/fetch.py +408 -0
  210. kafka/protocol/old/find_coordinator.py +72 -0
  211. kafka/protocol/old/group.py +451 -0
  212. kafka/protocol/old/init_producer_id.py +42 -0
  213. kafka/protocol/old/list_offsets.py +186 -0
  214. kafka/protocol/old/metadata.py +290 -0
  215. kafka/protocol/old/offset_for_leader_epoch.py +133 -0
  216. kafka/protocol/old/produce.py +247 -0
  217. kafka/protocol/old/sasl_authenticate.py +38 -0
  218. kafka/protocol/old/sasl_handshake.py +39 -0
  219. kafka/protocol/old/struct.py +87 -0
  220. kafka/protocol/old/txn_offset_commit.py +73 -0
  221. kafka/protocol/old/types.py +440 -0
  222. kafka/protocol/parser.py +191 -0
  223. kafka/protocol/producer/__init__.py +7 -0
  224. kafka/protocol/producer/produce.py +17 -0
  225. kafka/protocol/producer/produce.pyi +197 -0
  226. kafka/protocol/producer/transaction.py +30 -0
  227. kafka/protocol/producer/transaction.pyi +663 -0
  228. kafka/protocol/sasl.py +52 -0
  229. kafka/protocol/sasl.pyi +126 -0
  230. kafka/protocol/schemas/__init__.py +7 -0
  231. kafka/protocol/schemas/fields/__init__.py +7 -0
  232. kafka/protocol/schemas/fields/array.py +127 -0
  233. kafka/protocol/schemas/fields/base.py +156 -0
  234. kafka/protocol/schemas/fields/codecs/__init__.py +12 -0
  235. kafka/protocol/schemas/fields/codecs/encode_buffer.py +82 -0
  236. kafka/protocol/schemas/fields/codecs/tagged_fields.py +109 -0
  237. kafka/protocol/schemas/fields/codecs/types.py +505 -0
  238. kafka/protocol/schemas/fields/codegen.py +40 -0
  239. kafka/protocol/schemas/fields/simple.py +127 -0
  240. kafka/protocol/schemas/fields/struct.py +357 -0
  241. kafka/protocol/schemas/fields/struct_array.py +142 -0
  242. kafka/protocol/schemas/load_json.py +42 -0
  243. kafka/protocol/schemas/resources/AddOffsetsToTxnRequest.json +40 -0
  244. kafka/protocol/schemas/resources/AddOffsetsToTxnResponse.json +35 -0
  245. kafka/protocol/schemas/resources/AddPartitionsToTxnRequest.json +65 -0
  246. kafka/protocol/schemas/resources/AddPartitionsToTxnResponse.json +60 -0
  247. kafka/protocol/schemas/resources/AlterClientQuotasRequest.json +47 -0
  248. kafka/protocol/schemas/resources/AlterClientQuotasResponse.json +41 -0
  249. kafka/protocol/schemas/resources/AlterConfigsRequest.json +43 -0
  250. kafka/protocol/schemas/resources/AlterConfigsResponse.json +39 -0
  251. kafka/protocol/schemas/resources/AlterPartitionReassignmentsRequest.json +42 -0
  252. kafka/protocol/schemas/resources/AlterPartitionReassignmentsResponse.json +47 -0
  253. kafka/protocol/schemas/resources/AlterReplicaLogDirsRequest.json +41 -0
  254. kafka/protocol/schemas/resources/AlterReplicaLogDirsResponse.json +41 -0
  255. kafka/protocol/schemas/resources/AlterUserScramCredentialsRequest.json +45 -0
  256. kafka/protocol/schemas/resources/AlterUserScramCredentialsResponse.json +35 -0
  257. kafka/protocol/schemas/resources/ApiVersionsRequest.json +34 -0
  258. kafka/protocol/schemas/resources/ApiVersionsResponse.json +79 -0
  259. kafka/protocol/schemas/resources/ConsumerProtocolAssignment.json +42 -0
  260. kafka/protocol/schemas/resources/ConsumerProtocolSubscription.json +49 -0
  261. kafka/protocol/schemas/resources/CreateAclsRequest.json +46 -0
  262. kafka/protocol/schemas/resources/CreateAclsResponse.json +37 -0
  263. kafka/protocol/schemas/resources/CreatePartitionsRequest.json +47 -0
  264. kafka/protocol/schemas/resources/CreatePartitionsResponse.json +41 -0
  265. kafka/protocol/schemas/resources/CreateTopicsRequest.json +65 -0
  266. kafka/protocol/schemas/resources/CreateTopicsResponse.json +72 -0
  267. kafka/protocol/schemas/resources/DeleteAclsRequest.json +46 -0
  268. kafka/protocol/schemas/resources/DeleteAclsResponse.json +59 -0
  269. kafka/protocol/schemas/resources/DeleteGroupsRequest.json +30 -0
  270. kafka/protocol/schemas/resources/DeleteGroupsResponse.json +36 -0
  271. kafka/protocol/schemas/resources/DeleteRecordsRequest.json +42 -0
  272. kafka/protocol/schemas/resources/DeleteRecordsResponse.json +43 -0
  273. kafka/protocol/schemas/resources/DeleteTopicsRequest.json +43 -0
  274. kafka/protocol/schemas/resources/DeleteTopicsResponse.json +52 -0
  275. kafka/protocol/schemas/resources/DescribeAclsRequest.json +43 -0
  276. kafka/protocol/schemas/resources/DescribeAclsResponse.json +55 -0
  277. kafka/protocol/schemas/resources/DescribeClientQuotasRequest.json +37 -0
  278. kafka/protocol/schemas/resources/DescribeClientQuotasResponse.json +47 -0
  279. kafka/protocol/schemas/resources/DescribeClusterRequest.json +35 -0
  280. kafka/protocol/schemas/resources/DescribeClusterResponse.json +56 -0
  281. kafka/protocol/schemas/resources/DescribeConfigsRequest.json +42 -0
  282. kafka/protocol/schemas/resources/DescribeConfigsResponse.json +69 -0
  283. kafka/protocol/schemas/resources/DescribeGroupsRequest.json +38 -0
  284. kafka/protocol/schemas/resources/DescribeGroupsResponse.json +74 -0
  285. kafka/protocol/schemas/resources/DescribeLogDirsRequest.json +38 -0
  286. kafka/protocol/schemas/resources/DescribeLogDirsResponse.json +65 -0
  287. kafka/protocol/schemas/resources/DescribeProducersRequest.json +32 -0
  288. kafka/protocol/schemas/resources/DescribeProducersResponse.json +55 -0
  289. kafka/protocol/schemas/resources/DescribeQuorumRequest.json +39 -0
  290. kafka/protocol/schemas/resources/DescribeQuorumResponse.json +82 -0
  291. kafka/protocol/schemas/resources/DescribeTopicPartitionsRequest.json +40 -0
  292. kafka/protocol/schemas/resources/DescribeTopicPartitionsResponse.json +66 -0
  293. kafka/protocol/schemas/resources/DescribeTransactionsRequest.json +27 -0
  294. kafka/protocol/schemas/resources/DescribeTransactionsResponse.json +52 -0
  295. kafka/protocol/schemas/resources/DescribeUserScramCredentialsRequest.json +30 -0
  296. kafka/protocol/schemas/resources/DescribeUserScramCredentialsResponse.json +45 -0
  297. kafka/protocol/schemas/resources/ElectLeadersRequest.json +41 -0
  298. kafka/protocol/schemas/resources/ElectLeadersResponse.json +45 -0
  299. kafka/protocol/schemas/resources/EndTxnRequest.json +43 -0
  300. kafka/protocol/schemas/resources/EndTxnResponse.json +41 -0
  301. kafka/protocol/schemas/resources/FetchRequest.json +125 -0
  302. kafka/protocol/schemas/resources/FetchResponse.json +124 -0
  303. kafka/protocol/schemas/resources/FindCoordinatorRequest.json +43 -0
  304. kafka/protocol/schemas/resources/FindCoordinatorResponse.json +58 -0
  305. kafka/protocol/schemas/resources/HeartbeatRequest.json +39 -0
  306. kafka/protocol/schemas/resources/HeartbeatResponse.json +35 -0
  307. kafka/protocol/schemas/resources/IncrementalAlterConfigsRequest.json +44 -0
  308. kafka/protocol/schemas/resources/IncrementalAlterConfigsResponse.json +38 -0
  309. kafka/protocol/schemas/resources/InitProducerIdRequest.json +50 -0
  310. kafka/protocol/schemas/resources/InitProducerIdResponse.json +47 -0
  311. kafka/protocol/schemas/resources/JoinGroupRequest.json +63 -0
  312. kafka/protocol/schemas/resources/JoinGroupResponse.json +69 -0
  313. kafka/protocol/schemas/resources/LeaveGroupRequest.json +47 -0
  314. kafka/protocol/schemas/resources/LeaveGroupResponse.json +47 -0
  315. kafka/protocol/schemas/resources/ListConfigResourcesRequest.json +31 -0
  316. kafka/protocol/schemas/resources/ListConfigResourcesResponse.json +37 -0
  317. kafka/protocol/schemas/resources/ListGroupsRequest.json +36 -0
  318. kafka/protocol/schemas/resources/ListGroupsResponse.json +49 -0
  319. kafka/protocol/schemas/resources/ListOffsetsRequest.json +72 -0
  320. kafka/protocol/schemas/resources/ListOffsetsResponse.json +71 -0
  321. kafka/protocol/schemas/resources/ListPartitionReassignmentsRequest.json +34 -0
  322. kafka/protocol/schemas/resources/ListPartitionReassignmentsResponse.json +46 -0
  323. kafka/protocol/schemas/resources/ListTransactionsRequest.json +40 -0
  324. kafka/protocol/schemas/resources/ListTransactionsResponse.json +42 -0
  325. kafka/protocol/schemas/resources/MetadataRequest.json +56 -0
  326. kafka/protocol/schemas/resources/MetadataResponse.json +101 -0
  327. kafka/protocol/schemas/resources/OffsetCommitRequest.json +76 -0
  328. kafka/protocol/schemas/resources/OffsetCommitResponse.json +71 -0
  329. kafka/protocol/schemas/resources/OffsetDeleteRequest.json +39 -0
  330. kafka/protocol/schemas/resources/OffsetDeleteResponse.json +42 -0
  331. kafka/protocol/schemas/resources/OffsetFetchRequest.json +76 -0
  332. kafka/protocol/schemas/resources/OffsetFetchResponse.json +107 -0
  333. kafka/protocol/schemas/resources/OffsetForLeaderEpochRequest.json +52 -0
  334. kafka/protocol/schemas/resources/OffsetForLeaderEpochResponse.json +51 -0
  335. kafka/protocol/schemas/resources/ProduceRequest.json +73 -0
  336. kafka/protocol/schemas/resources/ProduceResponse.json +96 -0
  337. kafka/protocol/schemas/resources/RequestHeader.json +44 -0
  338. kafka/protocol/schemas/resources/ResponseHeader.json +26 -0
  339. kafka/protocol/schemas/resources/SaslAuthenticateRequest.json +29 -0
  340. kafka/protocol/schemas/resources/SaslAuthenticateResponse.json +34 -0
  341. kafka/protocol/schemas/resources/SaslHandshakeRequest.json +31 -0
  342. kafka/protocol/schemas/resources/SaslHandshakeResponse.json +32 -0
  343. kafka/protocol/schemas/resources/SyncGroupRequest.json +56 -0
  344. kafka/protocol/schemas/resources/SyncGroupResponse.json +46 -0
  345. kafka/protocol/schemas/resources/TxnOffsetCommitRequest.json +68 -0
  346. kafka/protocol/schemas/resources/TxnOffsetCommitResponse.json +47 -0
  347. kafka/protocol/schemas/resources/UpdateFeaturesRequest.json +43 -0
  348. kafka/protocol/schemas/resources/UpdateFeaturesResponse.json +39 -0
  349. kafka/protocol/schemas/resources/WriteTxnMarkersRequest.json +49 -0
  350. kafka/protocol/schemas/resources/WriteTxnMarkersResponse.json +45 -0
  351. kafka/protocol/schemas/resources/__init__.py +0 -0
  352. kafka/record/__init__.py +3 -0
  353. kafka/record/_crc32c.py +161 -0
  354. kafka/record/abc.py +144 -0
  355. kafka/record/default_records.py +782 -0
  356. kafka/record/legacy_records.py +587 -0
  357. kafka/record/memory_records.py +255 -0
  358. kafka/record/util.py +135 -0
  359. kafka/serializer/__init__.py +4 -0
  360. kafka/serializer/abstract.py +20 -0
  361. kafka/serializer/default.py +16 -0
  362. kafka/serializer/json.py +17 -0
  363. kafka/serializer/wrapper.py +21 -0
  364. kafka/structs.py +69 -0
  365. kafka/util.py +159 -0
  366. kafka/vendor/__init__.py +0 -0
  367. kafka/version.py +1 -0
  368. kafka_python-3.0.0.dist-info/METADATA +319 -0
  369. kafka_python-3.0.0.dist-info/RECORD +373 -0
  370. kafka_python-3.0.0.dist-info/WHEEL +5 -0
  371. kafka_python-3.0.0.dist-info/entry_points.txt +2 -0
  372. kafka_python-3.0.0.dist-info/licenses/LICENSE +202 -0
  373. kafka_python-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,126 @@
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.api_data import ApiData
7
+
8
+ __all__ = ['SaslHandshakeRequest', 'SaslHandshakeResponse', 'SaslAuthenticateRequest', 'SaslAuthenticateResponse', 'SaslBytesRequest', 'SaslBytesResponse']
9
+
10
+ class SaslHandshakeRequest(ApiMessage):
11
+ mechanism: str
12
+ def __init__(
13
+ self,
14
+ *args: Any,
15
+ mechanism: str = ...,
16
+ version: int | None = None,
17
+ **kwargs: Any,
18
+ ) -> None: ...
19
+ @property
20
+ def version(self) -> int | None: ...
21
+ def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
22
+ name: str
23
+ type: str
24
+ API_KEY: int
25
+ API_VERSION: int
26
+ valid_versions: tuple[int, int]
27
+ min_version: int
28
+ max_version: int
29
+ @property
30
+ def header(self) -> Any: ...
31
+ @classmethod
32
+ def is_request(cls) -> bool: ...
33
+ def expect_response(self) -> bool: ...
34
+ def with_header(self, correlation_id: int = 0, client_id: str = "kafka-python") -> None: ...
35
+
36
+ class SaslHandshakeResponse(ApiMessage):
37
+ error_code: int
38
+ mechanisms: list[str]
39
+ def __init__(
40
+ self,
41
+ *args: Any,
42
+ error_code: int = ...,
43
+ mechanisms: list[str] = ...,
44
+ version: int | None = None,
45
+ **kwargs: Any,
46
+ ) -> None: ...
47
+ @property
48
+ def version(self) -> int | None: ...
49
+ def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
50
+ name: str
51
+ type: str
52
+ API_KEY: int
53
+ API_VERSION: int
54
+ valid_versions: tuple[int, int]
55
+ min_version: int
56
+ max_version: int
57
+ @property
58
+ def header(self) -> Any: ...
59
+ @classmethod
60
+ def is_request(cls) -> bool: ...
61
+ def expect_response(self) -> bool: ...
62
+ def with_header(self, correlation_id: int = 0, client_id: str = "kafka-python") -> None: ...
63
+
64
+ class SaslAuthenticateRequest(ApiMessage):
65
+ auth_bytes: bytes | ApiData
66
+ def __init__(
67
+ self,
68
+ *args: Any,
69
+ auth_bytes: bytes | ApiData = ...,
70
+ version: int | None = None,
71
+ **kwargs: Any,
72
+ ) -> None: ...
73
+ @property
74
+ def version(self) -> int | None: ...
75
+ def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
76
+ name: str
77
+ type: str
78
+ API_KEY: int
79
+ API_VERSION: int
80
+ valid_versions: tuple[int, int]
81
+ min_version: int
82
+ max_version: int
83
+ @property
84
+ def header(self) -> Any: ...
85
+ @classmethod
86
+ def is_request(cls) -> bool: ...
87
+ def expect_response(self) -> bool: ...
88
+ def with_header(self, correlation_id: int = 0, client_id: str = "kafka-python") -> None: ...
89
+
90
+ class SaslAuthenticateResponse(ApiMessage):
91
+ error_code: int
92
+ error_message: str | None
93
+ auth_bytes: bytes | ApiData
94
+ session_lifetime_ms: int
95
+ def __init__(
96
+ self,
97
+ *args: Any,
98
+ error_code: int = ...,
99
+ error_message: str | None = ...,
100
+ auth_bytes: bytes | ApiData = ...,
101
+ session_lifetime_ms: int = ...,
102
+ version: int | None = None,
103
+ **kwargs: Any,
104
+ ) -> None: ...
105
+ @property
106
+ def version(self) -> int | None: ...
107
+ def to_dict(self, meta: bool = False, json: bool = True) -> dict: ...
108
+ name: str
109
+ type: str
110
+ API_KEY: int
111
+ API_VERSION: int
112
+ valid_versions: tuple[int, int]
113
+ min_version: int
114
+ max_version: int
115
+ @property
116
+ def header(self) -> Any: ...
117
+ @classmethod
118
+ def is_request(cls) -> bool: ...
119
+ def expect_response(self) -> bool: ...
120
+ def with_header(self, correlation_id: int = 0, client_id: str = "kafka-python") -> None: ...
121
+
122
+ class SaslBytesRequest:
123
+ API_VERSION: int
124
+
125
+ class SaslBytesResponse:
126
+ ...
@@ -0,0 +1,7 @@
1
+ from .fields import *
2
+ from .fields import __all__ as fields_all
3
+
4
+ from .load_json import load_json
5
+
6
+
7
+ __all__ = fields_all + ['load_json']
@@ -0,0 +1,7 @@
1
+ from .base import BaseField
2
+ from .simple import SimpleField
3
+ from .struct import StructField
4
+ from .array import ArrayField
5
+ from .struct_array import StructArrayField
6
+
7
+ __all__ = ["BaseField", "SimpleField", "StructField", "ArrayField", "StructArrayField"]
@@ -0,0 +1,127 @@
1
+ from .base import BaseField
2
+ from .simple import SimpleField
3
+ from .codecs import (
4
+ UnsignedVarInt32, Int32,
5
+ )
6
+
7
+
8
+ class ArrayField(BaseField):
9
+ @classmethod
10
+ def parse_inner_type(cls, json):
11
+ if 'fields' in json:
12
+ return
13
+ type_str = cls.parse_array_type(json)
14
+ if type_str is not None:
15
+ inner_json = {**json, 'type': type_str}
16
+ return SimpleField.parse_json(inner_json)
17
+
18
+ @classmethod
19
+ def parse_array_type(cls, json):
20
+ if json['type'].startswith('[]'):
21
+ type_str = json['type'][2:]
22
+ assert not type_str.startswith('[]'), 'Unexpected double-array type: %s' % json['type']
23
+ return type_str
24
+
25
+ @classmethod
26
+ def parse_json(cls, json):
27
+ inner_type = cls.parse_inner_type(json)
28
+ if inner_type is not None:
29
+ return cls(json, array_of=inner_type)
30
+
31
+ def __init__(self, json, array_of=None):
32
+ if array_of is None:
33
+ array_of = self.parse_inner_type(json)
34
+ assert array_of is not None, 'json does not contain a (simple) Array!'
35
+ super().__init__(json)
36
+ self.array_of = array_of # SimpleField
37
+
38
+ def is_array(self):
39
+ return True
40
+
41
+ def _calculate_default(self, default):
42
+ if default == 'null':
43
+ return None
44
+ elif not default:
45
+ return []
46
+ else:
47
+ raise ValueError('Invalid default for field %s. The only valid default is empty or null.' % self._name)
48
+
49
+ def encode(self, items, version=None, compact=False, tagged=False):
50
+ if compact:
51
+ size = UnsignedVarInt32.encode(len(items) + 1 if items is not None else 0)
52
+ else:
53
+ size = Int32.encode(len(items) if items is not None else -1)
54
+ if items is None:
55
+ return size
56
+ fields = [self.array_of.encode(item, version=version, compact=compact, tagged=tagged)
57
+ for item in items]
58
+ return b''.join([size] + fields)
59
+
60
+ def encode_into(self, items, out, version=None, compact=False, tagged=False):
61
+ if compact:
62
+ UnsignedVarInt32.encode_into(out, len(items) + 1 if items is not None else 0)
63
+ else:
64
+ Int32.encode_into(out, len(items) if items is not None else -1)
65
+ if items is None:
66
+ return
67
+ encode_into = self.array_of.encode_into
68
+ for item in items:
69
+ encode_into(item, out, version=version, compact=compact, tagged=tagged)
70
+
71
+ def emit_encode_into(self, ctx, val_expr, indent, version=None, compact=False, tagged=False):
72
+ if compact:
73
+ an = ctx.next_var('an')
74
+ ctx.emit(indent, '%s = len(%s) + 1 if %s is not None else 0' % (an, val_expr, val_expr))
75
+ UnsignedVarInt32.emit_encode_into(ctx, an, indent)
76
+ ctx.emit(indent, 'if %s is not None:' % val_expr)
77
+ else:
78
+ ctx.emit(indent, 'if %s is None:' % val_expr)
79
+ ctx.emit(indent, " pack_into('>i', buf, pos, -1)")
80
+ ctx.emit(indent, ' pos += 4')
81
+ ctx.emit(indent, 'else:')
82
+ ctx.emit(indent, " pack_into('>i', buf, pos, len(%s))" % val_expr)
83
+ ctx.emit(indent, ' pos += 4')
84
+ guard = indent + ' '
85
+ item_var = ctx.next_var('ai')
86
+ ctx.emit(guard, 'for %s in %s:' % (item_var, val_expr))
87
+ self.array_of.emit_encode_into(ctx, item_var, guard + ' ',
88
+ version=version, compact=compact, tagged=tagged)
89
+
90
+ def emit_decode_from(self, ctx, var_name, indent, version=None, compact=False, tagged=False):
91
+ n = ctx.next_var('n')
92
+ if compact:
93
+ UnsignedVarInt32.emit_decode_from(ctx, n, indent)
94
+ ctx.emit(indent, '%s -= 1' % n)
95
+ else:
96
+ ctx.emit(indent, '%s = unpack_from(">i", data, pos)[0]' % n)
97
+ ctx.emit(indent, 'pos += 4')
98
+ ctx.emit(indent, 'if %s == -1:' % n)
99
+ ctx.emit(indent, ' %s = None' % var_name)
100
+ ctx.emit(indent, 'else:')
101
+ inner_indent = indent + ' '
102
+ ctx.emit(inner_indent, '%s = []' % var_name)
103
+ idx = ctx.next_var('idx')
104
+ item = ctx.next_var('item')
105
+ ctx.emit(inner_indent, 'for %s in range(%s):' % (idx, n))
106
+ self.array_of.emit_decode_from(ctx, item, inner_indent + ' ',
107
+ version=version, compact=compact, tagged=tagged)
108
+ ctx.emit(inner_indent, ' %s.append(%s)' % (var_name, item))
109
+
110
+ def decode(self, data, version=None, compact=False, tagged=False):
111
+ if compact:
112
+ size = UnsignedVarInt32.decode(data)
113
+ size -= 1
114
+ else:
115
+ size = Int32.decode(data)
116
+ if size == -1:
117
+ return None
118
+ return [self.array_of.decode(data, version=version, compact=compact, tagged=tagged)
119
+ for _ in range(size)]
120
+
121
+ def to_json(self, val):
122
+ if val is None:
123
+ return None
124
+ return [self.array_of.to_json(i) for i in val]
125
+
126
+ def __repr__(self):
127
+ return 'ArrayField(%s)' % self._json
@@ -0,0 +1,156 @@
1
+ import re
2
+
3
+
4
+ class BaseField:
5
+ FIELD_TYPES = []
6
+
7
+ def __init_subclass__(cls, **kw):
8
+ cls.FIELD_TYPES.append(cls)
9
+
10
+ @classmethod
11
+ def parse_json_fields(cls, json):
12
+ return tuple(map(BaseField.parse_json, json.get('fields', []))) or None # Note: DFS Field construction
13
+
14
+ @classmethod
15
+ def parse_json(cls, json):
16
+ if 'type' not in json:
17
+ raise ValueError('No type found in json')
18
+ type_str = json['type']
19
+ for field_type in cls.FIELD_TYPES:
20
+ maybe_type = field_type.parse_json(json)
21
+ if maybe_type is not None:
22
+ return maybe_type
23
+ else:
24
+ raise ValueError('Unable to parse field type: %s' % type_str)
25
+
26
+ @classmethod
27
+ def underscore_name(cls, name):
28
+ return re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
29
+
30
+ @classmethod
31
+ def parse_versions(cls, versions):
32
+ if versions is None or versions.strip() == '':
33
+ return None
34
+ elif versions.strip() == 'none':
35
+ return (-1, -1)
36
+ elif versions[-1] == '+':
37
+ return (int(versions[:-1]), 32767)
38
+ elif versions.find('-') == -1:
39
+ return (int(versions), int(versions))
40
+ else:
41
+ return tuple(map(int, versions.split('-')))
42
+
43
+ def __init__(self, json):
44
+ self._json = json
45
+ self._name = json['name']
46
+ self.name = self.underscore_name(self._name)
47
+ # versions tells when to include the field in encode / decode
48
+ # 'validVersions' is included for top-level request/response structs
49
+ # otherwise this should always be 'versions'
50
+ for versions_key in ('versions', 'validVersions'):
51
+ if versions_key in json:
52
+ self._versions = self.parse_versions(json[versions_key])
53
+ if self._versions is not None:
54
+ break
55
+ else:
56
+ raise ValueError('Unable to find versions in json!')
57
+ # If the field is tagged, it should have 'tag' and 'taggedVersions'
58
+ self._tag = json.get('tag')
59
+ self._tagged_versions = self.parse_versions(json.get('taggedVersions'))
60
+ # flexibleVersions is used to override 'compact' string/bytes encoding for a specific field
61
+ # currently only used in RequestHeader client_id
62
+ self._flexible_versions = self.parse_versions(json.get('flexibleVersions'))
63
+ self._nullable_versions = self.parse_versions(json.get('nullableVersions'))
64
+ self._type_str = json['type']
65
+ if 'fields' in json:
66
+ self._fields = self.parse_json_fields(json)
67
+ else:
68
+ self._fields = None
69
+ self._ignorable = json.get('ignorable')
70
+ self._entity_type = json.get('entityType')
71
+ self._about = json.get('about', '')
72
+ self._zero_copy = json.get('zeroCopy') # ?
73
+
74
+ @property
75
+ def type_str(self):
76
+ return self._type_str
77
+
78
+ @property
79
+ def tag(self):
80
+ return self._tag
81
+
82
+ # Override in subclasses
83
+ def is_array(self):
84
+ return False
85
+
86
+ def is_struct(self):
87
+ return False
88
+
89
+ def is_struct_array(self):
90
+ return False
91
+
92
+ def is_batchable(self):
93
+ return False
94
+
95
+ def has_data_class(self):
96
+ return False
97
+
98
+ def __call__(self, *args, **kwargs):
99
+ raise NotImplementedError
100
+
101
+ @property
102
+ def fields(self):
103
+ return self._fields
104
+
105
+ @property
106
+ def min_version(self):
107
+ return self._versions[0]
108
+
109
+ @property
110
+ def max_version(self):
111
+ return self._versions[1]
112
+
113
+ def for_version_q(self, version):
114
+ return self._versions[0] <= version <= self._versions[1]
115
+
116
+ def nullable_for_version_q(self, version):
117
+ if self._nullable_versions is None:
118
+ return False
119
+ return self._nullable_versions[0] <= version <= self._nullable_versions[1]
120
+
121
+ def tagged_field_q(self, version):
122
+ if self._tag is None or self._tagged_versions is None:
123
+ return False
124
+ elif not self._tagged_versions[0] <= version <= self._tagged_versions[1]:
125
+ return False
126
+ else:
127
+ return True
128
+
129
+ def _calculate_default(self, default):
130
+ return default
131
+
132
+ @property
133
+ def default(self):
134
+ try:
135
+ return self._default # pylint: disable=E1101
136
+ except AttributeError:
137
+ self._default = self._calculate_default(self._json.get('default', ''))
138
+ return self._default
139
+
140
+ def encode(self, value, version=None, compact=False, tagged=False):
141
+ raise NotImplementedError
142
+
143
+ def decode(self, data, version=None, compact=False, tagged=False):
144
+ raise NotImplementedError
145
+
146
+ def __repr__(self):
147
+ return 'BaseField(%s)' % self._json
148
+
149
+ def __eq__(self, other):
150
+ if self.__class__ != other.__class__:
151
+ return False
152
+ if self.name != other.name:
153
+ return False
154
+ if self.tag != other.tag:
155
+ return False
156
+ return True
@@ -0,0 +1,12 @@
1
+ from .encode_buffer import EncodeBuffer, EncodeBufferPool
2
+ from .tagged_fields import TaggedFields
3
+ from .types import (
4
+ BitField, Boolean, UUID, Bytes, String,
5
+ Int8, Int16, Int32, Int64, UnsignedInt16, UnsignedVarInt32, Float64,
6
+ )
7
+
8
+ __all__ = [
9
+ 'BitField', 'Boolean', 'UUID', 'Bytes', 'String',
10
+ 'Int8', 'Int16', 'Int32', 'Int64', 'UnsignedInt16', 'UnsignedVarInt32', 'Float64',
11
+ 'TaggedFields', 'EncodeBuffer',
12
+ ]
@@ -0,0 +1,82 @@
1
+ import threading
2
+
3
+
4
+ class EncodeBuffer:
5
+ """Growable buffer for encode_into operations."""
6
+ __slots__ = ('buf', 'pos')
7
+
8
+ def __init__(self, size=65536):
9
+ self.buf = bytearray(size)
10
+ self.pos = 0
11
+
12
+ def reset(self):
13
+ """Reset position to 0 for reuse. The buffer retains its current size."""
14
+ self.pos = 0
15
+
16
+ def ensure(self, needed):
17
+ if self.pos + needed > len(self.buf):
18
+ new_size = max(len(self.buf) * 2, self.pos + needed)
19
+ new_buf = bytearray(new_size)
20
+ new_buf[:self.pos] = self.buf[:self.pos]
21
+ self.buf = new_buf
22
+
23
+ def result(self):
24
+ # Return a bytearray slice (one copy) rather than bytes(self.buf[:pos])
25
+ # (two copies - the slice creates a bytearray, then bytes() copies
26
+ # again). Downstream consumers (protocol codec slice assignment,
27
+ # socket.send) accept bytearray transparently.
28
+ return self.buf[:self.pos]
29
+
30
+
31
+ class EncodeBufferPool:
32
+ """Thread-local pool of reusable EncodeBuffer objects.
33
+
34
+ Each thread gets its own buffer that grows to match the largest message
35
+ encoded on that thread and stays that size - avoiding repeated allocation
36
+ of large bytearrays.
37
+
38
+ Usage:
39
+ with EncodeBufferPool.acquire() as out:
40
+ fast_encode(item, out)
41
+ return out.result()
42
+ """
43
+ _local = threading.local()
44
+
45
+ @classmethod
46
+ def acquire(cls):
47
+ """Return a context manager that provides a reset EncodeBuffer."""
48
+ return _PooledBuffer(cls)
49
+
50
+ @classmethod
51
+ def _get(cls):
52
+ buf = getattr(cls._local, 'buf', None)
53
+ if buf is None:
54
+ buf = EncodeBuffer()
55
+ cls._local.buf = buf
56
+ buf.reset()
57
+ return buf
58
+
59
+ @classmethod
60
+ def _release(cls, buf):
61
+ # Nothing to do - the buffer stays on the thread-local.
62
+ # Future: could cap max size to prevent memory leaks from
63
+ # one-off large messages.
64
+ pass
65
+
66
+
67
+ class _PooledBuffer:
68
+ """Context manager for EncodeBufferPool.acquire()."""
69
+ __slots__ = ('_pool', '_buf')
70
+
71
+ def __init__(self, pool):
72
+ self._pool = pool
73
+ self._buf = None
74
+
75
+ def __enter__(self):
76
+ self._buf = self._pool._get()
77
+ return self._buf
78
+
79
+ def __exit__(self, *exc):
80
+ self._pool._release(self._buf)
81
+ self._buf = None
82
+ return False
@@ -0,0 +1,109 @@
1
+ from .types import UnsignedVarInt32
2
+
3
+
4
+ def _uvarint_size(value):
5
+ """Return the number of bytes needed to encode value as an unsigned varint."""
6
+ if value < 0x80:
7
+ return 1
8
+ elif value < 0x4000:
9
+ return 2
10
+ elif value < 0x200000:
11
+ return 3
12
+ elif value < 0x10000000:
13
+ return 4
14
+ else:
15
+ return 5
16
+
17
+
18
+ class TaggedFields:
19
+ def __init__(self, fields):
20
+ self._fields = list(fields) # listify to clean filter() inputs
21
+ self._tags = {field.tag: field for field in self._fields}
22
+ self._names = {field.name: field for field in self._fields}
23
+
24
+ def encode(self, item, version=None):
25
+ if isinstance(item, dict):
26
+ tags = [(self._names[name].tag, val)
27
+ for name, val in item.items()
28
+ if name in self._names
29
+ and val != self._names[name].default]
30
+ else:
31
+ tags = [(self._names[name].tag, getattr(item, name))
32
+ for name in self._names
33
+ if hasattr(item, name)
34
+ and getattr(item, name) != self._names[name].default]
35
+ ret = [UnsignedVarInt32.encode(len(tags))]
36
+ for tag, val in tags:
37
+ ret.append(UnsignedVarInt32.encode(tag))
38
+ # struct tags have an empty nested tagged fields (tagged=None)
39
+ encoded_val = self._tags[tag].encode(val, version=version, compact=True, tagged=None)
40
+ ret.append(UnsignedVarInt32.encode(len(encoded_val)))
41
+ ret.append(encoded_val)
42
+ return b''.join(ret)
43
+
44
+ def encode_into(self, item, out, version=None):
45
+ if isinstance(item, dict):
46
+ tags = [(self._names[name].tag, name)
47
+ for name, val in item.items()
48
+ if name in self._names
49
+ and val != self._names[name].default]
50
+ else:
51
+ tags = [(self._names[name].tag, name)
52
+ for name in self._names
53
+ if hasattr(item, name)
54
+ and getattr(item, name) != self._names[name].default]
55
+ UnsignedVarInt32.encode_into(out, len(tags))
56
+ for tag, name in tags:
57
+ field = self._tags[tag]
58
+ val = item.get(name) if isinstance(item, dict) else getattr(item, name)
59
+ UnsignedVarInt32.encode_into(out, tag)
60
+ # Encode value into buffer after reserving space for size prefix.
61
+ # Strategy: assume size fits in 1 byte (< 128), encode value,
62
+ # then fix up if the size varint is larger.
63
+ size_pos = out.pos
64
+ out.pos += 1 # reserve 1 byte for size
65
+ val_start = out.pos
66
+ # struct tags have an empty nested tagged fields (tagged=None)
67
+ field.encode_into(val, out, version=version, compact=True, tagged=None)
68
+ val_size = out.pos - val_start
69
+ actual_size_len = _uvarint_size(val_size)
70
+ if actual_size_len == 1:
71
+ # Common case: size fits in 1 byte, just write it
72
+ out.buf[size_pos] = val_size
73
+ else:
74
+ # Rare case: size needs more bytes. Shift the value data forward.
75
+ extra = actual_size_len - 1
76
+ out.ensure(extra)
77
+ # Move value bytes forward to make room
78
+ out.buf[val_start + extra:out.pos + extra] = out.buf[val_start:out.pos]
79
+ out.pos += extra
80
+ # Write the multi-byte size at size_pos
81
+ saved_pos = out.pos
82
+ out.pos = size_pos
83
+ UnsignedVarInt32.encode_into(out, val_size)
84
+ out.pos = saved_pos
85
+
86
+ def decode(self, data, version=None):
87
+ num_fields = UnsignedVarInt32.decode(data)
88
+ ret = {}
89
+ for i in range(num_fields):
90
+ tag = UnsignedVarInt32.decode(data)
91
+ size = UnsignedVarInt32.decode(data)
92
+ if tag in self._tags:
93
+ field = self._tags[tag]
94
+ # struct tags have an empty nested tagged fields (tagged=None)
95
+ ret[field.name] = field.decode(data, version=version, compact=True, tagged=None)
96
+ else:
97
+ ret['_%d' % tag] = data.read(size)
98
+ return ret
99
+
100
+ @classmethod
101
+ def decode_empty(cls, data):
102
+ assert UnsignedVarInt32.decode(data) == 0
103
+
104
+ @classmethod
105
+ def encode_empty(cls):
106
+ return UnsignedVarInt32.encode(0)
107
+
108
+ def __repr__(self):
109
+ return 'TaggedFields(%s)' % list(self._names.keys())