repid 2.1.0__tar.gz → 2.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. {repid-2.1.0 → repid-2.1.2}/.pre-commit-config.yaml +1 -1
  2. {repid-2.1.0 → repid-2.1.2}/PKG-INFO +1 -1
  3. {repid-2.1.0 → repid-2.1.2}/docs/index.md +30 -16
  4. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/_decode.py +85 -24
  5. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/_encode.py +220 -43
  6. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/amqptypes.py +4 -0
  7. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/message.py +9 -7
  8. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/performatives.py +13 -0
  9. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/helpers.py +40 -57
  10. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/message_broker.py +23 -6
  11. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/connection.py +114 -21
  12. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/links.py +221 -53
  13. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/session.py +119 -22
  14. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/transport.py +32 -2
  15. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/subscriber.py +6 -9
  16. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/message_broker.py +23 -23
  17. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/protocol/__init__.py +5 -0
  18. repid-2.1.2/repid/connections/pubsub/protocol/client.py +123 -0
  19. repid-2.1.2/repid/connections/pubsub/protocol/control_batcher.py +225 -0
  20. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/protocol/received_message.py +21 -30
  21. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/protocol/subscriber.py +42 -86
  22. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/conftest.py +21 -0
  23. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_amqp_transport.py +91 -0
  24. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_connection.py +246 -5
  25. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_encoding_decoding.py +239 -12
  26. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_links.py +354 -15
  27. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_message.py +6 -6
  28. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_message_broker.py +222 -14
  29. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_session.py +200 -0
  30. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_uamqp_types.py +52 -24
  31. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/utils.py +41 -0
  32. repid-2.1.2/tests/unit/pubsub/protocol/test_client.py +103 -0
  33. repid-2.1.2/tests/unit/pubsub/protocol/test_control_batcher.py +284 -0
  34. repid-2.1.2/tests/unit/pubsub/protocol/test_received_message.py +218 -0
  35. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/protocol/test_subscriber.py +142 -133
  36. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/protocol/test_subscriber_execution.py +4 -70
  37. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/test_message_broker.py +103 -186
  38. {repid-2.1.0 → repid-2.1.2}/uv.lock +326 -268
  39. repid-2.1.0/tests/unit/pubsub/protocol/test_received_message.py +0 -157
  40. {repid-2.1.0 → repid-2.1.2}/.devcontainer/devcontainer.json +0 -0
  41. {repid-2.1.0 → repid-2.1.2}/.github/CODE_OF_CONDUCT.md +0 -0
  42. {repid-2.1.0 → repid-2.1.2}/.github/FUNDING.yml +0 -0
  43. {repid-2.1.0 → repid-2.1.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  44. {repid-2.1.0 → repid-2.1.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  45. {repid-2.1.0 → repid-2.1.2}/.github/ISSUE_TEMPLATE/other.md +0 -0
  46. {repid-2.1.0 → repid-2.1.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  47. {repid-2.1.0 → repid-2.1.2}/.github/dependabot.yml +0 -0
  48. {repid-2.1.0 → repid-2.1.2}/.github/workflows/codeql.yml +0 -0
  49. {repid-2.1.0 → repid-2.1.2}/.github/workflows/dependency-review.yml +0 -0
  50. {repid-2.1.0 → repid-2.1.2}/.github/workflows/docs.yml +0 -0
  51. {repid-2.1.0 → repid-2.1.2}/.github/workflows/mypy.yml +0 -0
  52. {repid-2.1.0 → repid-2.1.2}/.github/workflows/release.yaml +0 -0
  53. {repid-2.1.0 → repid-2.1.2}/.github/workflows/tests.yaml +0 -0
  54. {repid-2.1.0 → repid-2.1.2}/.gitignore +0 -0
  55. {repid-2.1.0 → repid-2.1.2}/LICENSE +0 -0
  56. {repid-2.1.0 → repid-2.1.2}/Makefile +0 -0
  57. {repid-2.1.0 → repid-2.1.2}/README.md +0 -0
  58. {repid-2.1.0 → repid-2.1.2}/SECURITY.md +0 -0
  59. {repid-2.1.0 → repid-2.1.2}/docs/advanced_user_guide/your_own_brokers.md +0 -0
  60. {repid-2.1.0 → repid-2.1.2}/docs/advanced_user_guide/your_own_converter.md +0 -0
  61. {repid-2.1.0 → repid-2.1.2}/docs/advanced_user_guide/your_own_serializer.md +0 -0
  62. {repid-2.1.0 → repid-2.1.2}/docs/benchmarks.md +0 -0
  63. {repid-2.1.0 → repid-2.1.2}/docs/benchmarks_img/.gitignore +0 -0
  64. {repid-2.1.0 → repid-2.1.2}/docs/benchmarks_img/chart.svg +0 -0
  65. {repid-2.1.0 → repid-2.1.2}/docs/contributing.md +0 -0
  66. {repid-2.1.0 → repid-2.1.2}/docs/cookbook/chaining_jobs.md +0 -0
  67. {repid-2.1.0 → repid-2.1.2}/docs/cookbook/large_payloads.md +0 -0
  68. {repid-2.1.0 → repid-2.1.2}/docs/cookbook/middlewares.md +0 -0
  69. {repid-2.1.0 → repid-2.1.2}/docs/cookbook/rabbitmq_retries.md +0 -0
  70. {repid-2.1.0 → repid-2.1.2}/docs/cookbook/sentry_middleware.md +0 -0
  71. {repid-2.1.0 → repid-2.1.2}/docs/cookbook/testing.md +0 -0
  72. {repid-2.1.0 → repid-2.1.2}/docs/features.md +0 -0
  73. {repid-2.1.0 → repid-2.1.2}/docs/getting_started/glossary.md +0 -0
  74. {repid-2.1.0 → repid-2.1.2}/docs/getting_started/quickstart.md +0 -0
  75. {repid-2.1.0 → repid-2.1.2}/docs/getting_started/supported_brokers.md +0 -0
  76. {repid-2.1.0 → repid-2.1.2}/docs/integrations/asyncapi.md +0 -0
  77. {repid-2.1.0 → repid-2.1.2}/docs/integrations/fastapi_and_pydantic.md +0 -0
  78. {repid-2.1.0 → repid-2.1.2}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
  79. {repid-2.1.0 → repid-2.1.2}/docs/playground.md +0 -0
  80. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/actors/confirmation_and_errors.md +0 -0
  81. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/actors/execution.md +0 -0
  82. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/actors/index.md +0 -0
  83. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/actors/parsing.md +0 -0
  84. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/actors/routers.md +0 -0
  85. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/actors/routing.md +0 -0
  86. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/dependency_injection.md +0 -0
  87. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/message_registry.md +0 -0
  88. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/messages.md +0 -0
  89. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/raw_message_and_eager_response.md +0 -0
  90. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/server_registry.md +0 -0
  91. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/server_specific_parameters.md +0 -0
  92. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/workers/built_in_servers.md +0 -0
  93. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/workers/concurrency.md +0 -0
  94. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/workers/index.md +0 -0
  95. {repid-2.1.0 → repid-2.1.2}/docs/user_guide/workers/lifecycle.md +0 -0
  96. {repid-2.1.0 → repid-2.1.2}/mkdocs.yml +0 -0
  97. {repid-2.1.0 → repid-2.1.2}/pyproject.toml +0 -0
  98. {repid-2.1.0 → repid-2.1.2}/repid/__init__.py +0 -0
  99. {repid-2.1.0 → repid-2.1.2}/repid/_runner.py +0 -0
  100. {repid-2.1.0 → repid-2.1.2}/repid/_utils/__init__.py +0 -0
  101. {repid-2.1.0 → repid-2.1.2}/repid/_utils/asyncify_.py +0 -0
  102. {repid-2.1.0 → repid-2.1.2}/repid/_utils/is_installed.py +0 -0
  103. {repid-2.1.0 → repid-2.1.2}/repid/_utils/json_encoder.py +0 -0
  104. {repid-2.1.0 → repid-2.1.2}/repid/_utils/not_set.py +0 -0
  105. {repid-2.1.0 → repid-2.1.2}/repid/_worker.py +0 -0
  106. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/__init__.py +0 -0
  107. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/generator.py +0 -0
  108. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/__init__.py +0 -0
  109. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/asyncapi.py +0 -0
  110. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/channels.py +0 -0
  111. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/common/__init__.py +0 -0
  112. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/common/bindings.py +0 -0
  113. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/common/correlation_id.py +0 -0
  114. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/common/external_docs.py +0 -0
  115. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/common/message.py +0 -0
  116. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/common/reference.py +0 -0
  117. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/common/tag.py +0 -0
  118. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/components.py +0 -0
  119. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/info.py +0 -0
  120. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/operations.py +0 -0
  121. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi/models/servers.py +0 -0
  122. {repid-2.1.0 → repid-2.1.2}/repid/asyncapi_server.py +0 -0
  123. {repid-2.1.0 → repid-2.1.2}/repid/connections/__init__.py +0 -0
  124. {repid-2.1.0 → repid-2.1.2}/repid/connections/abc.py +0 -0
  125. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/__init__.py +0 -0
  126. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/LICENSE.txt +0 -0
  127. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/constants.py +0 -0
  128. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/endpoints.py +0 -0
  129. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/_uamqp/outcomes.py +0 -0
  130. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/__init__.py +0 -0
  131. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/events.py +0 -0
  132. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/managed.py +0 -0
  133. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/reconnect.py +0 -0
  134. {repid-2.1.0 → repid-2.1.2}/repid/connections/amqp/protocol/states.py +0 -0
  135. {repid-2.1.0 → repid-2.1.2}/repid/connections/in_memory/__init__.py +0 -0
  136. {repid-2.1.0 → repid-2.1.2}/repid/connections/in_memory/message_broker.py +0 -0
  137. {repid-2.1.0 → repid-2.1.2}/repid/connections/in_memory/utils.py +0 -0
  138. {repid-2.1.0 → repid-2.1.2}/repid/connections/kafka/__init__.py +0 -0
  139. {repid-2.1.0 → repid-2.1.2}/repid/connections/kafka/message.py +0 -0
  140. {repid-2.1.0 → repid-2.1.2}/repid/connections/kafka/message_broker.py +0 -0
  141. {repid-2.1.0 → repid-2.1.2}/repid/connections/kafka/protocols.py +0 -0
  142. {repid-2.1.0 → repid-2.1.2}/repid/connections/kafka/subscriber.py +0 -0
  143. {repid-2.1.0 → repid-2.1.2}/repid/connections/nats/__init__.py +0 -0
  144. {repid-2.1.0 → repid-2.1.2}/repid/connections/nats/message_broker.py +0 -0
  145. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/__init__.py +0 -0
  146. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/helpers.py +0 -0
  147. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/protocol/_helpers.py +0 -0
  148. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/protocol/channel.py +0 -0
  149. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/protocol/credentials.py +0 -0
  150. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/protocol/proto.py +0 -0
  151. {repid-2.1.0 → repid-2.1.2}/repid/connections/pubsub/protocol/resilience.py +0 -0
  152. {repid-2.1.0 → repid-2.1.2}/repid/connections/redis/__init__.py +0 -0
  153. {repid-2.1.0 → repid-2.1.2}/repid/connections/redis/message_broker.py +0 -0
  154. {repid-2.1.0 → repid-2.1.2}/repid/connections/sqs/__init__.py +0 -0
  155. {repid-2.1.0 → repid-2.1.2}/repid/connections/sqs/constants.py +0 -0
  156. {repid-2.1.0 → repid-2.1.2}/repid/connections/sqs/message.py +0 -0
  157. {repid-2.1.0 → repid-2.1.2}/repid/connections/sqs/message_broker.py +0 -0
  158. {repid-2.1.0 → repid-2.1.2}/repid/connections/sqs/subscriber.py +0 -0
  159. {repid-2.1.0 → repid-2.1.2}/repid/converter.py +0 -0
  160. {repid-2.1.0 → repid-2.1.2}/repid/data/__init__.py +0 -0
  161. {repid-2.1.0 → repid-2.1.2}/repid/data/actor.py +0 -0
  162. {repid-2.1.0 → repid-2.1.2}/repid/data/channel.py +0 -0
  163. {repid-2.1.0 → repid-2.1.2}/repid/data/contact.py +0 -0
  164. {repid-2.1.0 → repid-2.1.2}/repid/data/converter_input_schema.py +0 -0
  165. {repid-2.1.0 → repid-2.1.2}/repid/data/external_docs.py +0 -0
  166. {repid-2.1.0 → repid-2.1.2}/repid/data/license.py +0 -0
  167. {repid-2.1.0 → repid-2.1.2}/repid/data/message.py +0 -0
  168. {repid-2.1.0 → repid-2.1.2}/repid/data/message_schema.py +0 -0
  169. {repid-2.1.0 → repid-2.1.2}/repid/data/operation.py +0 -0
  170. {repid-2.1.0 → repid-2.1.2}/repid/data/runner_info.py +0 -0
  171. {repid-2.1.0 → repid-2.1.2}/repid/data/tag.py +0 -0
  172. {repid-2.1.0 → repid-2.1.2}/repid/dependencies/__init__.py +0 -0
  173. {repid-2.1.0 → repid-2.1.2}/repid/dependencies/_utils.py +0 -0
  174. {repid-2.1.0 → repid-2.1.2}/repid/dependencies/depends.py +0 -0
  175. {repid-2.1.0 → repid-2.1.2}/repid/dependencies/full_payload.py +0 -0
  176. {repid-2.1.0 → repid-2.1.2}/repid/dependencies/header_dependency.py +0 -0
  177. {repid-2.1.0 → repid-2.1.2}/repid/dependencies/message_dependency.py +0 -0
  178. {repid-2.1.0 → repid-2.1.2}/repid/health_check_server.py +0 -0
  179. {repid-2.1.0 → repid-2.1.2}/repid/logger.py +0 -0
  180. {repid-2.1.0 → repid-2.1.2}/repid/main.py +0 -0
  181. {repid-2.1.0 → repid-2.1.2}/repid/message_registry.py +0 -0
  182. {repid-2.1.0 → repid-2.1.2}/repid/middlewares.py +0 -0
  183. {repid-2.1.0 → repid-2.1.2}/repid/py.typed +0 -0
  184. {repid-2.1.0 → repid-2.1.2}/repid/router.py +0 -0
  185. {repid-2.1.0 → repid-2.1.2}/repid/serializer.py +0 -0
  186. {repid-2.1.0 → repid-2.1.2}/repid/server_registry.py +0 -0
  187. {repid-2.1.0 → repid-2.1.2}/repid/test_client.py +0 -0
  188. {repid-2.1.0 → repid-2.1.2}/tests/__init__.py +0 -0
  189. {repid-2.1.0 → repid-2.1.2}/tests/integration/__init__.py +0 -0
  190. {repid-2.1.0 → repid-2.1.2}/tests/integration/conftest.py +0 -0
  191. {repid-2.1.0 → repid-2.1.2}/tests/integration/pubsub_proto_helpers.py +0 -0
  192. {repid-2.1.0 → repid-2.1.2}/tests/integration/rabbitmq_definitions.json +0 -0
  193. {repid-2.1.0 → repid-2.1.2}/tests/integration/test_asyncapi_compatibility.py +0 -0
  194. {repid-2.1.0 → repid-2.1.2}/tests/integration/test_default_flow.py +0 -0
  195. {repid-2.1.0 → repid-2.1.2}/tests/integration/test_kafka_specific.py +0 -0
  196. {repid-2.1.0 → repid-2.1.2}/tests/integration/test_nats_specific.py +0 -0
  197. {repid-2.1.0 → repid-2.1.2}/tests/integration/test_rabbitmq_specific.py +0 -0
  198. {repid-2.1.0 → repid-2.1.2}/tests/integration/test_sqs_specific.py +0 -0
  199. {repid-2.1.0 → repid-2.1.2}/tests/integration/test_worker.py +0 -0
  200. {repid-2.1.0 → repid-2.1.2}/tests/unit/__init__.py +0 -0
  201. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/__init__.py +0 -0
  202. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_event_emitter.py +0 -0
  203. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_frame_buffer.py +0 -0
  204. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_logging.py +0 -0
  205. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_managed.py +0 -0
  206. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_managed_pools.py +0 -0
  207. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_metrics.py +0 -0
  208. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_reconnect.py +0 -0
  209. {repid-2.1.0 → repid-2.1.2}/tests/unit/amqp/test_state_machine.py +0 -0
  210. {repid-2.1.0 → repid-2.1.2}/tests/unit/conftest.py +0 -0
  211. {repid-2.1.0 → repid-2.1.2}/tests/unit/in_memory/__init__.py +0 -0
  212. {repid-2.1.0 → repid-2.1.2}/tests/unit/in_memory/test_message_broker.py +0 -0
  213. {repid-2.1.0 → repid-2.1.2}/tests/unit/in_memory/test_utils.py +0 -0
  214. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/__init__.py +0 -0
  215. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/protocol/test_channel.py +0 -0
  216. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/protocol/test_credentials.py +0 -0
  217. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/protocol/test_helpers_internal.py +0 -0
  218. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/protocol/test_proto.py +0 -0
  219. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/protocol/test_resilience.py +0 -0
  220. {repid-2.1.0 → repid-2.1.2}/tests/unit/pubsub/test_helpers.py +0 -0
  221. {repid-2.1.0 → repid-2.1.2}/tests/unit/redis/__init__.py +0 -0
  222. {repid-2.1.0 → repid-2.1.2}/tests/unit/redis/test_message_broker.py +0 -0
  223. {repid-2.1.0 → repid-2.1.2}/tests/unit/redis/test_redis_keep_alive.py +0 -0
  224. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_asyncapi_generator.py +0 -0
  225. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_channel.py +0 -0
  226. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_converter.py +0 -0
  227. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_dependencies.py +0 -0
  228. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_health_check_server.py +0 -0
  229. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_main.py +0 -0
  230. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_middleware.py +0 -0
  231. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_router.py +0 -0
  232. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_runner.py +0 -0
  233. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_runner_manual_explicit.py +0 -0
  234. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_serializer.py +0 -0
  235. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_server_registry.py +0 -0
  236. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_test_client.py +0 -0
  237. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_utils.py +0 -0
  238. {repid-2.1.0 → repid-2.1.2}/tests/unit/test_worker.py +0 -0
@@ -19,7 +19,7 @@ repos:
19
19
  - id: end-of-file-fixer
20
20
 
21
21
  - repo: https://github.com/astral-sh/ruff-pre-commit
22
- rev: v0.15.12
22
+ rev: v0.15.15
23
23
  hooks:
24
24
  - id: ruff-check
25
25
  args: [--fix, --exit-non-zero-on-fix]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: repid
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: Repid is a simple, fast, and extensible async task queue framework, with built-in AsyncAPI 3.0 schema generation.
5
5
  Project-URL: documentation, https://repid.aleksul.space
6
6
  Project-URL: funding, https://github.com/sponsors/aleksul
@@ -65,33 +65,47 @@ if __name__ == "__main__":
65
65
 
66
66
  ## Install
67
67
 
68
- **Repid** supports Python versions 3.10 and up and is installable via `pip`.
68
+ **Repid** supports Python 3.10 and later. Install it with `pip`:
69
69
 
70
70
  ```bash
71
71
  pip install repid
72
72
  ```
73
73
 
74
- There are also a couple of additional dependencies you may want to install,
75
- depending on your use case:
74
+ Or with `uv`:
76
75
 
77
76
  ```bash
78
- pip install repid[amqp, redis, pubsub, pydantic]
77
+ uv add repid
78
+ ```
79
+
80
+ Install extras for the integrations you use:
81
+
82
+ - `pydantic` - Pydantic deserialization support
83
+ - `amqp` - AMQP 1.0 broker support
84
+ - `nats` - NATS broker support
85
+ - `redis` - Redis broker support
86
+ - `pubsub` - GCP Pub/Sub broker support
87
+ - `kafka` - Apache Kafka broker support
88
+ - `sqs` - Amazon SQS broker support
89
+
90
+ ```bash
91
+ pip install "repid[pydantic,amqp,nats,redis,pubsub,kafka,sqs]"
79
92
  ```
80
93
 
81
94
  ## Why Repid?
82
95
 
83
- **Repid** brings modern Python developer experience (DX) to background tasks, moving away from
84
- legacy patterns and embracing strong typing, clear architecture, and flexibility.
85
-
86
- - 📖 **AsyncAPI Native**: Stop maintaining outdated architecture diagrams. Repid automatically
87
- inspects your actors and generates AsyncAPI 3.0 schemas and interactive web documentation.
88
- - 🛡️ **Modern Typing & Validation**: First-class Pydantic support. Your message payloads and headers
89
- are strictly validated and type-coerced before your actors even run.
90
- - 💉 **Dependency Injection**: Write clean, testable code. Inject database connections, settings, or
91
- shared logic directly into your actor signatures.
92
- - 🔌 **Highly Unopinionated**: Repid doesn't force a strict ecosystem. You can use it as just a
93
- producer, just a consumer, or easily swap out underlying message brokers without rewriting your
94
- business logic.
96
+ **Repid** gives async Python applications a clean task queue API with type hints, schema generation,
97
+ and broker flexibility built in.
98
+
99
+ - **AsyncAPI native**: Repid inspects your actors and generates AsyncAPI 3.0 schemas with interactive
100
+ web documentation, so your task contracts stay close to the code that handles them.
101
+ - **Typed message handling**: With the `pydantic`, Repid can deserialize, validate, and coerce
102
+ message payloads and headers before an actor runs.
103
+ - **Async-first performance**: Repid keeps the worker path small and async-native, avoiding sync
104
+ compatibility layers around broker I/O and actor execution.
105
+ - **Dependency injection**: Actors can receive database connections, settings, clients, or other shared
106
+ objects directly through their function signatures, keeping task code easier to test and reuse.
107
+ - **Broker flexibility**: Use Repid as a producer, a consumer, or both. Broker implementations sit
108
+ behind the same application API, so business logic stays separate from transport code.
95
109
 
96
110
  ## LLMs
97
111
 
@@ -6,9 +6,12 @@ from collections.abc import Callable
6
6
  from dataclasses import fields
7
7
  from typing import Any, Literal, TypeVar
8
8
 
9
- from . import performatives
9
+ from . import endpoints, outcomes, performatives
10
10
  from .message import Header, Message, Properties
11
11
 
12
+ FRAME_HEADER_SIZE = 8
13
+ MIN_DOFF = 2
14
+
12
15
  # Maps fixed-width constructor bytes to the number of data bytes to skip.
13
16
  # Used to advance past the descriptor in a described type without allocating a Python object.
14
17
  _DESCRIPTOR_SKIP_SIZES: dict[int, int] = {
@@ -134,6 +137,22 @@ def _decode_timestamp(buffer: memoryview) -> tuple[memoryview, int]:
134
137
  return buffer[8:], c_signed_long_long.unpack(buffer[:8])[0]
135
138
 
136
139
 
140
+ def _decode_char(buffer: memoryview) -> tuple[memoryview, str]:
141
+ return buffer[4:], chr(c_unsigned_int.unpack(buffer[:4])[0])
142
+
143
+
144
+ def _decode_decimal32(buffer: memoryview) -> tuple[memoryview, bytes]:
145
+ return buffer[4:], buffer[:4].tobytes()
146
+
147
+
148
+ def _decode_decimal64(buffer: memoryview) -> tuple[memoryview, bytes]:
149
+ return buffer[8:], buffer[:8].tobytes()
150
+
151
+
152
+ def _decode_decimal128(buffer: memoryview) -> tuple[memoryview, bytes]:
153
+ return buffer[16:], buffer[:16].tobytes()
154
+
155
+
137
156
  def _decode_uuid(buffer: memoryview) -> tuple[memoryview, uuid.UUID]:
138
157
  return buffer[16:], uuid.UUID(bytes=buffer[:16].tobytes())
139
158
 
@@ -191,37 +210,53 @@ def _decode_map_large(buffer: memoryview) -> tuple[memoryview, dict[Any, Any]]:
191
210
  def _decode_array_small(buffer: memoryview) -> tuple[memoryview, list[Any]]:
192
211
  count = buffer[1] # Ignore first byte (size) and just rely on count
193
212
  if count:
194
- subconstructor = buffer[2]
195
- buffer = buffer[3:]
196
- values = [None] * count
197
- for i in range(count):
198
- buffer, values[i] = _DECODE_MAP[subconstructor](buffer)
199
- return buffer, values
213
+ return _decode_array_values(buffer[2], buffer[3:], count)
200
214
  return buffer[2:], []
201
215
 
202
216
 
203
217
  def _decode_array_large(buffer: memoryview) -> tuple[memoryview, list[Any]]:
204
218
  count = c_unsigned_long.unpack(buffer[4:8])[0]
205
219
  if count:
206
- subconstructor = buffer[8]
207
- buffer = buffer[9:]
208
- values = [None] * count
209
- for i in range(count):
210
- buffer, values[i] = _DECODE_MAP[subconstructor](buffer)
211
- return buffer, values
220
+ return _decode_array_values(buffer[8], buffer[9:], count)
212
221
  return buffer[8:], []
213
222
 
214
223
 
224
+ def _decode_array_values(
225
+ subconstructor: int,
226
+ buffer: memoryview,
227
+ count: int,
228
+ ) -> tuple[memoryview, list[Any]]:
229
+ descriptor: Any | None = None
230
+ if subconstructor == 0x00:
231
+ descriptor_constructor = buffer[0]
232
+ buffer, descriptor = _DECODE_MAP[descriptor_constructor](buffer[1:])
233
+ subconstructor = buffer[0]
234
+ buffer = buffer[1:]
235
+
236
+ values = [None] * count
237
+ decoder = _DECODE_MAP[subconstructor]
238
+ for i in range(count):
239
+ buffer, value = decoder(buffer)
240
+ if descriptor is not None:
241
+ value = _construct_described_value(descriptor, value)
242
+ values[i] = value
243
+ return buffer, values
244
+
245
+
215
246
  def _decode_described(buffer: memoryview) -> tuple[memoryview, object]:
216
247
  constructor = buffer[0]
217
- skip = _DESCRIPTOR_SKIP_SIZES.get(constructor)
218
- if skip is not None:
219
- buffer = buffer[1 + skip :]
220
- else:
221
- # Variable-length or nested described type: decode and discard the descriptor.
222
- buffer, _ = _DECODE_MAP[constructor](buffer[1:])
223
- result: tuple[memoryview, object] = _DECODE_MAP[buffer[0]](buffer[1:])
224
- return result
248
+ buffer, descriptor = _DECODE_MAP[constructor](buffer[1:])
249
+ buffer, value = _DECODE_MAP[buffer[0]](buffer[1:])
250
+ return buffer, _construct_described_value(descriptor, value)
251
+
252
+
253
+ def _construct_described_value(descriptor: Any, value: Any) -> object:
254
+ cls = DESCRIBED_TYPES_MAP.get(descriptor)
255
+ if cls is None:
256
+ return (descriptor, value)
257
+ if isinstance(value, list):
258
+ return _list_to_dataclass(cls, value)
259
+ return value
225
260
 
226
261
 
227
262
  def _decode_string_small(buffer: memoryview) -> tuple[memoryview, str]:
@@ -268,10 +303,14 @@ _DECODE_MAP: dict[int, Callable] = {
268
303
  0x00000070: _decode_uint_large,
269
304
  0x00000071: _decode_int_large,
270
305
  0x00000072: _decode_float,
306
+ 0x00000073: _decode_char,
307
+ 0x00000074: _decode_decimal32,
271
308
  0x00000080: _decode_ulong_large,
272
309
  0x00000081: _decode_long_large,
273
310
  0x00000082: _decode_double,
274
311
  0x00000083: _decode_timestamp,
312
+ 0x00000084: _decode_decimal64,
313
+ 0x00000094: _decode_decimal128,
275
314
  0x00000098: _decode_uuid,
276
315
  0x000000A0: _decode_binary_small,
277
316
  0x000000A1: _decode_string_small,
@@ -290,6 +329,18 @@ _DECODE_MAP: dict[int, Callable] = {
290
329
  ListToDataclassT = TypeVar("ListToDataclassT")
291
330
 
292
331
 
332
+ DESCRIBED_TYPES_MAP: dict[int, type[Any]] = {
333
+ performatives.Error.CODE: performatives.Error,
334
+ endpoints.Source.CODE: endpoints.Source,
335
+ endpoints.Target.CODE: endpoints.Target,
336
+ outcomes.Received.CODE: outcomes.Received,
337
+ outcomes.Accepted.CODE: outcomes.Accepted,
338
+ outcomes.Rejected.CODE: outcomes.Rejected,
339
+ outcomes.Released.CODE: outcomes.Released,
340
+ outcomes.Modified.CODE: outcomes.Modified,
341
+ }
342
+
343
+
293
344
  def _list_to_dataclass(cls: type[ListToDataclassT], fields_list: list[Any]) -> ListToDataclassT:
294
345
  kwargs = {}
295
346
  cls_fields = fields(cls) # type: ignore[arg-type]
@@ -311,7 +362,13 @@ def bytes_to_performative(data: bytes) -> performatives.Performative:
311
362
  # channel = struct.unpack(">H", buffer[6:8])[0]
312
363
 
313
364
  # Body
365
+ if size < FRAME_HEADER_SIZE:
366
+ raise ValueError(f"Invalid frame size: {size}")
367
+ if doff < MIN_DOFF:
368
+ raise ValueError(f"Invalid frame data offset: {doff}")
314
369
  body_start = doff * 4
370
+ if size < body_start:
371
+ raise ValueError(f"Frame size {size} smaller than data offset {body_start}")
315
372
  body_buffer = buffer[body_start:size]
316
373
 
317
374
  if len(body_buffer) == 0:
@@ -395,9 +452,13 @@ def _construct_message(payload: bytes) -> Message: # noqa: C901, PLR0912
395
452
  elif descriptor == 0x00000074: # Application Properties # noqa: PLR2004
396
453
  message.application_properties = value
397
454
  elif descriptor == 0x00000075: # Data # noqa: PLR2004
398
- message.data = value
455
+ if message.data is None:
456
+ message.data = []
457
+ message.data.append(value)
399
458
  elif descriptor == 0x00000076: # Sequence # noqa: PLR2004
400
- message.sequence = value
459
+ if message.sequence is None:
460
+ message.sequence = []
461
+ message.sequence.append(value)
401
462
  elif descriptor == 0x00000077: # Value # noqa: PLR2004
402
463
  message.value = value
403
464
  elif descriptor == 0x00000078: # Footer # noqa: PLR2004
@@ -411,7 +472,7 @@ def transfer_frames_to_message(frames: list[performatives.TransferFrame]) -> Mes
411
472
  for frame in frames:
412
473
  if frame.payload:
413
474
  payload.extend(frame.payload)
414
- return _construct_message(payload)
475
+ return _construct_message(bytes(payload))
415
476
 
416
477
 
417
478
  def decode_frame(data: bytes) -> tuple[int, performatives.Performative]: