datajunction 0.0.261__tar.gz → 0.0.263__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.261 → datajunction-0.0.263}/PKG-INFO +1 -1
  2. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/__about__.py +1 -1
  3. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/cli.py +13 -0
  4. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/deployment.py +3 -0
  5. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_cli.py +40 -0
  6. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_deploy.py +45 -0
  7. {datajunction-0.0.261 → datajunction-0.0.263}/.coveragerc +0 -0
  8. {datajunction-0.0.261 → datajunction-0.0.263}/.gitignore +0 -0
  9. {datajunction-0.0.261 → datajunction-0.0.263}/.pre-commit-config.yaml +0 -0
  10. {datajunction-0.0.261 → datajunction-0.0.263}/LICENSE.txt +0 -0
  11. {datajunction-0.0.261 → datajunction-0.0.263}/Makefile +0 -0
  12. {datajunction-0.0.261 → datajunction-0.0.263}/README.md +0 -0
  13. {datajunction-0.0.261 → datajunction-0.0.263}/claude_desktop_config.example.json +0 -0
  14. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/__init__.py +0 -0
  15. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/_base.py +0 -0
  16. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/_internal.py +0 -0
  17. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/admin.py +0 -0
  18. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/builder.py +0 -0
  19. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/client.py +0 -0
  20. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/compile.py +0 -0
  21. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/exceptions.py +0 -0
  22. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/mcp/__init__.py +0 -0
  23. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/mcp/cli.py +0 -0
  24. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/mcp/config.py +0 -0
  25. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/models.py +0 -0
  26. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/nodes.py +0 -0
  27. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/rendering.py +0 -0
  28. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/init_system_nodes.py +0 -0
  29. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/date.yaml +0 -0
  30. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/deployment.yaml +0 -0
  31. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/dimension_link.yaml +0 -0
  32. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/distinct_node_authors.yaml +0 -0
  33. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/distinct_node_editors.yaml +0 -0
  34. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/dj.yaml +0 -0
  35. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/is_active.yaml +0 -0
  36. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/materialization.yaml +0 -0
  37. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/median_deployment_duration_seconds.yaml +0 -0
  38. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/median_dim_links_per_node.yaml +0 -0
  39. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/median_dimension_indegree.yaml +0 -0
  40. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/median_downstream_count.yaml +0 -0
  41. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/median_revisions_per_node.yaml +0 -0
  42. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/median_upstream_count.yaml +0 -0
  43. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/namespace.yaml +0 -0
  44. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/node_revision.yaml +0 -0
  45. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/node_type.yaml +0 -0
  46. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/nodes.yaml +0 -0
  47. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/number_of_branches.yaml +0 -0
  48. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/number_of_deployments.yaml +0 -0
  49. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/number_of_materializations.yaml +0 -0
  50. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/number_of_namespaces.yaml +0 -0
  51. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/number_of_nodes.yaml +0 -0
  52. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/number_of_orphan_nodes.yaml +0 -0
  53. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/number_of_unused_dimensions.yaml +0 -0
  54. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/repo.yaml +0 -0
  55. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/seed/nodes/user.yaml +0 -0
  56. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/skills/datajunction/SKILL.md +0 -0
  57. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/skills/datajunction-api/SKILL.md +0 -0
  58. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/skills/datajunction-query/SKILL.md +0 -0
  59. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/skills/datajunction-repo/SKILL.md +0 -0
  60. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/skills/datajunction-semantic-model/SKILL.md +0 -0
  61. {datajunction-0.0.261 → datajunction-0.0.263}/datajunction/tags.py +0 -0
  62. {datajunction-0.0.261 → datajunction-0.0.263}/pyproject.toml +0 -0
  63. {datajunction-0.0.261 → datajunction-0.0.263}/setup.cfg +0 -0
  64. {datajunction-0.0.261 → datajunction-0.0.263}/tests/__init__.py +0 -0
  65. {datajunction-0.0.261 → datajunction-0.0.263}/tests/conftest.py +0 -0
  66. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/deploy0/dj.yaml +0 -0
  67. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/deploy0/roads/companies.yaml +0 -0
  68. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/deploy0/roads/companies_dim.yaml +0 -0
  69. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/deploy0/roads/contractor.yaml +0 -0
  70. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/deploy0/roads/contractors.yaml +0 -0
  71. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/deploy0/roads/us_state.yaml +0 -0
  72. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/deploy0/roads/us_states.yaml +0 -0
  73. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/dj.yaml +0 -0
  74. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/avg_length_of_employment.metric.yaml +0 -0
  75. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/avg_repair_price.metric.yaml +0 -0
  76. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/avg_time_to_dispatch.metric.yaml +0 -0
  77. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/contractor.dimension.yaml +0 -0
  78. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/contractors.source.yaml +0 -0
  79. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/date.source.yaml +0 -0
  80. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/date_dim.dimension.yaml +0 -0
  81. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/dispatcher.dimension.yaml +0 -0
  82. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/dispatchers.source.yaml +0 -0
  83. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/hard_hat.dimension.yaml +0 -0
  84. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/hard_hat_state.source.yaml +0 -0
  85. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/hard_hats.source.yaml +0 -0
  86. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/local_hard_hats.dimension.yaml +0 -0
  87. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/municipality.source.yaml +0 -0
  88. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/municipality_dim.dimension.yaml +0 -0
  89. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/municipality_municipality_type.source.yaml +0 -0
  90. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/municipality_type.source.yaml +0 -0
  91. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/national_level_agg.transform.yaml +0 -0
  92. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/num_repair_orders.metric.yaml +0 -0
  93. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/regional_level_agg.transform.yaml +0 -0
  94. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/regional_repair_efficiency.metric.yaml +0 -0
  95. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/repair_order.dimension.yaml +0 -0
  96. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/repair_order_details.source.yaml +0 -0
  97. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/repair_order_transform.transform.yaml +0 -0
  98. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/repair_orders.source.yaml +0 -0
  99. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/repair_orders_cube.cube.yaml +0 -0
  100. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/repair_type.source.yaml +0 -0
  101. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/total_repair_cost.metric.yaml +0 -0
  102. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/total_repair_order_discounts.metric.yaml +0 -0
  103. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/us_region.source.yaml +0 -0
  104. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/us_state.dimension.yaml +0 -0
  105. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project1/roads/us_states.source.yaml +0 -0
  106. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project10/dj.yaml +0 -0
  107. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/avg_length_of_employment.metric.yaml +0 -0
  108. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/avg_repair_price.metric.yaml +0 -0
  109. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/avg_time_to_dispatch.metric.yaml +0 -0
  110. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/contractor.dimension.yaml +0 -0
  111. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/contractors.source.yaml +0 -0
  112. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/date.source.yaml +0 -0
  113. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/date_dim.dimension.yaml +0 -0
  114. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/dispatcher.dimension.yaml +0 -0
  115. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/dispatchers.source.yaml +0 -0
  116. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/dj.yaml +0 -0
  117. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/hard_hat.dimension.yaml +0 -0
  118. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/hard_hat_state.source.yaml +0 -0
  119. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/hard_hats.source.yaml +0 -0
  120. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/local_hard_hats.dimension.yaml +0 -0
  121. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/municipality.source.yaml +0 -0
  122. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/municipality_dim.dimension.yaml +0 -0
  123. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/municipality_municipality_type.source.yaml +0 -0
  124. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/municipality_type.source.yaml +0 -0
  125. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/national_level_agg.transform.yaml +0 -0
  126. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/num_repair_orders.metric.yaml +0 -0
  127. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/regional_level_agg.transform.yaml +0 -0
  128. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/regional_repair_efficiency.metric.yaml +0 -0
  129. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/repair_order.dimension.yaml +0 -0
  130. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/repair_order_details.source.yaml +0 -0
  131. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/repair_order_transform.transform.yaml +0 -0
  132. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/repair_orders.source.yaml +0 -0
  133. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/repair_orders_cube.cube.yaml +0 -0
  134. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/repair_type.source.yaml +0 -0
  135. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/total_repair_cost.metric.yaml +0 -0
  136. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/total_repair_order_discounts.metric.yaml +0 -0
  137. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/us_region.source.yaml +0 -0
  138. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/us_state.dimension.yaml +0 -0
  139. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project11/us_states.source.yaml +0 -0
  140. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project12/dj.yaml +0 -0
  141. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project12/roads/companies.source.yaml +0 -0
  142. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project12/roads/companies_dim.dimension.yaml +0 -0
  143. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project12/roads/contractor.dimension.yaml +0 -0
  144. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project12/roads/contractors.source.yaml +0 -0
  145. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project12/roads/us_state.dimension.yaml +0 -0
  146. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project12/roads/us_states.source.yaml +0 -0
  147. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project2/dj.yaml +0 -0
  148. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project2/some_node.source.yaml +0 -0
  149. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project3/dj.yaml +0 -0
  150. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project3/some_node.yaml +0 -0
  151. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project4/dj.yaml +0 -0
  152. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project4/very/very/deeply/nested/namespace/some_node.source.yaml +0 -0
  153. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project5/dj.yaml +0 -0
  154. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project5/some_node.a.b.c.source.yaml +0 -0
  155. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project6/dj.yaml +0 -0
  156. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project6/roads/contractor.dimension.yaml +0 -0
  157. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project6/roads/contractors.source.yaml +0 -0
  158. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project7/dj.yaml +0 -0
  159. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project7/roads/contractor.dimension.yaml +0 -0
  160. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project7/roads/contractors.source.yaml +0 -0
  161. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project8/dj.yaml +0 -0
  162. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project9/dj.yaml +0 -0
  163. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project9/roads/companies.source.yaml +0 -0
  164. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project9/roads/companies_dim.dimension.yaml +0 -0
  165. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project9/roads/contractor.dimension.yaml +0 -0
  166. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project9/roads/contractors.source.yaml +0 -0
  167. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project9/roads/us_state.dimension.yaml +0 -0
  168. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples/project9/roads/us_states.source.yaml +0 -0
  169. {datajunction-0.0.261 → datajunction-0.0.263}/tests/examples.py +0 -0
  170. {datajunction-0.0.261 → datajunction-0.0.263}/tests/mcp/README.md +0 -0
  171. {datajunction-0.0.261 → datajunction-0.0.263}/tests/mcp/__init__.py +0 -0
  172. {datajunction-0.0.261 → datajunction-0.0.263}/tests/mcp/test_cli.py +0 -0
  173. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test__internal.py +0 -0
  174. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_admin.py +0 -0
  175. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_base.py +0 -0
  176. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_builder.py +0 -0
  177. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_client.py +0 -0
  178. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_compile.py +0 -0
  179. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_generated_client.py +0 -0
  180. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_integration.py +0 -0
  181. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_models.py +0 -0
  182. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_plugin_mirror.py +0 -0
  183. {datajunction-0.0.261 → datajunction-0.0.263}/tests/test_skills.py +0 -0
  184. {datajunction-0.0.261 → datajunction-0.0.263}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: datajunction
3
- Version: 0.0.261
3
+ Version: 0.0.263
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.261"
5
+ __version__ = "0.0.263"
@@ -46,6 +46,7 @@ class DJCLI:
46
46
  namespace: str | None = None,
47
47
  verbose: bool = False,
48
48
  force: bool = False,
49
+ force_nodes: list[str] | None = None,
49
50
  allow_empty: bool = False,
50
51
  format: str = "text",
51
52
  ):
@@ -57,6 +58,7 @@ class DJCLI:
57
58
  namespace=namespace,
58
59
  verbose=verbose,
59
60
  force=force,
61
+ force_nodes=force_nodes,
60
62
  allow_empty=allow_empty,
61
63
  format=format,
62
64
  )
@@ -904,6 +906,16 @@ class DJCLI:
904
906
  action="store_true",
905
907
  help="Force update all nodes even if they are unchanged",
906
908
  )
909
+ push_parser.add_argument(
910
+ "--force-node",
911
+ action="append",
912
+ dest="force_nodes",
913
+ metavar="NODE",
914
+ help=(
915
+ "Force update only this node (full name) even if it is unchanged. "
916
+ "Repeat for several nodes"
917
+ ),
918
+ )
907
919
  push_parser.add_argument(
908
920
  "--allow-empty",
909
921
  action="store_true",
@@ -1524,6 +1536,7 @@ class DJCLI:
1524
1536
  namespace=args.namespace,
1525
1537
  verbose=args.verbose,
1526
1538
  force=args.force,
1539
+ force_nodes=args.force_nodes,
1527
1540
  allow_empty=args.allow_empty,
1528
1541
  format=args.format,
1529
1542
  )
