recce-nightly 1.10.0.20250625__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 (229) hide show
  1. recce/VERSION +1 -1
  2. recce/__init__.py +5 -0
  3. recce/adapter/dbt_adapter/__init__.py +343 -245
  4. recce/apis/check_api.py +20 -14
  5. recce/apis/check_events_api.py +353 -0
  6. recce/apis/check_func.py +5 -5
  7. recce/apis/run_func.py +32 -3
  8. recce/artifact.py +76 -3
  9. recce/cli.py +705 -82
  10. recce/config.py +2 -2
  11. recce/connect_to_cloud.py +1 -1
  12. recce/core.py +3 -3
  13. recce/data/404/index.html +2 -0
  14. recce/data/404.html +2 -22
  15. recce/data/__next.@lineage.!KHNsb3Qp.__PAGE__.txt +7 -0
  16. recce/data/__next.@lineage.!KHNsb3Qp.txt +4 -0
  17. recce/data/__next.__PAGE__.txt +6 -0
  18. recce/data/__next._full.txt +32 -0
  19. recce/data/__next._head.txt +8 -0
  20. recce/data/__next._index.txt +14 -0
  21. recce/data/__next._tree.txt +8 -0
  22. recce/data/_next/static/chunks/025a7e3e3f9f40ae.js +1 -0
  23. recce/data/_next/static/chunks/0ce56d67ef5779ca.js +4 -0
  24. recce/data/_next/static/chunks/1a6a78780155dac7.js +48 -0
  25. recce/data/_next/static/chunks/1de8485918b9182a.css +2 -0
  26. recce/data/_next/static/chunks/1e4b1b50d1e34993.js +1 -0
  27. recce/data/_next/static/chunks/206d5d181e4c738e.js +1 -0
  28. recce/data/_next/static/chunks/2c357efc34c5b859.js +25 -0
  29. recce/data/_next/static/chunks/2e9d95d2d48c479c.js +1 -0
  30. recce/data/_next/static/chunks/2f016dc4a3edad2e.js +2 -0
  31. recce/data/_next/static/chunks/313251962d698f7c.js +1 -0
  32. recce/data/_next/static/chunks/3a9f021f38eb5574.css +1 -0
  33. recce/data/_next/static/chunks/40079da8d2b8f651.js +1 -0
  34. recce/data/_next/static/chunks/4599182bffb64661.js +38 -0
  35. recce/data/_next/static/chunks/4e62f6e184173580.js +1 -0
  36. recce/data/_next/static/chunks/5c4dfb0d09eaa401.js +1 -0
  37. recce/data/_next/static/chunks/69e4f06ccfdfc3ac.js +1 -0
  38. recce/data/_next/static/chunks/6b206cb4707d6bee.js +1 -0
  39. recce/data/_next/static/chunks/6d8557f062aa4386.css +1 -0
  40. recce/data/_next/static/chunks/7fbe3650bd83b6b5.js +1 -0
  41. recce/data/_next/static/chunks/83fa823a825674f6.js +1 -0
  42. recce/data/_next/static/chunks/848a6c9b5f55f7ed.js +1 -0
  43. recce/data/_next/static/chunks/859462b0858aef88.css +2 -0
  44. recce/data/_next/static/chunks/923964f18c87d0f1.css +1 -0
  45. recce/data/_next/static/chunks/939390f911895d7c.js +48 -0
  46. recce/data/_next/static/chunks/99a9817237a07f43.js +1 -0
  47. recce/data/_next/static/chunks/9fed8b4b2b924054.js +5 -0
  48. recce/data/_next/static/chunks/b6949f6c5892110c.js +1 -0
  49. recce/data/_next/static/chunks/b851a1d3f8149828.js +1 -0
  50. recce/data/_next/static/chunks/c734f9ad957de0b4.js +1 -0
  51. recce/data/_next/static/chunks/cdde321b0ec75717.js +2 -0
  52. recce/data/_next/static/chunks/d0f91117d77ff844.css +1 -0
  53. recce/data/_next/static/chunks/d6c8667911c2500f.js +1 -0
  54. recce/data/_next/static/chunks/da8dab68c02752cf.js +74 -0
  55. recce/data/_next/static/chunks/dc074049c9d12d97.js +109 -0
  56. recce/data/_next/static/chunks/ee7f1a8227342421.js +1 -0
  57. recce/data/_next/static/chunks/fa2f4e56c2fccc73.js +1 -0
  58. recce/data/_next/static/chunks/turbopack-1fad664f62979b93.js +3 -0
  59. recce/data/_next/static/media/favicon.a8d38d84.ico +0 -0
  60. recce/data/_next/static/media/montserrat-cyrillic-800-normal.d80d830d.woff2 +0 -0
  61. recce/data/_next/static/media/{montserrat-cyrillic-800-normal.bd5c9f50.woff → montserrat-cyrillic-800-normal.f9d58125.woff} +0 -0
  62. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.076c2a93.woff2 +0 -0
  63. recce/data/_next/static/media/montserrat-latin-800-normal.cde454cc.woff2 +0 -0
  64. recce/data/_next/static/media/{montserrat-latin-800-normal.fc315020.woff → montserrat-latin-800-normal.d5761935.woff} +0 -0
  65. recce/data/_next/static/media/montserrat-latin-ext-800-normal.40ec0659.woff2 +0 -0
  66. recce/data/_next/static/media/{montserrat-latin-ext-800-normal.2e5381b2.woff → montserrat-latin-ext-800-normal.b671449b.woff} +0 -0
  67. recce/data/_next/static/media/{montserrat-vietnamese-800-normal.20c545e6.woff → montserrat-vietnamese-800-normal.9f7b8541.woff} +0 -0
  68. recce/data/_next/static/media/montserrat-vietnamese-800-normal.f9eb854e.woff2 +0 -0
  69. recce/data/_next/static/nX-Uz0AH6Tc6hIQUFGqaB/_buildManifest.js +11 -0
  70. recce/data/_next/static/nX-Uz0AH6Tc6hIQUFGqaB/_clientMiddlewareManifest.json +1 -0
  71. recce/data/_not-found/__next._full.txt +24 -0
  72. recce/data/_not-found/__next._head.txt +8 -0
  73. recce/data/_not-found/__next._index.txt +13 -0
  74. recce/data/_not-found/__next._not-found.__PAGE__.txt +5 -0
  75. recce/data/_not-found/__next._not-found.txt +4 -0
  76. recce/data/_not-found/__next._tree.txt +6 -0
  77. recce/data/_not-found/index.html +2 -0
  78. recce/data/_not-found/index.txt +24 -0
  79. recce/data/auth_callback.html +1 -1
  80. recce/data/checks/__next.@lineage.__DEFAULT__.txt +7 -0
  81. recce/data/checks/__next._full.txt +39 -0
  82. recce/data/checks/__next._head.txt +8 -0
  83. recce/data/checks/__next._index.txt +14 -0
  84. recce/data/checks/__next._tree.txt +8 -0
  85. recce/data/checks/__next.checks.__PAGE__.txt +10 -0
  86. recce/data/checks/__next.checks.txt +4 -0
  87. recce/data/checks/index.html +2 -0
  88. recce/data/checks/index.txt +39 -0
  89. recce/data/index.html +2 -27
  90. recce/data/index.txt +32 -8
  91. recce/data/lineage/__next.@lineage.__DEFAULT__.txt +7 -0
  92. recce/data/lineage/__next._full.txt +39 -0
  93. recce/data/lineage/__next._head.txt +8 -0
  94. recce/data/lineage/__next._index.txt +14 -0
  95. recce/data/lineage/__next._tree.txt +8 -0
  96. recce/data/lineage/__next.lineage.__PAGE__.txt +10 -0
  97. recce/data/lineage/__next.lineage.txt +4 -0
  98. recce/data/lineage/index.html +2 -0
  99. recce/data/lineage/index.txt +39 -0
  100. recce/data/query/__next.@lineage.__DEFAULT__.txt +7 -0
  101. recce/data/query/__next._full.txt +37 -0
  102. recce/data/query/__next._head.txt +8 -0
  103. recce/data/query/__next._index.txt +14 -0
  104. recce/data/query/__next._tree.txt +8 -0
  105. recce/data/query/__next.query.__PAGE__.txt +9 -0
  106. recce/data/query/__next.query.txt +4 -0
  107. recce/data/query/index.html +2 -0
  108. recce/data/query/index.txt +37 -0
  109. recce/event/CONFIG.bak +1 -0
  110. recce/event/__init__.py +9 -8
  111. recce/event/collector.py +6 -2
  112. recce/event/track.py +10 -0
  113. recce/github.py +1 -1
  114. recce/mcp_server.py +725 -0
  115. recce/models/check.py +433 -15
  116. recce/models/types.py +61 -2
  117. recce/pull_request.py +1 -1
  118. recce/run.py +37 -17
  119. recce/server.py +216 -21
  120. recce/state/__init__.py +31 -0
  121. recce/state/cloud.py +644 -0
  122. recce/state/const.py +26 -0
  123. recce/state/local.py +56 -0
  124. recce/state/state.py +119 -0
  125. recce/state/state_loader.py +174 -0
  126. recce/summary.py +25 -3
  127. recce/tasks/dataframe.py +63 -1
  128. recce/tasks/query.py +40 -3
  129. recce/tasks/rowcount.py +4 -1
  130. recce/tasks/schema.py +4 -1
  131. recce/tasks/utils.py +147 -0
  132. recce/tasks/valuediff.py +85 -57
  133. recce/util/api_token.py +11 -2
  134. recce/util/breaking.py +10 -1
  135. recce/util/cll.py +1 -2
  136. recce/util/cloud/__init__.py +15 -0
  137. recce/util/cloud/base.py +115 -0
  138. recce/util/cloud/check_events.py +190 -0
  139. recce/util/cloud/checks.py +242 -0
  140. recce/util/io.py +2 -2
  141. recce/util/lineage.py +19 -18
  142. recce/util/perf_tracking.py +85 -0
  143. recce/util/recce_cloud.py +254 -5
  144. recce/util/startup_perf.py +121 -0
  145. recce/yaml/__init__.py +2 -2
  146. {recce_nightly-1.10.0.20250625.dist-info → recce_nightly-1.30.0.20251221.dist-info}/METADATA +91 -71
  147. recce_nightly-1.30.0.20251221.dist-info/RECORD +183 -0
  148. {recce_nightly-1.10.0.20250625.dist-info → recce_nightly-1.30.0.20251221.dist-info}/WHEEL +1 -2
  149. recce/data/_next/static/abCX3x3UoIdRLEDWxx4xd/_buildManifest.js +0 -1
  150. recce/data/_next/static/chunks/181-acc61ddada3bc0ca.js +0 -43
  151. recce/data/_next/static/chunks/1bff33f1-1ef85cf5e658a751.js +0 -1
  152. recce/data/_next/static/chunks/217-879a84d70f7a907c.js +0 -2
  153. recce/data/_next/static/chunks/29e3cc0d-60045b2e47aa3916.js +0 -1
  154. recce/data/_next/static/chunks/36e1c10d-8e7be4a6c1f6ab2d.js +0 -1
  155. recce/data/_next/static/chunks/3998a672-03adacad07b346ac.js +0 -1
  156. recce/data/_next/static/chunks/3a92ee20-1081c360214f9602.js +0 -1
  157. recce/data/_next/static/chunks/42-cd3c06533f5fd47c.js +0 -9
  158. recce/data/_next/static/chunks/450c323b-fd94e7ffaa4a5efa.js +0 -1
  159. recce/data/_next/static/chunks/47d8844f-929aed9b1c73a905.js +0 -1
  160. recce/data/_next/static/chunks/608-3b079b544e5d5f5e.js +0 -15
  161. recce/data/_next/static/chunks/6dc81886-adbfa45836061d79.js +0 -1
  162. recce/data/_next/static/chunks/7a8a3e83-edf6dc64b5d5f0a5.js +0 -1
  163. recce/data/_next/static/chunks/7f27ae6c-d5f0438edd5c2a5b.js +0 -1
  164. recce/data/_next/static/chunks/86730205-cfb14e3f051bab35.js +0 -1
  165. recce/data/_next/static/chunks/8d700b6a.8bb140898499c512.js +0 -1
  166. recce/data/_next/static/chunks/92-607cd1af83c41f43.js +0 -1
  167. recce/data/_next/static/chunks/9746af58-a42b7d169cacadf0.js +0 -1
  168. recce/data/_next/static/chunks/a30376cd-de84559016d7e133.js +0 -1
  169. recce/data/_next/static/chunks/app/_not-found/page-01ed58b7f971d311.js +0 -1
  170. recce/data/_next/static/chunks/app/layout-177a410a97e0d018.js +0 -1
  171. recce/data/_next/static/chunks/app/page-da6e046a8235dbfc.js +0 -1
  172. recce/data/_next/static/chunks/b63b1b3f-4282bdcf459e075c.js +0 -1
  173. recce/data/_next/static/chunks/bbda5537-9ec25eb1dd62348a.js +0 -1
  174. recce/data/_next/static/chunks/c132bf7d-08cb668a789d6afd.js +0 -1
  175. recce/data/_next/static/chunks/ce84277d-2e5d1d46910cf052.js +0 -1
  176. recce/data/_next/static/chunks/febdd86e-c6b525341634b860.js +0 -54
  177. recce/data/_next/static/chunks/fee69bc6-2dbccaf9b90474e6.js +0 -1
  178. recce/data/_next/static/chunks/framework-ded83d71b51ce901.js +0 -1
  179. recce/data/_next/static/chunks/main-app-39061b0166c47f55.js +0 -1
  180. recce/data/_next/static/chunks/main-b5b3ae20a1405261.js +0 -1
  181. recce/data/_next/static/chunks/pages/_app-437c455677d62394.js +0 -1
  182. recce/data/_next/static/chunks/pages/_error-e7650df18ca04bde.js +0 -1
  183. recce/data/_next/static/chunks/webpack-7b49d5ba7e3a434d.js +0 -1
  184. recce/data/_next/static/css/17a96168e3a9db13.css +0 -1
  185. recce/data/_next/static/css/1b121dc4d36aeb4d.css +0 -3
  186. recce/data/_next/static/css/35c6679a098e1e34.css +0 -1
  187. recce/data/_next/static/css/951e2e0eea2d4a5b.css +0 -14
  188. recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2 +0 -0
  189. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.94a63aea.woff2 +0 -0
  190. recce/data/_next/static/media/montserrat-latin-800-normal.6f8fa298.woff2 +0 -0
  191. recce/data/_next/static/media/montserrat-latin-ext-800-normal.013b84f9.woff2 +0 -0
  192. recce/data/_next/static/media/montserrat-vietnamese-800-normal.c0035377.woff2 +0 -0
  193. recce/data/_next/static/media/reload-image.79aabb7d.svg +0 -4
  194. recce/state.py +0 -786
  195. recce_nightly-1.10.0.20250625.dist-info/RECORD +0 -154
  196. recce_nightly-1.10.0.20250625.dist-info/top_level.txt +0 -2
  197. tests/__init__.py +0 -0
  198. tests/adapter/__init__.py +0 -0
  199. tests/adapter/dbt_adapter/__init__.py +0 -0
  200. tests/adapter/dbt_adapter/conftest.py +0 -17
  201. tests/adapter/dbt_adapter/dbt_test_helper.py +0 -298
  202. tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -25
  203. tests/adapter/dbt_adapter/test_dbt_cll.py +0 -384
  204. tests/adapter/dbt_adapter/test_selector.py +0 -202
  205. tests/tasks/__init__.py +0 -0
  206. tests/tasks/conftest.py +0 -4
  207. tests/tasks/test_histogram.py +0 -129
  208. tests/tasks/test_lineage.py +0 -55
  209. tests/tasks/test_preset_checks.py +0 -64
  210. tests/tasks/test_profile.py +0 -397
  211. tests/tasks/test_query.py +0 -151
  212. tests/tasks/test_row_count.py +0 -135
  213. tests/tasks/test_schema.py +0 -122
  214. tests/tasks/test_top_k.py +0 -77
  215. tests/tasks/test_valuediff.py +0 -85
  216. tests/test_cli.py +0 -133
  217. tests/test_config.py +0 -43
  218. tests/test_connect_to_cloud.py +0 -82
  219. tests/test_core.py +0 -29
  220. tests/test_dbt.py +0 -36
  221. tests/test_pull_request.py +0 -130
  222. tests/test_server.py +0 -104
  223. tests/test_state.py +0 -134
  224. tests/test_summary.py +0 -65
  225. /recce/data/_next/static/chunks/{polyfills-42372ed130431b0a.js → a6dad97d9634a72d.js} +0 -0
  226. /recce/data/_next/static/media/{montserrat-cyrillic-ext-800-normal.e6e0d8d0.woff → montserrat-cyrillic-ext-800-normal.a4fa76b5.woff} +0 -0
  227. /recce/data/_next/static/{abCX3x3UoIdRLEDWxx4xd → nX-Uz0AH6Tc6hIQUFGqaB}/_ssgManifest.js +0 -0
  228. {recce_nightly-1.10.0.20250625.dist-info → recce_nightly-1.30.0.20251221.dist-info}/entry_points.txt +0 -0
  229. {recce_nightly-1.10.0.20250625.dist-info → recce_nightly-1.30.0.20251221.dist-info}/licenses/LICENSE +0 -0
