recce-nightly 1.8.0.20250616__tar.gz → 1.8.0.20250617__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.

Potentially problematic release.


This version of recce-nightly might be problematic. Click here for more details.

Files changed (159) hide show
  1. {recce_nightly-1.8.0.20250616/recce_nightly.egg-info → recce_nightly-1.8.0.20250617}/PKG-INFO +1 -1
  2. recce_nightly-1.8.0.20250617/recce/VERSION +1 -0
  3. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/adapter/dbt_adapter/__init__.py +211 -110
  4. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/cli.py +4 -4
  5. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/404.html +2 -2
  6. recce_nightly-1.8.0.20250617/recce/data/_next/static/chunks/92-bd5f33f1c3cb9d93.js +1 -0
  7. recce_nightly-1.8.0.20250616/recce/data/_next/static/chunks/app/page-848f2149d3c62dd1.js → recce_nightly-1.8.0.20250617/recce/data/_next/static/chunks/app/page-f1048e1fe24111f8.js +1 -1
  8. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/index.html +2 -2
  9. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/index.txt +3 -3
  10. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/models/types.py +1 -13
  11. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/server.py +17 -0
  12. recce_nightly-1.8.0.20250617/recce/util/lineage.py +78 -0
  13. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617/recce_nightly.egg-info}/PKG-INFO +1 -1
  14. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce_nightly.egg-info/SOURCES.txt +4 -4
  15. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/adapter/dbt_adapter/test_dbt_cll.py +165 -23
  16. recce_nightly-1.8.0.20250616/recce/VERSION +0 -1
  17. recce_nightly-1.8.0.20250616/recce/data/_next/static/chunks/92-8753f5687183e400.js +0 -1
  18. recce_nightly-1.8.0.20250616/recce/util/lineage.py +0 -136
  19. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/LICENSE +0 -0
  20. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/README.md +0 -0
  21. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/pyproject.toml +0 -0
  22. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/__init__.py +0 -0
  23. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/adapter/__init__.py +0 -0
  24. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/adapter/base.py +0 -0
  25. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/adapter/dbt_adapter/dbt_version.py +0 -0
  26. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/adapter/sqlmesh_adapter.py +0 -0
  27. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/apis/__init__.py +0 -0
  28. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/apis/check_api.py +0 -0
  29. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/apis/check_func.py +0 -0
  30. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/apis/run_api.py +0 -0
  31. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/apis/run_func.py +0 -0
  32. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/artifact.py +0 -0
  33. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/config.py +0 -0
  34. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/core.py +0 -0
  35. {recce_nightly-1.8.0.20250616/recce/data/_next/static/w18Z-hT6EIuYJQK1WQHit → recce_nightly-1.8.0.20250617/recce/data/_next/static/6pJWLeTWseySFL3ozLQBi}/_buildManifest.js +0 -0
  36. {recce_nightly-1.8.0.20250616/recce/data/_next/static/w18Z-hT6EIuYJQK1WQHit → recce_nightly-1.8.0.20250617/recce/data/_next/static/6pJWLeTWseySFL3ozLQBi}/_ssgManifest.js +0 -0
  37. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/1bff33f1-1ef85cf5e658a751.js +0 -0
  38. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/217-879a84d70f7a907c.js +0 -0
  39. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/29e3cc0d-60045b2e47aa3916.js +0 -0
  40. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/36e1c10d-35e36448f4f83961.js +0 -0
  41. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/3998a672-03adacad07b346ac.js +0 -0
  42. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/3a92ee20-1081c360214f9602.js +0 -0
  43. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/450c323b-fd94e7ffaa4a5efa.js +0 -0
  44. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/47d8844f-929aed9b1c73a905.js +0 -0
  45. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/608-3b079b544e5d5f5e.js +0 -0
  46. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/6dc81886-adbfa45836061d79.js +0 -0
  47. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/7a8a3e83-edf6dc64b5d5f0a5.js +0 -0
  48. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/7f27ae6c-d5f0438edd5c2a5b.js +0 -0
  49. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/826-1fdc111c49b34b0f.js +0 -0
  50. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/86730205-cfb14e3f051bab35.js +0 -0
  51. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/8d700b6a.8bb140898499c512.js +0 -0
  52. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/960-49d66f0cbac6af8a.js +0 -0
  53. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/9746af58-a42b7d169cacadf0.js +0 -0
  54. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/a30376cd-de84559016d7e133.js +0 -0
  55. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/app/_not-found/page-01ed58b7f971d311.js +0 -0
  56. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/app/layout-af033601bf81ed53.js +0 -0
  57. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/b63b1b3f-4282bdcf459e075c.js +0 -0
  58. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/bbda5537-9ec25eb1dd62348a.js +0 -0
  59. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/c132bf7d-08cb668a789d6afd.js +0 -0
  60. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/ce84277d-2e5d1d46910cf052.js +0 -0
  61. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/febdd86e-c6b525341634b860.js +0 -0
  62. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/fee69bc6-2dbccaf9b90474e6.js +0 -0
  63. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/framework-ded83d71b51ce901.js +0 -0
  64. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/main-app-39061b0166c47f55.js +0 -0
  65. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/main-b5b3ae20a1405261.js +0 -0
  66. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/pages/_app-437c455677d62394.js +0 -0
  67. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/pages/_error-e7650df18ca04bde.js +0 -0
  68. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
  69. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/chunks/webpack-7b49d5ba7e3a434d.js +0 -0
  70. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/css/17a96168e3a9db13.css +0 -0
  71. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/css/1b121dc4d36aeb4d.css +0 -0
  72. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/css/35c6679a098e1e34.css +0 -0
  73. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/css/951e2e0eea2d4a5b.css +0 -0
  74. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2 +0 -0
  75. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-cyrillic-800-normal.bd5c9f50.woff +0 -0
  76. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.94a63aea.woff2 +0 -0
  77. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.e6e0d8d0.woff +0 -0
  78. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-latin-800-normal.6f8fa298.woff2 +0 -0
  79. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-latin-800-normal.fc315020.woff +0 -0
  80. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-latin-ext-800-normal.013b84f9.woff2 +0 -0
  81. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-latin-ext-800-normal.2e5381b2.woff +0 -0
  82. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-vietnamese-800-normal.20c545e6.woff +0 -0
  83. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/montserrat-vietnamese-800-normal.c0035377.woff2 +0 -0
  84. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/_next/static/media/reload-image.79aabb7d.svg +0 -0
  85. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/favicon.ico +0 -0
  86. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/imgs/feedback/thumbs-down.png +0 -0
  87. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/imgs/feedback/thumbs-up.png +0 -0
  88. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/imgs/reload-image.svg +0 -0
  89. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/data/logo/recce-logo-white.png +0 -0
  90. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/diff.py +0 -0
  91. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/event/CONFIG +0 -0
  92. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/event/SENTRY_DNS +0 -0
  93. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/event/__init__.py +0 -0
  94. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/event/collector.py +0 -0
  95. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/event/track.py +0 -0
  96. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/exceptions.py +0 -0
  97. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/git.py +0 -0
  98. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/github.py +0 -0
  99. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/models/__init__.py +0 -0
  100. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/models/check.py +0 -0
  101. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/models/run.py +0 -0
  102. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/pull_request.py +0 -0
  103. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/run.py +0 -0
  104. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/state.py +0 -0
  105. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/summary.py +0 -0
  106. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/__init__.py +0 -0
  107. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/core.py +0 -0
  108. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/dataframe.py +0 -0
  109. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/histogram.py +0 -0
  110. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/lineage.py +0 -0
  111. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/profile.py +0 -0
  112. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/query.py +0 -0
  113. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/rowcount.py +0 -0
  114. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/schema.py +0 -0
  115. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/top_k.py +0 -0
  116. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/tasks/valuediff.py +0 -0
  117. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/__init__.py +0 -0
  118. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/api_token.py +0 -0
  119. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/breaking.py +0 -0
  120. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/cache.py +0 -0
  121. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/cll.py +0 -0
  122. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/io.py +0 -0
  123. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/logger.py +0 -0
  124. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/pydantic_model.py +0 -0
  125. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/recce_cloud.py +0 -0
  126. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/util/singleton.py +0 -0
  127. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce/yaml/__init__.py +0 -0
  128. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce_nightly.egg-info/dependency_links.txt +0 -0
  129. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce_nightly.egg-info/entry_points.txt +0 -0
  130. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce_nightly.egg-info/requires.txt +0 -0
  131. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/recce_nightly.egg-info/top_level.txt +0 -0
  132. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/setup.cfg +0 -0
  133. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/setup.py +0 -0
  134. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/__init__.py +0 -0
  135. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/adapter/__init__.py +0 -0
  136. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/adapter/dbt_adapter/__init__.py +0 -0
  137. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/adapter/dbt_adapter/conftest.py +0 -0
  138. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/adapter/dbt_adapter/dbt_test_helper.py +0 -0
  139. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -0
  140. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/adapter/dbt_adapter/test_selector.py +0 -0
  141. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/__init__.py +0 -0
  142. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/conftest.py +0 -0
  143. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_histogram.py +0 -0
  144. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_lineage.py +0 -0
  145. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_preset_checks.py +0 -0
  146. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_profile.py +0 -0
  147. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_query.py +0 -0
  148. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_row_count.py +0 -0
  149. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_schema.py +0 -0
  150. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_top_k.py +0 -0
  151. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/tasks/test_valuediff.py +0 -0
  152. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/test_cli.py +0 -0
  153. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/test_config.py +0 -0
  154. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/test_core.py +0 -0
  155. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/test_dbt.py +0 -0
  156. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/test_pull_request.py +0 -0
  157. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/test_server.py +0 -0
  158. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/test_state.py +0 -0
  159. {recce_nightly-1.8.0.20250616 → recce_nightly-1.8.0.20250617}/tests/test_summary.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: recce-nightly
