datajunction 0.0.235__tar.gz → 0.0.237__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 (184) hide show
  1. {datajunction-0.0.235 → datajunction-0.0.237}/PKG-INFO +1 -1
  2. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/__about__.py +1 -1
  3. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/cli.py +10 -3
  4. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/deployment.py +35 -25
  5. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_cli.py +22 -0
  6. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_deploy.py +127 -0
  7. {datajunction-0.0.235 → datajunction-0.0.237}/.coveragerc +0 -0
  8. {datajunction-0.0.235 → datajunction-0.0.237}/.gitignore +0 -0
  9. {datajunction-0.0.235 → datajunction-0.0.237}/.pre-commit-config.yaml +0 -0
  10. {datajunction-0.0.235 → datajunction-0.0.237}/LICENSE.txt +0 -0
  11. {datajunction-0.0.235 → datajunction-0.0.237}/Makefile +0 -0
  12. {datajunction-0.0.235 → datajunction-0.0.237}/README.md +0 -0
  13. {datajunction-0.0.235 → datajunction-0.0.237}/claude_desktop_config.example.json +0 -0
  14. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/__init__.py +0 -0
  15. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/_base.py +0 -0
  16. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/_internal.py +0 -0
  17. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/admin.py +0 -0
  18. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/builder.py +0 -0
  19. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/client.py +0 -0
  20. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/compile.py +0 -0
  21. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/exceptions.py +0 -0
  22. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/mcp/__init__.py +0 -0
  23. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/mcp/cli.py +0 -0
  24. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/mcp/config.py +0 -0
  25. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/models.py +0 -0
  26. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/nodes.py +0 -0
  27. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/rendering.py +0 -0
  28. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/init_system_nodes.py +0 -0
  29. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/date.yaml +0 -0
  30. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/deployment.yaml +0 -0
  31. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/dimension_link.yaml +0 -0
  32. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/distinct_node_authors.yaml +0 -0
  33. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/distinct_node_editors.yaml +0 -0
  34. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/dj.yaml +0 -0
  35. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/is_active.yaml +0 -0
  36. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/materialization.yaml +0 -0
  37. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/median_deployment_duration_seconds.yaml +0 -0
  38. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/median_dim_links_per_node.yaml +0 -0
  39. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/median_dimension_indegree.yaml +0 -0
  40. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/median_downstream_count.yaml +0 -0
  41. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/median_revisions_per_node.yaml +0 -0
  42. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/median_upstream_count.yaml +0 -0
  43. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/namespace.yaml +0 -0
  44. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/node_revision.yaml +0 -0
  45. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/node_type.yaml +0 -0
  46. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/nodes.yaml +0 -0
  47. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/number_of_branches.yaml +0 -0
  48. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/number_of_deployments.yaml +0 -0
  49. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/number_of_materializations.yaml +0 -0
  50. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/number_of_namespaces.yaml +0 -0
  51. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/number_of_nodes.yaml +0 -0
  52. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/number_of_orphan_nodes.yaml +0 -0
  53. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/number_of_unused_dimensions.yaml +0 -0
  54. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/repo.yaml +0 -0
  55. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/seed/nodes/user.yaml +0 -0
  56. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/skills/datajunction/SKILL.md +0 -0
  57. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/skills/datajunction-api/SKILL.md +0 -0
  58. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/skills/datajunction-query/SKILL.md +0 -0
  59. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/skills/datajunction-repo/SKILL.md +0 -0
  60. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/skills/datajunction-semantic-model/SKILL.md +0 -0
  61. {datajunction-0.0.235 → datajunction-0.0.237}/datajunction/tags.py +0 -0
  62. {datajunction-0.0.235 → datajunction-0.0.237}/pyproject.toml +0 -0
  63. {datajunction-0.0.235 → datajunction-0.0.237}/setup.cfg +0 -0
  64. {datajunction-0.0.235 → datajunction-0.0.237}/tests/__init__.py +0 -0
  65. {datajunction-0.0.235 → datajunction-0.0.237}/tests/conftest.py +0 -0
  66. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/deploy0/dj.yaml +0 -0
  67. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/deploy0/roads/companies.yaml +0 -0
  68. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/deploy0/roads/companies_dim.yaml +0 -0
  69. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/deploy0/roads/contractor.yaml +0 -0
  70. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/deploy0/roads/contractors.yaml +0 -0
  71. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/deploy0/roads/us_state.yaml +0 -0
  72. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/deploy0/roads/us_states.yaml +0 -0
  73. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/dj.yaml +0 -0
  74. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/avg_length_of_employment.metric.yaml +0 -0
  75. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/avg_repair_price.metric.yaml +0 -0
  76. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/avg_time_to_dispatch.metric.yaml +0 -0
  77. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/contractor.dimension.yaml +0 -0
  78. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/contractors.source.yaml +0 -0
  79. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/date.source.yaml +0 -0
  80. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/date_dim.dimension.yaml +0 -0
  81. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/dispatcher.dimension.yaml +0 -0
  82. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/dispatchers.source.yaml +0 -0
  83. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/hard_hat.dimension.yaml +0 -0
  84. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/hard_hat_state.source.yaml +0 -0
  85. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/hard_hats.source.yaml +0 -0
  86. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/local_hard_hats.dimension.yaml +0 -0
  87. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/municipality.source.yaml +0 -0
  88. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/municipality_dim.dimension.yaml +0 -0
  89. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/municipality_municipality_type.source.yaml +0 -0
  90. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/municipality_type.source.yaml +0 -0
  91. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/national_level_agg.transform.yaml +0 -0
  92. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/num_repair_orders.metric.yaml +0 -0
  93. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/regional_level_agg.transform.yaml +0 -0
  94. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/regional_repair_efficiency.metric.yaml +0 -0
  95. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/repair_order.dimension.yaml +0 -0
  96. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/repair_order_details.source.yaml +0 -0
  97. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/repair_order_transform.transform.yaml +0 -0
  98. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/repair_orders.source.yaml +0 -0
  99. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/repair_orders_cube.cube.yaml +0 -0
  100. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/repair_type.source.yaml +0 -0
  101. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/total_repair_cost.metric.yaml +0 -0
  102. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/total_repair_order_discounts.metric.yaml +0 -0
  103. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/us_region.source.yaml +0 -0
  104. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/us_state.dimension.yaml +0 -0
  105. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project1/roads/us_states.source.yaml +0 -0
  106. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project10/dj.yaml +0 -0
  107. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/avg_length_of_employment.metric.yaml +0 -0
  108. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/avg_repair_price.metric.yaml +0 -0
  109. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/avg_time_to_dispatch.metric.yaml +0 -0
  110. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/contractor.dimension.yaml +0 -0
  111. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/contractors.source.yaml +0 -0
  112. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/date.source.yaml +0 -0
  113. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/date_dim.dimension.yaml +0 -0
  114. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/dispatcher.dimension.yaml +0 -0
  115. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/dispatchers.source.yaml +0 -0
  116. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/dj.yaml +0 -0
  117. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/hard_hat.dimension.yaml +0 -0
  118. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/hard_hat_state.source.yaml +0 -0
  119. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/hard_hats.source.yaml +0 -0
  120. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/local_hard_hats.dimension.yaml +0 -0
  121. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/municipality.source.yaml +0 -0
  122. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/municipality_dim.dimension.yaml +0 -0
  123. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/municipality_municipality_type.source.yaml +0 -0
  124. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/municipality_type.source.yaml +0 -0
  125. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/national_level_agg.transform.yaml +0 -0
  126. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/num_repair_orders.metric.yaml +0 -0
  127. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/regional_level_agg.transform.yaml +0 -0
  128. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/regional_repair_efficiency.metric.yaml +0 -0
  129. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/repair_order.dimension.yaml +0 -0
  130. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/repair_order_details.source.yaml +0 -0
  131. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/repair_order_transform.transform.yaml +0 -0
  132. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/repair_orders.source.yaml +0 -0
  133. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/repair_orders_cube.cube.yaml +0 -0
  134. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/repair_type.source.yaml +0 -0
  135. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/total_repair_cost.metric.yaml +0 -0
  136. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/total_repair_order_discounts.metric.yaml +0 -0
  137. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/us_region.source.yaml +0 -0
  138. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/us_state.dimension.yaml +0 -0
  139. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project11/us_states.source.yaml +0 -0
  140. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project12/dj.yaml +0 -0
  141. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project12/roads/companies.source.yaml +0 -0
  142. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project12/roads/companies_dim.dimension.yaml +0 -0
  143. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project12/roads/contractor.dimension.yaml +0 -0
  144. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project12/roads/contractors.source.yaml +0 -0
  145. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project12/roads/us_state.dimension.yaml +0 -0
  146. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project12/roads/us_states.source.yaml +0 -0
  147. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project2/dj.yaml +0 -0
  148. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project2/some_node.source.yaml +0 -0
  149. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project3/dj.yaml +0 -0
  150. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project3/some_node.yaml +0 -0
  151. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project4/dj.yaml +0 -0
  152. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project4/very/very/deeply/nested/namespace/some_node.source.yaml +0 -0
  153. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project5/dj.yaml +0 -0
  154. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project5/some_node.a.b.c.source.yaml +0 -0
  155. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project6/dj.yaml +0 -0
  156. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project6/roads/contractor.dimension.yaml +0 -0
  157. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project6/roads/contractors.source.yaml +0 -0
  158. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project7/dj.yaml +0 -0
  159. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project7/roads/contractor.dimension.yaml +0 -0
  160. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project7/roads/contractors.source.yaml +0 -0
  161. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project8/dj.yaml +0 -0
  162. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project9/dj.yaml +0 -0
  163. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project9/roads/companies.source.yaml +0 -0
  164. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project9/roads/companies_dim.dimension.yaml +0 -0
  165. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project9/roads/contractor.dimension.yaml +0 -0
  166. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project9/roads/contractors.source.yaml +0 -0
  167. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project9/roads/us_state.dimension.yaml +0 -0
  168. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples/project9/roads/us_states.source.yaml +0 -0
  169. {datajunction-0.0.235 → datajunction-0.0.237}/tests/examples.py +0 -0
  170. {datajunction-0.0.235 → datajunction-0.0.237}/tests/mcp/README.md +0 -0
  171. {datajunction-0.0.235 → datajunction-0.0.237}/tests/mcp/__init__.py +0 -0
  172. {datajunction-0.0.235 → datajunction-0.0.237}/tests/mcp/test_cli.py +0 -0
  173. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test__internal.py +0 -0
  174. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_admin.py +0 -0
  175. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_base.py +0 -0
  176. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_builder.py +0 -0
  177. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_client.py +0 -0
  178. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_compile.py +0 -0
  179. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_generated_client.py +0 -0
  180. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_integration.py +0 -0
  181. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_models.py +0 -0
  182. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_plugin_mirror.py +0 -0
  183. {datajunction-0.0.235 → datajunction-0.0.237}/tests/test_skills.py +0 -0
  184. {datajunction-0.0.235 → datajunction-0.0.237}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: datajunction
