datajunction 0.0.182__tar.gz → 0.0.184__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.182 → datajunction-0.0.184}/Makefile +1 -1
  2. {datajunction-0.0.182 → datajunction-0.0.184}/PKG-INFO +2 -3
  3. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/__about__.py +1 -1
  4. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/_internal.py +2 -12
  5. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/cli.py +137 -41
  6. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/deployment.py +26 -2
  7. datajunction-0.0.184/datajunction/skills/datajunction-api.md +232 -0
  8. datajunction-0.0.184/datajunction/skills/datajunction-query.md +248 -0
  9. datajunction-0.0.184/datajunction/skills/datajunction-repo.md +692 -0
  10. datajunction-0.0.184/datajunction/skills/datajunction-semantic-model.md +379 -0
  11. datajunction-0.0.184/datajunction/skills/datajunction.md +253 -0
  12. {datajunction-0.0.182 → datajunction-0.0.184}/pyproject.toml +1 -1
  13. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_cli.py +151 -25
  14. datajunction-0.0.184/tests/test_skills.py +193 -0
  15. datajunction-0.0.182/datajunction/skills/datajunction.md +0 -1823
  16. {datajunction-0.0.182 → datajunction-0.0.184}/.coveragerc +0 -0
  17. {datajunction-0.0.182 → datajunction-0.0.184}/.gitignore +0 -0
  18. {datajunction-0.0.182 → datajunction-0.0.184}/.pre-commit-config.yaml +0 -0
  19. {datajunction-0.0.182 → datajunction-0.0.184}/LICENSE.txt +0 -0
  20. {datajunction-0.0.182 → datajunction-0.0.184}/README.md +0 -0
  21. {datajunction-0.0.182 → datajunction-0.0.184}/claude_desktop_config.example.json +0 -0
  22. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/__init__.py +0 -0
  23. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/_base.py +0 -0
  24. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/admin.py +0 -0
  25. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/builder.py +0 -0
  26. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/client.py +0 -0
  27. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/compile.py +0 -0
  28. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/exceptions.py +0 -0
  29. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/mcp/__init__.py +0 -0
  30. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/mcp/cli.py +0 -0
  31. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/mcp/config.py +0 -0
  32. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/models.py +0 -0
  33. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/nodes.py +0 -0
  34. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/rendering.py +0 -0
  35. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/init_system_nodes.py +0 -0
  36. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/date.yaml +0 -0
  37. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/deployment.yaml +0 -0
  38. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/dimension_link.yaml +0 -0
  39. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/distinct_node_authors.yaml +0 -0
  40. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/distinct_node_editors.yaml +0 -0
  41. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/dj.yaml +0 -0
  42. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/is_active.yaml +0 -0
  43. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/materialization.yaml +0 -0
  44. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/median_deployment_duration_seconds.yaml +0 -0
  45. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/median_dim_links_per_node.yaml +0 -0
  46. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/median_dimension_indegree.yaml +0 -0
  47. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/median_downstream_count.yaml +0 -0
  48. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/median_revisions_per_node.yaml +0 -0
  49. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/median_upstream_count.yaml +0 -0
  50. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/namespace.yaml +0 -0
  51. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/node_revision.yaml +0 -0
  52. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/node_type.yaml +0 -0
  53. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/nodes.yaml +0 -0
  54. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/number_of_branches.yaml +0 -0
  55. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/number_of_deployments.yaml +0 -0
  56. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/number_of_materializations.yaml +0 -0
  57. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/number_of_namespaces.yaml +0 -0
  58. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/number_of_nodes.yaml +0 -0
  59. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/number_of_orphan_nodes.yaml +0 -0
  60. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/number_of_unused_dimensions.yaml +0 -0
  61. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/repo.yaml +0 -0
  62. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/seed/nodes/user.yaml +0 -0
  63. {datajunction-0.0.182 → datajunction-0.0.184}/datajunction/tags.py +0 -0
  64. {datajunction-0.0.182 → datajunction-0.0.184}/setup.cfg +0 -0
  65. {datajunction-0.0.182 → datajunction-0.0.184}/tests/__init__.py +0 -0
  66. {datajunction-0.0.182 → datajunction-0.0.184}/tests/conftest.py +0 -0
  67. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/deploy0/dj.yaml +0 -0
  68. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/deploy0/roads/companies.yaml +0 -0
  69. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/deploy0/roads/companies_dim.yaml +0 -0
  70. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/deploy0/roads/contractor.yaml +0 -0
  71. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/deploy0/roads/contractors.yaml +0 -0
  72. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/deploy0/roads/us_state.yaml +0 -0
  73. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/deploy0/roads/us_states.yaml +0 -0
  74. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/dj.yaml +0 -0
  75. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/avg_length_of_employment.metric.yaml +0 -0
  76. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/avg_repair_price.metric.yaml +0 -0
  77. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/avg_time_to_dispatch.metric.yaml +0 -0
  78. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/contractor.dimension.yaml +0 -0
  79. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/contractors.source.yaml +0 -0
  80. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/date.source.yaml +0 -0
  81. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/date_dim.dimension.yaml +0 -0
  82. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/dispatcher.dimension.yaml +0 -0
  83. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/dispatchers.source.yaml +0 -0
  84. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/hard_hat.dimension.yaml +0 -0
  85. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/hard_hat_state.source.yaml +0 -0
  86. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/hard_hats.source.yaml +0 -0
  87. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/local_hard_hats.dimension.yaml +0 -0
  88. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/municipality.source.yaml +0 -0
  89. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/municipality_dim.dimension.yaml +0 -0
  90. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/municipality_municipality_type.source.yaml +0 -0
  91. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/municipality_type.source.yaml +0 -0
  92. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/national_level_agg.transform.yaml +0 -0
  93. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/num_repair_orders.metric.yaml +0 -0
  94. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/regional_level_agg.transform.yaml +0 -0
  95. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/regional_repair_efficiency.metric.yaml +0 -0
  96. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/repair_order.dimension.yaml +0 -0
  97. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/repair_order_details.source.yaml +0 -0
  98. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/repair_order_transform.transform.yaml +0 -0
  99. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/repair_orders.source.yaml +0 -0
  100. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/repair_orders_cube.cube.yaml +0 -0
  101. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/repair_type.source.yaml +0 -0
  102. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/total_repair_cost.metric.yaml +0 -0
  103. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/total_repair_order_discounts.metric.yaml +0 -0
  104. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/us_region.source.yaml +0 -0
  105. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/us_state.dimension.yaml +0 -0
  106. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project1/roads/us_states.source.yaml +0 -0
  107. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project10/dj.yaml +0 -0
  108. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/avg_length_of_employment.metric.yaml +0 -0
  109. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/avg_repair_price.metric.yaml +0 -0
  110. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/avg_time_to_dispatch.metric.yaml +0 -0
  111. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/contractor.dimension.yaml +0 -0
  112. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/contractors.source.yaml +0 -0
  113. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/date.source.yaml +0 -0
  114. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/date_dim.dimension.yaml +0 -0
  115. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/dispatcher.dimension.yaml +0 -0
  116. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/dispatchers.source.yaml +0 -0
  117. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/dj.yaml +0 -0
  118. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/hard_hat.dimension.yaml +0 -0
  119. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/hard_hat_state.source.yaml +0 -0
  120. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/hard_hats.source.yaml +0 -0
  121. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/local_hard_hats.dimension.yaml +0 -0
  122. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/municipality.source.yaml +0 -0
  123. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/municipality_dim.dimension.yaml +0 -0
  124. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/municipality_municipality_type.source.yaml +0 -0
  125. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/municipality_type.source.yaml +0 -0
  126. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/national_level_agg.transform.yaml +0 -0
  127. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/num_repair_orders.metric.yaml +0 -0
  128. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/regional_level_agg.transform.yaml +0 -0
  129. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/regional_repair_efficiency.metric.yaml +0 -0
  130. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/repair_order.dimension.yaml +0 -0
  131. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/repair_order_details.source.yaml +0 -0
  132. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/repair_order_transform.transform.yaml +0 -0
  133. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/repair_orders.source.yaml +0 -0
  134. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/repair_orders_cube.cube.yaml +0 -0
  135. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/repair_type.source.yaml +0 -0
  136. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/total_repair_cost.metric.yaml +0 -0
  137. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/total_repair_order_discounts.metric.yaml +0 -0
  138. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/us_region.source.yaml +0 -0
  139. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/us_state.dimension.yaml +0 -0
  140. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project11/us_states.source.yaml +0 -0
  141. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project12/dj.yaml +0 -0
  142. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project12/roads/companies.source.yaml +0 -0
  143. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project12/roads/companies_dim.dimension.yaml +0 -0
  144. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project12/roads/contractor.dimension.yaml +0 -0
  145. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project12/roads/contractors.source.yaml +0 -0
  146. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project12/roads/us_state.dimension.yaml +0 -0
  147. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project12/roads/us_states.source.yaml +0 -0
  148. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project2/dj.yaml +0 -0
  149. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project2/some_node.source.yaml +0 -0
  150. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project3/dj.yaml +0 -0
  151. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project3/some_node.yaml +0 -0
  152. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project4/dj.yaml +0 -0
  153. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project4/very/very/deeply/nested/namespace/some_node.source.yaml +0 -0
  154. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project5/dj.yaml +0 -0
  155. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project5/some_node.a.b.c.source.yaml +0 -0
  156. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project6/dj.yaml +0 -0
  157. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project6/roads/contractor.dimension.yaml +0 -0
  158. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project6/roads/contractors.source.yaml +0 -0
  159. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project7/dj.yaml +0 -0
  160. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project7/roads/contractor.dimension.yaml +0 -0
  161. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project7/roads/contractors.source.yaml +0 -0
  162. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project8/dj.yaml +0 -0
  163. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project9/dj.yaml +0 -0
  164. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project9/roads/companies.source.yaml +0 -0
  165. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project9/roads/companies_dim.dimension.yaml +0 -0
  166. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project9/roads/contractor.dimension.yaml +0 -0
  167. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project9/roads/contractors.source.yaml +0 -0
  168. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project9/roads/us_state.dimension.yaml +0 -0
  169. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples/project9/roads/us_states.source.yaml +0 -0
  170. {datajunction-0.0.182 → datajunction-0.0.184}/tests/examples.py +0 -0
  171. {datajunction-0.0.182 → datajunction-0.0.184}/tests/mcp/README.md +0 -0
  172. {datajunction-0.0.182 → datajunction-0.0.184}/tests/mcp/__init__.py +0 -0
  173. {datajunction-0.0.182 → datajunction-0.0.184}/tests/mcp/test_cli.py +0 -0
  174. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test__internal.py +0 -0
  175. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_admin.py +0 -0
  176. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_base.py +0 -0
  177. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_builder.py +0 -0
  178. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_client.py +0 -0
  179. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_compile.py +0 -0
  180. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_deploy.py +0 -0
  181. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_generated_client.py +0 -0
  182. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_integration.py +0 -0
  183. {datajunction-0.0.182 → datajunction-0.0.184}/tests/test_models.py +0 -0
  184. {datajunction-0.0.182 → datajunction-0.0.184}/tox.ini +0 -0
