moru 0.1.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 (152) hide show
  1. moru/__init__.py +174 -0
  2. moru/api/__init__.py +164 -0
  3. moru/api/client/__init__.py +8 -0
  4. moru/api/client/api/__init__.py +1 -0
  5. moru/api/client/api/sandboxes/__init__.py +1 -0
  6. moru/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +161 -0
  7. moru/api/client/api/sandboxes/get_sandboxes.py +176 -0
  8. moru/api/client/api/sandboxes/get_sandboxes_metrics.py +173 -0
  9. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id.py +163 -0
  10. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +199 -0
  11. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +212 -0
  12. moru/api/client/api/sandboxes/get_v2_sandboxes.py +230 -0
  13. moru/api/client/api/sandboxes/post_sandboxes.py +172 -0
  14. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
  15. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py +165 -0
  16. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py +181 -0
  17. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py +189 -0
  18. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py +193 -0
  19. moru/api/client/api/templates/__init__.py +1 -0
  20. moru/api/client/api/templates/delete_templates_template_id.py +157 -0
  21. moru/api/client/api/templates/get_templates.py +172 -0
  22. moru/api/client/api/templates/get_templates_template_id.py +195 -0
  23. moru/api/client/api/templates/get_templates_template_id_builds_build_id_status.py +217 -0
  24. moru/api/client/api/templates/get_templates_template_id_files_hash.py +180 -0
  25. moru/api/client/api/templates/patch_templates_template_id.py +183 -0
  26. moru/api/client/api/templates/post_templates.py +172 -0
  27. moru/api/client/api/templates/post_templates_template_id.py +181 -0
  28. moru/api/client/api/templates/post_templates_template_id_builds_build_id.py +170 -0
  29. moru/api/client/api/templates/post_v2_templates.py +172 -0
  30. moru/api/client/api/templates/post_v3_templates.py +172 -0
  31. moru/api/client/api/templates/post_v_2_templates_template_id_builds_build_id.py +192 -0
  32. moru/api/client/client.py +286 -0
  33. moru/api/client/errors.py +16 -0
  34. moru/api/client/models/__init__.py +123 -0
  35. moru/api/client/models/aws_registry.py +85 -0
  36. moru/api/client/models/aws_registry_type.py +8 -0
  37. moru/api/client/models/build_log_entry.py +89 -0
  38. moru/api/client/models/build_status_reason.py +95 -0
  39. moru/api/client/models/connect_sandbox.py +59 -0
  40. moru/api/client/models/created_access_token.py +100 -0
  41. moru/api/client/models/created_team_api_key.py +166 -0
  42. moru/api/client/models/disk_metrics.py +91 -0
  43. moru/api/client/models/error.py +67 -0
  44. moru/api/client/models/gcp_registry.py +69 -0
  45. moru/api/client/models/gcp_registry_type.py +8 -0
  46. moru/api/client/models/general_registry.py +77 -0
  47. moru/api/client/models/general_registry_type.py +8 -0
  48. moru/api/client/models/identifier_masking_details.py +83 -0
  49. moru/api/client/models/listed_sandbox.py +154 -0
  50. moru/api/client/models/log_level.py +11 -0
  51. moru/api/client/models/max_team_metric.py +78 -0
  52. moru/api/client/models/mcp_type_0.py +44 -0
  53. moru/api/client/models/new_access_token.py +59 -0
  54. moru/api/client/models/new_sandbox.py +172 -0
  55. moru/api/client/models/new_team_api_key.py +59 -0
  56. moru/api/client/models/node.py +155 -0
  57. moru/api/client/models/node_detail.py +165 -0
  58. moru/api/client/models/node_metrics.py +122 -0
  59. moru/api/client/models/node_status.py +11 -0
  60. moru/api/client/models/node_status_change.py +79 -0
  61. moru/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py +59 -0
  62. moru/api/client/models/post_sandboxes_sandbox_id_timeout_body.py +59 -0
  63. moru/api/client/models/resumed_sandbox.py +68 -0
  64. moru/api/client/models/sandbox.py +145 -0
  65. moru/api/client/models/sandbox_detail.py +183 -0
  66. moru/api/client/models/sandbox_log.py +70 -0
  67. moru/api/client/models/sandbox_log_entry.py +93 -0
  68. moru/api/client/models/sandbox_log_entry_fields.py +44 -0
  69. moru/api/client/models/sandbox_logs.py +91 -0
  70. moru/api/client/models/sandbox_metric.py +118 -0
  71. moru/api/client/models/sandbox_network_config.py +92 -0
  72. moru/api/client/models/sandbox_state.py +9 -0
  73. moru/api/client/models/sandboxes_with_metrics.py +59 -0
  74. moru/api/client/models/team.py +83 -0
  75. moru/api/client/models/team_api_key.py +158 -0
  76. moru/api/client/models/team_metric.py +86 -0
  77. moru/api/client/models/team_user.py +68 -0
  78. moru/api/client/models/template.py +217 -0
  79. moru/api/client/models/template_build.py +139 -0
  80. moru/api/client/models/template_build_file_upload.py +70 -0
  81. moru/api/client/models/template_build_info.py +126 -0
  82. moru/api/client/models/template_build_request.py +115 -0
  83. moru/api/client/models/template_build_request_v2.py +88 -0
  84. moru/api/client/models/template_build_request_v3.py +88 -0
  85. moru/api/client/models/template_build_start_v2.py +184 -0
  86. moru/api/client/models/template_build_status.py +11 -0
  87. moru/api/client/models/template_legacy.py +207 -0
  88. moru/api/client/models/template_request_response_v3.py +83 -0
  89. moru/api/client/models/template_step.py +91 -0
  90. moru/api/client/models/template_update_request.py +59 -0
  91. moru/api/client/models/template_with_builds.py +148 -0
  92. moru/api/client/models/update_team_api_key.py +59 -0
  93. moru/api/client/py.typed +1 -0
  94. moru/api/client/types.py +54 -0
  95. moru/api/client_async/__init__.py +50 -0
  96. moru/api/client_sync/__init__.py +52 -0
  97. moru/api/metadata.py +14 -0
  98. moru/connection_config.py +217 -0
  99. moru/envd/api.py +59 -0
  100. moru/envd/filesystem/filesystem_connect.py +193 -0
  101. moru/envd/filesystem/filesystem_pb2.py +76 -0
  102. moru/envd/filesystem/filesystem_pb2.pyi +233 -0
  103. moru/envd/process/process_connect.py +155 -0
  104. moru/envd/process/process_pb2.py +92 -0
  105. moru/envd/process/process_pb2.pyi +304 -0
  106. moru/envd/rpc.py +61 -0
  107. moru/envd/versions.py +6 -0
  108. moru/exceptions.py +95 -0
  109. moru/sandbox/commands/command_handle.py +69 -0
  110. moru/sandbox/commands/main.py +39 -0
  111. moru/sandbox/filesystem/filesystem.py +94 -0
  112. moru/sandbox/filesystem/watch_handle.py +60 -0
  113. moru/sandbox/main.py +210 -0
  114. moru/sandbox/mcp.py +1120 -0
  115. moru/sandbox/network.py +8 -0
  116. moru/sandbox/sandbox_api.py +210 -0
  117. moru/sandbox/signature.py +45 -0
  118. moru/sandbox/utils.py +34 -0
  119. moru/sandbox_async/commands/command.py +336 -0
  120. moru/sandbox_async/commands/command_handle.py +196 -0
  121. moru/sandbox_async/commands/pty.py +240 -0
  122. moru/sandbox_async/filesystem/filesystem.py +531 -0
  123. moru/sandbox_async/filesystem/watch_handle.py +62 -0
  124. moru/sandbox_async/main.py +734 -0
  125. moru/sandbox_async/paginator.py +69 -0
  126. moru/sandbox_async/sandbox_api.py +325 -0
  127. moru/sandbox_async/utils.py +7 -0
  128. moru/sandbox_sync/commands/command.py +328 -0
  129. moru/sandbox_sync/commands/command_handle.py +150 -0
  130. moru/sandbox_sync/commands/pty.py +230 -0
  131. moru/sandbox_sync/filesystem/filesystem.py +518 -0
  132. moru/sandbox_sync/filesystem/watch_handle.py +69 -0
  133. moru/sandbox_sync/main.py +726 -0
  134. moru/sandbox_sync/paginator.py +69 -0
  135. moru/sandbox_sync/sandbox_api.py +308 -0
  136. moru/template/consts.py +30 -0
  137. moru/template/dockerfile_parser.py +275 -0
  138. moru/template/logger.py +232 -0
  139. moru/template/main.py +1360 -0
  140. moru/template/readycmd.py +138 -0
  141. moru/template/types.py +105 -0
  142. moru/template/utils.py +320 -0
  143. moru/template_async/build_api.py +202 -0
  144. moru/template_async/main.py +366 -0
  145. moru/template_sync/build_api.py +199 -0
  146. moru/template_sync/main.py +371 -0
  147. moru-0.1.0.dist-info/METADATA +63 -0
  148. moru-0.1.0.dist-info/RECORD +152 -0
  149. moru-0.1.0.dist-info/WHEEL +4 -0
  150. moru-0.1.0.dist-info/licenses/LICENSE +9 -0
  151. moru_connect/__init__.py +1 -0
  152. moru_connect/client.py +493 -0
@@ -0,0 +1,152 @@
1
+ moru/__init__.py,sha256=OTepvrwEO-_wqXdxox-BB0_PEcbK0gCaq8iuCvMTJe8,4044
2
+ moru/api/__init__.py,sha256=Kex7ww-Wsd9n13YP4V0szE31tDsg4nwAMs3KOetkvU8,5292
3
+ moru/api/client/__init__.py,sha256=b28MpwoIgPULais3BheaYT1RIUdlNVBhXD1vrn4oE6A,151
4
+ moru/api/client/api/__init__.py,sha256=zTSiG_ujSjAqWPyc435YXaX9XTlpMjiJWBbV-f-YtdA,45
5
+ moru/api/client/api/sandboxes/__init__.py,sha256=5vd9uJWAjRqa9xzxzYkLD1yoZ12Ld_bAaNB5WX4fbE8,56
6
+ moru/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py,sha256=exBkD4FP0t730uuuKvNPWwm9PMOE68BDeaKmt98gPlg,3945
7
+ moru/api/client/api/sandboxes/get_sandboxes.py,sha256=cte-9oyXExgevw28JmoYcFF_GiCeCr0vkCf47LGtLxA,4745
8
+ moru/api/client/api/sandboxes/get_sandboxes_metrics.py,sha256=KCF1aSbx_1PL2xAhfFqBYIueLYyzCiRomjSgXOU9HBA,4613
9
+ moru/api/client/api/sandboxes/get_sandboxes_sandbox_id.py,sha256=M4a8lrM0NgaIF4G6rMw2LcoLs2FK6b4Dfc15JoroSkc,4133
10
+ moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py,sha256=EQmwi1HGcadWZOCSQ3UrtrT3quNHnJkPnanvd-gW0sM,5217
11
+ moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py,sha256=jE5r70f4aVA7raa9nRw3syGmXWjmKMdLD7-NrVLjdl0,5909
12
+ moru/api/client/api/sandboxes/get_v2_sandboxes.py,sha256=vSR1tqr1cawaQqPBmX8hj79R46fluIIOKQwPlAGMNns,6705
13
+ moru/api/client/api/sandboxes/post_sandboxes.py,sha256=XygFg6q9nF5aNZUOEMn-W1cL0O0rNmtCRY9vXrLSiag,4269
14
+ moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py,sha256=V8hxnasDuLaAwk-V5g0iT-RcpCtep2qv-JP2pdG0Vik,5148
15
+ moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py,sha256=dD0M7vx5MV-tCw4o2by1csKnIDVmO2YxaPkKDxNpEJc,4082
16
+ moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py,sha256=euCZrWCPDvSGFq7_0qLgXSF6Ff95jobfQMdgnpLQG80,4753
17
+ moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py,sha256=rGHH24aBNYrMHkvDoQkC15yvS6Ku8TjznauD7vcUtzg,4728
18
+ moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py,sha256=PDthaR57kLmY6Nz1FrpcDqPWZm_F-KaR338-bQagrk0,5674
19
+ moru/api/client/api/templates/__init__.py,sha256=5vd9uJWAjRqa9xzxzYkLD1yoZ12Ld_bAaNB5WX4fbE8,56
20
+ moru/api/client/api/templates/delete_templates_template_id.py,sha256=kuk9ZCyk1LNb1khjW-PcwP7YrMXYpzO0rnAWgXXH-YQ,3854
21
+ moru/api/client/api/templates/get_templates.py,sha256=ZN3PG1_HsJnLmJZ00ZzFk9XGf9mTM6JxLNlT95F3A0w,4598
22
+ moru/api/client/api/templates/get_templates_template_id.py,sha256=yzbvqTmLXw4ky4yGBL5Uqax-oC3q1RHzsKJHP2vGob8,5342
23
+ moru/api/client/api/templates/get_templates_template_id_builds_build_id_status.py,sha256=Iv1g0rxGp1HJc0Zthq-s0xkdnEzBw795M1gB4I_o-EI,6039
24
+ moru/api/client/api/templates/get_templates_template_id_files_hash.py,sha256=7ntCFSxZER4f2KURZwttJAw0i-hCEueZKdHu9GZCCi8,4914
25
+ moru/api/client/api/templates/patch_templates_template_id.py,sha256=RMCVX8WXVMuwgGqmpeqAedVZ8SVjuLR7uL0MgK87Igk,4593
26
+ moru/api/client/api/templates/post_templates.py,sha256=-Z4ZlPCDXSy-AJLglk6IHc0MJsPMVm8xVbHaboaHeKw,4420
27
+ moru/api/client/api/templates/post_templates_template_id.py,sha256=YiGS01zYOHgVXdRD5hhSEHzXfuTRzJUdL35hjR_ZG44,4660
28
+ moru/api/client/api/templates/post_templates_template_id_builds_build_id.py,sha256=xCkIlP3CV0ZHsfsIp4qi4yNBqPlc4rjG0M_vxgdpwTo,4165
29
+ moru/api/client/api/templates/post_v2_templates.py,sha256=hJczq9aJpaPo4i_ubo5bQzL-h5AYuY21YOsLJAFLFuA,4446
30
+ moru/api/client/api/templates/post_v3_templates.py,sha256=3AgCaMwzVHaXjCsBm5z7FhTdOpW9-NaEAnyBIoAY58Y,4591
31
+ moru/api/client/api/templates/post_v_2_templates_template_id_builds_build_id.py,sha256=Uqrs2EpcoYBKe9lz_369BOxt6J0S-Np5hHct_p4T3NA,4785
32
+ moru/api/client/client.py,sha256=O6MiIbTg_Z-szhiNi8RhaBwI7chi3y9xvPfnYiGXMb4,12581
33
+ moru/api/client/errors.py,sha256=gO8GBmKqmSNgAg-E5oT-oOyxztvp7V_6XG7OUTT15q0,546
34
+ moru/api/client/models/__init__.py,sha256=UoFfw_fpf5ZA_Z6Q1vr4zc9vLINWJmu_YSjSY22ETzU,4099
35
+ moru/api/client/models/aws_registry.py,sha256=YKwQXCuutv3XwgEJWbBTyX6KmLi866-ASsHpu-n0H2w,2486
36
+ moru/api/client/models/aws_registry_type.py,sha256=8gBrOkfd2OaBDPRRJDmF6t2luvz01A0QExzfHRsgUg8,136
37
+ moru/api/client/models/build_log_entry.py,sha256=JKbGEBu5YMNL8o62xuX7YhrOi8T8EBV-e_gotu8jOj8,2379
38
+ moru/api/client/models/build_status_reason.py,sha256=rGwEYbmIFjSG3QPpPm-iX1rDVDPC3Jkn33dDljbLyWM,2878
39
+ moru/api/client/models/connect_sandbox.py,sha256=095nNrudNKwrD1fjsTTNeaf-4D_jJ2NsvIEQhYAVBHY,1561
40
+ moru/api/client/models/created_access_token.py,sha256=VjU_tuW67zrtc3V1po-MVtPo8J1dtRkwy-6uTe2AEf0,2639
41
+ moru/api/client/models/created_team_api_key.py,sha256=QO2jAIR8u1Xxn26jnftkDNYCI1mEqDMt-ZUIQS1y1NU,5040
42
+ moru/api/client/models/disk_metrics.py,sha256=2bZEe84P2wBqQb9_RR-xR743ZDKCzjbzXmjmTDsXwI8,2442
43
+ moru/api/client/models/error.py,sha256=xGvyYQQHv0ZrxvhrVvFlXPaosmt24ivIh3U4gItpBKY,1594
44
+ moru/api/client/models/gcp_registry.py,sha256=jU0_iH1H0JBGHyl0IVuQl44yQ18qyTqYaPNd8S_yZyg,1923
45
+ moru/api/client/models/gcp_registry_type.py,sha256=QcMwg9qUyr6e7VRinI0iRa9lhYvryj7vZEeTK0yEZVM,136
46
+ moru/api/client/models/general_registry.py,sha256=J_-i7kLmsPy018YFhBKDH5YAToey4MnCIivPUKSpTc8,2052
47
+ moru/api/client/models/general_registry_type.py,sha256=VwyEKt25wUh0y8Qj4Wpeolus-Cpt31Snhhy-UM_DfMk,150
48
+ moru/api/client/models/identifier_masking_details.py,sha256=97xSg4Nr3D5xbjGDuZ16doEMOlck0EtyjMxtHQR9TKk,2496
49
+ moru/api/client/models/listed_sandbox.py,sha256=zyuxeHjkrar1GTnKVCvgRXV4Zvdfq8FcZGOXnxHQ5a8,4382
50
+ moru/api/client/models/log_level.py,sha256=uv6u1nkqfzdxTjJAxLZdWuH5goVI_g-ULLhh6TU5dw8,189
51
+ moru/api/client/models/max_team_metric.py,sha256=HQuDBFHMIsTJbWTl0kOX4ADIfWb1E97J-PB0NNoRJCw,2187
52
+ moru/api/client/models/mcp_type_0.py,sha256=U_8DsmxiUkD4s4_ODbE6sAlURThIqS6v1rUpt3CE1FE,1220
53
+ moru/api/client/models/new_access_token.py,sha256=sjlQ7dEj4ByCgwud750SbxwyjggAKB1s-o_N7dRCo7s,1480
54
+ moru/api/client/models/new_sandbox.py,sha256=a9puqtwleHhMr_z8h_WE58eXtE6QNPNl4Huar44I_oU,5603
55
+ moru/api/client/models/new_team_api_key.py,sha256=neYLvvvzyPcpXYV5gDHVkv_ovjKdIBKUTX04cD5QKGA,1473
56
+ moru/api/client/models/node.py,sha256=P6x2a_6Nj58YlqiLjU1xqJ8nF0VGcvqdN-w-CwMpHVg,4352
57
+ moru/api/client/models/node_detail.py,sha256=KXosKYhqOyVwgBPSlb2xVnlECIlONZzD0UiiIKf_wko,4782
58
+ moru/api/client/models/node_metrics.py,sha256=EveG1M2dLWteatFWvFQMa9aKzz8urRlOOZ7QD_8Xd0o,3642
59
+ moru/api/client/models/node_status.py,sha256=bZkWsNgKncRmFxatPdKlJTu9H4GTBbgQ2XF9JNvW16I,219
60
+ moru/api/client/models/node_status_change.py,sha256=g59HSBpip8R7egNghe7QxYZ_MH-bgijGac36S5-WdYg,2236
61
+ moru/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py,sha256=VwMoBB9y2vFP7kcLDJ0Q9kVGOBqD2W3VvAEKv_XHd2Y,1763
62
+ moru/api/client/models/post_sandboxes_sandbox_id_timeout_body.py,sha256=iay4pLjwIryb6J8fjx3UjThsNJ5AvqArzAwr5K8LnNs,1668
63
+ moru/api/client/models/resumed_sandbox.py,sha256=spSSP0TXWz8QmDoJprqIRToktgd8pvmiPTwZt5pKB2w,1964
64
+ moru/api/client/models/sandbox.py,sha256=z5OUJActzzFq2us2ttM-BQU-pJ9esi0qBjKtrqNhjE0,4600
65
+ moru/api/client/models/sandbox_detail.py,sha256=L3QNx7SlJyrqpWtchieKmXRh5MrOJfP2CF2CCibJpiI,5494
66
+ moru/api/client/models/sandbox_log.py,sha256=tXw35j3poz7DMJrLeoxr4oYdbcYJV5ep3E0bVdQsS2o,1806
67
+ moru/api/client/models/sandbox_log_entry.py,sha256=rbwY2MBahRLhcCP081XczQI3AksuLMbflNh9pOeCfjA,2502
68
+ moru/api/client/models/sandbox_log_entry_fields.py,sha256=SYwtEgNOKPtmf9BqIiRS44bEgcbbbHMq2qdCShpj8QI,1256
69
+ moru/api/client/models/sandbox_logs.py,sha256=3UC3ngilUpl7Wye7rl5Md9DR1loa_7chGTBx9tRb6LY,2658
70
+ moru/api/client/models/sandbox_metric.py,sha256=j90tDplFtQwdzHKpBVk5044T4uVrLwVTGBvAAkVaGdI,3280
71
+ moru/api/client/models/sandbox_network_config.py,sha256=iBSiOsOpPBkdHvIfwlVSxRRjgdffkMP_p7hDNFEhKco,3290
72
+ moru/api/client/models/sandbox_state.py,sha256=iztDupSF2SrYQGV2UTcnZRH_U3GxSmHYKHMMUksO_7M,163
73
+ moru/api/client/models/sandboxes_with_metrics.py,sha256=CuOZ1ismyjPLrxPcKaDqLKZL5Iun0njN70Qqhubc1Ps,1535
74
+ moru/api/client/models/team.py,sha256=rGLOfphzsP7VA9SLmQn8vnUfxB9KILfMwNfh4hVy3IE,2042
75
+ moru/api/client/models/team_api_key.py,sha256=4aqRT8gF32WJwuteq6h7ag2wdpZuVCpaOEZuj1j3Dx4,4844
76
+ moru/api/client/models/team_metric.py,sha256=itcMm3hTxv_S7DG14JYI2LTOIPwrc_1rhP-UmRQRt84,2619
77
+ moru/api/client/models/team_user.py,sha256=UCF9Ajj0QOrE_RxFusWnDM9N4PI0DOZHZaksMILLdS4,1631
78
+ moru/api/client/models/template.py,sha256=HcA4xZqCf-YyNhALo3ysvM9_V0dRc8fXsBjo2DG1tw8,6739
79
+ moru/api/client/models/template_build.py,sha256=5GpCKpvI6vi86r7wV2Ylv3qQxJEL3wBbrXCRx7lTFQo,4323
80
+ moru/api/client/models/template_build_file_upload.py,sha256=iqgQEKVJxWD8ezd_w44NoYmFCVDyTSUcH474KRCaXDY,1879
81
+ moru/api/client/models/template_build_info.py,sha256=IXZM16g5tWbwqtGMnzUj3IRkd3H9HmsYwpNCEEp_AkQ,3798
82
+ moru/api/client/models/template_build_request.py,sha256=iMy655tp09fTr8gNgu8uHwQm4IA_8IUx4xWQxZQnzjI,3433
83
+ moru/api/client/models/template_build_request_v2.py,sha256=KoETYShWCXHBo6Mt4WF_WHHJnHxd66cbAQ0JMum8Ino,2459
84
+ moru/api/client/models/template_build_request_v3.py,sha256=jfEfMfOtUyGRPOId16RJgocDd1uBcb32-mtCBHUF7mE,2459
85
+ moru/api/client/models/template_build_start_v2.py,sha256=TIZjDcqPCwGQeHOWXMYPbf3W1fkbbCMqI9xo8DhQREY,6543
86
+ moru/api/client/models/template_build_status.py,sha256=MpTZ_bM8-_WvttJg1Q08_ZGHdrJ6JTEl_6pv8NFETyM,214
87
+ moru/api/client/models/template_legacy.py,sha256=MQ0GpvoH-VDyh-07sQYqnud3AZx4A4AhK-SpTCkS444,6399
88
+ moru/api/client/models/template_request_response_v3.py,sha256=fU2pqGzWNiKLaaO9G0WlwKRk7Yj2ZniV-3m7dlzHCLM,2307
89
+ moru/api/client/models/template_step.py,sha256=qmCseK5OJXN2Ffirl0A0J4neqyfDqA-a-mYZbmwKOyM,2561
90
+ moru/api/client/models/template_update_request.py,sha256=KMlSyGf7hX75GqXxEP-OiExnABql4MKdLBfHPd02gFo,1663
91
+ moru/api/client/models/template_with_builds.py,sha256=D_euGW7ByyN8BKHUNN_SEgF6YbZl5ZsCbWDRhwz3J_0,4606
92
+ moru/api/client/models/update_team_api_key.py,sha256=UEHHUJxwHWTOd-AuDE-Z26E4lX2Ck9SPq8MO-Trc9Uc,1493
93
+ moru/api/client/py.typed,sha256=8ZJUsxZiuOy1oJeVhsTWQhTG_6pTVHVXk5hJL79ebTk,25
94
+ moru/api/client/types.py,sha256=AX4orxQZQJat3vZrgjJ-TYb2sNBL8kNo9yqYDT-n8y8,1391
95
+ moru/api/client_async/__init__.py,sha256=AZ3Ju_yzZLdWwZ98AR2__PGr5t-uClxOJ4Y22HII7Sk,1337
96
+ moru/api/client_sync/__init__.py,sha256=9GzuwlCxcJEHgH2HTvUrqTXHIkCHwpk0V9EewkZUt8o,1313
97
+ moru/api/metadata.py,sha256=ytPkGmfWh6FJ4yUOPQA_-BRW7b27hLdgxQFn07MtXhQ,320
98
+ moru/connection_config.py,sha256=LZCS95mhGyjb6VWqlo2vXYTTnXOT8C-3umQoiEfWlXk,6799
99
+ moru/envd/api.py,sha256=eK_ka4Pj3h-5pDic-wLzr94fFnYpGQYqIALPkPFr4kg,1491
100
+ moru/envd/filesystem/filesystem_connect.py,sha256=mJwggEN7UPSEHDWD_m9NTpFD3LtY8hKhI1aMJJ1_RfA,7528
101
+ moru/envd/filesystem/filesystem_pb2.py,sha256=PaXEqiiGUeIfsZmx488TpDBwZn4AcV6eUugdYVhc61w,8024
102
+ moru/envd/filesystem/filesystem_pb2.pyi,sha256=8LnxvXgCosUrTtiXKkyN-ZroQ2JKf8FjnaJ8jGqlRVo,7631
103
+ moru/envd/process/process_connect.py,sha256=bn8svNcgvgwjjOWspvLZkB7gxNbxBrXnVbTx6licVfg,5693
104
+ moru/envd/process/process_pb2.py,sha256=EGGYkdTw7NZFAXLJHpXZZhTytl9ExgIE8roDfi4hPbA,9794
105
+ moru/envd/process/process_pb2.pyi,sha256=ufwRFK1P7p_UHEazlxNiUs2itEhgYZtdOV-YY8RRu94,9688
106
+ moru/envd/rpc.py,sha256=ueOxpa9HyeUToMWZFHDADxXG5HrQRu0T-Ks2Zvktk-0,2237
107
+ moru/envd/versions.py,sha256=hX1p5B7268L73ZZTgG9W_oWFqPspyRHH7I2KUizveIk,205
108
+ moru/exceptions.py,sha256=E97UKGcnMTnMXRR1XpHDg5dfjZdWxFjqX3hzDiRueRo,2229
109
+ moru/sandbox/commands/command_handle.py,sha256=Kr0NoZc9QwzRPw7zdXWY4hFP-xr37geK08WbfTL1mmc,1078
110
+ moru/sandbox/commands/main.py,sha256=t8hk44wZX27OqRrYHo_FhvhzfOvIVK-6NO4HpfiOhpo,692
111
+ moru/sandbox/filesystem/filesystem.py,sha256=Yk2DBMkTDkVz_c6XVwHNLhTRPVECo2tHeDl6cTtNOJE,1880
112
+ moru/sandbox/filesystem/watch_handle.py,sha256=8oUe5mx0xIvv40LzBDYCYeDOirya-2pbut7FDaM86aQ,1387
113
+ moru/sandbox/main.py,sha256=6t_MR9IIO6XTmk38vu3vqwmSz5DmfM0MjDklDAl3w4o,6267
114
+ moru/sandbox/mcp.py,sha256=CRwNOla9Raz2j5Q5g4d65sE6hZ3Adj8RCZ0USold25s,23142
115
+ moru/sandbox/network.py,sha256=tmOG2Ya1MyYk58_BnV546xsQVQHfqnHgsa-H5HB6XZE,133
116
+ moru/sandbox/sandbox_api.py,sha256=vfqzl-rCF51YQFTtHUioOwiI05bEC4LUq7Wrffeipgg,5923
117
+ moru/sandbox/signature.py,sha256=QIMpJHE_UD00iQiwsGAdO8gJpqoP2MP1zHV8bbGWKDc,1203
118
+ moru/sandbox/utils.py,sha256=grMOJpeyk9YeS6dE7qCwBaJUaqgvrE4aKkGc9nVVfhI,1300
119
+ moru/sandbox_async/commands/command.py,sha256=b60rBXH6Akg_ioQqDp8fOye3ngfFu1lkLMA_QFlCrZ4,12485
120
+ moru/sandbox_async/commands/command_handle.py,sha256=5M05YMdMrNxboOpOSqy9htlGQOq9jCNkU78zBWzg5t4,5771
121
+ moru/sandbox_async/commands/pty.py,sha256=yIi-e_iWg0XWBXnze9UXyZTtQ8PNNEuV8cbXSopDKwA,7982
122
+ moru/sandbox_async/filesystem/filesystem.py,sha256=gKZzuQVB6g4U1Y6JPHcb1OgSBSeMw9b08yOhgc2pbig,18707
123
+ moru/sandbox_async/filesystem/watch_handle.py,sha256=EWe7Rd5r3LkCtF8jAKSNO400FxBnGqiXfVMYWEyXlgc,1969
124
+ moru/sandbox_async/main.py,sha256=EhRJX32q2VT9ORXCKZF9NbemwSC1ycgRJI2Ltm5Nn_o,23583
125
+ moru/sandbox_async/paginator.py,sha256=eW5hKXItevPPEuuAuItSao2zvLBOOQjeMaoJ3NlnbUI,2296
126
+ moru/sandbox_async/sandbox_api.py,sha256=a9g5KeSjbht64PAKrXtJ1PgITQuNPO7tvSXc7CwoeoE,9995
127
+ moru/sandbox_async/utils.py,sha256=mplhnoDat1PswDksAlnz2Zp4zzUGSIdr_76kiFYZQK8,159
128
+ moru/sandbox_sync/commands/command.py,sha256=dI1GrzzdUBB4wnzFegPh3oWfzVSRltNRtzcld_M1f4g,11626
129
+ moru/sandbox_sync/commands/command_handle.py,sha256=d1HDROr_hw3I9JW2yaCJcKOyDnSI2V1JHvTKHWwgG3k,4633
130
+ moru/sandbox_sync/commands/pty.py,sha256=IZUpyR0-XaEDcEn2MLxb-WtF9DFa3eK0bzdLKkeqLac,7590
131
+ moru/sandbox_sync/filesystem/filesystem.py,sha256=MMdW-zMCXWPmJRQuri5jWn51xLhQihg9u1F4R_vG7iI,17852
132
+ moru/sandbox_sync/filesystem/watch_handle.py,sha256=R5KnqUFQjb_nfQ29B0jfG4Imm-YjK09tYrRUU36n5hM,2059
133
+ moru/sandbox_sync/main.py,sha256=K6cg4lt8nqgWByBerPhjS9drPi_EPs_XKSxDQfczUtQ,22948
134
+ moru/sandbox_sync/paginator.py,sha256=FqWhMm7ykqmDYITc8cz7muUH-AUsi3cydBiJYWqsaZo,2264
135
+ moru/sandbox_sync/sandbox_api.py,sha256=f2-m8mIMmHR9qAWOlACiJOGLOn9DTt6NvUFkNoI1LUo,9171
136
+ moru/template/consts.py,sha256=opZ2iHQxt1gpR67PlbJvpxYfHlzsAB8q7XD0a98cu5o,756
137
+ moru/template/dockerfile_parser.py,sha256=SzOeZdyk5bI0f9PDTP4ST4ZTBUOoBwsC0vUvY2PoilM,8996
138
+ moru/template/logger.py,sha256=_L8HSaoAcWaBHcqbJ-7gUkAf_ccqSi2ZtQfGGL6rwQg,6088
139
+ moru/template/main.py,sha256=F1byCKH4pPbMctU6oydqxYNWumEpmZsJjSe7RzhAWeg,43618
140
+ moru/template/readycmd.py,sha256=7GP9p-epA4nP0F5IvjQ1V67XWVpLHlu8UX_ZMauheks,3210
141
+ moru/template/types.py,sha256=81eOKx63GpjvlgsdoBGJhXL1like2Cy7mmxo9omu_f8,2291
142
+ moru/template/utils.py,sha256=tCacYCwzI5puclQjlRwfPXk9gp4tDhVycBjkkXbbj38,9655
143
+ moru/template_async/build_api.py,sha256=98OrYIGcuDroT5bihx8RejAm0ge0ADg_YX1ms6axF6k,6076
144
+ moru/template_async/main.py,sha256=T9AKqw7ekdagDj8WKBAmAEvkqpj8kOMwdVENagyoLZE,11943
145
+ moru/template_sync/build_api.py,sha256=4SM9WDlX5HyVlA2NdJAquM1c8ax_9cc_wKr1MGwu9p4,5951
146
+ moru/template_sync/main.py,sha256=NSFhKjhv_n5vV4Ra2bc1zBDxcBFRumBlUnV_lPfBZCI,11901
147
+ moru_connect/__init__.py,sha256=ToGN4_2p-tV3QVUKcfHNg6U1qbbERaUjym8SJN3VCls,81
148
+ moru_connect/client.py,sha256=u1kYyb1wuE0-rdGw-ymCftxGH_o-8mb1w3Q8NFVSJ8E,13030
149
+ moru-0.1.0.dist-info/METADATA,sha256=SBdbX-AIBCbXizCg-HCm6bnq4NBBO4uCtAWpEcw_8Nw,1691
150
+ moru-0.1.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
151
+ moru-0.1.0.dist-info/licenses/LICENSE,sha256=ONtx_RW5j6C0mPjF7nBaSVcOMREIXCd_uJteoQfsTcs,1074
152
+ moru-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.2.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 FOUNDRYLABS, INC.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ from .client import Client, GzipCompressor, ConnectException, Code # noqa: F401
moru_connect/client.py ADDED
@@ -0,0 +1,493 @@
1
+ import gzip
2
+ import inspect
3
+ import json
4
+ import struct
5
+ import typing
6
+
7
+ from httpcore import (
8
+ ConnectionPool,
9
+ AsyncConnectionPool,
10
+ RemoteProtocolError,
11
+ Response,
12
+ )
13
+ from enum import Flag, Enum
14
+ from typing import Callable, Optional, Dict, Any, Generator, Tuple
15
+ from google.protobuf import json_format
16
+
17
+
18
+ class EnvelopeFlags(Flag):
19
+ compressed = 0b00000001
20
+ end_stream = 0b00000010
21
+
22
+
23
+ class Code(Enum):
24
+ canceled = "canceled"
25
+ unknown = "unknown"
26
+ invalid_argument = "invalid_argument"
27
+ deadline_exceeded = "deadline_exceeded"
28
+ not_found = "not_found"
29
+ already_exists = "already_exists"
30
+ permission_denied = "permission_denied"
31
+ resource_exhausted = "resource_exhausted"
32
+ failed_precondition = "failed_precondition"
33
+ aborted = "aborted"
34
+ out_of_range = "out_of_range"
35
+ unimplemented = "unimplemented"
36
+ internal = "internal"
37
+ unavailable = "unavailable"
38
+ data_loss = "data_loss"
39
+ unauthenticated = "unauthenticated"
40
+
41
+
42
+ def make_error_from_http_code(http_code: int):
43
+ error_code_map = {
44
+ 400: Code.invalid_argument,
45
+ 401: Code.unauthenticated,
46
+ 403: Code.permission_denied,
47
+ 404: Code.not_found,
48
+ 409: Code.already_exists,
49
+ 413: Code.resource_exhausted,
50
+ 429: Code.resource_exhausted,
51
+ 499: Code.canceled,
52
+ 500: Code.internal,
53
+ 501: Code.unimplemented,
54
+ 502: Code.unavailable,
55
+ 503: Code.unavailable,
56
+ 504: Code.deadline_exceeded,
57
+ 505: Code.unimplemented,
58
+ }
59
+
60
+ return error_code_map.get(http_code, Code.unknown)
61
+
62
+
63
+ class ConnectException(Exception):
64
+ def __init__(self, status: Code, message: str):
65
+ self.status = status
66
+ self.message = message
67
+
68
+
69
+ envelope_header_length = 5
70
+ envelope_header_pack = ">BI"
71
+
72
+
73
+ def encode_envelope(*, flags: EnvelopeFlags, data):
74
+ return encode_envelope_header(flags=flags.value, data=data) + data
75
+
76
+
77
+ def encode_envelope_header(*, flags, data):
78
+ return struct.pack(envelope_header_pack, flags, len(data))
79
+
80
+
81
+ def decode_envelope_header(header):
82
+ flags, data_len = struct.unpack(envelope_header_pack, header)
83
+ return EnvelopeFlags(flags), data_len
84
+
85
+
86
+ def error_for_response(http_resp: Response):
87
+ try:
88
+ error = json.loads(http_resp.content)
89
+ return make_error(error)
90
+ except (json.decoder.JSONDecodeError, KeyError):
91
+ error = {"code": http_resp.status, "message": http_resp.content.decode("utf-8")}
92
+ return make_error(error)
93
+
94
+
95
+ def make_error(error):
96
+ status = None
97
+ try:
98
+ code_value = error.get("code")
99
+ # return error code from http status code
100
+ if isinstance(code_value, int):
101
+ status = make_error_from_http_code(code_value)
102
+ else:
103
+ status = Code(code_value)
104
+ except (KeyError, ValueError):
105
+ status = Code.unknown
106
+
107
+ return ConnectException(status, error.get("message", ""))
108
+
109
+
110
+ def _sync_retry(func, exc, retries):
111
+ def retry(*args, **kwargs):
112
+ for _ in range(retries):
113
+ try:
114
+ return func(*args, **kwargs)
115
+ except exc:
116
+ continue
117
+
118
+ return func(*args, **kwargs)
119
+
120
+ return retry
121
+
122
+
123
+ def _async_retry(func, exc, retries):
124
+ async def retry(*args, **kwargs):
125
+ for _ in range(retries):
126
+ try:
127
+ return await func(*args, **kwargs)
128
+ except exc:
129
+ continue
130
+
131
+ return await func(*args, **kwargs)
132
+
133
+ return retry
134
+
135
+
136
+ def _retry(exc: typing.Type[Exception], retries: int):
137
+ def decorator(func):
138
+ if inspect.iscoroutinefunction(func):
139
+ return _async_retry(func, exc, retries)
140
+
141
+ return _sync_retry(func, exc, retries)
142
+
143
+ return decorator
144
+
145
+
146
+ class GzipCompressor:
147
+ name = "gzip"
148
+ decompress = gzip.decompress
149
+ compress = gzip.compress
150
+
151
+
152
+ class JSONCodec:
153
+ content_type = "json"
154
+
155
+ @staticmethod
156
+ def encode(msg):
157
+ return json_format.MessageToJson(msg).encode("utf8")
158
+
159
+ @staticmethod
160
+ def decode(data, *, msg_type):
161
+ msg = msg_type()
162
+ json_format.Parse(data.decode("utf8"), msg, ignore_unknown_fields=True)
163
+ return msg
164
+
165
+
166
+ class ProtobufCodec:
167
+ content_type = "proto"
168
+
169
+ @staticmethod
170
+ def encode(msg):
171
+ return msg.SerializeToString()
172
+
173
+ @staticmethod
174
+ def decode(data, *, msg_type):
175
+ msg = msg_type()
176
+ msg.ParseFromString(data)
177
+ return msg
178
+
179
+
180
+ class Client:
181
+ def __init__(
182
+ self,
183
+ *,
184
+ pool: Optional[ConnectionPool] = None,
185
+ async_pool: Optional[AsyncConnectionPool] = None,
186
+ url: str,
187
+ response_type,
188
+ compressor=None,
189
+ json: Optional[bool] = False,
190
+ headers: Optional[Dict[str, str]] = None,
191
+ ):
192
+ if headers is None:
193
+ headers = {}
194
+
195
+ self.pool = pool
196
+ self.async_pool = async_pool
197
+ self.url = url
198
+ self._codec = JSONCodec if json else ProtobufCodec
199
+ self._response_type = response_type
200
+ self._compressor = compressor
201
+ self._headers = headers
202
+ self._connection_retries = 3
203
+
204
+ def _prepare_unary_request(
205
+ self,
206
+ req,
207
+ request_timeout=None,
208
+ headers: Optional[dict] = None,
209
+ **opts,
210
+ ) -> dict:
211
+ data = self._codec.encode(req)
212
+
213
+ if self._compressor is not None:
214
+ data = self._compressor.compress(data)
215
+
216
+ if headers is None:
217
+ headers = {}
218
+
219
+ extensions = (
220
+ None
221
+ if request_timeout is None
222
+ else {
223
+ "timeout": {
224
+ "connect": request_timeout,
225
+ "pool": request_timeout,
226
+ "read": request_timeout,
227
+ "write": request_timeout,
228
+ }
229
+ }
230
+ )
231
+
232
+ return {
233
+ "method": "POST",
234
+ "url": self.url,
235
+ "content": data,
236
+ "extensions": extensions,
237
+ "headers": {
238
+ **self._headers,
239
+ **headers,
240
+ **opts.get("headers", {}),
241
+ "connect-protocol-version": "1",
242
+ "content-encoding": (
243
+ "identity" if self._compressor is None else self._compressor.name
244
+ ),
245
+ "content-type": f"application/{self._codec.content_type}",
246
+ },
247
+ }
248
+
249
+ def _process_unary_response(
250
+ self,
251
+ http_resp: Response,
252
+ ):
253
+ if http_resp.status != 200:
254
+ raise error_for_response(http_resp)
255
+
256
+ content = http_resp.content
257
+
258
+ if self._compressor is not None:
259
+ content = self._compressor.decompress(content)
260
+
261
+ return self._codec.decode(
262
+ content,
263
+ msg_type=self._response_type,
264
+ )
265
+
266
+ @_retry(RemoteProtocolError, 3)
267
+ async def acall_unary(
268
+ self,
269
+ req,
270
+ request_timeout=None,
271
+ headers: Optional[dict] = None,
272
+ **opts,
273
+ ):
274
+ if self.async_pool is None:
275
+ raise ValueError("async_pool is required")
276
+
277
+ req_data = self._prepare_unary_request(
278
+ req,
279
+ request_timeout,
280
+ headers,
281
+ **opts,
282
+ )
283
+
284
+ res = await self.async_pool.request(**req_data)
285
+ return self._process_unary_response(res)
286
+
287
+ @_retry(RemoteProtocolError, 3)
288
+ def call_unary(
289
+ self,
290
+ req,
291
+ request_timeout=None,
292
+ headers: Optional[dict] = None,
293
+ **opts,
294
+ ):
295
+ if self.pool is None:
296
+ raise ValueError("pool is required")
297
+
298
+ req_data = self._prepare_unary_request(
299
+ req,
300
+ request_timeout,
301
+ headers,
302
+ **opts,
303
+ )
304
+
305
+ res = self.pool.request(**req_data)
306
+ return self._process_unary_response(res)
307
+
308
+ def _create_stream_timeout(self, timeout: Optional[int]):
309
+ if timeout:
310
+ return {"connect-timeout-ms": str(timeout * 1000)}
311
+ return {}
312
+
313
+ def _prepare_server_stream_request(
314
+ self,
315
+ req,
316
+ request_timeout=None,
317
+ timeout=None,
318
+ headers: Optional[dict] = None,
319
+ **opts,
320
+ ) -> dict:
321
+ headers = headers or {}
322
+ data = self._codec.encode(req)
323
+ flags = EnvelopeFlags(0)
324
+
325
+ extensions = (
326
+ None
327
+ if request_timeout is None
328
+ else {"timeout": {"connect": request_timeout, "pool": request_timeout}}
329
+ )
330
+
331
+ if self._compressor is not None:
332
+ data = self._compressor.compress(data)
333
+ flags |= EnvelopeFlags.compressed
334
+
335
+ stream_timeout = self._create_stream_timeout(timeout)
336
+
337
+ return {
338
+ "method": "POST",
339
+ "url": self.url,
340
+ "content": encode_envelope(
341
+ flags=flags,
342
+ data=data,
343
+ ),
344
+ "extensions": extensions,
345
+ "headers": {
346
+ **self._headers,
347
+ **headers,
348
+ **opts.get("headers", {}),
349
+ **stream_timeout,
350
+ "connect-protocol-version": "1",
351
+ "connect-content-encoding": (
352
+ "identity" if self._compressor is None else self._compressor.name
353
+ ),
354
+ "content-type": f"application/connect+{self._codec.content_type}",
355
+ },
356
+ }
357
+
358
+ @_retry(RemoteProtocolError, 3)
359
+ async def acall_server_stream(
360
+ self,
361
+ req,
362
+ request_timeout=None,
363
+ timeout=None,
364
+ headers: Optional[dict] = None,
365
+ **opts,
366
+ ):
367
+ if self.async_pool is None:
368
+ raise ValueError("async_pool is required")
369
+
370
+ req_data = self._prepare_server_stream_request(
371
+ req,
372
+ request_timeout,
373
+ timeout,
374
+ headers,
375
+ **opts,
376
+ )
377
+
378
+ parser = ServerStreamParser(
379
+ decode=self._codec.decode,
380
+ response_type=self._response_type,
381
+ )
382
+
383
+ async with self.async_pool.stream(**req_data) as http_resp:
384
+ if http_resp.status != 200:
385
+ await http_resp.aread()
386
+ raise error_for_response(http_resp)
387
+
388
+ async for chunk in http_resp.aiter_stream():
389
+ for parsed in parser.parse(chunk):
390
+ yield parsed
391
+
392
+ @_retry(RemoteProtocolError, 3)
393
+ def call_server_stream(
394
+ self,
395
+ req,
396
+ request_timeout=None,
397
+ timeout=None,
398
+ headers: Optional[dict] = None,
399
+ **opts,
400
+ ):
401
+ if self.pool is None:
402
+ raise ValueError("pool is required")
403
+
404
+ req_data = self._prepare_server_stream_request(
405
+ req,
406
+ request_timeout,
407
+ timeout,
408
+ headers,
409
+ **opts,
410
+ )
411
+
412
+ parser = ServerStreamParser(
413
+ decode=self._codec.decode,
414
+ response_type=self._response_type,
415
+ )
416
+
417
+ with self.pool.stream(**req_data) as http_resp:
418
+ if http_resp.status != 200:
419
+ http_resp.read()
420
+ raise error_for_response(http_resp)
421
+
422
+ for chunk in http_resp.iter_stream():
423
+ for parsed in parser.parse(chunk):
424
+ yield parsed
425
+
426
+ def call_client_stream(self, req, **opts):
427
+ raise NotImplementedError("client stream not supported")
428
+
429
+ def acall_client_stream(self, req, **opts):
430
+ raise NotImplementedError("client stream not supported")
431
+
432
+ def call_bidi_stream(self, req, **opts):
433
+ raise NotImplementedError("bidi stream not supported")
434
+
435
+ def acall_bidi_stream(self, req, **opts):
436
+ raise NotImplementedError("bidi stream not supported")
437
+
438
+
439
+ DataLen = int
440
+
441
+
442
+ class ServerStreamParser:
443
+ def __init__(
444
+ self,
445
+ decode: Callable,
446
+ response_type: Any,
447
+ ):
448
+ self.decode = decode
449
+ self.response_type = response_type
450
+
451
+ self.buffer: bytes = b""
452
+ self._header: Optional[tuple[EnvelopeFlags, DataLen]] = None
453
+
454
+ def shift_buffer(self, size: int):
455
+ buffer = self.buffer[:size]
456
+ self.buffer = self.buffer[size:]
457
+ return buffer
458
+
459
+ @property
460
+ def header(self) -> Tuple[EnvelopeFlags, DataLen]:
461
+ if self._header:
462
+ return self._header
463
+
464
+ header_data = self.shift_buffer(envelope_header_length)
465
+ self._header = decode_envelope_header(header_data)
466
+
467
+ return self._header
468
+
469
+ @header.deleter
470
+ def header(self):
471
+ self._header = None
472
+
473
+ def parse(self, chunk: bytes) -> Generator[Any, None, None]:
474
+ self.buffer += chunk
475
+
476
+ while len(self.buffer) >= envelope_header_length:
477
+ flags, data_len = self.header
478
+
479
+ if data_len > len(self.buffer):
480
+ break
481
+
482
+ data = self.shift_buffer(data_len)
483
+
484
+ if EnvelopeFlags.end_stream in flags:
485
+ data = json.loads(data)
486
+
487
+ if "error" in data:
488
+ raise make_error(data["error"])
489
+
490
+ return
491
+
492
+ yield self.decode(data, msg_type=self.response_type)
493
+ del self.header