@@ -139,6 +139,7 @@ class DeploymentService:
139
139
  console: Console | None = None,
140
140
  verbose: bool = False,
141
141
  force: bool = False,
142
+ force_nodes: list[str] | None = None,
142
143
  allow_empty: bool = False,
143
144
  format: str = "text",
144
145
  ):
@@ -196,6 +197,8 @@ class DeploymentService:
196
197
  )
197
198
  if force:
198
199
  deployment_spec["force"] = True
200
+ if force_nodes:
201
+ deployment_spec["force_nodes"] = list(force_nodes)
199
202
  if allow_empty:
200
203
  deployment_spec["allow_empty"] = True
201
204
  deployment_data = self.client.deploy(deployment_spec)
@@ -1526,6 +1526,46 @@ class TestImpactAnalysis:
1526
1526
  _, kwargs = mock_push.call_args
1527
1527
  assert kwargs.get("allow_empty") is False
1528
1528
 
1529
+ def test_push_force_node_flag_passed_to_service(self, tmp_path):
1530
+ """--force-node on `dj push` is repeatable and reaches the service as a list."""
1531
+ from datajunction.cli import DJCLI
1532
+
1533
+ cli = DJCLI(builder_client=mock.MagicMock())
1534
+ with patch.object(cli.deployment_service, "push") as mock_push:
1535
+ mock_push.return_value = None
1536
+ with patch.object(
1537
+ sys,
1538
+ "argv",
1539
+ [
1540
+ "dj",
1541
+ "push",
1542
+ str(tmp_path),
1543
+ "--force-node",
1544
+ "ns.first",
1545
+ "--force-node",
1546
+ "ns.second",
1547
+ ],
1548
+ ):
1549
+ cli.run()
1550
+
1551
+ mock_push.assert_called_once()
1552
+ _, kwargs = mock_push.call_args
1553
+ assert kwargs.get("force_nodes") == ["ns.first", "ns.second"]
1554
+ assert kwargs.get("force") is False
1555
+
1556
+ def test_push_without_force_node_flag_defaults_none(self, tmp_path):
1557
+ """Omitting --force-node on `dj push` must pass force_nodes=None."""
1558
+ from datajunction.cli import DJCLI
1559
+
1560
+ cli = DJCLI(builder_client=mock.MagicMock())
1561
+ with patch.object(cli.deployment_service, "push") as mock_push:
1562
+ mock_push.return_value = None
1563
+ with patch.object(sys, "argv", ["dj", "push", str(tmp_path)]):
1564
+ cli.run()
1565
+
1566
+ _, kwargs = mock_push.call_args
1567
+ assert kwargs.get("force_nodes") is None
1568
+
1529
1569
 
