nextmv 1.4.2.dev3__tar.gz → 1.6.0__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 (397) hide show
  1. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/PKG-INFO +2 -1
  2. nextmv-1.6.0/nextmv/__about__.py +1 -0
  3. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/logs.py +5 -6
  4. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/run/create.py +51 -1
  5. nextmv-1.6.0/nextmv/cli/local/run/logs.py +173 -0
  6. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_run.py +2 -2
  7. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/local/application.py +93 -1
  8. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/local/executor.py +110 -52
  9. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/local/runner.py +13 -1
  10. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/polling.py +2 -2
  11. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/pyproject.toml +2 -0
  12. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/local/test_executor.py +111 -48
  13. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_entrypoint/test_entrypoint.py +1 -1
  14. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_options.py +37 -34
  15. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/uv.lock +1128 -433
  16. nextmv-1.4.2.dev3/nextmv/__about__.py +0 -1
  17. nextmv-1.4.2.dev3/nextmv/cli/local/run/logs.py +0 -69
  18. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/.gitignore +0 -0
  19. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/.python-version +0 -0
  20. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/CONTRIBUTING.md +0 -0
  21. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/LICENSE +0 -0
  22. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/README.md +0 -0
  23. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/__entrypoint__.py +0 -0
  24. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/__init__.py +0 -0
  25. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/_serialization.py +0 -0
  26. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/account.py +0 -0
  27. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/base_model.py +0 -0
  28. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/__init__.py +0 -0
  29. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/__init__.py +0 -0
  30. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/acceptance/__init__.py +0 -0
  31. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/acceptance/create.py +0 -0
  32. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/acceptance/delete.py +0 -0
  33. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/acceptance/get.py +0 -0
  34. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/acceptance/list.py +0 -0
  35. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/acceptance/update.py +0 -0
  36. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/account/__init__.py +0 -0
  37. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/account/create.py +0 -0
  38. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/account/delete.py +0 -0
  39. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/account/get.py +0 -0
  40. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/account/update.py +0 -0
  41. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/app/__init__.py +0 -0
  42. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/app/create.py +0 -0
  43. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/app/delete.py +0 -0
  44. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/app/exists.py +0 -0
  45. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/app/get.py +0 -0
  46. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/app/list.py +0 -0
  47. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/app/push.py +0 -0
  48. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/app/update.py +0 -0
  49. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/batch/__init__.py +0 -0
  50. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/batch/create.py +0 -0
  51. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/batch/delete.py +0 -0
  52. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/batch/get.py +0 -0
  53. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/batch/list.py +0 -0
  54. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/batch/metadata.py +0 -0
  55. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/batch/update.py +0 -0
  56. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/data/__init__.py +0 -0
  57. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/data/upload.py +0 -0
  58. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/ensemble/__init__.py +0 -0
  59. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/ensemble/create.py +0 -0
  60. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/ensemble/delete.py +0 -0
  61. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/ensemble/get.py +0 -0
  62. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/ensemble/list.py +0 -0
  63. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/ensemble/update.py +0 -0
  64. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/input_set/__init__.py +0 -0
  65. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/input_set/create.py +0 -0
  66. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/input_set/delete.py +0 -0
  67. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/input_set/get.py +0 -0
  68. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/input_set/list.py +0 -0
  69. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/input_set/update.py +0 -0
  70. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/instance/__init__.py +0 -0
  71. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/instance/create.py +0 -0
  72. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/instance/delete.py +0 -0
  73. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/instance/exists.py +0 -0
  74. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/instance/get.py +0 -0
  75. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/instance/list.py +0 -0
  76. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/instance/update.py +0 -0
  77. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/managed_input/__init__.py +0 -0
  78. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/managed_input/create.py +0 -0
  79. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/managed_input/delete.py +0 -0
  80. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/managed_input/get.py +0 -0
  81. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/managed_input/list.py +0 -0
  82. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/managed_input/update.py +0 -0
  83. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/__init__.py +0 -0
  84. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/app/__init__.py +0 -0
  85. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/app/create.py +0 -0
  86. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/app/get.py +0 -0
  87. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/app/list.py +0 -0
  88. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/app/update.py +0 -0
  89. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/subscription/__init__.py +0 -0
  90. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/subscription/create.py +0 -0
  91. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/subscription/delete.py +0 -0
  92. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/subscription/get.py +0 -0
  93. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/subscription/list.py +0 -0
  94. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/version/__init__.py +0 -0
  95. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/version/create.py +0 -0
  96. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/version/get.py +0 -0
  97. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/version/list.py +0 -0
  98. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/marketplace/version/update.py +0 -0
  99. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/__init__.py +0 -0
  100. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/cancel.py +0 -0
  101. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/create.py +0 -0
  102. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/delete.py +0 -0
  103. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/get.py +0 -0
  104. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/input.py +0 -0
  105. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/list.py +0 -0
  106. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/metadata.py +0 -0
  107. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/run/track.py +0 -0
  108. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/scenario/__init__.py +0 -0
  109. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/scenario/create.py +0 -0
  110. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/scenario/delete.py +0 -0
  111. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/scenario/get.py +0 -0
  112. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/scenario/list.py +0 -0
  113. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/scenario/metadata.py +0 -0
  114. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/scenario/update.py +0 -0
  115. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/secrets/__init__.py +0 -0
  116. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/secrets/create.py +0 -0
  117. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/secrets/delete.py +0 -0
  118. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/secrets/get.py +0 -0
  119. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/secrets/list.py +0 -0
  120. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/secrets/update.py +0 -0
  121. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/__init__.py +0 -0
  122. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/create.py +0 -0
  123. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/delete.py +0 -0
  124. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/get.py +0 -0
  125. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/list.py +0 -0
  126. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/metadata.py +0 -0
  127. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/start.py +0 -0
  128. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/stop.py +0 -0
  129. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/shadow/update.py +0 -0
  130. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/__init__.py +0 -0
  131. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/create.py +0 -0
  132. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/delete.py +0 -0
  133. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/disable.py +0 -0
  134. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/domain/__init__.py +0 -0
  135. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/domain/delete.py +0 -0
  136. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/enable.py +0 -0
  137. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/get.py +0 -0
  138. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/sso/update.py +0 -0
  139. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/__init__.py +0 -0
  140. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/create.py +0 -0
  141. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/delete.py +0 -0
  142. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/get.py +0 -0
  143. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/list.py +0 -0
  144. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/metadata.py +0 -0
  145. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/start.py +0 -0
  146. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/stop.py +0 -0
  147. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/switchback/update.py +0 -0
  148. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/upload/__init__.py +0 -0
  149. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/upload/create.py +0 -0
  150. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/version/__init__.py +0 -0
  151. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/version/create.py +0 -0
  152. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/version/delete.py +0 -0
  153. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/version/exists.py +0 -0
  154. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/version/get.py +0 -0
  155. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/version/list.py +0 -0
  156. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/cloud/version/update.py +0 -0
  157. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/community/__init__.py +0 -0
  158. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/community/clone.py +0 -0
  159. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/community/list.py +0 -0
  160. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/configuration/__init__.py +0 -0
  161. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/configuration/config.py +0 -0
  162. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/configuration/create.py +0 -0
  163. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/configuration/delete.py +0 -0
  164. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/configuration/list.py +0 -0
  165. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/init.py +0 -0
  166. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/__init__.py +0 -0
  167. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/app/__init__.py +0 -0
  168. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/app/delete.py +0 -0
  169. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/app/get.py +0 -0
  170. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/app/list.py +0 -0
  171. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/app/register.py +0 -0
  172. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/app/registered.py +0 -0
  173. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/app/sync.py +0 -0
  174. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/app/update.py +0 -0
  175. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/run/__init__.py +0 -0
  176. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/run/get.py +0 -0
  177. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/run/input.py +0 -0
  178. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/run/list.py +0 -0
  179. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/run/metadata.py +0 -0
  180. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/local/run/visuals.py +0 -0
  181. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/main.py +0 -0
  182. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/manifest/__init__.py +0 -0
  183. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/manifest/init.py +0 -0
  184. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/manifest/validate.py +0 -0
  185. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/__init__.py +0 -0
  186. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/serve.py +0 -0
  187. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/server.py +0 -0
  188. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/WORKFLOW.md +0 -0
  189. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/__init__.py +0 -0
  190. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/_helpers.py +0 -0
  191. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/acceptance.py +0 -0
  192. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/account.py +0 -0
  193. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/app.py +0 -0
  194. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/batch.py +0 -0
  195. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/community.py +0 -0
  196. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/ensemble.py +0 -0
  197. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/guide.py +0 -0
  198. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/input_set.py +0 -0
  199. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/instance.py +0 -0
  200. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/local.py +0 -0
  201. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/managed_input.py +0 -0
  202. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/profile.py +0 -0
  203. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/run.py +0 -0
  204. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/scenario.py +0 -0
  205. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/secrets.py +0 -0
  206. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/shadow.py +0 -0
  207. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/sso.py +0 -0
  208. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/switchback.py +0 -0
  209. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/mcp/tools/version.py +0 -0
  210. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/message.py +0 -0
  211. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/options.py +0 -0
  212. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cli/version.py +0 -0
  213. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/__init__.py +0 -0
  214. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/acceptance_test.py +0 -0
  215. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/account.py +0 -0
  216. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/__init__.py +0 -0
  217. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_acceptance.py +0 -0
  218. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_batch_scenario.py +0 -0
  219. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_ensemble.py +0 -0
  220. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_input_set.py +0 -0
  221. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_instance.py +0 -0
  222. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_managed_input.py +0 -0
  223. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_secrets.py +0 -0
  224. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_shadow.py +0 -0
  225. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_switchback.py +0 -0
  226. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_utils.py +0 -0
  227. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/application/_version.py +0 -0
  228. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/assets.py +0 -0
  229. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/batch_experiment.py +0 -0
  230. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/client.py +0 -0
  231. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/community.py +0 -0
  232. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/ensemble.py +0 -0
  233. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/input_set.py +0 -0
  234. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/instance.py +0 -0
  235. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/integration.py +0 -0
  236. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/marketplace.py +0 -0
  237. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/package.py +0 -0
  238. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/scenario.py +0 -0
  239. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/secrets.py +0 -0
  240. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/shadow.py +0 -0
  241. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/sso.py +0 -0
  242. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/switchback.py +0 -0
  243. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/url.py +0 -0
  244. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/cloud/version.py +0 -0
  245. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/content_format.py +0 -0
  246. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/default_app/.gitignore +0 -0
  247. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/default_app/README.md +0 -0
  248. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/default_app/app.yaml +0 -0
  249. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/default_app/input.json +0 -0
  250. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/default_app/main.py +0 -0
  251. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/default_app/requirements.txt +0 -0
  252. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/default_app/src/__init__.py +0 -0
  253. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/default_app/src/visuals.py +0 -0
  254. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/deprecated.py +0 -0
  255. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/input.py +0 -0
  256. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/local/__init__.py +0 -0
  257. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/local/geojson_handler.py +0 -0
  258. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/local/local.py +0 -0
  259. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/local/plotly_handler.py +0 -0
  260. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/local/registry.py +0 -0
  261. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/logger.py +0 -0
  262. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/manifest.py +0 -0
  263. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/model.py +0 -0
  264. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/options.py +0 -0
  265. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/output.py +0 -0
  266. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/run.py +0 -0
  267. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/safe.py +0 -0
  268. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/status.py +0 -0
  269. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/binary_json_app.yaml +0 -0
  270. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/binary_multi-file_app.yaml +0 -0
  271. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_json_app.yaml +0 -0
  272. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_json_hello-world/.gitignore +0 -0
  273. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_json_hello-world/README.md +0 -0
  274. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_json_hello-world/app.yaml +0 -0
  275. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_json_hello-world/go.mod +0 -0
  276. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_json_hello-world/input.json +0 -0
  277. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_json_hello-world/main.go +0 -0
  278. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_multi-file_app.yaml +0 -0
  279. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_multi-file_hello-world/.gitignore +0 -0
  280. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_multi-file_hello-world/README.md +0 -0
  281. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_multi-file_hello-world/app.yaml +0 -0
  282. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_multi-file_hello-world/go.mod +0 -0
  283. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_multi-file_hello-world/inputs/input.json +0 -0
  284. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/go_multi-file_hello-world/main.go +0 -0
  285. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_json_app.yaml +0 -0
  286. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_json_hello-world/.gitignore +0 -0
  287. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_json_hello-world/Main.java +0 -0
  288. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_json_hello-world/README.md +0 -0
  289. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_json_hello-world/app.yaml +0 -0
  290. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_json_hello-world/input.json +0 -0
  291. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_json_hello-world/pom.xml +0 -0
  292. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_multi-file_app.yaml +0 -0
  293. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_multi-file_hello-world/.gitignore +0 -0
  294. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_multi-file_hello-world/Main.java +0 -0
  295. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_multi-file_hello-world/README.md +0 -0
  296. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_multi-file_hello-world/app.yaml +0 -0
  297. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_multi-file_hello-world/inputs/input.json +0 -0
  298. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/java_multi-file_hello-world/pom.xml +0 -0
  299. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_app.yaml +0 -0
  300. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_class-assign/.gitignore +0 -0
  301. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_class-assign/README.md +0 -0
  302. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_class-assign/app.yaml +0 -0
  303. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_class-assign/input.json +0 -0
  304. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_class-assign/main.py +0 -0
  305. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_class-assign/requirements.txt +0 -0
  306. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_class-assign/visualizations.py +0 -0
  307. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/.gitignore +0 -0
  308. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/README.md +0 -0
  309. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/allocation/README.md +0 -0
  310. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/allocation/app.yaml +0 -0
  311. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/allocation/input.json +0 -0
  312. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/allocation/main.py +0 -0
  313. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/allocation/requirements.txt +0 -0
  314. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/allocation/visuals.py +0 -0
  315. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/workflow/README.md +0 -0
  316. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/workflow/app.yaml +0 -0
  317. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/workflow/input.json +0 -0
  318. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/workflow/main.py +0 -0
  319. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/workflow/requirements.txt +0 -0
  320. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_demand-alloc/workflow/visuals.py +0 -0
  321. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_hello-world/.gitignore +0 -0
  322. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_hello-world/README.md +0 -0
  323. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_hello-world/app.yaml +0 -0
  324. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_hello-world/input.json +0 -0
  325. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_hello-world/main.py +0 -0
  326. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_json_hello-world/requirements.txt +0 -0
  327. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_app.yaml +0 -0
  328. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_class-assign/.gitignore +0 -0
  329. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_class-assign/README.md +0 -0
  330. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_class-assign/app.yaml +0 -0
  331. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_class-assign/inputs/input.json +0 -0
  332. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_class-assign/main.py +0 -0
  333. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_class-assign/requirements.txt +0 -0
  334. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_class-assign/visualizations.py +0 -0
  335. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/README.md +0 -0
  336. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/allocation/README.md +0 -0
  337. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/allocation/app.yaml +0 -0
  338. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/allocation/input.json +0 -0
  339. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/allocation/main.py +0 -0
  340. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/allocation/requirements.txt +0 -0
  341. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/allocation/visuals.py +0 -0
  342. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/workflow/.gitignore +0 -0
  343. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/workflow/README.md +0 -0
  344. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/workflow/app.yaml +0 -0
  345. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/workflow/inputs/input.json +0 -0
  346. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/workflow/main.py +0 -0
  347. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/workflow/requirements.txt +0 -0
  348. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_demand-alloc/workflow/visuals.py +0 -0
  349. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_hello-world/.gitignore +0 -0
  350. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_hello-world/README.md +0 -0
  351. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_hello-world/app.yaml +0 -0
  352. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_hello-world/inputs/input.json +0 -0
  353. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_hello-world/main.py +0 -0
  354. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/nextmv/templates/python_multi-file_hello-world/requirements.txt +0 -0
  355. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/__init__.py +0 -0
  356. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cli/__init__.py +0 -0
  357. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cli/test_configuration.py +0 -0
  358. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cli/test_main.py +0 -0
  359. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cli/test_mcp.py +0 -0
  360. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cli/test_version.py +0 -0
  361. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cloud/__init__.py +0 -0
  362. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cloud/app.yaml +0 -0
  363. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cloud/test_client.py +0 -0
  364. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cloud/test_instance.py +0 -0
  365. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cloud/test_package.py +0 -0
  366. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/cloud/test_scenario.py +0 -0
  367. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/integration/__init__.py +0 -0
  368. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/integration/cloud/__init__.py +0 -0
  369. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/integration/cloud/test_integration_cloud.py +0 -0
  370. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/integration/cloud/test_integration_marketplace.py +0 -0
  371. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/local/__init__.py +0 -0
  372. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/local/test_application.py +0 -0
  373. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/local/test_registry.py +0 -0
  374. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/local/test_runner.py +0 -0
  375. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/scripts/__init__.py +0 -0
  376. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/scripts/options1.py +0 -0
  377. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/scripts/options2.py +0 -0
  378. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/scripts/options3.py +0 -0
  379. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/scripts/options4.py +0 -0
  380. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/scripts/options5.py +0 -0
  381. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/scripts/options6.py +0 -0
  382. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/scripts/options7.py +0 -0
  383. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_base_model.py +0 -0
  384. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_entrypoint/__init__.py +0 -0
  385. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_input.py +0 -0
  386. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_inputs/test_data.csv +0 -0
  387. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_inputs/test_data.json +0 -0
  388. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_inputs/test_data.txt +0 -0
  389. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_logger.py +0 -0
  390. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_manifest.py +0 -0
  391. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_model.py +0 -0
  392. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_output.py +0 -0
  393. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_polling.py +0 -0
  394. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_run.py +0 -0
  395. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_safe.py +0 -0
  396. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_serialization.py +0 -0
  397. {nextmv-1.4.2.dev3 → nextmv-1.6.0}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextmv
3
- Version: 1.4.2.dev3
3
+ Version: 1.6.0
4
4
  Summary: The all-purpose Python SDK for Nextmv
5
5
  Project-URL: Homepage, https://www.nextmv.io
6
6
  Project-URL: Documentation, https://nextmv-py.docs.nextmv.io/en/latest/nextmv/
@@ -227,6 +227,7 @@ Requires-Dist: questionary>=2.1.1
227
227
  Requires-Dist: requests>=2.31.0
228
228
  Requires-Dist: typer>=0.20.1
229
229
  Requires-Dist: urllib3>=2.1.0
230
+ Requires-Dist: uv>=0.4.0
230
231
  Provides-Extra: mcp
231
232
  Requires-Dist: mcp[cli]>=1.0; extra == 'mcp'
232
233
  Provides-Extra: notebook
@@ -0,0 +1 @@
1
+ __version__ = "v1.6.0"
@@ -108,14 +108,13 @@ def handle_logs(
108
108
  """
109
109
  Handle retrieving and outputting logs from a run.
110
110
 
111
- If neither `tail` is True nor `logs` is specified, this function
112
- returns early without doing anything. Otherwise, logs are retrieved and
113
- optionally written to a file.
114
-
115
111
  When `tail` is True, logs are streamed in real-time to stderr as the run
116
112
  executes. When `logs` is specified (without tailing), the function waits
117
- for the run to complete and then fetches all logs at once. In both cases,
118
- if a `logs` file path is provided, the logs are persisted to that file.
113
+ for the run to complete and then fetches all logs at once. When neither
114
+ `tail` is True nor `file_output` is set, logs are fetched immediately and
115
+ printed to stderr without waiting for the run to complete. In all cases
116
+ where `tail` is True or `logs` is specified, if a `logs` file path is
117
+ provided, the logs are persisted to that file.
119
118
 
120
119
  Parameters
121
120
  ----------
@@ -11,6 +11,7 @@ import typer
11
11
 
12
12
  from nextmv.cli.configuration.config import build_local_app
13
13
  from nextmv.cli.local.run.get import handle_outputs
14
+ from nextmv.cli.local.run.logs import handle_logs
14
15
  from nextmv.cli.message import enum_values, error, print_json, success
15
16
  from nextmv.cli.options import LocalAppIDOption, LocalAppSrcOption
16
17
  from nextmv.input import InputFormat
@@ -39,6 +40,16 @@ def create(
39
40
  ),
40
41
  ] = None,
41
42
  # Options for controlling output.
43
+ logs: Annotated[
44
+ str | None,
45
+ typer.Option(
46
+ "--logs",
47
+ "-l",
48
+ help="Waits for the run to complete and saves the logs to this location.",
49
+ metavar="LOGS_PATH",
50
+ rich_help_panel="Output control",
51
+ ),
52
+ ] = None,
42
53
  output: Annotated[
43
54
  str | None,
44
55
  typer.Option(
@@ -50,6 +61,16 @@ def create(
50
61
  rich_help_panel="Output control",
51
62
  ),
52
63
  ] = None,
64
+ tail: Annotated[
65
+ bool,
66
+ typer.Option(
67
+ "--tail",
68
+ "-t",
69
+ help="Tail the logs until the run completes. Logs are streamed to [magenta]stderr[/magenta]. "
70
+ "Specify log output location with --logs.",
71
+ rich_help_panel="Output control",
72
+ ),
73
+ ] = False,
53
74
  wait: Annotated[
54
75
  bool,
55
76
  typer.Option(
@@ -134,6 +155,10 @@ def create(
134
155
  specify a destination (file or dir) for the output, depending on the
135
156
  content type.
136
157
 
158
+ Use the --tail flag to stream logs to [magenta]stderr[/magenta] until the
159
+ run completes. Using the --logs flag will also activate waiting, and allows
160
+ you to specify a file to write the logs to.
161
+
137
162
  [bold][underline]Examples[/underline][/bold]
138
163
 
139
164
  - Read a [magenta]json[/magenta] input via [magenta]stdin[/magenta], from an [magenta]input.json[/magenta] file,
@@ -149,11 +174,28 @@ def create(
149
174
  Wait for the run to complete and print the result to [magenta]stdout[/magenta].
150
175
  $ [dim]nextmv local run create --app-src ./my-app --input input.json --wait[/dim]
151
176
 
177
+ - Read a [magenta]json[/magenta] input from an [magenta]input.json[/magenta] file, and
178
+ create a run for an app at path [magenta]./my-app[/magenta].
179
+ Tail the run's logs, streaming to [magenta]stderr[/magenta].
180
+ $ [dim]nextmv local run create --app-src ./my-app --input input.json --tail[/dim]
181
+
152
182
  - Read a [magenta]json[/magenta] input from an [magenta]input.json[/magenta] file, and
153
183
  create a run for an app with ID [magenta]hare-app[/magenta].
154
184
  Wait for the run to complete and write the result to an [magenta]output.json[/magenta] file.
155
185
  $ [dim]nextmv local run create --app-id hare-app --input input.json --output output.json[/dim]
156
186
 
187
+ - Read a [magenta]json[/magenta] input from an [magenta]input.json[/magenta] file, and
188
+ create a run for an app with ID [magenta]hare-app[/magenta].
189
+ Wait for the run to complete, and write the logs to a [magenta]logs.log[/magenta] file.
190
+ $ [dim]nextmv local run create --app-id hare-app --input input.json --logs logs.log[/dim]
191
+
192
+ - Read a [magenta]json[/magenta] input from an [magenta]input.json[/magenta] file, and create a run for an app at
193
+ path [magenta]./my-app[/magenta]. Wait for the run to complete. Tail the run's logs, streaming to
194
+ [magenta]stderr[/magenta]. Write the logs to a [magenta]logs.log[/magenta] file. Write the result to an
195
+ [magenta]output.json[/magenta] file.
196
+ $ [dim]nextmv local run create --app-src ./my-app --input input.json --tail --logs logs.log \\
197
+ --output output.json[/dim]
198
+
157
199
  - Read a [magenta]multi-file[/magenta] input from an [magenta]inputs[/magenta] directory, and
158
200
  create a run for an app at path [magenta]./my-app[/magenta].
159
201
  $ [dim]nextmv local run create --app-src ./my-app --input inputs --content-format multi-file[/dim]
@@ -196,7 +238,7 @@ def create(
196
238
  )
197
239
 
198
240
  # If we don't need to poll at all we are done.
199
- if not wait and output is None:
241
+ if not wait and not tail and output is None and logs is None:
200
242
  print_json({"run_id": run_id})
201
243
 
202
244
  return
@@ -209,6 +251,14 @@ def create(
209
251
 
210
252
  # Handle what happens after the run is created for logging and result
211
253
  # retrieval.
254
+ handle_logs(
255
+ local_app=local_app,
256
+ run_id=run_id,
257
+ tail=tail,
258
+ logs=logs,
259
+ polling_options=polling_options,
260
+ file_output=True,
261
+ )
212
262
  handle_outputs(
213
263
  local_app=local_app,
214
264
  run_id=run_id,
@@ -0,0 +1,173 @@
1
+ """
2
+ This module defines the local run logs command for the Nextmv CLI.
3
+ """
4
+
5
+ import sys
6
+ from pathlib import Path
7
+ from typing import Annotated
8
+
9
+ import rich
10
+ import typer
11
+
12
+ from nextmv.cli.configuration.config import build_local_app
13
+ from nextmv.cli.message import in_progress, success
14
+ from nextmv.cli.options import LocalAppIDOption, LocalAppSrcOption, RunIDOption
15
+ from nextmv.local.application import Application
16
+ from nextmv.polling import PollingOptions, default_polling_options
17
+
18
+ # Set up subcommand application.
19
+ app = typer.Typer()
20
+
21
+
22
+ @app.command()
23
+ def logs(
24
+ run_id: RunIDOption,
25
+ app_id: LocalAppIDOption = None,
26
+ app_src: LocalAppSrcOption = ".",
27
+ output: Annotated[
28
+ str | None,
29
+ typer.Option(
30
+ "--output",
31
+ "-o",
32
+ help="Waits for the run to complete and saves the logs to this location.",
33
+ metavar="OUTPUT_PATH",
34
+ ),
35
+ ] = None,
36
+ tail: Annotated[
37
+ bool,
38
+ typer.Option(
39
+ "--tail",
40
+ "-t",
41
+ help="Tail the logs until the run completes. Logs are streamed to [magenta]stderr[/magenta]. "
42
+ "Specify log output location with --output.",
43
+ ),
44
+ ] = False,
45
+ timeout: Annotated[
46
+ int,
47
+ typer.Option(
48
+ help="The maximum time in seconds to wait for results when polling. Poll indefinitely if not set.",
49
+ metavar="TIMEOUT_SECONDS",
50
+ ),
51
+ ] = -1,
52
+ ) -> None:
53
+ """
54
+ Get the logs of a local application run.
55
+
56
+ You may identify the app by using --app-src, or --app-id if it has been
57
+ registered. If the app is not already registered, this command will
58
+ register it.
59
+
60
+ By default, the logs are fetched and printed to [magenta]stderr[/magenta].
61
+ Use the --tail flag to stream logs to [magenta]stderr[/magenta] until the
62
+ run completes. Using the --output flag will also activate waiting, and
63
+ allows you to specify a file to write the logs to.
64
+
65
+ [bold][underline]Examples[/underline][/bold]
66
+
67
+ - Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
68
+ [magenta]hare-app[/magenta]. Logs are printed to [magenta]stderr[/magenta].
69
+ $ [dim]nextmv local run logs --app-id hare-app --run-id burrow-123[/dim]
70
+
71
+ - Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
72
+ [magenta]hare-app[/magenta]. Tail the logs until the run completes.
73
+ $ [dim]nextmv local run logs --app-id hare-app --run-id burrow-123 --tail[/dim]
74
+
75
+ - Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
76
+ [magenta]hare-app[/magenta]. Save the logs to a [magenta]logs.log[/magenta] file.
77
+ $ [dim]nextmv local run logs --app-id hare-app --run-id burrow-123 --output logs.log[/dim]
78
+
79
+ - Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with ID
80
+ [magenta]hare-app[/magenta]. Tail the logs and save them to a [magenta]logs.log[/magenta] file.
81
+ $ [dim]nextmv local run logs --app-id hare-app --run-id burrow-123 --tail --output logs.log[/dim]
82
+
83
+ - Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with source path
84
+ [magenta]./my-app[/magenta].
85
+ $ [dim]nextmv local run logs --app-src ./my-app --run-id burrow-123[/dim]
86
+
87
+ - Get the logs of a run with ID [magenta]burrow-123[/magenta], belonging to an app with source path
88
+ [magenta]./my-app[/magenta]. Set a timeout of [magenta]60[/magenta] seconds.
89
+ $ [dim]nextmv local run logs --app-src ./my-app --run-id burrow-123 --timeout 60[/dim]
90
+ """
91
+
92
+ local_app = build_local_app(app_src, app_id)
93
+
94
+ # Build the polling options.
95
+ polling_options = default_polling_options()
96
+ polling_options.max_duration = timeout
97
+
98
+ handle_logs(
99
+ local_app=local_app,
100
+ run_id=run_id,
101
+ tail=tail,
102
+ logs=output,
103
+ polling_options=polling_options,
104
+ file_output=output is not None,
105
+ )
106
+
107
+
108
+ def handle_logs(
109
+ local_app: Application,
110
+ run_id: str,
111
+ tail: bool,
112
+ logs: str | None,
113
+ polling_options: PollingOptions,
114
+ file_output: bool,
115
+ ) -> None:
116
+ """
117
+ Handle retrieving and outputting logs from a run.
118
+
119
+ When `tail` is True, logs are streamed in real-time to stderr as the run
120
+ executes. When `logs` is specified (without tailing), the function waits
121
+ for the run to complete and then fetches all logs at once. When neither
122
+ `tail` is True nor `file_output` is set, logs are fetched immediately and
123
+ printed to stderr without waiting for the run to complete. In all cases
124
+ where `tail` is True or `logs` is specified, if a `logs` file path is
125
+ provided, the logs are persisted to that file.
126
+
127
+ Parameters
128
+ ----------
129
+ local_app : Application
130
+ The local application instance used to interact with the Nextmv Local
131
+ API.
132
+ run_id : str
133
+ The unique identifier of the run to retrieve logs for.
134
+ tail : bool
135
+ If True, streams logs in real-time to stderr as the run executes.
136
+ logs : str | None
137
+ The file path where logs should be written. If None, logs are only
138
+ displayed to stderr (when tailing) and not persisted to a file.
139
+ polling_options : PollingOptions
140
+ Configuration options for polling behavior, including timeout and
141
+ interval settings.
142
+ file_output : bool
143
+ Indicates whether logs should be written to a file. If False, logs are
144
+ only printed to stderr, no matter the status of the run.
145
+ """
146
+
147
+ if tail:
148
+ in_progress(msg="Tailing logs...")
149
+ fetched_logs = local_app.run_logs_with_polling(
150
+ run_id=run_id,
151
+ polling_options=polling_options,
152
+ verbose=True,
153
+ rich_print=True,
154
+ )
155
+ if logs is None:
156
+ return
157
+
158
+ log_content = "\n".join(log_entry for log_entry in fetched_logs)
159
+ elif logs is not None and logs != "" and file_output:
160
+ in_progress(msg="Getting run logs...")
161
+ local_app.run_result_with_polling(run_id=run_id, polling_options=polling_options)
162
+ run_logs = local_app.run_logs(run_id=run_id)
163
+ log_content = run_logs
164
+ elif not file_output:
165
+ in_progress(msg="Getting run logs...")
166
+ run_logs = local_app.run_logs(run_id=run_id)
167
+ rich.print(run_logs, file=sys.stderr)
168
+ return
169
+ else:
170
+ return
171
+
172
+ Path(logs).write_text(log_content)
173
+ success(f"Run logs written to [magenta]{logs}[/magenta].")
@@ -824,7 +824,7 @@ class ApplicationRunMixin:
824
824
 
825
825
  Examples
826
826
  --------
827
- >>> from nextmv.cloud import PollingOptions
827
+ >>> from nextmv import PollingOptions
828
828
  >>> # Create custom polling options
829
829
  >>> polling_opts = PollingOptions(max_tries=50, max_duration=600)
830
830
  >>> # Get run logs with polling
@@ -1058,7 +1058,7 @@ class ApplicationRunMixin:
1058
1058
 
1059
1059
  Examples
1060
1060
  --------
1061
- >>> from nextmv.cloud import PollingOptions
1061
+ >>> from nextmv import PollingOptions
1062
1062
  >>> # Create custom polling options
1063
1063
  >>> polling_opts = PollingOptions(max_tries=50, max_duration=600)
1064
1064
  >>> # Get run result with polling
@@ -16,6 +16,7 @@ import shutil
16
16
  import sys
17
17
  import tempfile
18
18
  import webbrowser
19
+ from collections.abc import Callable
19
20
  from datetime import datetime, timezone
20
21
  from typing import Any
21
22
 
@@ -853,6 +854,97 @@ class Application(BaseModel):
853
854
 
854
855
  return logs
855
856
 
857
+ def run_logs_with_polling(
858
+ self,
859
+ run_id: str,
860
+ verbose: bool = False,
861
+ rich_print: bool = False,
862
+ polling_options: PollingOptions = DEFAULT_POLLING_OPTIONS,
863
+ log_func: Callable[[str], None] | None = None,
864
+ ) -> list[str]:
865
+ """
866
+ Get the logs of a local run with polling.
867
+
868
+ Retrieves the logs of a run. This method polls for the logs until the
869
+ run finishes executing or the polling strategy is exhausted. It is the
870
+ "real-time" equivalent of the `run_logs` method. After the polling is
871
+ done, all the logs are returned as a list of strings (one per line).
872
+ You can use the `verbose` parameter to print the logs as they are
873
+ obtained during the polling process. You can also use the `rich_print`
874
+ parameter to enable rich printing for better formatting of the logs.
875
+
876
+ Parameters
877
+ ----------
878
+ run_id : str
879
+ ID of the run to retrieve the logs for.
880
+ verbose : bool, default=False
881
+ Whether to print the logs as they are obtained during the polling
882
+ process.
883
+ rich_print : bool, default=False
884
+ Whether to use rich printing for better formatting of the logs.
885
+ polling_options : PollingOptions, default=DEFAULT_POLLING_OPTIONS
886
+ Options to use when polling for the run logs.
887
+ log_func : Optional[Callable[[str], None]], default=None
888
+ Optional custom logging function callback. This function is invoked
889
+ independently of the `verbose` flag. It needs to take a `str` as
890
+ its argument and return `None`.
891
+
892
+ Returns
893
+ -------
894
+ list[str]
895
+ List of log lines of the run.
896
+
897
+ Raises
898
+ ------
899
+ TimeoutError
900
+ If the run does not complete after the polling strategy is
901
+ exhausted based on time duration.
902
+ RuntimeError
903
+ If the run does not complete after the polling strategy is
904
+ exhausted based on number of tries.
905
+
906
+ Examples
907
+ --------
908
+ >>> from nextmv import PollingOptions
909
+ >>> polling_opts = PollingOptions(max_tries=50, max_duration=600)
910
+ >>> logs = app.run_logs_with_polling("run-123", polling_opts)
911
+ >>> for line in logs:
912
+ ... print(line)
913
+ Starting optimization...
914
+ Found initial solution
915
+ """
916
+
917
+ all_logs: list[str] = []
918
+ lines_seen = 0
919
+
920
+ def polling_func() -> tuple[Any, bool]:
921
+ nonlocal lines_seen
922
+
923
+ # Check if the run has finalized. If so, all logs are guaranteed
924
+ # to have been flushed to the file before this check returned.
925
+ run_information = self.run_metadata(run_id=run_id)
926
+ is_done = run_information.metadata.run_is_finalized()
927
+
928
+ # Read the current log file contents and emit only new lines.
929
+ log_contents = self.run_logs(run_id)
930
+ current_lines = log_contents.splitlines() if log_contents else []
931
+ for line in current_lines[lines_seen:]:
932
+ if log_func is not None:
933
+ log_func(line)
934
+ if verbose:
935
+ if rich_print:
936
+ rich.print(line, file=sys.stderr)
937
+ else:
938
+ log(line)
939
+ all_logs.append(line)
940
+ lines_seen = len(current_lines)
941
+
942
+ return all_logs, is_done
943
+
944
+ all_logs = poll(polling_options=polling_options, polling_func=polling_func)
945
+
946
+ return all_logs
947
+
856
948
  def run_metadata(self, run_id: str) -> RunInformation:
857
949
  """
858
950
  Get the metadata of a local run.
@@ -1002,7 +1094,7 @@ class Application(BaseModel):
1002
1094
 
1003
1095
  Examples
1004
1096
  --------
1005
- >>> from nextmv.cloud import PollingOptions
1097
+ >>> from nextmv import PollingOptions
1006
1098
  >>> # Create custom polling options
1007
1099
  >>> polling_opts = PollingOptions(max_tries=50, max_duration=600)
1008
1100
  >>> # Get run result with polling
@@ -20,8 +20,6 @@ resolve_output_format
20
20
  Function to determine the output format from manifest or directory structure.
21
21
  process_run_information
22
22
  Function to update run metadata including duration and status.
23
- process_run_logs
24
- Function to process and save run logs.
25
23
  process_run_metrics
26
24
  Function to process and save run metrics.
27
25
  process_run_statistics
@@ -43,6 +41,7 @@ import shutil
43
41
  import subprocess
44
42
  import sys
45
43
  import tempfile
44
+ import threading
46
45
  from datetime import datetime, timezone
47
46
  from typing import Any
48
47
 
@@ -159,16 +158,100 @@ def execute_run(
159
158
  cwd = __determine_cwd(manifest, default=temp_src)
160
159
  args = __determine_command(manifest) + [entrypoint] + options_args(options)
161
160
 
162
- result = subprocess.run(
161
+ # Determine whether stdout should be streamed live to the log file.
162
+ # For MULTI_FILE format, stdout carries log output and must be streamed
163
+ # immediately. For other formats (JSON, CSV_ARCHIVE), stdout carries
164
+ # structured output consumed after the process completes.
165
+ is_multi_file = (
166
+ manifest.configuration is not None
167
+ and manifest.configuration.content is not None
168
+ and manifest.configuration.content.format == InputFormat.MULTI_FILE
169
+ ) or run_config["format"]["input"]["type"] == InputFormat.MULTI_FILE.value
170
+
171
+ log_file_path = os.path.join(logs_dir, LOGS_FILE)
172
+ stdout_lines: list[str] = []
173
+ stderr_lines: list[str] = []
174
+
175
+ # Force unbuffered stdout/stderr in child processes so both
176
+ # streams are written to the log file in real time.
177
+ child_env = os.environ.copy()
178
+ child_env["PYTHONUNBUFFERED"] = "1"
179
+
180
+ # This is the process that actually executes the entrypoint script.
181
+ # We use subprocess.Popen instead of subprocess.run because we need
182
+ # to stream the output in real time, which is not possible with
183
+ # subprocess.run.
184
+ process = subprocess.Popen(
163
185
  args,
164
- env=os.environ,
165
- check=False,
186
+ env=child_env,
166
187
  text=True,
167
- capture_output=True,
168
- input=stdin_input,
188
+ stdin=subprocess.PIPE,
189
+ stdout=subprocess.PIPE,
190
+ stderr=subprocess.PIPE,
169
191
  cwd=cwd,
170
192
  )
171
193
 
194
+ def write_stdin() -> None:
195
+ # Write all input at once then close so the child process receives EOF.
196
+ process.stdin.write(stdin_input)
197
+ process.stdin.close()
198
+
199
+ # A lock to serialize writes from the stdout and stderr threads so log
200
+ # lines are never interleaved in the log file.
201
+ log_lock = threading.Lock()
202
+ log_f = open(log_file_path, "a")
203
+
204
+ def stream_stderr() -> None:
205
+ # Stderr is always streamed live to the log file so errors appear
206
+ # immediately even if the process is still running.
207
+ for line in process.stderr:
208
+ with log_lock:
209
+ log_f.write(line)
210
+ log_f.flush()
211
+ stderr_lines.append(line)
212
+
213
+ def stream_stdout() -> None:
214
+ # For multi-file runs, stdout carries log output, so mirror it to
215
+ # the log file in real time just like stderr. For other formats,
216
+ # stdout carries the structured result and is only buffered.
217
+ if is_multi_file:
218
+ for line in process.stdout:
219
+ with log_lock:
220
+ log_f.write(line)
221
+ log_f.flush()
222
+ stdout_lines.append(line)
223
+ else:
224
+ for line in process.stdout:
225
+ stdout_lines.append(line)
226
+
227
+ # Run stdin, stdout, and stderr on separate threads so no single pipe
228
+ # can fill its OS buffer and block the process while another pipe waits,
229
+ # which would cause a deadlock.
230
+ stdin_thread = threading.Thread(target=write_stdin)
231
+ stderr_thread = threading.Thread(target=stream_stderr)
232
+ stdout_thread = threading.Thread(target=stream_stdout)
233
+
234
+ stdin_thread.start()
235
+ stderr_thread.start()
236
+ stdout_thread.start()
237
+
238
+ # Wait for all streams to be fully consumed before calling process.wait()
239
+ # to ensure no output is lost.
240
+ stdin_thread.join()
241
+ stderr_thread.join()
242
+ stdout_thread.join()
243
+ process.wait()
244
+ log_f.close()
245
+
246
+ # Assemble a CompletedProcess so the rest of the pipeline can treat this
247
+ # the same as a synchronous subprocess.run() result.
248
+ result = subprocess.CompletedProcess(
249
+ args=args,
250
+ returncode=process.returncode,
251
+ stdout="".join(stdout_lines),
252
+ stderr="".join(stderr_lines),
253
+ )
254
+
172
255
  process_run_output(
173
256
  manifest=manifest,
174
257
  run_id=run_id,
@@ -344,12 +427,6 @@ def process_run_output(
344
427
  run_dir=run_dir,
345
428
  result=result,
346
429
  )
347
- process_run_logs(
348
- output_format=output_format,
349
- run_dir=run_dir,
350
- result=result,
351
- stdout_output=stdout_output,
352
- )
353
430
  process_run_metrics(
354
431
  temp_run_outputs_dir=temp_run_outputs_dir,
355
432
  outputs_dir=outputs_dir,
@@ -472,44 +549,6 @@ def process_run_information(run_id: str, run_dir: str, result: subprocess.Comple
472
549
  json.dump(info, f, indent=2)
473
550
 
474
551
 
475
- def process_run_logs(
476
- output_format: OutputFormat,
477
- run_dir: str,
478
- result: subprocess.CompletedProcess[str],
479
- stdout_output: str | dict[str, Any],
480
- ) -> None:
481
- """
482
- Processes the logs of the run. Writes the logs to a logs directory.
483
- For multi-file format, stdout is written to logs if present.
484
-
485
- Parameters
486
- ----------
487
- output_format : OutputFormat
488
- The output format of the run (JSON, CSV_ARCHIVE, or MULTI_FILE).
489
- run_dir : str
490
- The path to the run directory where logs will be stored.
491
- result : subprocess.CompletedProcess[str]
492
- The result of the subprocess run containing stderr output.
493
- stdout_output : Union[str, dict[str, Any]]
494
- The stdout output of the run, either as raw string or parsed dictionary.
495
- """
496
-
497
- logs_dir = os.path.join(run_dir, LOGS_KEY)
498
- os.makedirs(logs_dir, exist_ok=True)
499
- std_err = result.stderr
500
- with open(os.path.join(logs_dir, LOGS_FILE), "w") as f:
501
- if output_format == OutputFormat.MULTI_FILE and bool(stdout_output):
502
- if isinstance(stdout_output, dict):
503
- f.write(json.dumps(stdout_output))
504
- elif isinstance(stdout_output, str):
505
- f.write(stdout_output)
506
-
507
- if std_err:
508
- f.write("\n")
509
-
510
- f.write(std_err)
511
-
512
-
513
552
  def process_run_metrics(
514
553
  temp_run_outputs_dir: str,
515
554
  outputs_dir: str,
@@ -1096,7 +1135,26 @@ def __determine_command(manifest: Manifest) -> list[str]:
1096
1135
  The command prefix to use for execution. Empty list for binary executables.
1097
1136
  """
1098
1137
  if manifest.type == ManifestType.PYTHON:
1099
- return [sys.executable]
1138
+ if manifest.python and manifest.python.pip_requirements:
1139
+ if isinstance(manifest.python.pip_requirements, list):
1140
+ return [
1141
+ sys.executable,
1142
+ "-m",
1143
+ "uv",
1144
+ "run",
1145
+ "--with",
1146
+ ",".join(manifest.python.pip_requirements),
1147
+ ]
1148
+ elif isinstance(manifest.python.pip_requirements, str):
1149
+ return [
1150
+ sys.executable,
1151
+ "-m",
1152
+ "uv",
1153
+ "run",
1154
+ "--with-requirements",
1155
+ manifest.python.pip_requirements,
1156
+ ]
1157
+ return [sys.executable, "-m", "uv", "run"]
1100
1158
  elif manifest.type == ManifestType.GO:
1101
1159
  return []
1102
1160
  elif manifest.type == ManifestType.BINARY: