recce-nightly 0.62.0.20250417__py3-none-any.whl → 1.30.0.20251221__py3-none-any.whl

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 (245) hide show
  1. recce/VERSION +1 -1
  2. recce/__init__.py +27 -22
  3. recce/adapter/base.py +11 -14
  4. recce/adapter/dbt_adapter/__init__.py +845 -461
  5. recce/adapter/dbt_adapter/dbt_version.py +3 -0
  6. recce/adapter/sqlmesh_adapter.py +24 -35
  7. recce/apis/check_api.py +59 -42
  8. recce/apis/check_events_api.py +353 -0
  9. recce/apis/check_func.py +41 -35
  10. recce/apis/run_api.py +25 -19
  11. recce/apis/run_func.py +64 -25
  12. recce/artifact.py +119 -51
  13. recce/cli.py +1301 -324
  14. recce/config.py +43 -34
  15. recce/connect_to_cloud.py +138 -0
  16. recce/core.py +55 -47
  17. recce/data/404/index.html +2 -0
  18. recce/data/404.html +2 -1
  19. recce/data/__next.@lineage.!KHNsb3Qp.__PAGE__.txt +7 -0
  20. recce/data/__next.@lineage.!KHNsb3Qp.txt +4 -0
  21. recce/data/__next.__PAGE__.txt +6 -0
  22. recce/data/__next._full.txt +32 -0
  23. recce/data/__next._head.txt +8 -0
  24. recce/data/__next._index.txt +14 -0
  25. recce/data/__next._tree.txt +8 -0
  26. recce/data/_next/static/chunks/025a7e3e3f9f40ae.js +1 -0
  27. recce/data/_next/static/chunks/0ce56d67ef5779ca.js +4 -0
  28. recce/data/_next/static/chunks/1a6a78780155dac7.js +48 -0
  29. recce/data/_next/static/chunks/1de8485918b9182a.css +2 -0
  30. recce/data/_next/static/chunks/1e4b1b50d1e34993.js +1 -0
  31. recce/data/_next/static/chunks/206d5d181e4c738e.js +1 -0
  32. recce/data/_next/static/chunks/2c357efc34c5b859.js +25 -0
  33. recce/data/_next/static/chunks/2e9d95d2d48c479c.js +1 -0
  34. recce/data/_next/static/chunks/2f016dc4a3edad2e.js +2 -0
  35. recce/data/_next/static/chunks/313251962d698f7c.js +1 -0
  36. recce/data/_next/static/chunks/3a9f021f38eb5574.css +1 -0
  37. recce/data/_next/static/chunks/40079da8d2b8f651.js +1 -0
  38. recce/data/_next/static/chunks/4599182bffb64661.js +38 -0
  39. recce/data/_next/static/chunks/4e62f6e184173580.js +1 -0
  40. recce/data/_next/static/chunks/5c4dfb0d09eaa401.js +1 -0
  41. recce/data/_next/static/chunks/69e4f06ccfdfc3ac.js +1 -0
  42. recce/data/_next/static/chunks/6b206cb4707d6bee.js +1 -0
  43. recce/data/_next/static/chunks/6d8557f062aa4386.css +1 -0
  44. recce/data/_next/static/chunks/7fbe3650bd83b6b5.js +1 -0
  45. recce/data/_next/static/chunks/83fa823a825674f6.js +1 -0
  46. recce/data/_next/static/chunks/848a6c9b5f55f7ed.js +1 -0
  47. recce/data/_next/static/chunks/859462b0858aef88.css +2 -0
  48. recce/data/_next/static/chunks/923964f18c87d0f1.css +1 -0
  49. recce/data/_next/static/chunks/939390f911895d7c.js +48 -0
  50. recce/data/_next/static/chunks/99a9817237a07f43.js +1 -0
  51. recce/data/_next/static/chunks/9fed8b4b2b924054.js +5 -0
  52. recce/data/_next/static/chunks/b6949f6c5892110c.js +1 -0
  53. recce/data/_next/static/chunks/b851a1d3f8149828.js +1 -0
  54. recce/data/_next/static/chunks/c734f9ad957de0b4.js +1 -0
  55. recce/data/_next/static/chunks/cdde321b0ec75717.js +2 -0
  56. recce/data/_next/static/chunks/d0f91117d77ff844.css +1 -0
  57. recce/data/_next/static/chunks/d6c8667911c2500f.js +1 -0
  58. recce/data/_next/static/chunks/da8dab68c02752cf.js +74 -0
  59. recce/data/_next/static/chunks/dc074049c9d12d97.js +109 -0
  60. recce/data/_next/static/chunks/ee7f1a8227342421.js +1 -0
  61. recce/data/_next/static/chunks/fa2f4e56c2fccc73.js +1 -0
  62. recce/data/_next/static/chunks/turbopack-1fad664f62979b93.js +3 -0
  63. recce/data/_next/static/media/favicon.a8d38d84.ico +0 -0
  64. recce/data/_next/static/media/montserrat-cyrillic-800-normal.d80d830d.woff2 +0 -0
  65. recce/data/_next/static/media/montserrat-cyrillic-800-normal.f9d58125.woff +0 -0
  66. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.076c2a93.woff2 +0 -0
  67. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.a4fa76b5.woff +0 -0
  68. recce/data/_next/static/media/montserrat-latin-800-normal.cde454cc.woff2 +0 -0
  69. recce/data/_next/static/media/montserrat-latin-800-normal.d5761935.woff +0 -0
  70. recce/data/_next/static/media/montserrat-latin-ext-800-normal.40ec0659.woff2 +0 -0
  71. recce/data/_next/static/media/montserrat-latin-ext-800-normal.b671449b.woff +0 -0
  72. recce/data/_next/static/media/montserrat-vietnamese-800-normal.9f7b8541.woff +0 -0
  73. recce/data/_next/static/media/montserrat-vietnamese-800-normal.f9eb854e.woff2 +0 -0
  74. recce/data/_next/static/nX-Uz0AH6Tc6hIQUFGqaB/_buildManifest.js +11 -0
  75. recce/data/_next/static/nX-Uz0AH6Tc6hIQUFGqaB/_clientMiddlewareManifest.json +1 -0
  76. recce/data/_not-found/__next._full.txt +24 -0
  77. recce/data/_not-found/__next._head.txt +8 -0
  78. recce/data/_not-found/__next._index.txt +13 -0
  79. recce/data/_not-found/__next._not-found.__PAGE__.txt +5 -0
  80. recce/data/_not-found/__next._not-found.txt +4 -0
  81. recce/data/_not-found/__next._tree.txt +6 -0
  82. recce/data/_not-found/index.html +2 -0
  83. recce/data/_not-found/index.txt +24 -0
  84. recce/data/auth_callback.html +68 -0
  85. recce/data/checks/__next.@lineage.__DEFAULT__.txt +7 -0
  86. recce/data/checks/__next._full.txt +39 -0
  87. recce/data/checks/__next._head.txt +8 -0
  88. recce/data/checks/__next._index.txt +14 -0
  89. recce/data/checks/__next._tree.txt +8 -0
  90. recce/data/checks/__next.checks.__PAGE__.txt +10 -0
  91. recce/data/checks/__next.checks.txt +4 -0
  92. recce/data/checks/index.html +2 -0
  93. recce/data/checks/index.txt +39 -0
  94. recce/data/imgs/reload-image.svg +4 -0
  95. recce/data/index.html +2 -27
  96. recce/data/index.txt +32 -7
  97. recce/data/lineage/__next.@lineage.__DEFAULT__.txt +7 -0
  98. recce/data/lineage/__next._full.txt +39 -0
  99. recce/data/lineage/__next._head.txt +8 -0
  100. recce/data/lineage/__next._index.txt +14 -0
  101. recce/data/lineage/__next._tree.txt +8 -0
  102. recce/data/lineage/__next.lineage.__PAGE__.txt +10 -0
  103. recce/data/lineage/__next.lineage.txt +4 -0
  104. recce/data/lineage/index.html +2 -0
  105. recce/data/lineage/index.txt +39 -0
  106. recce/data/query/__next.@lineage.__DEFAULT__.txt +7 -0
  107. recce/data/query/__next._full.txt +37 -0
  108. recce/data/query/__next._head.txt +8 -0
  109. recce/data/query/__next._index.txt +14 -0
  110. recce/data/query/__next._tree.txt +8 -0
  111. recce/data/query/__next.query.__PAGE__.txt +9 -0
  112. recce/data/query/__next.query.txt +4 -0
  113. recce/data/query/index.html +2 -0
  114. recce/data/query/index.txt +37 -0
  115. recce/diff.py +6 -12
  116. recce/event/CONFIG.bak +1 -0
  117. recce/event/__init__.py +86 -74
  118. recce/event/collector.py +33 -22
  119. recce/event/track.py +49 -27
  120. recce/exceptions.py +1 -1
  121. recce/git.py +7 -7
  122. recce/github.py +57 -53
  123. recce/mcp_server.py +725 -0
  124. recce/models/__init__.py +4 -1
  125. recce/models/check.py +438 -21
  126. recce/models/run.py +1 -0
  127. recce/models/types.py +134 -28
  128. recce/pull_request.py +27 -25
  129. recce/run.py +179 -122
  130. recce/server.py +394 -104
  131. recce/state/__init__.py +31 -0
  132. recce/state/cloud.py +644 -0
  133. recce/state/const.py +26 -0
  134. recce/state/local.py +56 -0
  135. recce/state/state.py +119 -0
  136. recce/state/state_loader.py +174 -0
  137. recce/summary.py +196 -149
  138. recce/tasks/__init__.py +19 -3
  139. recce/tasks/core.py +11 -13
  140. recce/tasks/dataframe.py +82 -18
  141. recce/tasks/histogram.py +69 -34
  142. recce/tasks/lineage.py +2 -2
  143. recce/tasks/profile.py +152 -86
  144. recce/tasks/query.py +180 -89
  145. recce/tasks/rowcount.py +37 -31
  146. recce/tasks/schema.py +18 -15
  147. recce/tasks/top_k.py +35 -35
  148. recce/tasks/utils.py +147 -0
  149. recce/tasks/valuediff.py +247 -155
  150. recce/util/__init__.py +3 -0
  151. recce/util/api_token.py +80 -0
  152. recce/util/breaking.py +105 -100
  153. recce/util/cll.py +274 -219
  154. recce/util/cloud/__init__.py +15 -0
  155. recce/util/cloud/base.py +115 -0
  156. recce/util/cloud/check_events.py +190 -0
  157. recce/util/cloud/checks.py +242 -0
  158. recce/util/io.py +22 -17
  159. recce/util/lineage.py +65 -16
  160. recce/util/logger.py +1 -1
  161. recce/util/onboarding_state.py +45 -0
  162. recce/util/perf_tracking.py +85 -0
  163. recce/util/recce_cloud.py +347 -72
  164. recce/util/singleton.py +4 -4
  165. recce/util/startup_perf.py +121 -0
  166. recce/yaml/__init__.py +7 -10
  167. recce_nightly-1.30.0.20251221.dist-info/METADATA +195 -0
  168. recce_nightly-1.30.0.20251221.dist-info/RECORD +183 -0
  169. {recce_nightly-0.62.0.20250417.dist-info → recce_nightly-1.30.0.20251221.dist-info}/WHEEL +1 -2
  170. recce/data/_next/static/chunks/1f229bf6-d9fe92e56db8d93b.js +0 -1
  171. recce/data/_next/static/chunks/29e3cc0d-8c150e37dff9631b.js +0 -1
  172. recce/data/_next/static/chunks/36e1c10d-bb0210cbd6573a8d.js +0 -1
  173. recce/data/_next/static/chunks/3998a672-eaad84bdd88cc73e.js +0 -1
  174. recce/data/_next/static/chunks/450c323b-1bb5db526e54435a.js +0 -1
  175. recce/data/_next/static/chunks/47d8844f-79a1b53c66a7d7ec.js +0 -1
  176. recce/data/_next/static/chunks/500-e51c92a025a51234.js +0 -65
  177. recce/data/_next/static/chunks/6dc81886-c94b9b91bc2c3caf.js +0 -1
  178. recce/data/_next/static/chunks/700-3b65fc3666820d00.js +0 -2
  179. recce/data/_next/static/chunks/7a8a3e83-d7fa409d97b38b2b.js +0 -1
  180. recce/data/_next/static/chunks/7f27ae6c-413f6b869a04183a.js +0 -1
  181. recce/data/_next/static/chunks/9746af58-d74bef4d03eea6ab.js +0 -1
  182. recce/data/_next/static/chunks/a30376cd-7d806e1602f2dc3a.js +0 -1
  183. recce/data/_next/static/chunks/app/_not-found/page-8a886fa0855c3105.js +0 -1
  184. recce/data/_next/static/chunks/app/layout-9102e22cb73f74d6.js +0 -1
  185. recce/data/_next/static/chunks/app/page-9adc25782272ed2e.js +0 -1
  186. recce/data/_next/static/chunks/b63b1b3f-7395c74e11a14e95.js +0 -1
  187. recce/data/_next/static/chunks/c132bf7d-8102037f9ccf372a.js +0 -1
  188. recce/data/_next/static/chunks/c1ceaa8b-a1e442154d23515e.js +0 -1
  189. recce/data/_next/static/chunks/cd9f8d63-cf0d5a7b0f7a92e8.js +0 -54
  190. recce/data/_next/static/chunks/ce84277d-f42c2c58049cea2d.js +0 -1
  191. recce/data/_next/static/chunks/e24bf851-0f8cbc99656833e7.js +0 -1
  192. recce/data/_next/static/chunks/fee69bc6-f17d36c080742e74.js +0 -1
  193. recce/data/_next/static/chunks/framework-ded83d71b51ce901.js +0 -1
  194. recce/data/_next/static/chunks/main-a0859f1f36d0aa6c.js +0 -1
  195. recce/data/_next/static/chunks/main-app-0225a2255968e566.js +0 -1
  196. recce/data/_next/static/chunks/pages/_app-d5672bf3d8b6371b.js +0 -1
  197. recce/data/_next/static/chunks/pages/_error-ed75be3f25588548.js +0 -1
  198. recce/data/_next/static/chunks/webpack-567d72f0bc0820d5.js +0 -1
  199. recce/data/_next/static/css/c9ecb46a4b21c126.css +0 -14
  200. recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2 +0 -0
  201. recce/data/_next/static/media/montserrat-cyrillic-800-normal.31d693bb.woff +0 -0
  202. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.7e2c1e62.woff +0 -0
  203. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.94a63aea.woff2 +0 -0
  204. recce/data/_next/static/media/montserrat-latin-800-normal.6f8fa298.woff2 +0 -0
  205. recce/data/_next/static/media/montserrat-latin-800-normal.97e20d5e.woff +0 -0
  206. recce/data/_next/static/media/montserrat-latin-ext-800-normal.013b84f9.woff2 +0 -0
  207. recce/data/_next/static/media/montserrat-latin-ext-800-normal.aff52ab0.woff +0 -0
  208. recce/data/_next/static/media/montserrat-vietnamese-800-normal.5f21869b.woff +0 -0
  209. recce/data/_next/static/media/montserrat-vietnamese-800-normal.c0035377.woff2 +0 -0
  210. recce/data/_next/static/qiyFlux77VkhxiceAJe_F/_buildManifest.js +0 -1
  211. recce/state.py +0 -753
  212. recce_nightly-0.62.0.20250417.dist-info/METADATA +0 -311
  213. recce_nightly-0.62.0.20250417.dist-info/RECORD +0 -139
  214. recce_nightly-0.62.0.20250417.dist-info/top_level.txt +0 -2
  215. tests/__init__.py +0 -0
  216. tests/adapter/__init__.py +0 -0
  217. tests/adapter/dbt_adapter/__init__.py +0 -0
  218. tests/adapter/dbt_adapter/conftest.py +0 -13
  219. tests/adapter/dbt_adapter/dbt_test_helper.py +0 -283
  220. tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -40
  221. tests/adapter/dbt_adapter/test_dbt_cll.py +0 -102
  222. tests/adapter/dbt_adapter/test_selector.py +0 -177
  223. tests/tasks/__init__.py +0 -0
  224. tests/tasks/conftest.py +0 -4
  225. tests/tasks/test_histogram.py +0 -137
  226. tests/tasks/test_lineage.py +0 -42
  227. tests/tasks/test_preset_checks.py +0 -50
  228. tests/tasks/test_profile.py +0 -73
  229. tests/tasks/test_query.py +0 -151
  230. tests/tasks/test_row_count.py +0 -116
  231. tests/tasks/test_schema.py +0 -99
  232. tests/tasks/test_top_k.py +0 -73
  233. tests/tasks/test_valuediff.py +0 -74
  234. tests/test_cli.py +0 -122
  235. tests/test_config.py +0 -45
  236. tests/test_core.py +0 -27
  237. tests/test_dbt.py +0 -36
  238. tests/test_pull_request.py +0 -130
  239. tests/test_server.py +0 -98
  240. tests/test_state.py +0 -123
  241. tests/test_summary.py +0 -57
  242. /recce/data/_next/static/chunks/{polyfills-42372ed130431b0a.js → a6dad97d9634a72d.js} +0 -0
  243. /recce/data/_next/static/{qiyFlux77VkhxiceAJe_F → nX-Uz0AH6Tc6hIQUFGqaB}/_ssgManifest.js +0 -0
  244. {recce_nightly-0.62.0.20250417.dist-info → recce_nightly-1.30.0.20251221.dist-info}/entry_points.txt +0 -0
  245. {recce_nightly-0.62.0.20250417.dist-info → recce_nightly-1.30.0.20251221.dist-info}/licenses/LICENSE +0 -0