1530
1570
  class TestDJCLIClientCreation:
1531
1571
  """Tests for DJCLI client creation from environment variables."""
@@ -1043,6 +1043,51 @@ def test_push_without_force_does_not_set_flag(monkeypatch, tmp_path):
1043
1043
  assert "force" not in spec_sent
1044
1044
 
1045
1045
 
1046
+ def test_push_force_nodes_sets_list_in_spec(monkeypatch, tmp_path):
1047
+ """push(force_nodes=[...]) must send the names as `force_nodes` in the spec."""
1048
+ (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "foo"}))
1049
+ (tmp_path / "bar.yaml").write_text(yaml.safe_dump({"name": "foo.bar"}))
1050
+
1051
+ client = MagicMock()
1052
+ client.deploy.return_value = {
1053
+ "uuid": "abc",
1054
+ "status": "success",
1055
+ "results": [],
1056
+ "namespace": "foo",
1057
+ }
1058
+
1059
+ svc = DeploymentService(client, console=Console(file=io.StringIO()))
1060
+ monkeypatch.setattr(time, "sleep", lambda _: None)
1061
+
1062
+ svc.push(tmp_path, force_nodes=["foo.bar"])
1063
+
1064
+ spec_sent = client.deploy.call_args[0][0]
1065
+ assert spec_sent.get("force_nodes") == ["foo.bar"]
1066
+ assert "force" not in spec_sent
1067
+
1068
+
1069
+ def test_push_without_force_nodes_does_not_set_list(monkeypatch, tmp_path):
1070
+ """push() without force_nodes must not include it in the spec."""
1071
+ (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "foo"}))
1072
+ (tmp_path / "bar.yaml").write_text(yaml.safe_dump({"name": "foo.bar"}))
1073
+
1074
+ client = MagicMock()
1075
+ client.deploy.return_value = {
1076
+ "uuid": "abc",
1077
+ "status": "success",
1078
+ "results": [],
1079
+ "namespace": "foo",
1080
+ }
1081
+
1082
+ svc = DeploymentService(client, console=Console(file=io.StringIO()))
1083
+ monkeypatch.setattr(time, "sleep", lambda _: None)
1084
+
1085
+ svc.push(tmp_path)
1086
+
1087
+ spec_sent = client.deploy.call_args[0][0]
1088
+ assert "force_nodes" not in spec_sent
1089
+
1090
+
1046
1091
  def test_push_times_out(monkeypatch, tmp_path):
1047
1092
  # minimal project structure so _reconstruct_deployment_spec works
1048
1093
  (tmp_path / "dj.yaml").write_text(yaml.safe_dump({"namespace": "foo"}))
File without changes
File without changes
File without changes
File without changes