3
- Version: 0.0.235
3
+ Version: 0.0.237
4
4
  Summary: DataJunction client library for connecting to a DataJunction server
5
5
  Project-URL: repository, https://github.com/DataJunction/dj
6
6
  Author-email: DataJunction Authors <yian.shang@gmail.com>
@@ -2,4 +2,4 @@
2
2
  Version for Hatch
3
3
  """
4
4
 
5
- __version__ = "0.0.235"
5
+ __version__ = "0.0.237"
@@ -47,6 +47,7 @@ class DJCLI:
47
47
  verbose: bool = False,
48
48
  force: bool = False,
49
49
  allow_empty: bool = False,
50
+ format: str = "text",
50
51
  ):
51
52
  """
52
53
  Alias for deploy without dryrun.
@@ -57,6 +58,7 @@ class DJCLI:
57
58
  verbose=verbose,
58
59
  force=force,
59
60
  allow_empty=allow_empty,
61
+ format=format,
60
62
  )
61
63
 
62
64
  def dryrun(
@@ -916,7 +918,7 @@ class DJCLI:
916
918
  type=str,
917
919
  default="text",
918
920
  choices=["text", "json"],
919
- help="Output format for dry run (default: text)",
921
+ help="Output format for the deployment result (default: text)",
920
922
  )
921
923
  # Deployment source tracking flags
922
924
  push_parser.add_argument(
@@ -1523,12 +1525,17 @@ class DJCLI:
1523
1525
  verbose=args.verbose,
1524
1526
  force=args.force,
1525
1527
  allow_empty=args.allow_empty,
1528
+ format=args.format,
1526
1529
  )
1527
1530
  except DJDeploymentFailure:
1528
- # Errors already displayed in the deployment panel
1531
+ # Errors already displayed in the deployment panel (or, in
1532
+ # --format json mode, in the JSON already printed to stdout)
1529
1533
  raise SystemExit(1)
1530
1534
  except DJClientException as exc:
1531
- Console().print(f"[red bold]ERROR:[/red bold] {exc}")
1535
+ if args.format == "json":
1536
+ print(json.dumps({"error": str(exc)}, indent=2))
1537
+ else:
1538
+ Console().print(f"[red bold]ERROR:[/red bold] {exc}")
1532
1539
  raise SystemExit(1)
1533
1540
  elif args.command == "generate-codeowners":
1534
1541
  count = DeploymentService.build_codeowners(
@@ -140,11 +140,13 @@ class DeploymentService:
140
140
  verbose: bool = False,
141
141
  force: bool = False,
142
142
  allow_empty: bool = False,
143
+ format: str = "text",
143
144
  ):