@@ -1,5 +1,5 @@
1
1
  setup:
2
- uv sync --extra mcp --group test --extra pandas
2
+ uv sync --extra mcp --group test
3
3
  check:
4
4
  uv run pre-commit run --all-files
5
5
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datajunction
3
- Version: 0.0.182
3
+ Version: 0.0.184
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>
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.12
14
14
  Requires-Python: <4.0,>=3.10
15
15
  Requires-Dist: alive-progress>=3.1.2
16
16
  Requires-Dist: httpx>=0.27.0
17
+ Requires-Dist: pandas>=2.0.2
17
18
  Requires-Dist: pytest-xdist>=3.5.0
18
19
  Requires-Dist: pyyaml>=6.0.1
19
20
  Requires-Dist: requests<3.0.0,>=2.28.2
@@ -22,8 +23,6 @@ Provides-Extra: mcp
22
23
  Requires-Dist: mcp>=1.0.0; extra == 'mcp'
23
24
  Requires-Dist: pydantic-settings>=2.10.1; extra == 'mcp'
24
25
  Requires-Dist: pydantic>=2.0; extra == 'mcp'
25
- Provides-Extra: pandas
26
- Requires-Dist: pandas>=2.0.2; extra == 'pandas'
27
26
  Description-Content-Type: text/markdown
28
27
 
29
28
  # DataJunction Python Client
@@ -2,4 +2,4 @@
2
2
  Version for Hatch
3
3
  """
4
4
 
5
- __version__ = "0.0.182"
5
+ __version__ = "0.0.184"
@@ -4,21 +4,11 @@
4
4
  import logging
5
5
  import os
6
6
  import platform
7
- import warnings
8
7
  from dataclasses import asdict, dataclass
9
8
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, TypedDict, Union
10
9
  from urllib.parse import urljoin
11
10
 
12
- try:
13
- import pandas as pd
14
- except ImportError: # pragma: no cover
15
- warnings.warn(
16
- (
17
- "Optional dependency `pandas` not found, data retrieval"
18
- "disabled. You can install pandas by running `pip install pandas`."
19
- ),
20
- ImportWarning,
21
- )
11
+ import pandas as pd
22
12
  import requests
23
13
  from requests.adapters import CaseInsensitiveDict, HTTPAdapter
24
14
 
@@ -271,7 +261,7 @@ class DJClient:
271
261
  @staticmethod
272
262
  def process_results(results) -> "pd.DataFrame":
273
263
  """
274
- Return a pandas dataframe of the results if pandas is installed
264
+ Return a pandas dataframe of the results
275
265
  """
276
266
  if "results" in results and results["results"]:
277
267
  columns = results["results"][0]["columns"]
@@ -5,7 +5,7 @@ import json
5
5
  import logging
6
6
  import os
7
7
  from pathlib import Path
8
- from typing import Optional
8
+ from typing import Any, Optional
9
9
 
10
10
  from rich import box
11
11
  from rich.console import Console, Group
@@ -601,10 +601,15 @@ class DJCLI:
601
601
  )
602
602
  return
603
603
 
604
- # Handle error responses
605
- if isinstance(result, dict) and "message" in result:
606
- console.print(f"[bold red]ERROR:[/bold red] {result['message']}")
607
- return
604
+ # Handle error responses and raw dict responses.
605
+ # data() / node_data() should return a DataFrame via process_results,
606
+ # but if the raw query response dict is returned instead, try to
607
+ # process it here rather than crashing on result.columns.
608
+ if isinstance(result, dict):
609
+ if "message" in result:
610
+ console.print(f"[bold red]ERROR:[/bold red] {result['message']}")
611
+ return
612
+ result = self.builder_client.process_results(result)
608
613
 
609
614
  # result should be a DataFrame (already limited by API)
610
615
  if format == "json":
@@ -958,6 +963,27 @@ class DJCLI:
958
963
  default="GITHUB_TOKEN",
959
964
  help="Name of the env var holding the GitHub token (default: GITHUB_TOKEN)",
960
965
  )
966
+ codeowners_parser.add_argument(
967
+ "--default-owner",
968
+ type=str,
969
+ default=None,
970
+ help=(
971
+ "Owner for a leading `* <owner>` rule. Unmatched files and any "
972
+ "--exclude'd directories fall through to it (e.g. '@org/team')."
973
+ ),
974
+ )
975
+ codeowners_parser.add_argument(
976
+ "--exclude",
977
+ action="append",
978
+ default=None,
979
+ dest="exclude_dirs",
980
+ metavar="DIR",
981
+ help=(
982
+ "Directory (relative to <directory>) whose nodes get no per-file "
983
+ "owners — they fall through to --default-owner. Repeatable. Use for "
984
+ "machine-generated trees like 'nodes/generated'."
985
+ ),
986
+ )
961
987
 
962
988
  # `dj pull <namespace> <directory>`
963
989
  pull_parser = subparsers.add_parser(
@@ -1489,6 +1515,8 @@ class DJCLI:
1489
1515
  output=args.output,
1490
1516
  github_api_url=args.github_api_url,
1491
1517
  github_token_env=args.github_token_env,
1518
+ default_owner=args.default_owner,
1519
+ exclude_dirs=args.exclude_dirs,
1492
1520
  )
1493
1521
  console = Console()
1494
1522
  console.print(
@@ -1620,52 +1648,115 @@ class DJCLI:
1620
1648
  output_dir.mkdir(parents=True, exist_ok=True)
1621
1649
 
1622
1650
  console.print(
1623
- "[bold]📚 Installing DJ skill[/bold]\n",
1651
+ "[bold]📚 Installing DJ skills[/bold]\n",
1624
1652
  )
1625
1653
 
1626
- # Load bundled skill from package
1627
- dir_name = "datajunction"
1628
- skill_dir = output_dir / dir_name
1629
- skill_file = skill_dir / "SKILL.md"
1630
-
1631
- console.print(f"Installing [cyan]{dir_name}[/cyan]...")
1632
-
1633
- # Find bundled skill file
1634
1654
  from datajunction import __version__ as dj_version
1635
1655
  from importlib.resources import files
1636
1656
 
1637
- try:
1638
- # Read bundled skill markdown using importlib.resources (Python 3.9+)
1639
- skill_file_path = files("datajunction").joinpath(
1640
- "skills/datajunction.md",
1641
- )
1642
- bundled_skill = skill_file_path.read_text(encoding="utf-8")
1657
+ # All bundled DJ skills. ``datajunction`` is the core concepts
1658
+ # skill (always loaded); the others are audience-specific
1659
+ # extensions that compose on top of it.
1660
+ bundled_skills: list[dict[str, Any]] = [
1661
+ {
1662
+ "name": "datajunction",
1663
+ "filename": "datajunction.md",
1664
+ "description": "Core DataJunction concepts and vocabulary",
1665
+ "keywords": [
1666
+ "DataJunction",
1667
+ "DJ",
1668
+ "semantic layer",
1669
+ "dimension link",
1670
+ "star schema",
1671
+ "node types",
1672
+ ],
1673
+ },
1674
+ {
1675
+ "name": "datajunction-query",
1676
+ "filename": "datajunction-query.md",
1677
+ "description": "Querying DJ metrics via MCP tools and APIs",
1678
+ "keywords": [
1679
+ "query metric",
1680
+ "generate SQL",
1681
+ "get metric data",
1682
+ "search_nodes",
1683
+ "build_metric_sql",
1684
+ "common dimensions",
1685
+ ],
1686
+ },
1687
+ {
1688
+ "name": "datajunction-semantic-model",
1689
+ "filename": "datajunction-semantic-model.md",
1690
+ "description": "DJ semantic modeling: query-to-nodes decomposition, ratio decomposition, naming, ownership",
1691
+ "keywords": [
1692
+ "semantic modeling",
1693
+ "decompose query",
1694
+ "ratio metric",
1695
+ "derived metric",
1696
+ "base metric",
1697
+ "metric naming",
1698
+ "namespace organization",
1699
+ "node ownership",
1700
+ ],
1701
+ },
1702
+ {
1703
+ "name": "datajunction-repo",
1704
+ "filename": "datajunction-repo.md",
1705
+ "description": "Authoring DJ nodes via YAML in a git-backed repository",
1706
+ "keywords": [
1707
+ "YAML nodes",
1708
+ "repo-backed namespace",
1709
+ "feature branch",
1710
+ "git workflow",
1711
+ "cube YAML",
1712
+ "metric YAML",
1713
+ "temporal partition",
1714
+ ],
1715
+ },
1716
+ {
1717
+ "name": "datajunction-api",
1718
+ "filename": "datajunction-api.md",
1719
+ "description": "Direct REST API authoring of DJ nodes for exploration / prototyping",
1720
+ "keywords": [
1721
+ "DJ API",
1722
+ "REST API",
1723
+ "curl",
1724
+ "POST nodes",
1725
+ "API authoring",
1726
+ "prototyping",
1727
+ ],
1728
+ },
1729
+ ]
1730
+
1731
+ missing: list[str] = []
1732
+ for skill in bundled_skills:
1733
+ dir_name = skill["name"]
1734
+ skill_dir = output_dir / dir_name
1735
+ skill_file = skill_dir / "SKILL.md"
1736
+
1737
+ console.print(f"Installing [cyan]{dir_name}[/cyan]...")
1738
+
1739
+ try:
1740
+ skill_file_path = files("datajunction").joinpath(
1741
+ f"skills/{skill['filename']}",
1742
+ )
1743
+ bundled_skill = skill_file_path.read_text(encoding="utf-8")
1744
+ except FileNotFoundError: # pragma: no cover
1745
+ missing.append(skill["filename"])
1746
+ continue
1643
1747
 
1644
- # Create directory
1645
1748
  skill_dir.mkdir(parents=True, exist_ok=True)
1646
1749
 
1647
- # Write SKILL.md
1648
1750
  with open(skill_file, "w") as f:
1649
1751
  f.write(bundled_skill)
1650
1752
 
1651
- # Write metadata
1652
1753
  metadata_file = skill_dir / "metadata.json"
1653
1754
  with open(metadata_file, "w") as f:
1654
1755
  metadata = {
1655
- "name": "datajunction",
1756
+ "name": skill["name"],
1656
1757
  "version": dj_version,
1657
- "description": "Comprehensive DataJunction semantic layer guide",
1658
- "keywords": [
1659
- "DataJunction",
1660
- "DJ",
1661
- "semantic layer",
1662
- "dimension link",
1663
- "metric",
1664
- "SQL generation",
1665
- "YAML nodes",
1666
- "git workflow",
1667
- "repo-backed namespace",
1668
- ],
1758
+ "description": skill["description"],
1759
+ "keywords": skill["keywords"],
1669
1760
  "metadata": {
1670
1761
  "source": "bundled",
1671
1762
  "dj_version": dj_version,
@@ -1681,13 +1772,14 @@ class DJCLI:
1681
1772
  f" [dim]└─ metadata.json (v{dj_version})[/dim]\n",
1682
1773
  )
1683
1774
 
1775
+ if missing: # pragma: no cover
1684
1776
  console.print(
1685
- f"[bold green] Skill installed to {output_dir}[/bold green]\n",
1777
+ f"[red] Bundled skills not found: {', '.join(missing)}. "
1778
+ f"Please ensure datajunction is properly installed.[/red]",
1686
1779
  )
1687
-
1688
- except FileNotFoundError: # pragma: no cover
1780
+ else:
1689
1781
  console.print(
1690
- "[red] Bundled skill not found. Please ensure datajunction is properly installed.[/red]",
1782
+ f"[bold green] Skills installed to {output_dir}[/bold green]\n",
1691
1783
  )
1692
1784
 
1693
1785
  # Install subagent if requested
@@ -1704,9 +1796,13 @@ name: dj
1704
1796
  description: >
1705
1797
  DataJunction semantic layer expert. Use proactively for any DataJunction
1706
1798
  or DJ work — querying metrics, exploring nodes and dimensions, building
1707
- SQL, understanding lineage, and semantic layer design.
1799
+ SQL, understanding lineage, authoring metrics, and semantic layer design.
1708
1800
  skills:
1709
1801
  - datajunction
1802
+ - datajunction-query
1803
+ - datajunction-semantic-model
1804
+ - datajunction-repo
1805
+ - datajunction-api
1710
1806
  model: inherit
1711
1807
  ---
1712
1808
  """
@@ -304,6 +304,8 @@ class DeploymentService:
304
304
  output: str | Path = ".github/CODEOWNERS",
305
305
  github_api_url: str | None = None,
306
306
  github_token_env: str = "GITHUB_TOKEN",
307
+ default_owner: str | None = None,
308
+ exclude_dirs: list[str] | None = None,
307
309
  ) -> int:
308
310
  """
309
311
  Generate a CODEOWNERS file from the owners fields in DJ node YAML files.
@@ -317,9 +319,24 @@ class DeploymentService:
317
319
  email addresses in owners fields are resolved to GitHub usernames via the
318
320
  search API. Unresolvable emails are emitted as-is with a warning comment.
319
321
 
320
- Returns the number of entries written.
322
+ ``default_owner``, when set, emits a leading ``* <default_owner>`` rule so
323
+ unmatched files (and any excluded directories) fall through to it. Because
324
+ CODEOWNERS is last-match-wins, the per-file rules below it still take
325
+ precedence for the files they name.
326
+
327
+ ``exclude_dirs`` lists directories (relative to base_dir) whose nodes are
328
+ NOT given per-file owners — they fall through to ``default_owner`` instead.
329
+ This is for machine-generated trees (e.g. ``nodes/generated``) that have no
330
+ individual human owner and should be team-owned as a block.
331
+
332
+ Returns the number of per-file entries written (excludes the default rule).
321
333
  """
322
334
  base = Path(base_dir).resolve()
335
+ excluded_dirs = [(base / d).resolve() for d in (exclude_dirs or [])]
336
+
337
+ def _is_excluded(path: Path) -> bool:
338
+ return any(d == path or d in path.parents for d in excluded_dirs)
339
+
323
340
  _token = os.getenv(github_token_env)
324
341
  # Only resolve if both API URL and token are available
325
342
  lookup: tuple[str, str] | None = (
@@ -353,6 +370,8 @@ class DeploymentService:
353
370
  for path in sorted(base.rglob("*.yaml")):
354
371
  if path.name == "dj.yaml":
355
372
  continue
373
+ if _is_excluded(path):
374
+ continue
356
375
  try:
357
376
  node = DeploymentService.read_yaml_file(path)
358
377
  except Exception: # skip unreadable / non-dict files
@@ -376,7 +395,12 @@ class DeploymentService:
376
395
  )
377
396
  for w in warnings:
378
397
  lines.append(f"# {w}")
379
- lines += ["", *entries, ""]
398
+ lines.append("")
399
+ # Default rule first so per-file rules below win (last-match-wins).
400
+ if default_owner:
401
+ lines.append(f"* {default_owner}")
402
+ lines.append("")
403
+ lines += [*entries, ""]
380
404
  content = "\n".join(lines)