@@ -1,129 +0,0 @@
1
- import pytest
2
-
3
- from recce.tasks.histogram import (
4
- HistogramDiffCheckValidator,
5
- HistogramDiffTask,
6
- _is_histogram_supported,
7
- )
8
-
9
-
10
- def test_histogram(dbt_test_helper):
11
- csv_data = """
12
- customer_id,name,age
13
- 1,Alice,30
14
- 2,Bob,25
15
- 3,Charlie,35
16
- 4,Dolly,50
17
- """
18
-
19
- dbt_test_helper.create_model("customers", csv_data, csv_data)
20
-
21
- params = {"model": "customers", "column_name": "age", "column_type": "int"}
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 = {"model": "customers", "column_name": "age", "column_type": "int"}
60
-
61
- task = HistogramDiffTask(params)
62
- run_result = task.execute()
63
-
64
- assert len(run_result["current"]["counts"]) == 0
65
- assert run_result["current"]["total"] == 0
66
- assert run_result["min"] is None
67
- assert run_result["max"] is None
68
- assert len(run_result["bin_edges"]) == 0
69
-
70
- params = {"model": "customers2", "column_name": "age", "column_type": "int"}
71
-
72
- task = HistogramDiffTask(params)
73
- run_result = task.execute()
74
- assert run_result["base"]["counts"][0] == 1
75
- assert run_result["base"]["counts"][-1] == 1
76
- assert run_result["base"]["total"] == 4
77
- assert run_result["current"]["counts"][0] == 0
78
- assert run_result["current"]["counts"][-1] == 0
79
- assert run_result["current"]["total"] == 0
80
- assert run_result["min"] == 25
81
- assert run_result["max"] == 50
82
- assert run_result["bin_edges"][0] == 25
83
- assert run_result["bin_edges"][-1] == 51
84
-
85
- params = {"model": "customers3", "column_name": "age", "column_type": "int"}
86
-
87
- task = HistogramDiffTask(params)
88
- run_result = task.execute()
89
- assert run_result["base"]["counts"][0] == 0
90
- assert run_result["base"]["counts"][-1] == 0
91
- assert run_result["base"]["total"] == 0
92
- assert run_result["current"]["counts"][0] == 1
93
- assert run_result["current"]["counts"][-1] == 1
94
- assert run_result["current"]["total"] == 4
95
- assert run_result["min"] == 25
96
- assert run_result["max"] == 50
97
- assert run_result["bin_edges"][0] == 25
98
- assert run_result["bin_edges"][-1] == 51
99
-
100
-
101
- def test_validator():
102
- def validate(params: dict = {}, view_options: dict = {}):
103
- HistogramDiffCheckValidator().validate(
104
- {
105
- "name": "test",
106
- "type": "histogram_diff",
107
- "params": params,
108
- "view_options": view_options,
109
- }
110
- )
111
-
112
- validate(
113
- {
114
- "model": "customers",
115
- "column_name": "age",
116
- "column_type": "int",
117
- }
118
- )
119
-
120
- with pytest.raises(ValueError):
121
- validate({})
122
-
123
-
124
- def test_is_column_type_supported_by_histogram():
125
- assert _is_histogram_supported("varchar") is False
126
- assert _is_histogram_supported("varchar(16)") is False
127
- assert _is_histogram_supported("varchar(256)") is False
128
- assert _is_histogram_supported("bool") is False
129
- assert _is_histogram_supported("int") is True
@@ -1,55 +0,0 @@
1
- import pytest
2
-
3
-
4
- def test_validator():
5
- from recce.tasks.lineage import LineageDiffCheckValidator
6
-
7
- validator = LineageDiffCheckValidator()
8
-
9
- def validate(params: dict):
10
- validator.validate(
11
- {
12
- "name": "test",
13
- "type": "schema_diff",
14
- "params": params,
15
- }
16
- )
17
-
18
- # Select all models
19
- validate({})
20
-
21
- # Select by selector
22
- validate(
23
- {
24
- "select": "customers",
25
- "exclude": "customers",
26
- "packages": ["jaffle_shop"],
27
- "view_mode": "all",
28
- }
29
- )
30
-
31
- # packages should be an array
32
- with pytest.raises(ValueError):
33
- validate(
34
- {
35
- "packages": "jaffle_shop",
36
- }
37
- )
38
-
39
- # view_mode should be 'all' or 'changed_models'
40
- validate(
41
- {
42
- "view_mode": None,
43
- }
44
- )
45
- validate(
46
- {
47
- "view_mode": "all",
48
- }
49
- )
50
- with pytest.raises(ValueError):
51
- validate(
52
- {
53
- "view_mode": "abc",
54
- }
55
- )
@@ -1,64 +0,0 @@
1
- import pytest
2
-
3
-
4
- def test_default_validator():
5
- from recce.tasks.core import CheckValidator
6
-
7
- CheckValidator().validate(
8
- {
9
- "name": "test",
10
- "type": "row_count_diff",
11
- "params": {},
12
- }
13
- )
14
-
15
- with pytest.raises(ValueError):
16
- CheckValidator().validate(
17
- {
18
- "type": "row_count_diff",
19
- }
20
- )
21
-
22
-
23
- def test_query_diff_validator():
24
- from recce.tasks.query import QueryDiffCheckValidator
25
-
26
- QueryDiffCheckValidator().validate(
27
- {
28
- "name": "test",
29
- "type": "query_diff",
30
- "params": {"sql_template": "select * from {{ model }}"},
31
- }
32
- )
33
- with pytest.raises(ValueError):
34
- QueryDiffCheckValidator().validate(
35
- {
36
- "name": "test",
37
- "type": "query_diff",
38
- }
39
- )
40
-
41
-
42
- def test_lineage_diff_validator():
43
- from recce.tasks.lineage import LineageDiffCheckValidator
44
-
45
- LineageDiffCheckValidator().validate(
46
- {
47
- "name": "test",
48
- "type": "lineage_diff",
49
- "params": {},
50
- }
51
- )
52
- LineageDiffCheckValidator().validate(
53
- {
54
- "name": "test",
55
- "type": "lineage_diff",
56
- "view_options": {},
57
- }
58
- )
59
- with pytest.raises(ValueError):
60
- LineageDiffCheckValidator().validate(
61
- {
62
- "type": "lineage_diff",
63
- }
64
- )
@@ -1,397 +0,0 @@
1
- import pytest
2
- from jinja2 import Template
3
- from sqlglot import parse_one
4
-
5
- from recce.tasks import ProfileDiffTask, ProfileTask
6
- from recce.tasks.profile import PROFILE_COLUMN_JINJA_TEMPLATE
7
-
8
- csv_data_curr = """
9
- customer_id,name,age
10
- 1,Alice,30
11
- 2,Bob,25
12
- 3,Charlie,35
13
- """
14
-
15
- csv_data_base = """
16
- customer_id,name,age
17
- 1,Alice,35
18
- 2,Bob,25
19
- 3,Charlie,35
20
- """
21
-
22
-
23
- def test_profile(dbt_test_helper):
24
- dbt_test_helper.create_model("customers", None, csv_data_curr)
25
- params = dict(model="customers")
26
- task = ProfileTask(params)
27
- run_result = task.execute()
28
-
29
- assert len(run_result.current.data) == 3
30
-
31
-
32
- def test_profile_with_selected_columns(dbt_test_helper):
33
- dbt_test_helper.create_model("customers", None, csv_data_curr)
34
- params = dict(model="customers", columns=["name", "age"])
35
- task = ProfileTask(params)
36
- run_result = task.execute()
37
- assert len(run_result.current.data) == 2
38
-
39
-
40
- def test_profile_diff(dbt_test_helper):
41
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr)
42
- params = dict(model="customers")
43
- task = ProfileDiffTask(params)
44
- run_result = task.execute()
45
-
46
- assert len(run_result.current.data) == 3
47
- assert len(run_result.base.data) == 3
48
-
49
-
50
- def test_profile_diff_with_selected_columns(dbt_test_helper):
51
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr)
52
- params = dict(model="customers", columns=["name", "age"])
53
- task = ProfileDiffTask(params)
54
- run_result = task.execute()
55
- assert len(run_result.current.data) == 2
56
- assert len(run_result.base.data) == 2
57
-
58
-
59
- def test_validator():
60
- from recce.tasks.profile import ProfileCheckValidator
61
-
62
- def validate(params: dict = {}, view_options: dict = {}):
63
- ProfileCheckValidator().validate(
64
- {
65
- "name": "test",
66
- "type": "profile_diff",
67
- "params": params,
68
- "view_options": view_options,
69
- }
70
- )
71
-
72
- validate(
73
- {
74
- "model": "customers",
75
- }
76
- )
77
-
78
- with pytest.raises(ValueError):
79
- validate({})
80
-
81
-
82
- def test_profile_column_jinja_template():
83
-
84
- class DummyAdapter:
85
- def __init__(self, database_type="duckdb"):
86
- self.database_type = database_type
87
-
88
- def quote(self, col):
89
- quote_marks = {
90
- "athena": '"',
91
- "bigquery": "`",
92
- "databricks": "`",
93
- "duckdb": '"',
94
- "postgres": '"',
95
- "redshift": '"',
96
- "snowflake": '"',
97
- "sqlite": '"',
98
- "sqlserver": '"',
99
- "trino": '"',
100
- }
101
- quote_mark = quote_marks.get(self.database_type, '"')
102
- return f"{quote_mark}{col}{quote_mark}"
103
-
104
- class DummyDbt:
105
- def __init__(self, database_type="Postgres"):
106
- self.database_type = database_type
107
-
108
- def type_bigint(self):
109
- bigint_types = {
110
- "athena": "BIGINT",
111
- "bigquery": "INT64",
112
- "databricks": "BIGINT",
113
- "duckdb": "BIGINT",
114
- "postgres": "BIGINT",
115
- "redshift": "BIGINT",
116
- "snowflake": "NUMBER",
117
- "sqlite": "INTEGER",
118
- "sqlserver": "BIGINT",
119
- "trino": "BIGINT",
120
- }
121
- return bigint_types.get(self.database_type, "bigint")
122
-
123
- def type_numeric(self):
124
- numeric_types = {
125
- "athena": "DECIMAL",
126
- "bigquery": "NUMERIC",
127
- "databricks": "DECIMAL",
128
- "duckdb": "DECIMAL",
129
- "postgres": "NUMERIC",
130
- "redshift": "DECIMAL",
131
- "snowflake": "NUMBER",
132
- "sqlite": "NUMERIC",
133
- "sqlserver": "DECIMAL",
134
- "trino": "DECIMAL",
135
- }
136
- return numeric_types.get(self.database_type, "numeric")
137
-
138
- def type_string(self):
139
- string_types = {
140
- "athena": "VARCHAR",
141
- "bigquery": "STRING",
142
- "databricks": "STRING",
143
- "duckdb": "VARCHAR",
144
- "postgres": "TEXT",
145
- "redshift": "VARCHAR",
146
- "snowflake": "VARCHAR",
147
- "sqlite": "TEXT",
148
- "sqlserver": "VARCHAR",
149
- "trino": "VARCHAR",
150
- }
151
- return string_types.get(self.database_type, "varchar")
152
-
153
- test_db_column_types = {
154
- "athena": [
155
- "boolean",
156
- "int",
157
- "double",
158
- "decimal",
159
- "char",
160
- "string",
161
- "binary",
162
- "date",
163
- "array",
164
- "struct",
165
- "map",
166
- ],
167
- "bigquery": [
168
- "array",
169
- "bool",
170
- "bytes",
171
- "date",
172
- "datetime",
173
- "interval",
174
- "json",
175
- "int64",
176
- "bignumeric",
177
- "range",
178
- "string",
179
- "struct",
180
- "time",
181
- "timestamp",
182
- ],
183
- "databricks": [
184
- "bigint",
185
- "binary",
186
- "boolean",
187
- "date",
188
- "decimal",
189
- "double",
190
- "float",
191
- "int",
192
- "interval",
193
- "void",
194
- "string",
195
- "timestamp",
196
- "array",
197
- "map",
198
- "struct",
199
- "variant",
200
- "object",
201
- ],
202
- "duckdb": [
203
- "boolean",
204
- "integer",
205
- "bigint",
206
- "real",
207
- "double",
208
- "decimal",
209
- "varchar",
210
- "date",
211
- "time",
212
- "timestamp",
213
- "blob",
214
- "array",
215
- "list",
216
- "struct",
217
- "map",
218
- "union",
219
- "uuid",
220
- "json",
221
- ],
222
- "postgres": [
223
- "bigint",
224
- "bigserial",
225
- "bit",
226
- "boolean",
227
- "box",
228
- "bytea",
229
- "character",
230
- "cidr",
231
- "circle",
232
- "date",
233
- "double precision",
234
- "inet",
235
- "integer",
236
- "interval",
237
- "json",
238
- "jsonb",
239
- "line",
240
- "lseg",
241
- "macaddr",
242
- "money",
243
- "numeric",
244
- "path",
245
- "pg_lsn",
246
- "point",
247
- "polygon",
248
- "real",
249
- "smallint",
250
- "smallserial",
251
- "serial",
252
- "text",
253
- "time",
254
- "timestamp",
255
- "tsquery",
256
- "tsvector",
257
- "txid_snapshot",
258
- "uuid",
259
- "xml",
260
- "array",
261
- ],
262
- "redshift": [
263
- "smallint",
264
- "integer",
265
- "bigint",
266
- "decimal",
267
- "real",
268
- "double precision",
269
- "boolean",
270
- "char",
271
- "varchar",
272
- "date",
273
- "timestamp",
274
- "timestamptz",
275
- "super",
276
- "time",
277
- "timetz",
278
- "varbyte",
279
- "geometry",
280
- "geography",
281
- "hllsketch",
282
- ],
283
- "snowflake": [
284
- "number",
285
- "decimal",
286
- "numeric",
287
- "int",
288
- "integer",
289
- "bigint",
290
- "smallint",
291
- "tinyint",
292
- "byteint",
293
- "float",
294
- "float4",
295
- "float8",
296
- "double",
297
- "double precision",
298
- "real",
299
- "varchar",
300
- "char",
301
- "character",
302
- "string",
303
- "text",
304
- "binary",
305
- "varbinary",
306
- "boolean",
307
- "date",
308
- "datetime",
309
- "time",
310
- "timestamp",
311
- "timestamp_ltz",
312
- "timestamp_ntz",
313
- "timestamp_tz",
314
- "variant",
315
- "object",
316
- "array",
317
- "geography",
318
- "geometry",
319
- ],
320
- "sqlite": ["integer", "real", "text", "blob", "numeric", "boolean", "date", "datetime", "json"],
321
- "trino": [
322
- "boolean",
323
- "tinyint",
324
- "smallint",
325
- "integer",
326
- "bigint",
327
- "real",
328
- "double",
329
- "decimal",
330
- "varchar",
331
- "char",
332
- "varbinary",
333
- "json",
334
- "date",
335
- "time",
336
- "timestamp",
337
- "timestamp with time zone",
338
- "interval year to month",
339
- "interval day to second",
340
- "array",
341
- "map",
342
- "row",
343
- "ipaddress",
344
- "uuid",
345
- "hyperloglog",
346
- "p4hyperloglog",
347
- "qdigest",
348
- ],
349
- "sqlserver": [
350
- "bigint",
351
- "int",
352
- "smallint",
353
- "tinyint",
354
- "bit",
355
- "decimal",
356
- "numeric",
357
- "money",
358
- "smallmoney",
359
- "float",
360
- "real",
361
- "date",
362
- "datetime",
363
- "datetime2",
364
- "smalldatetime",
365
- "time",
366
- "char",
367
- "varchar",
368
- "text",
369
- "nchar",
370
- "nvarchar",
371
- "ntext",
372
- "binary",
373
- "varbinary",
374
- "image",
375
- "timestamp",
376
- "uniqueidentifier",
377
- "xml",
378
- "cursor",
379
- "table",
380
- "sql_variant",
381
- ],
382
- }
383
-
384
- for db_type, column_types in test_db_column_types.items():
385
- for column_type in column_types:
386
- context = {
387
- "column_type": column_type,
388
- "column_name": "profile_column",
389
- "db_type": db_type,
390
- "relation": "test_table",
391
- "adapter": DummyAdapter(),
392
- "dbt": DummyDbt(),
393
- }
394
-
395
- sql = Template(PROFILE_COLUMN_JINJA_TEMPLATE).render(context)
396
- dialect = db_type if db_type != "sqlserver" else "tsql"
397
- parse_one(sql, read=dialect)