144
145
  """
145
146
  Push a local project to a namespace.
146
147
  """
147
148
  console = console or self.console
149
+ as_json = format == "json"
148
150
 
149
151
  deployment_spec, file_errors = self._reconstruct_deployment_spec(source_path)
150
152
 
@@ -161,13 +163,14 @@ class DeploymentService:
161
163
  branch,
162
164
  )
163
165
 
164
- print_deployment_header(
165
- mode="push",
166
- namespace=deployment_spec["namespace"],
167
- console=console,
168
- repo=source.get("repository"),
169
- branch=source.get("branch") or branch,
170
- )
166
+ if not as_json:
167
+ print_deployment_header(
168
+ mode="push",
169
+ namespace=deployment_spec["namespace"],
170
+ console=console,
171
+ repo=source.get("repository"),
172
+ branch=source.get("branch") or branch,
173
+ )
171
174
 
172
175
  # Apply git config in the normal push flow. Skip only when the
173
176
  # caller passed an explicit ``namespace`` equal to the project's
@@ -186,10 +189,11 @@ class DeploymentService:
186
189
  parent_namespace=parent_namespace or None,
187
190
  )
188
191
  except Exception as e: # pylint: disable=broad-except
189
- console.print(
190
- f"[yellow]Warning: could not set git config on namespace "
191
- f"'{deployment_spec['namespace']}': {e}[/yellow]",
192
- )
192
+ if not as_json:
193
+ console.print(
194
+ f"[yellow]Warning: could not set git config on namespace "
195
+ f"'{deployment_spec['namespace']}': {e}[/yellow]",
196
+ )
193
197
  if force:
194
198
  deployment_spec["force"] = True
195
199
  if allow_empty:
@@ -211,25 +215,30 @@ class DeploymentService:
211
215
  raise DJClientException("Deployment timed out after 5 minutes")
212
216
 
213
217
  deployment = DeploymentInfo.from_dict(deployment_data)
214
- print_results(
215
- deployment_uuid,
216
- deployment,
217
- console,
218
- verbose=verbose,
219
- )
218
+ if as_json:
219
+ print(json.dumps(deployment_data, indent=2))
220
+ else:
221
+ print_results(
222
+ deployment_uuid,
223
+ deployment,
224
+ console,
225
+ verbose=verbose,
226
+ )
220
227
  if deployment.status == DeploymentStatus.SUCCESS:
221
228
  invalid_results = [
222
229
  r for r in deployment.results if r.status == ResultStatus.INVALID
223
230
  ]
224
231
  if invalid_results:
225
- console.print(
226
- "\nDeployment finished: [bold yellow]SUCCESS with invalid nodes[/bold yellow]",
227
- )
232
+ if not as_json:
233
+ console.print(
234
+ "\nDeployment finished: [bold yellow]SUCCESS with invalid nodes[/bold yellow]",
235
+ )
228
236
  raise DJDeploymentFailure(
229
237
  project_name=deployment_spec.get("namespace", source_path),
230
238
  errors=[r.__dict__ for r in invalid_results],
231
239
  )
232
- console.print("\nDeployment finished: [bold green]SUCCESS[/bold green]")
240
+ if not as_json:
241
+ console.print("\nDeployment finished: [bold green]SUCCESS[/bold green]")
233
242
  if deployment.status == DeploymentStatus.FAILED:
234
243
  errors = [
235
244
  r
@@ -241,10 +250,11 @@ class DeploymentService:
241
250
  errors=[r.__dict__ for r in (errors if errors else deployment.results)],
242
251
  )
243
252
  if file_errors:
244
- console.print()
245
- console.rule("[red bold]Errors[/red bold]", style="red", align="left")
246
- for err in file_errors:
247
- console.print(f"[red] {err}[/red]")
253
+ if not as_json:
254
+ console.print()
255
+ console.rule("[red bold]Errors[/red bold]", style="red", align="left")
256
+ for err in file_errors:
257
+ console.print(f"[red] {err}[/red]")
248
258
  raise DJClientException(
249
259
  "Fix file name mismatches before deploying.",
250
260
  )