381
405
 
382
406
  output_path = Path(output)
@@ -0,0 +1,232 @@
1
+ ---
2
+ name: datajunction-api
3
+ description: |
4
+ Activate this skill when authoring DataJunction (DJ) nodes via the REST
5
+ API directly (curl, HTTP clients) — typically for exploration, ad-hoc
6
+ prototyping, or namespaces that aren't repo-backed. For modeling
7
+ decisions and the decomposition workflow, invoke `datajunction-semantic-model`.
8
+ For repo-backed YAML authoring (the production path), invoke
9
+ `datajunction-repo`. For concepts, invoke `datajunction`.
10
+ Keywords:
11
+ - DJ API, REST API, curl
12
+ - POST nodes/metric, POST nodes/dimension
13
+ - create metric, create dimension, create cube
14
+ - API approach, direct API changes
15
+ - prototyping, exploration
16
+ user-invocable: false
17
+ ---
18
+
19
+ # DataJunction Direct API Authoring
20
+
21
+ Direct REST API authoring for DJ nodes. Use this skill for quick exploration, prototyping, or working in namespaces that don't use the repo-backed workflow.
22
+
23
+ For the modeling work upstream of any authoring (decomposition, naming, ratio decomposition, etc.), see `datajunction-semantic-model`. For the production-path equivalent of these patterns in YAML, see `datajunction-repo`.
24
+
25
+ ## When to Use the API Approach
26
+
27
+ **✅ MUST use repo workflow instead** (`datajunction-repo`) for:
28
+ - Namespaces configured as repo-backed and read-only (`git_only: true`) — direct API changes are rejected
29
+
30
+ **✅ Should use repo workflow** for:
31
+ - Production changes (review required)
32
+ - Multi-node changes (related metrics/dimensions)
33
+ - Team environments (multiple contributors)
34
+ - Audit-trail requirements
35
+ - Complex refactoring
36
+
37
+ **✅ API workflow is appropriate** for:
38
+ - Quick exploration and prototyping
39
+ - Ad-hoc analysis
40
+ - Single-user, non-production namespaces
41
+ - Temporary metrics
42
+ - Non-production experiments
43
+ - Only when the target namespace is NOT read-only repo-backed
44
+
45
+ ---
46
+
47
+ ## Checking if a Namespace Is Repo-Backed
48
+
49
+ Before authoring via API, verify the target namespace allows it.
50
+
51
+ **Best approach — `get_node_details` MCP tool** (`datajunction-query` skill):
52
+
53
+ ```
54
+ get_node_details(name="finance.total_revenue")
55
+ ```
56
+
57
+ The response will include git repository information:
58
+ ```
59
+ Git Repository:
60
+ Repo: owner/dj-finance
61
+ Branch: main
62
+ Default Branch: main
63
+ → This namespace is repo-backed (use git workflow for changes)
64
+ ```
65
+
66
+ **Alternative — REST API** (shows read-only status):
67
+ ```bash
68
+ curl -b ~/.dj/cookies.txt -X GET $DJ_URL/namespaces/finance/git
69
+
70
+ # Response:
71
+ {
72
+ "github_repo_path": "owner/dj-finance",
73
+ "git_branch": "main",
74
+ "default_branch": "main",
75
+ "git_path": "nodes/",
76
+ "git_only": true ← If true, namespace is read-only (API changes blocked)
77
+ }
78
+ ```
79
+
80
+ **Decision tree:**
81
+ - **If git info is present AND `git_only: true`**: MUST use repo workflow (API changes will fail)
82
+ - **If git info is present AND `git_only: false`**: Can use either workflow
83
+ - **If git info is null**: Use API workflow (direct POST/PATCH)
84
+
85
+ ---
86
+
87
+ ## Creating a Metric
88
+
89
+ ### Metric Structure
90
+
91
+ ```sql
92
+ SELECT <aggregation_expression> AS <metric_name>
93
+ FROM <single_node>
94
+ ```
95
+
96
+ Metrics select a **single expression** from a **single source, transform, or dimension node**. They cannot contain WHERE clauses — use CASE WHEN instead. See `datajunction-semantic-model` for the modeling rationale.
97
+
98
+ ### Metric Metadata Fields
99
+
100
+ **Required:**
101
+ - `name` — Fully qualified metric name (e.g., `finance.total_revenue`)
102
+ - `query` — SQL aggregation expression
103
+
104
+ **Recommended:**
105
+ - `description` — Human-readable description
106
+ - `metric_metadata.direction` — `higher_is_better` / `lower_is_better` / `neutral`
107
+ - `metric_metadata.unit` — `dollar` / `unitless` (**⚠️ NOT `count`** — server rejects)
108
+ - `mode` — `draft` / `published`
109
+ - `required_dimensions` — Dimensions required for this metric to make sense
110
+ - `owners` — List of email addresses (prefer team emails)
111
+
112
+ ### Examples
113
+
114
+ **COUNT**:
115
+ ```bash
116
+ curl -b ~/.dj/cookies.txt -X POST $DJ_URL/nodes/metric/ \
117
+ -H 'Content-Type: application/json' \
118
+ -d '{
119
+ "name": "finance.num_transactions",
120
+ "description": "Total number of transactions",
121
+ "query": "SELECT COUNT(transaction_id) AS num_transactions FROM finance.transactions",
122
+ "owners": ["data-platform-team@company.com"],
123
+ "mode": "published"
124
+ }'
125
+ ```
126
+
127
+ **SUM**:
128
+ ```bash
129
+ curl -b ~/.dj/cookies.txt -X POST $DJ_URL/nodes/metric/ \
130
+ -H 'Content-Type: application/json' \
131
+ -d '{
132
+ "name": "finance.total_revenue",
133
+ "description": "Total revenue from all transactions",
134
+ "query": "SELECT SUM(amount_usd) AS total_revenue FROM finance.transactions",
135
+ "metric_metadata": {
136
+ "direction": "higher_is_better",
137
+ "unit": "dollar"
138
+ },
139
+ "owners": ["finance-data-team@company.com"],
140
+ "mode": "published"
141
+ }'
142
+ ```
143
+
144
+ **Conditional aggregation** (CASE WHEN, not WHERE):
145
+ ```bash
146
+ curl -b ~/.dj/cookies.txt -X POST $DJ_URL/nodes/metric/ \
147
+ -H 'Content-Type: application/json' \
148
+ -d '{
149
+ "name": "finance.completed_revenue",
150
+ "description": "Revenue from completed non-refund transactions",
151
+ "query": "
152
+ SELECT SUM(
153
+ CASE
154
+ WHEN status = '\''completed'\'' AND refund_flag = false
155
+ THEN amount_usd
156
+ ELSE 0
157
+ END
158
+ ) AS completed_revenue
159
+ FROM finance.transactions
160
+ ",
161
+ "metric_metadata": {
162
+ "direction": "higher_is_better",
163
+ "unit": "dollar"
164
+ },
165
+ "owners": ["finance-data-team@company.com"],
166
+ "mode": "published"
167
+ }'
168
+ ```
169
+
170
+ **Ratio over base metrics** (decompose first, then derive — see `datajunction-semantic-model`):
171
+ ```bash
172
+ # Step 1: create the base metrics (one curl each)
173
+ curl -X POST $DJ_URL/nodes/metric/ -d '{
174
+ "name": "finance.clicks",
175
+ "query": "SELECT COUNT_IF(event = '\''click'\'') FROM finance.events",
176
+ "owners": ["marketing@company.com"],
177
+ "mode": "published"
178
+ }'
179
+
180
+ curl -X POST $DJ_URL/nodes/metric/ -d '{
181
+ "name": "finance.impressions",
182
+ "query": "SELECT COUNT_IF(event = '\''impression'\'') FROM finance.events",
183
+ "owners": ["marketing@company.com"],
184
+ "mode": "published"
185
+ }'
186
+
187
+ # Step 2: derived ratio metric referencing the base metrics
188
+ curl -X POST $DJ_URL/nodes/metric/ -d '{
189
+ "name": "finance.conversion_rate",
190
+ "description": "Click-through rate as percentage",
191
+ "query": "SELECT finance.clicks * 100.0 / NULLIF(finance.impressions, 0)",
192
+ "metric_metadata": {
193
+ "direction": "higher_is_better",
194
+ "unit": "unitless"
195
+ },
196
+ "owners": ["marketing@company.com"],
197
+ "mode": "published"
198
+ }'
199
+ ```
200
+
201
+ DJ automatically handles divide-by-zero, but `NULLIF()` is extra safety.
202
+
203
+ ---
204
+
205
+ ## Creating Other Node Types via API
206
+
207
+ Same pattern as metrics — POST JSON to the appropriate endpoint:
208
+
209
+ - `POST /nodes/source/` — source nodes (catalog/schema/table refs)
210
+ - `POST /nodes/dimension/` — dimension nodes
211
+ - `POST /nodes/transform/` — transform nodes
212
+ - `POST /nodes/cube/` — cubes (metric + dimension combinations)
213
+
214
+ For the YAML-equivalent shapes of each, see `datajunction-repo` — the field set is the same, just expressed in JSON instead of YAML.
215
+
216
+ ---
217
+
218
+ ## Updating and Deleting Nodes
219
+
220
+ **Update** (PATCH):
221
+ ```bash
222
+ curl -b ~/.dj/cookies.txt -X PATCH $DJ_URL/nodes/finance.total_revenue/ \
223
+ -H 'Content-Type: application/json' \
224
+ -d '{"description": "Updated description"}'
225
+ ```
226
+
227
+ **Deactivate** (soft delete):
228
+ ```bash
229
+ curl -b ~/.dj/cookies.txt -X DELETE $DJ_URL/nodes/finance.total_revenue/
230
+ ```
231
+
232
+ Deactivated nodes can be revived. For hard-delete (irreversible), use the `dj` CLI: `dj delete-node finance.total_revenue --hard`.