3
- Version: 1.8.0.20250616
3
+ Version: 1.8.0.20250617
4
4
  Summary: Environment diff tool for dbt
5
5
  Home-page: https://github.com/InfuseAI/recce
6
6
  Author: InfuseAI Dev Team
@@ -0,0 +1 @@
1
+ 1.8.0.20250617
@@ -23,10 +23,8 @@ from typing import (
23
23
 
24
24
  from recce.event import log_performance
25
25
  from recce.exceptions import RecceException
26
- from recce.util.cll import CllColumnDep, CLLPerformanceTracking, cll
26
+ from recce.util.cll import CLLPerformanceTracking, cll
27
27
  from recce.util.lineage import (
28
- build_dependency_maps,
29
- build_lineage_vertices,
30
28
  filter_dependency_maps,
31
29
  filter_lineage_vertices,
32
30
  find_column_dependencies,
@@ -56,7 +54,6 @@ from ...models.types import (
56
54
  CllColumn,
57
55
  CllData,
58
56
  CllNode,
59
- CllNodeDependsOn,
60
57
  LineageDiff,
61
58
  NodeChange,
62
59
  NodeDiff,
@@ -145,6 +142,7 @@ def silence_no_nodes_warning():
145
142
 
146
143
 
147
144
  logger = logging.getLogger("uvicorn")
145
+ MIN_DBT_NODE_COMPOSITION = 3
148
146
 
149
147
 
150
148
  class ArtifactsEventHandler(FileSystemEventHandler):
@@ -702,7 +700,7 @@ class DbtAdapter(BaseAdapter):
702
700
  for child in child_map:
703
701
  node_name = node["name"]
704
702
  comps = child.split(".")
705
- if len(comps) < 2:
703
+ if len(comps) < MIN_DBT_NODE_COMPOSITION:
706
704
  # only happens in unittest
707
705
  continue
708
706
 
@@ -919,22 +917,21 @@ class DbtAdapter(BaseAdapter):
919
917
 
920
918
  def get_cll(self, node_id: str, column: Optional[str]) -> CllData:
921
919
  cll = self.get_cll_by_node_id(node_id)
922
- if column:
923
- parent_map, child_map = build_dependency_maps(cll)
924
- lineage_nodes, lineage_columns = build_lineage_vertices(cll)
925
- target_column = f"{node_id}_{column}"
926
- upstream, downstream = find_column_dependencies(target_column, parent_map, child_map)
927
- relevant_columns = {target_column}
928
- relevant_columns.update(upstream, downstream)
929
- nodes, columns = filter_lineage_vertices(lineage_nodes, lineage_columns, relevant_columns)
930
- p_map, c_map = filter_dependency_maps(parent_map, child_map, relevant_columns)
931
- return CllData(
932
- nodes=cll.nodes,
933
- lineage_nodes=nodes,
934
- lineage_columns=columns,
935
- parent_map=p_map,
936
- child_map=c_map,
937
- )
920
+ if not column:
921
+ return cll
922
+
923
+ target_column = f"{node_id}_{column}"
924
+ upstream, downstream = find_column_dependencies(target_column, cll.parent_map, cll.child_map)
925
+ relevant_columns = {target_column}
926
+ relevant_columns.update(upstream, downstream)
927
+ nodes, columns = filter_lineage_vertices(cll.nodes, cll.columns, relevant_columns)
928
+ p_map, c_map = filter_dependency_maps(cll.parent_map, cll.child_map, relevant_columns)
929
+ return CllData(
930
+ nodes=nodes,
931
+ columns=columns,
932
+ parent_map=p_map,
933
+ child_map=c_map,
934
+ )
938
935
 
939
936
  def get_cll_by_node_id(self, node_id: str, base: Optional[bool] = False) -> CllData:
940
937
  cll_tracker = CLLPerformanceTracking()
@@ -948,60 +945,72 @@ class DbtAdapter(BaseAdapter):
948
945
  cll_node_ids = parent_ids.union(child_ids)
949
946
  cll_node_ids.add(node_id)
950
947
 
951
- node_manifest = self.get_cll_nodes_from_metadata(base=base)
952
948
  nodes = {}
949
+ cll_data = CllData()
953
950
  for node_id in cll_node_ids:
954
- if node_id not in node_manifest:
951
+ if node_id not in manifest.sources and node_id not in manifest.nodes and node_id not in manifest.exposures:
952
+ continue
953
+ cll_data_one = self.get_cll_cached(node_id, base=base)
954
+ if cll_data_one is None:
955
955
  continue
956
- nodes[node_id] = self.get_cll_cached(node_id, base=base)
956
+ for n_id, n in cll_data_one.nodes.items():
957
+ cll_data.nodes[n_id] = n
958
+ for c_id, c in cll_data_one.columns.items():
959
+ cll_data.columns[c_id] = c
960
+ for p_id, parents in cll_data_one.parent_map.items():
961
+ cll_data.parent_map[p_id] = parents
962
+
963
+ # build the child map
964
+ cll_data.child_map = {}
965
+ for node_id, parents in cll_data.parent_map.items():
966
+ for parent in parents:
967
+ if parent not in cll_data.child_map:
968
+ cll_data.child_map[parent] = set()
969
+ cll_data.child_map[parent].add(node_id)
957
970
 
958
971
  cll_tracker.end_column_lineage()
959
972
  cll_tracker.set_total_nodes(len(nodes))
960
973
  log_performance("column level lineage", cll_tracker.to_dict())
961
974
  cll_tracker.reset()
962
975
 
963
- return CllData(nodes=nodes)
976
+ return cll_data
964
977
 
965
978
  @lru_cache(maxsize=128)
966
- def get_cll_cached(self, node_id: str, base: Optional[bool] = False) -> CllNode:
967
- nodes = self.get_cll_nodes_from_metadata(base=base)
968
-
969
- manifest = self.curr_manifest if base is False else self.base_manifest
970
- manifest_dict = manifest.to_dict()
971
- parent_list = []
972
- if node_id in manifest_dict["parent_map"]:
973
- parent_list = manifest_dict["parent_map"][node_id]
979
+ def get_cll_cached(self, node_id: str, base: Optional[bool] = False) -> Optional[CllData]:
980
+ cll_tracker = CLLPerformanceTracking()
974
981
 
975
- node = nodes[node_id]
976
- self.append_column_lineage(node, parent_list, base)
977
- return node
982
+ node, parent_list = self.get_cll_node(node_id, base=base)
983
+ if node is None:
984
+ return None
978
985
 
979
- def append_column_lineage(self, node: CllNode, parent_list: List, base: Optional[bool] = False):
980
986
  def _apply_all_columns(node: CllNode, transformation_type):
987
+ cll_data = CllData()
988
+ cll_data.nodes[node.id] = node
989
+ cll_data.parent_map[node.id] = set(parent_list)
981
990
  for col in node.columns.values():
991
+ column_id = f"{node.id}_{col.name}"
982
992
  col.transformation_type = transformation_type
993
+ cll_data.columns[column_id] = col
994
+ cll_data.parent_map[column_id] = set()
995
+ return cll_data
983
996
 
984
- cll_tracker = CLLPerformanceTracking()
985
- nodes = self.get_cll_nodes_from_metadata(base=base)
986
997
  manifest = as_manifest(self.get_manifest(base))
998
+ catalog = self.curr_catalog if base is False else self.base_catalog
987
999
  resource_type = node.resource_type
988
1000
  if resource_type not in {"model", "seed", "source", "snapshot"}:
989
- return
1001
+ return _apply_all_columns(node, "unknown")
990
1002
 
991
1003
  if resource_type == "source" or resource_type == "seed":
992
- _apply_all_columns(node, "source")
993
- return
1004
+ return _apply_all_columns(node, "source")
994
1005
 
995
1006
  if node.raw_code is None or self.is_python_model(node.id, base=base):
996
- _apply_all_columns(node, "unknown")
997
- return
1007
+ return _apply_all_columns(node, "unknown")
998
1008
 
999
1009
  if node.name == "metricflow_time_spine":
1000
- _apply_all_columns(node, "source")
1001
- return
1010
+ return _apply_all_columns(node, "source")
1002
1011
 
1003
1012
  if not node.columns:
1004
- return
1013
+ return _apply_all_columns(node, "unknown")
1005
1014
 
1006
1015
  table_id_map = {}
1007
1016
 
@@ -1015,17 +1024,14 @@ class DbtAdapter(BaseAdapter):
1015
1024
  project_or_package = args[0]
1016
1025
  node_name = args[1]
1017
1026
 
1018
- for key, n in nodes.items():
1019
- if n.resource_type == "source":
1020
- # For resource_type==source, you should use "source(...)"
1021
- continue
1027
+ for key, n in manifest.nodes.items():
1022
1028
  if n.name != node_name:
1023
1029
  continue
1024
1030
  if project_or_package is not None and n.package_name != project_or_package:
1025
1031
  continue
1026
1032
 
1027
1033
  # replace id "." to "_"
1028
- unique_id = n.id
1034
+ unique_id = n.unique_id
1029
1035
  table_name = unique_id.replace(".", "_")
1030
1036
  table_id_map[table_name.lower()] = unique_id
1031
1037
  return table_name
@@ -1033,16 +1039,14 @@ class DbtAdapter(BaseAdapter):
1033
1039
  raise ValueError(f"Cannot find node {node_name} in the manifest")
1034
1040
 
1035
1041
  def source_func(source_name, name):
1036
- for key, n in nodes.items():
1037
- if n.resource_type != "source":
1038
- continue
1042
+ for key, n in manifest.sources.items():
1039
1043
  if n.source_name != source_name:
1040
1044
  continue
1041
1045
  if n.name != name:
1042
1046
  continue
1043
1047
 
1044
1048
  # replace id "." to "_"
1045
- unique_id = n.id
1049
+ unique_id = n.unique_id
1046
1050
  table_name = unique_id.replace(".", "_")
1047
1051
  table_id_map[table_name.lower()] = unique_id
1048
1052
  return table_name
@@ -1056,13 +1060,17 @@ class DbtAdapter(BaseAdapter):
1056
1060
  )
1057
1061
 
1058
1062
  schema = {}
1059
- for parent_id in parent_list:
1060
- parent_node = nodes.get(parent_id)
1061
- if parent_node is None:
1062
- continue
1063
- columns = parent_node.columns
1064
- table_name = parent_id.replace(".", "_")
1065
- schema[table_name] = {name: column.type for name, column in columns.items()}
1063
+ if catalog is not None:
1064
+ for parent_id in parent_list:
1065
+ table_name = parent_id.replace(".", "_")
1066
+ columns = {}
1067
+ if parent_id in catalog.nodes:
1068
+ for col_name, col_metadata in catalog.nodes[parent_id].columns.items():
1069
+ columns[col_name] = col_metadata.type
1070
+ if parent_id in catalog.sources:
1071
+ for col_name, col_metadata in catalog.sources[parent_id].columns.items():
1072
+ columns[col_name] = col_metadata.type
1073
+ schema[table_name] = columns
1066
1074
 
1067
1075
  try:
1068
1076
  compiled_sql = self.generate_sql(raw_code, base=base, context=jinja_context, provided_manifest=manifest)
@@ -1071,75 +1079,103 @@ class DbtAdapter(BaseAdapter):
1071
1079
  dialect = self.get_manifest(base).metadata.adapter_type
1072
1080
  m2c, c2c_map = cll(compiled_sql, schema=schema, dialect=dialect)
1073
1081
  except RecceException:
1074
- _apply_all_columns(node, "unknown")
1075
1082
  cll_tracker.increment_sqlglot_error_nodes()
1076
- return
1083
+ return _apply_all_columns(node, "unknown")
1077
1084
  except Exception:
1078
- _apply_all_columns(node, "unknown")
1079
1085
  cll_tracker.increment_other_error_nodes()
1080
- return
1086
+ return _apply_all_columns(node, "unknown")
1081
1087
 
1082
1088
  # Add cll dependency to the node.
1083
- depends_on = [CllColumnDep(node=table_id_map[d.node.lower()], column=d.column) for d in m2c]
1084
- node.depends_on.columns = depends_on
1089
+ cll_data = CllData()
1090
+ cll_data.nodes[node.id] = node
1091
+ cll_data.columns = {f"{node.id}_{col.name}": col for col in node.columns.values()}
1092
+
1093
+ # parent map for node
1094
+ depends_on = set(parent_list)
1095
+ for d in m2c:
1096
+ parent_key = f"{table_id_map[d.node.lower()]}_{d.column}"
1097
+ depends_on.add(parent_key)
1098
+ cll_data.parent_map[node_id] = depends_on
1099
+
1100
+ # parent map for columns
1085
1101
  for name, column in node.columns.items():
1102
+ depends_on = set()
1103
+ column_id = f"{node.id}_{name}"
1086
1104
  if name in c2c_map:
1087
- column.depends_on = [
1088
- CllColumnDep(node=table_id_map[d.node.lower()], column=d.column) for d in c2c_map[name].depends_on
1089
- ]
1105
+ for d in c2c_map[name].depends_on:
1106
+ parent_key = f"{table_id_map[d.node.lower()]}_{d.column}"
1107
+ depends_on.add(parent_key)
1090
1108
  column.transformation_type = c2c_map[name].transformation_type
1109
+ cll_data.parent_map[column_id] = set(depends_on)
1110
+ return cll_data
1091
1111
 
1092
- @lru_cache(maxsize=2)
1093
- def get_cll_nodes_from_metadata(self, base: Optional[bool] = False) -> Dict[str, CllNode]:
1112
+ def get_cll_node(self, node_id: str, base: Optional[bool] = False) -> Tuple[Optional[CllNode], list[str]]:
1094
1113
  manifest = self.curr_manifest if base is False else self.base_manifest
1095
1114
  catalog = self.curr_catalog if base is False else self.base_catalog
1096
- manifest_dict = manifest.to_dict()
1097
-
1098
- nodes = {}
1099
- for node in manifest_dict["nodes"].values():
1100
- unique_id = node["unique_id"]
1101
- resource_type = node["resource_type"]
1102
-
1103
- if resource_type not in ["model", "seed", "exposure", "snapshot"]:
1104
- continue
1105
-
1106
- nodes[unique_id] = CllNode(
1107
- id=node["unique_id"],
1108
- name=node["name"],
1109
- package_name=node["package_name"],
1110
- resource_type=node["resource_type"],
1111
- raw_code=node["raw_code"],
1112
- depends_on=CllNodeDependsOn(
1113
- nodes=node.get("depends_on").get("nodes", []),
1114
- ),
1115
+ parent_list = []
1116
+ node = None
1117
+
1118
+ # model, seed, snapshot
1119
+ if node_id in manifest.nodes:
1120
+ found = manifest.nodes[node_id]
1121
+ if found.resource_type not in ["model", "seed", "snapshot"]:
1122
+ return None, []
1123
+
1124
+ unique_id = found.unique_id
1125
+ node = CllNode(
1126
+ id=found.unique_id,
1127
+ name=found.name,
1128
+ package_name=found.package_name,
1129
+ resource_type=found.resource_type,
1130
+ raw_code=found.raw_code,
1115
1131
  )
1132
+ if hasattr(found.depends_on, "nodes"):
1133
+ parent_list = found.depends_on.nodes
1116
1134
 
1117
1135
  if catalog is not None and unique_id in catalog.nodes:
1118
1136
  columns = {}
1119
1137
  for col_name, col_metadata in catalog.nodes[unique_id].columns.items():
1120
- col = CllColumn(name=col_name, type=col_metadata.type)
1138
+ column_id = f"{unique_id}_{col_name}"
1139
+ col = CllColumn(id=column_id, name=col_name, table_id=unique_id, type=col_metadata.type)
1121
1140
  columns[col_name] = col
1122
- nodes[unique_id].columns = columns
1123
-
1124
- for source in manifest_dict["sources"].values():
1125
- unique_id = source["unique_id"]
1126
-
1127
- nodes[unique_id] = CllNode(
1128
- id=source["unique_id"],
1129
- name=source["name"],
1130
- package_name=source["package_name"],
1131
- resource_type=source["resource_type"],
1132
- source_name=source["source_name"],
1141
+ node.columns = columns
1142
+
1143
+ # source
1144
+ if node_id in manifest.sources:
1145
+ found = manifest.sources[node_id]
1146
+ unique_id = found.unique_id
1147
+
1148
+ node = CllNode(
1149
+ id=found.unique_id,
1150
+ name=found.name,
1151
+ package_name=found.package_name,
1152
+ resource_type=found.resource_type,
1153
+ source_name=found.source_name,
1133
1154
  )
1155
+ parent_list = []
1134
1156
 
1135
1157
  if catalog is not None and unique_id in catalog.sources:
1136
1158
  columns = {}
1137
1159
  for col_name, col_metadata in catalog.sources[unique_id].columns.items():
1138
- col = CllColumn(name=col_name, type=col_metadata.type)
1160
+ column_id = f"{unique_id}_{col_name}"
1161
+ col = CllColumn(id=column_id, name=col_name, table_id=unique_id, type=col_metadata.type)
1139
1162
  columns[col_name] = col
1140
- nodes[unique_id].columns = columns
1163
+ node.columns = columns
1141
1164
 
1142
- return nodes
1165
+ # exposure
1166
+ if node_id in manifest.exposures:
1167
+ found = manifest.exposures[node_id]
1168
+
1169
+ node = CllNode(
1170
+ id=found.unique_id,
1171
+ name=found.name,
1172
+ package_name=found.package_name,
1173
+ resource_type=found.resource_type,
1174
+ )
1175
+ if hasattr(found.depends_on, "nodes"):
1176
+ parent_list = found.depends_on.nodes
1177
+
1178
+ return node, parent_list
1143
1179
 
1144
1180
  def get_manifests_by_id(self, unique_id: str):
1145
1181
  curr_manifest = self.get_manifest(base=False)
@@ -1151,6 +1187,73 @@ class DbtAdapter(BaseAdapter):
1151
1187
  }
1152
1188
  return None
1153
1189
 
1190
+ def get_impact_radius(self, node_id: str) -> CllData:
1191
+ impacted_nodes = self.get_impacted_nodes(node_id)
1192
+ impacted_cll = self.get_impacted_cll(node_id)
1193
+
1194
+ # merge impact radius
1195
+ return self._merge_cll_data(impacted_nodes, impacted_cll)
1196
+
1197
+ def get_impacted_nodes(self, node_id: str) -> CllData:
1198
+ lineage_diff = self.get_lineage_diff()
1199
+ diff_info = lineage_diff.diff.get(node_id)
1200
+ if diff_info is None:
1201
+ return CllData()
1202
+ change_category = diff_info.change.category
1203
+
1204
+ if change_category == "breaking":
1205
+ cll = self.get_cll_by_node_id(node_id)
1206
+ _, downstream = find_column_dependencies(node_id, cll.parent_map, cll.child_map)
1207
+ relevant_columns = {node_id}
1208
+ relevant_columns.update(downstream)
1209
+ nodes, columns = filter_lineage_vertices(cll.nodes, cll.columns, relevant_columns)
1210
+ p_map, c_map = filter_dependency_maps(cll.parent_map, cll.child_map, relevant_columns)
1211
+
1212
+ return CllData(nodes=nodes, columns=columns, parent_map=p_map, child_map=c_map)
1213
+
1214
+ return CllData()
1215
+
1216
+ def get_impacted_cll(self, node_id: str) -> CllData:
1217
+ lineage_diff = self.get_lineage_diff()
1218
+ diff_info = lineage_diff.diff.get(node_id)
1219
+ if diff_info is None:
1220
+ return CllData()
1221
+ change_columns = diff_info.change.columns
1222
+
1223
+ cll = self.get_cll_by_node_id(node_id)
1224
+ relevant_columns = set()
1225
+ for col, change_status in change_columns.items():
1226
+ if change_status == "removed":
1227
+ continue
1228
+ target_column = f"{node_id}_{col}"
1229
+ _, downstream = find_column_dependencies(target_column, cll.parent_map, cll.child_map)
1230
+ relevant_columns.add(target_column)
1231
+ relevant_columns.update(downstream)
1232
+
1233
+ nodes, columns = filter_lineage_vertices(cll.nodes, cll.columns, relevant_columns)
1234
+ p_map, c_map = filter_dependency_maps(cll.parent_map, cll.child_map, relevant_columns)
1235
+
1236
+ return CllData(nodes=nodes, columns=columns, parent_map=p_map, child_map=c_map)
1237
+
1238
+ @staticmethod
1239
+ def _merge_cll_data(base: CllData, target: CllData) -> CllData:
1240
+ merged_nodes = {**base.nodes, **target.nodes}
1241
+ merged_columns = {**base.columns, **target.columns}
1242
+
1243
+ merged_parent_map = {}
1244
+ merged_keys = set(base.parent_map.keys()).union(set(target.parent_map.keys()))
1245
+ for key in merged_keys:
1246
+ merged_parent_map[key] = base.parent_map.get(key, set()).union(target.parent_map.get(key, set()))
1247
+
1248
+ merged_child_map = {}
1249
+ merged_keys = set(base.child_map.keys()).union(set(target.child_map.keys()))
1250
+ for key in merged_keys:
1251
+ merged_child_map[key] = base.child_map.get(key, set()).union(target.child_map.get(key, set()))
1252
+
1253
+ return CllData(
1254
+ nodes=merged_nodes, columns=merged_columns, parent_map=merged_parent_map, child_map=merged_child_map
1255
+ )
1256
+
1154
1257
  def build_name_to_unique_id_index(self) -> Dict[str, str]:
1155
1258
  name_to_unique_id = {}
1156
1259
  curr_manifest = self.get_manifest(base=False)
@@ -1238,10 +1341,8 @@ class DbtAdapter(BaseAdapter):
1238
1341
  self.curr_manifest = load_manifest(path=refresh_file_path)
1239
1342
  self.manifest = as_manifest(self.curr_manifest)
1240
1343
  self.get_cll_cached.cache_clear()
1241
- self.get_cll_nodes_from_metadata.cache_clear()
1242
1344
  elif refresh_file_path.endswith("catalog.json"):
1243
1345
  self.curr_catalog = load_catalog(path=refresh_file_path)
1244
- self.get_cll_nodes_from_metadata.cache_clear()
1245
1346
  elif self.base_path and target_type == os.path.basename(self.base_path):
1246
1347
  if refresh_file_path.endswith("manifest.json"):
1247
1348
  self.base_manifest = load_manifest(path=refresh_file_path)
@@ -202,7 +202,7 @@ def debug(**kwargs):
202
202
  def check_artifacts(env_name, target_path):
203
203
  console.rule(f"{env_name} Environment", style="orange3")
204
204
  if not target_path.is_dir():
205
- console.print(f"[[red]MISS[/red]] Directory does not exist: {target_path}")
205
+ console.print(f"[[red]MISS[/red]] Directory not found: {target_path}")
206
206
  return [False, False, False]
207
207
 
208
208
  console.print(f"[[green]OK[/green]] Directory exists: {target_path}")
@@ -212,21 +212,21 @@ def debug(**kwargs):
212
212
  if manifest_is_ready:
213
213
  console.print(f"[[green]OK[/green]] Manifest JSON file exists : {manifest_path}")
214
214
  else:
215
- console.print(f"[[red]MISS[/red]] Manifest JSON file does not exist: {manifest_path}")
215
+ console.print(f"[[red]MISS[/red]] Manifest JSON file not found: {manifest_path}")
216
216
 
217
217
  catalog_path = target_path / "catalog.json"
218
218
  catalog_is_ready = catalog_path.is_file()
219
219
  if catalog_is_ready:
220
220
  console.print(f"[[green]OK[/green]] Catalog JSON file exists: {catalog_path}")
221
221
  else:
222
- console.print(f"[[red]MISS[/red]] Catalog JSON file does not exist: {catalog_path}")
222
+ console.print(f"[[red]MISS[/red]] Catalog JSON file not found: {catalog_path}")
223
223
 
224
224
  return [True, manifest_is_ready, catalog_is_ready]
225
225
 
226
226
  target_path = Path(kwargs.get("target_path", "target"))
227
227
  target_base_path = Path(kwargs.get("target_base_path", "target-base"))
228
228
 
229
- curr_is_ready = check_artifacts("development", target_path)
229
+ curr_is_ready = check_artifacts("Development", target_path)
230
230
  base_is_ready = check_artifacts("Base", target_base_path)
231
231
 
232
232
  console.rule("Warehouse Connection", style="orange3")