@@ -2447,6 +2447,28 @@ class TestDeploymentFailureExitsWithCode1:
2447
2447
  cli.run()
2448
2448
  assert exc_info.value.code == 1
2449
2449
 
2450
+ def test_push_generic_client_error_format_json(self, tmp_path, capsys):
2451
+ """A non-deployment error in --format json mode prints a JSON error object."""
2452
+ from datajunction.cli import DJCLI
2453
+ from datajunction.exceptions import DJClientException
2454
+
2455
+ cli = DJCLI(builder_client=mock.MagicMock())
2456
+ with patch.object(
2457
+ cli,
2458
+ "push",
2459
+ side_effect=DJClientException("Connection refused"),
2460
+ ):
2461
+ with patch.object(
2462
+ sys,
2463
+ "argv",
2464
+ ["dj", "push", str(tmp_path), "--format", "json"],
2465
+ ):
2466
+ with pytest.raises(SystemExit) as exc_info:
2467
+ cli.run()
2468
+ assert exc_info.value.code == 1
2469
+ printed = json.loads(capsys.readouterr().out)
2470
+ assert printed == {"error": "Connection refused"}
2471
+
2450
2472
 
2451
2473
  class TestGenerateCodeowners:
2452
2474
  """Tests for `dj generate-codeowners` and DeploymentService.build_codeowners."""
@@ -1,5 +1,6 @@
1
1
  import importlib.metadata
2
2
  import io
3
+ import json
3
4
  from pathlib import Path
4
5
  import time
5
6
  import zipfile
@@ -891,6 +892,37 @@ def test_push_waits_until_success(monkeypatch, tmp_path):
891
892
  client.check_deployment.assert_called()
892
893
 
893
894
 
895
+ def test_push_format_json_prints_deployment_data(monkeypatch, tmp_path, capsys):
896
+ """push(format="json") must print the raw deployment dict to stdout
897
+ instead of the rich text panel, so a caller (e.g. a CI script posting
898
+ a PR comment) can parse the wet-run result."""
899
+ (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "foo"}))
900
+ (tmp_path / "bar.yaml").write_text(yaml.safe_dump({"name": "foo.bar"}))
901
+
902
+ client = MagicMock()
903
+ client.deploy.return_value = {
904
+ "uuid": "abc",
905
+ "status": "success",
906
+ "results": [
907
+ {
908
+ "name": "foo.bar",
909
+ "operation": "update",
910
+ "status": "success",
911
+ "changed_fields": ["query"],
912
+ },
913
+ ],
914
+ "namespace": "foo",
915
+ }
916
+
917
+ svc = DeploymentService(client, console=Console(file=io.StringIO()))
918
+ monkeypatch.setattr(time, "sleep", lambda _: None)
919
+
920
+ svc.push(tmp_path, format="json")
921
+
922
+ printed = json.loads(capsys.readouterr().out)
923
+ assert printed == client.deploy.return_value
924
+
925
+
894
926
  def test_push_force_sets_flag_in_spec(monkeypatch, tmp_path):
895
927
  """push(force=True) must include {"force": True} in the spec sent to client.deploy."""
896
928
  (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "foo"}))
@@ -1038,6 +1070,38 @@ def test_push_raises_on_success_with_invalid_nodes(monkeypatch, tmp_path):
1038
1070
  assert exc_info.value.errors[0]["name"] == "foo.bar"
1039
1071
 
1040
1072
 
1073
+ def test_push_format_json_raises_on_success_with_invalid_nodes(monkeypatch, tmp_path):
1074
+ """Same as above in --format json mode: still raises, and skips the rich
1075
+ text warning (the JSON dump already carries the invalid-node status)."""
1076
+ (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "foo"}))
1077
+ (tmp_path / "bar.yaml").write_text(yaml.safe_dump({"name": "foo.bar"}))
1078
+
1079
+ invalid_results = [
1080
+ {
1081
+ "deploy_type": "node",
1082
+ "name": "foo.bar",
1083
+ "operation": "create",
1084
+ "status": "invalid",
1085
+ "message": "One or more metrics are INVALID",
1086
+ },
1087
+ ]
1088
+ client = MagicMock()
1089
+ client.deploy.return_value = {
1090
+ "uuid": "456",
1091
+ "status": "success",
1092
+ "results": invalid_results,
1093
+ "namespace": "foo",
1094
+ }
1095
+
1096
+ svc = DeploymentService(client, console=Console(file=io.StringIO()))
1097
+ monkeypatch.setattr(time, "sleep", lambda _: None)
1098
+
1099
+ with pytest.raises(DJDeploymentFailure) as exc_info:
1100
+ svc.push(tmp_path, format="json")
1101
+
1102
+ assert exc_info.value.errors[0]["name"] == "foo.bar"
1103
+
1104
+
1041
1105
  @pytest.mark.timeout(2)