@@ -1,137 +0,0 @@
1
- import pytest
2
-
3
- from recce.tasks.histogram import HistogramDiffTask, HistogramDiffCheckValidator, _is_histogram_supported
4
-
5
-
6
- def test_histogram(dbt_test_helper):
7
- csv_data = """
8
- customer_id,name,age
9
- 1,Alice,30
10
- 2,Bob,25
11
- 3,Charlie,35
12
- 4,Dolly,50
13
- """
14
-
15
- dbt_test_helper.create_model("customers", csv_data, csv_data)
16
-
17
- params = {
18
- "model": "customers",
19
- "column_name": "age",
20
- "column_type": "int"
21
- }
22
-
23
- task = HistogramDiffTask(params)
24
- run_result = task.execute()
25
-
26
- # {
27
- # 'base': {'counts': [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 'total': 4},
28
- # 'current': {'counts': [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 'total': 4},
29
- # 'min': 25, 'max': 50,
30
- # 'bin_edges': [25, 26, ..., 51],
31
- # 'labels': ['25-26', ..., '51-52']
32
- # }
33
- assert run_result['current']['counts'][0] == 1
34
- assert run_result['current']['counts'][-1] == 1
35
- assert run_result['current']['total'] == 4
36
- assert run_result['min'] == 25
37
- assert run_result['max'] == 50
38
- assert run_result['bin_edges'][0] == 25
39
- assert run_result['bin_edges'][-1] == 51
40
-
41
-
42
- def test_histogram_emtpy(dbt_test_helper):
43
- csv_data = """
44
- customer_id,name,age
45
- 1,Alice,30
46
- 2,Bob,25
47
- 3,Charlie,35
48
- 4,Dolly,50
49
- """
50
-
51
- csv_data_zero = """
52
- customer_id,name,age
53
- """
54
-
55
- dbt_test_helper.create_model("customers", csv_data_zero, csv_data_zero)
56
- dbt_test_helper.create_model("customers2", csv_data, csv_data_zero)
57
- dbt_test_helper.create_model("customers3", csv_data_zero, csv_data)
58
-
59
- params = {
60
- "model": "customers",
61
- "column_name": "age",
62
- "column_type": "int"
63
- }
64
-
65
- task = HistogramDiffTask(params)
66
- run_result = task.execute()
67
-
68
- assert len(run_result['current']['counts']) == 0
69
- assert run_result['current']['total'] == 0
70
- assert run_result['min'] is None
71
- assert run_result['max'] is None
72
- assert len(run_result['bin_edges']) == 0
73
-
74
- params = {
75
- "model": "customers2",
76
- "column_name": "age",
77
- "column_type": "int"
78
- }
79
-
80
- task = HistogramDiffTask(params)
81
- run_result = task.execute()
82
- assert run_result['base']['counts'][0] == 1
83
- assert run_result['base']['counts'][-1] == 1
84
- assert run_result['base']['total'] == 4
85
- assert run_result['current']['counts'][0] == 0
86
- assert run_result['current']['counts'][-1] == 0
87
- assert run_result['current']['total'] == 0
88
- assert run_result['min'] == 25
89
- assert run_result['max'] == 50
90
- assert run_result['bin_edges'][0] == 25
91
- assert run_result['bin_edges'][-1] == 51
92
-
93
- params = {
94
- "model": "customers3",
95
- "column_name": "age",
96
- "column_type": "int"
97
- }
98
-
99
- task = HistogramDiffTask(params)
100
- run_result = task.execute()
101
- assert run_result['base']['counts'][0] == 0
102
- assert run_result['base']['counts'][-1] == 0
103
- assert run_result['base']['total'] == 0
104
- assert run_result['current']['counts'][0] == 1
105
- assert run_result['current']['counts'][-1] == 1
106
- assert run_result['current']['total'] == 4
107
- assert run_result['min'] == 25
108
- assert run_result['max'] == 50
109
- assert run_result['bin_edges'][0] == 25
110
- assert run_result['bin_edges'][-1] == 51
111
-
112
-
113
- def test_validator():
114
- def validate(params: dict = {}, view_options: dict = {}):
115
- HistogramDiffCheckValidator().validate({
116
- 'name': 'test',
117
- 'type': 'histogram_diff',
118
- 'params': params,
119
- 'view_options': view_options,
120
- })
121
-
122
- validate({
123
- "model": "customers",
124
- "column_name": "age",
125
- "column_type": "int",
126
- })
127
-
128
- with pytest.raises(ValueError):
129
- validate({})
130
-
131
-
132
- def test_is_column_type_supported_by_histogram():
133
- assert _is_histogram_supported("varchar") is False
134
- assert _is_histogram_supported("varchar(16)") is False
135
- assert _is_histogram_supported("varchar(256)") is False
136
- assert _is_histogram_supported("bool") is False
137
- assert _is_histogram_supported("int") is True
@@ -1,42 +0,0 @@
1
- import pytest
2
-
3
-
4
- def test_validator():
5
- from recce.tasks.lineage import LineageDiffCheckValidator
6
- validator = LineageDiffCheckValidator()
7
-
8
- def validate(params: dict):
9
- validator.validate({
10
- 'name': 'test',
11
- 'type': 'schema_diff',
12
- 'params': params,
13
- })
14
-
15
- # Select all models
16
- validate({})
17
-
18
- # Select by selector
19
- validate({
20
- 'select': 'customers',
21
- 'exclude': 'customers',
22
- 'packages': ['jaffle_shop'],
23
- 'view_mode': 'all',
24
- })
25
-
26
- # packages should be an array
27
- with pytest.raises(ValueError):
28
- validate({
29
- 'packages': 'jaffle_shop',
30
- })
31
-
32
- # view_mode should be 'all' or 'changed_models'
33
- validate({
34
- 'view_mode': None,
35
- })
36
- validate({
37
- 'view_mode': 'all',
38
- })
39
- with pytest.raises(ValueError):
40
- validate({
41
- 'view_mode': 'abc',
42
- })
@@ -1,50 +0,0 @@
1
- import pytest
2
-
3
-
4
- def test_default_validator():
5
- from recce.tasks.core import CheckValidator
6
-
7
- CheckValidator().validate({
8
- "name": "test",
9
- "type": "row_count_diff",
10
- "params": {},
11
- })
12
-
13
- with pytest.raises(ValueError):
14
- CheckValidator().validate({
15
- "type": "row_count_diff",
16
- })
17
-
18
-
19
- def test_query_diff_validator():
20
- from recce.tasks.query import QueryDiffCheckValidator
21
- QueryDiffCheckValidator().validate({
22
- "name": "test",
23
- "type": "query_diff",
24
- "params": {
25
- "sql_template": "select * from {{ model }}"
26
- },
27
- })
28
- with pytest.raises(ValueError):
29
- QueryDiffCheckValidator().validate({
30
- "name": "test",
31
- "type": "query_diff",
32
- })
33
-
34
-
35
- def test_lineage_diff_validator():
36
- from recce.tasks.lineage import LineageDiffCheckValidator
37
- LineageDiffCheckValidator().validate({
38
- "name": "test",
39
- "type": "lineage_diff",
40
- "params": {},
41
- })
42
- LineageDiffCheckValidator().validate({
43
- "name": "test",
44
- "type": "lineage_diff",
45
- "view_options": {},
46
- })
47
- with pytest.raises(ValueError):
48
- LineageDiffCheckValidator().validate({
49
- "type": "lineage_diff",
50
- })
@@ -1,73 +0,0 @@
1
- import pytest
2
-
3
- from recce.tasks import ProfileDiffTask, ProfileTask
4
-
5
- csv_data_curr = """
6
- customer_id,name,age
7
- 1,Alice,30
8
- 2,Bob,25
9
- 3,Charlie,35
10
- """
11
-
12
- csv_data_base = """
13
- customer_id,name,age
14
- 1,Alice,35
15
- 2,Bob,25
16
- 3,Charlie,35
17
- """
18
-
19
-
20
- def test_profile(dbt_test_helper):
21
- dbt_test_helper.create_model("customers", None, csv_data_curr)
22
- params = dict(model='customers')
23
- task = ProfileTask(params)
24
- run_result = task.execute()
25
-
26
- assert len(run_result.current.data) == 3
27
-
28
-
29
- def test_profile_with_selected_columns(dbt_test_helper):
30
- dbt_test_helper.create_model("customers", None, csv_data_curr)
31
- params = dict(model='customers', columns=['name', 'age'])
32
- task = ProfileTask(params)
33
- run_result = task.execute()
34
- assert len(run_result.current.data) == 2
35
-
36
-
37
- def test_profile_diff(dbt_test_helper):
38
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr)
39
- params = dict(model='customers')
40
- task = ProfileDiffTask(params)
41
- run_result = task.execute()
42
-
43
- assert len(run_result.current.data) == 3
44
- assert len(run_result.base.data) == 3
45
-
46
-
47
- def test_profile_diff_with_selected_columns(dbt_test_helper):
48
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr)
49
- params = dict(model='customers', columns=['name', 'age'])
50
- task = ProfileDiffTask(params)
51
- run_result = task.execute()
52
- assert len(run_result.current.data) == 2
53
- assert len(run_result.base.data) == 2
54
-
55
-
56
- def test_validator():
57
- from recce.tasks.profile import ProfileCheckValidator
58
-
59
- def validate(params: dict = {}, view_options: dict = {}):
60
- ProfileCheckValidator().validate({
61
- 'name': 'test',
62
- 'type': 'profile_diff',
63
- 'params': params,
64
- 'view_options': view_options,
65
- })
66
-
67
- validate({
68
- 'model': 'customers',
69
- })
70
-
71
- with pytest.raises(ValueError):
72
- validate({
73
- })
tests/tasks/test_query.py DELETED
@@ -1,151 +0,0 @@
1
- import pytest
2
-
3
- from recce.tasks import QueryDiffTask, QueryTask
4
-
5
-
6
- def test_query_diff_in_client(dbt_test_helper):
7
- csv_data_curr = """
8
- customer_id,name,age
9
- 1,Alice,30
10
- 2,Bob,25
11
- 3,Charlie,35
12
- """
13
-
14
- csv_data_base = """
15
- customer_id,name,age
16
- 1,Alice,35
17
- 2,Bob,25
18
- 3,Charlie,35
19
- """
20
-
21
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr)
22
- params = dict(sql_template=f'select * from {{{{ ref("customers") }}}}')
23
- task = QueryTask(params)
24
- run_result = task.execute()
25
- assert len(run_result.current.data) == 3
26
-
27
-
28
- def test_query_diff_in_client(dbt_test_helper):
29
- csv_data_curr = """
30
- customer_id,name,age
31
- 1,Alice,30
32
- 2,Bob,25
33
- 3,Charlie,35
34
- """
35
-
36
- csv_data_base = """
37
- customer_id,name,age
38
- 1,Alice,35
39
- 2,Bob,25
40
- 3,Charlie,35
41
- """
42
-
43
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr)
44
- params = dict(sql_template=f'select * from {{{{ ref("customers") }}}}')
45
- task = QueryDiffTask(params)
46
- run_result = task.execute()
47
- assert len(run_result.base.data) == 3
48
- assert len(run_result.current.data) == 3
49
-
50
- params = dict(
51
- base_sql_template=f'select * from {{{{ ref("customers") }}}} where customer_id <= 2',
52
- sql_template=f'select * from {{{{ ref("customers") }}}}',
53
- )
54
- task = QueryDiffTask(params)
55
- run_result = task.execute()
56
- assert len(run_result.base.data) == 2
57
- assert len(run_result.current.data) == 3
58
-
59
-
60
- def test_query_diff_in_warehouse(dbt_test_helper):
61
- csv_data_curr = """
62
- customer_id,name,age
63
- 1,Alice,30
64
- 2,Bob,25
65
- 3,Charlie,35
66
- """
67
-
68
- csv_data_base = """
69
- customer_id,name,age
70
- 1,Alice,35
71
- 2,Bob,25
72
- 3,Charlie,35
73
- """
74
-
75
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr)
76
- params = dict(sql_template=f'select * from {{{{ ref("customers") }}}}', primary_keys=['customer_id'])
77
- task = QueryDiffTask(params)
78
- run_result = task.execute()
79
- assert len(run_result.diff.data) == 2
80
-
81
- params = dict(
82
- base_sql_template=f'select * from {{{{ ref("customers") }}}} where customer_id == 1',
83
- sql_template=f'select * from {{{{ ref("customers") }}}}',
84
- primary_keys=['customer_id'],
85
- )
86
- task = QueryDiffTask(params)
87
- run_result = task.execute()
88
- assert len(run_result.diff.data) == 4
89
-
90
-
91
- def test_validator():
92
- from recce.tasks.query import QueryCheckValidator, QueryDiffCheckValidator
93
-
94
- def validate(params: dict = {}, view_options: dict = {}):
95
- QueryCheckValidator().validate({
96
- 'name': 'test',
97
- 'type': 'query',
98
- 'params': params,
99
- 'view_options': view_options,
100
- })
101
-
102
- def validate_diff(params: dict = {}, view_options: dict = {}):
103
- QueryDiffCheckValidator().validate({
104
- 'name': 'test',
105
- 'type': 'query_diff',
106
- 'params': params,
107
- 'view_options': view_options,
108
- })
109
-
110
- # query
111
- validate({
112
- 'sql_template': 'select * from abc'
113
- })
114
-
115
- # diff in client
116
- validate_diff({
117
- 'sql_template': 'select * from abc'
118
- })
119
- validate_diff({
120
- 'sql_template': 'select * from abc',
121
- 'base_sql_template': 'select * from abc',
122
- })
123
-
124
- # diff in warehouse
125
- validate_diff({
126
- 'primary_keys': ['customer_id'],
127
- 'sql_template': 'select * from abc',
128
- })
129
- validate_diff({
130
- 'sql_template': 'select * from abc',
131
- 'base_sql_template': 'select * from abc',
132
- 'primary_keys': ['customer_id']
133
- })
134
- validate_diff({
135
- 'sql_template': 'select * from abc',
136
- 'base_sql_template': 'select * from abc',
137
- 'primary_keys': ['customer_id']
138
- })
139
-
140
- # invalid
141
- with pytest.raises(ValueError):
142
- validate()
143
-
144
- with pytest.raises(ValueError):
145
- validate_diff()
146
-
147
- with pytest.raises(ValueError):
148
- validate_diff({'sql_template': 123, 'primary_keys': 'xyz'})
149
-
150
- with pytest.raises(ValueError):
151
- validate_diff({'sql_template': 's', 'primary_keys': 'xyz'})
@@ -1,116 +0,0 @@
1
- import pytest
2
-
3
- from recce.tasks import RowCountDiffTask
4
-
5
-
6
- def test_row_count(dbt_test_helper):
7
- csv_data_curr = """
8
- customer_id,name,age
9
- 1,Alice,30
10
- 2,Bob,25
11
- 3,Charlie,35
12
- """
13
-
14
- csv_data_base = """
15
- customer_id,name,age
16
- 1,Alice,35
17
- 2,Bob,25
18
- """
19
-
20
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr, unique_id='model.customers')
21
- task = RowCountDiffTask(dict(node_names=['customers']))
22
- run_result = task.execute()
23
- assert run_result['customers']['base'] == 2
24
- assert run_result['customers']['curr'] == 3
25
-
26
- task = RowCountDiffTask(dict(node_names=['customers_']))
27
- run_result = task.execute()
28
- assert run_result['customers_']['base'] is None
29
- assert run_result['customers_']['curr'] is None
30
-
31
- task = RowCountDiffTask(dict(node_ids=['model.customers']))
32
- run_result = task.execute()
33
- assert run_result['customers']['base'] == 2
34
- assert run_result['customers']['curr'] == 3
35
-
36
-
37
- def test_row_count_with_selector(dbt_test_helper):
38
- csv_data_1 = """
39
- customer_id,name,age
40
- 1,Alice,30
41
- 2,Bob,25
42
- 3,Charlie,35
43
- """
44
-
45
- csv_data_2 = """
46
- customer_id,name,age
47
- 1,Alice,35
48
- 2,Bob,25
49
- """
50
-
51
- dbt_test_helper.create_model("model_1", csv_data_1, csv_data_2, depends_on=[])
52
- dbt_test_helper.create_model("model_2", csv_data_1, csv_data_1, depends_on=['model_1'],
53
- package_name='other_package')
54
- task = RowCountDiffTask(dict(select='model_1'))
55
- run_result = task.execute()
56
- assert len(run_result) == 1
57
-
58
- task = RowCountDiffTask(dict(select='model_1+'))
59
- run_result = task.execute()
60
- assert len(run_result) == 2
61
-
62
-
63
- def test_validator():
64
- from recce.tasks.rowcount import RowCountDiffCheckValidator
65
-
66
- validator = RowCountDiffCheckValidator()
67
-
68
- def validate(params: dict):
69
- validator.validate({
70
- 'name': 'test',
71
- 'type': 'row_count_diff',
72
- 'params': params,
73
- })
74
-
75
- # Select all modesl
76
- validate({})
77
-
78
- # Select by node name
79
- validate({
80
- 'node_names': ['abc'],
81
- })
82
- with pytest.raises(ValueError):
83
- validate({
84
- 'node_names': 'abc',
85
- })
86
-
87
- # Select by node id
88
- validate({
89
- 'node_ids': ['model.abc'],
90
- })
91
-
92
- # Select by selector
93
- validate({
94
- 'select': 'customers',
95
- 'exclude': 'customers',
96
- 'packages': ['jaffle_shop'],
97
- 'view_mode': 'all',
98
- })
99
-
100
- # packages should be an array
101
- with pytest.raises(ValueError):
102
- validate({
103
- 'packages': 'jaffle_shop',
104
- })
105
-
106
- # view_mode should be 'all' or 'changed_models'
107
- validate({
108
- 'view_mode': None,
109
- })
110
- validate({
111
- 'view_mode': 'all',
112
- })
113
- with pytest.raises(ValueError):
114
- validate({
115
- 'view_mode': 'abc',
116
- })
@@ -1,99 +0,0 @@
1
- import os
2
- from unittest import TestCase
3
- from unittest.mock import MagicMock
4
-
5
- import pytest
6
-
7
- from recce.adapter.dbt_adapter import load_manifest, load_catalog, DbtAdapter
8
- from recce.core import RecceContext, set_default_context
9
- from recce.run import schema_diff_should_be_approved
10
-
11
-
12
- def test_validator():
13
- from recce.tasks.schema import SchemaDiffCheckValidator
14
- validator = SchemaDiffCheckValidator()
15
-
16
- def validate(params: dict):
17
- validator.validate({
18
- 'name': 'test',
19
- 'type': 'schema_diff',
20
- 'params': params,
21
- })
22
-
23
- # Select all models
24
- validate({})
25
-
26
- # Select by node name
27
- validate({
28
- 'node_id': 'abc',
29
- })
30
- validate({
31
- 'node_id': ['abc'],
32
- })
33
-
34
- # Select by selector
35
- validate({
36
- 'select': 'customers',
37
- 'exclude': 'customers',
38
- 'packages': ['jaffle_shop'],
39
- 'view_mode': 'all',
40
- })
41
-
42
- # packages should be an array
43
- with pytest.raises(ValueError):
44
- validate({
45
- 'packages': 'jaffle_shop',
46
- })
47
-
48
- # view_mode should be 'all' or 'changed_models'
49
- validate({
50
- 'view_mode': None,
51
- })
52
- validate({
53
- 'view_mode': 'all',
54
- })
55
- with pytest.raises(ValueError):
56
- validate({
57
- 'view_mode': 'abc',
58
- })
59
-
60
-
61
- test_root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
62
-
63
-
64
- class TestSchemaDiffAutoApprove(TestCase):
65
-
66
- def setUp(self):
67
- self.default_context = MagicMock(spec=RecceContext)
68
- manifest = load_manifest(path=os.path.join(test_root_path, 'manifest.json'))
69
- catalog = load_catalog(path=os.path.join(test_root_path, 'catalog.json'))
70
- dbt_adapter = DbtAdapter(curr_manifest=manifest, curr_catalog=catalog)
71
- self.default_context.adapter = dbt_adapter
72
-
73
- dbt_adapter.adapter = MagicMock()
74
- dbt_adapter.adapter.type.return_value = None
75
-
76
- dbt_adapter.select_nodes = MagicMock()
77
- # Base and Current will be the same
78
- self.default_context.get_lineage.return_value = dbt_adapter.get_lineage()
79
- set_default_context(self.default_context)
80
-
81
- def test_schema_diff_should_be_approved(self):
82
- # Node_id is string
83
- is_approved = schema_diff_should_be_approved({
84
- 'node_id': 'model.jaffle_shop.customers',
85
- })
86
- assert is_approved is True
87
-
88
- # Node_id is list
89
- is_approved = schema_diff_should_be_approved({
90
- 'node_id': ['model.jaffle_shop.customers'],
91
- })
92
- assert is_approved is True
93
-
94
- # Select all models
95
- self.default_context.adapter.select_nodes.return_value = ['model.jaffle_shop.customers']
96
- is_approved = schema_diff_should_be_approved({
97
- 'select': 'customers',
98
- })
99
- assert is_approved is True