1042
1106
  def test_push_raises_after_polling_to_failure(monkeypatch, tmp_path):
1043
1107
  (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "ns"}))
@@ -1704,6 +1768,47 @@ class TestPushBranchDetection:
1704
1768
  assert "Warning" in out.getvalue()
1705
1769
  client.deploy.assert_called_once()
1706
1770
 
1771
+ def test_push_git_config_failure_is_silent_in_format_json(
1772
+ self,
1773
+ monkeypatch,
1774
+ tmp_path,
1775
+ ):
1776
+ """Same as above in --format json mode: the warning is suppressed so
1777
+ it doesn't pollute the JSON on stdout."""
1778
+ (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "project.main"}))
1779
+ (tmp_path / "my_node.yaml").write_text(
1780
+ yaml.safe_dump({"name": "project.my_node"}),
1781
+ )
1782
+
1783
+ monkeypatch.delenv("DJ_DEPLOY_REPO", raising=False)
1784
+ monkeypatch.setattr(
1785
+ DeploymentService,
1786
+ "_detect_git_branch",
1787
+ staticmethod(lambda cwd=None: "main"),
1788
+ )
1789
+ monkeypatch.setattr(
1790
+ DeploymentService,
1791
+ "_detect_git_repo",
1792
+ staticmethod(lambda cwd=None: None),
1793
+ )
1794
+ monkeypatch.setattr(time, "sleep", lambda _: None)
1795
+
1796
+ client = MagicMock()
1797
+ client._set_namespace_git_config.side_effect = Exception("network error")
1798
+ client.deploy.return_value = {"uuid": "abc", "status": "success", "results": []}
1799
+ client.check_deployment.return_value = {
1800
+ "uuid": "abc",
1801
+ "status": "success",
1802
+ "results": [],
1803
+ }
1804
+
1805
+ out = io.StringIO()
1806
+ svc = DeploymentService(client, console=Console(file=out))
1807
+ svc.push(tmp_path, format="json")
1808
+
1809
+ assert "Warning" not in out.getvalue()
1810
+ client.deploy.assert_called_once()
1811
+
1707
1812
 
1708
1813
  def test_djdeploymentfailure_str_with_errors():
1709
1814
  exc = DJDeploymentFailure(
@@ -1748,6 +1853,28 @@ def test_push_raises_on_file_name_mismatch(monkeypatch, tmp_path):
1748
1853
  svc.push(tmp_path)
1749
1854
 
1750
1855
 
1856
+ def test_push_format_json_raises_on_file_name_mismatch(monkeypatch, tmp_path):
1857
+ """Same as above in --format json mode: still raises, and skips the rich
1858
+ text error rule/listing (nothing to print — the JSON on stdout is the
1859
+ deployment result, not the file-name-mismatch warnings)."""
1860
+ (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "foo"}))
1861
+ (tmp_path / "wrong.yaml").write_text(yaml.safe_dump({"name": "foo.bar"}))
1862
+
1863
+ client = MagicMock()
1864
+ client.deploy.return_value = {
1865
+ "uuid": "abc",
1866
+ "status": "success",
1867
+ "results": [],
1868
+ "namespace": "foo",
1869
+ }
1870
+
1871
+ svc = DeploymentService(client, console=Console(file=io.StringIO()))
1872
+ monkeypatch.setattr(time, "sleep", lambda _: None)
1873
+
1874
+ with pytest.raises(DJClientException, match="Fix file name mismatches"):
1875
+ svc.push(tmp_path, format="json")
1876
+
1877
+
1751
1878
  def test_collect_nodes_skips_validation_for_unnamed_node(tmp_path):
1752
1879
  """A YAML file with no 'name' field should still be collected without warnings."""
1753
1880
  (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "foo"}))
File without changes
File without changes
File without changes
File without changes