recce-nightly 1.2.0.20250506__py3-none-any.whl → 1.26.0.20251124__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 (213) 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 +810 -480
  5. recce/adapter/dbt_adapter/dbt_version.py +3 -0
  6. recce/adapter/sqlmesh_adapter.py +24 -35
  7. recce/apis/check_api.py +39 -28
  8. recce/apis/check_func.py +33 -27
  9. recce/apis/run_api.py +25 -19
  10. recce/apis/run_func.py +29 -23
  11. recce/artifact.py +119 -51
  12. recce/cli.py +1299 -323
  13. recce/config.py +42 -33
  14. recce/connect_to_cloud.py +138 -0
  15. recce/core.py +55 -47
  16. recce/data/404.html +1 -1
  17. recce/data/__next.__PAGE__.txt +10 -0
  18. recce/data/__next._full.txt +23 -0
  19. recce/data/__next._head.txt +8 -0
  20. recce/data/__next._index.txt +8 -0
  21. recce/data/__next._tree.txt +5 -0
  22. recce/data/_next/static/52aV_JrNUZU6dMFgvTQEO/_buildManifest.js +11 -0
  23. recce/data/_next/static/52aV_JrNUZU6dMFgvTQEO/_clientMiddlewareManifest.json +1 -0
  24. recce/data/_next/static/chunks/02b996c7f6a29a06.js +4 -0
  25. recce/data/_next/static/chunks/19c10d219a6a21ff.js +1 -0
  26. recce/data/_next/static/chunks/2df9ec28a061971d.js +11 -0
  27. recce/data/_next/static/chunks/3098c987393bda15.js +1 -0
  28. recce/data/_next/static/chunks/393dc43e483f717a.css +2 -0
  29. recce/data/_next/static/chunks/399e8d91a7e45073.js +2 -0
  30. recce/data/_next/static/chunks/4d0186f631230245.js +1 -0
  31. recce/data/_next/static/chunks/5794ba9e10a9c060.js +11 -0
  32. recce/data/_next/static/chunks/715761c929a3f28b.js +110 -0
  33. recce/data/_next/static/chunks/71f88fcc615bf282.js +1 -0
  34. recce/data/_next/static/chunks/80d2a95eaf1201ea.js +1 -0
  35. recce/data/_next/static/chunks/9979c6109bbbee35.js +1 -0
  36. recce/data/_next/static/chunks/99d638224186c118.js +1 -0
  37. recce/data/_next/static/chunks/d003eb36240e92f3.js +1 -0
  38. recce/data/_next/static/chunks/d3167cdfec4fc351.js +1 -0
  39. recce/data/_next/static/chunks/e124bccf574a3361.css +1 -0
  40. recce/data/_next/static/chunks/f40141db1bdb46f0.css +6 -0
  41. recce/data/_next/static/chunks/fcc53a88741a52f9.js +1 -0
  42. recce/data/_next/static/chunks/turbopack-b1920d28cfb1f28d.js +3 -0
  43. recce/data/_next/static/media/favicon.a8d38d84.ico +0 -0
  44. recce/data/_next/static/media/montserrat-cyrillic-800-normal.d80d830d.woff2 +0 -0
  45. recce/data/_next/static/media/montserrat-cyrillic-800-normal.f9d58125.woff +0 -0
  46. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.076c2a93.woff2 +0 -0
  47. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.a4fa76b5.woff +0 -0
  48. recce/data/_next/static/media/montserrat-latin-800-normal.cde454cc.woff2 +0 -0
  49. recce/data/_next/static/media/montserrat-latin-800-normal.d5761935.woff +0 -0
  50. recce/data/_next/static/media/montserrat-latin-ext-800-normal.40ec0659.woff2 +0 -0
  51. recce/data/_next/static/media/montserrat-latin-ext-800-normal.b671449b.woff +0 -0
  52. recce/data/_next/static/media/montserrat-vietnamese-800-normal.9f7b8541.woff +0 -0
  53. recce/data/_next/static/media/montserrat-vietnamese-800-normal.f9eb854e.woff2 +0 -0
  54. recce/data/_next/static/media/reload-image.7aa931c7.svg +4 -0
  55. recce/data/_not-found/__next._full.txt +17 -0
  56. recce/data/_not-found/__next._head.txt +8 -0
  57. recce/data/_not-found/__next._index.txt +8 -0
  58. recce/data/_not-found/__next._not-found.__PAGE__.txt +5 -0
  59. recce/data/_not-found/__next._not-found.txt +4 -0
  60. recce/data/_not-found/__next._tree.txt +3 -0
  61. recce/data/_not-found.html +1 -0
  62. recce/data/_not-found.txt +17 -0
  63. recce/data/auth_callback.html +68 -0
  64. recce/data/imgs/reload-image.svg +4 -0
  65. recce/data/index.html +1 -27
  66. recce/data/index.txt +23 -7
  67. recce/diff.py +6 -12
  68. recce/event/__init__.py +86 -74
  69. recce/event/collector.py +33 -22
  70. recce/event/track.py +49 -27
  71. recce/exceptions.py +1 -1
  72. recce/git.py +7 -7
  73. recce/github.py +57 -53
  74. recce/mcp_server.py +716 -0
  75. recce/models/__init__.py +4 -1
  76. recce/models/check.py +6 -7
  77. recce/models/run.py +1 -0
  78. recce/models/types.py +131 -28
  79. recce/pull_request.py +27 -25
  80. recce/run.py +165 -121
  81. recce/server.py +303 -111
  82. recce/state/__init__.py +31 -0
  83. recce/state/cloud.py +632 -0
  84. recce/state/const.py +26 -0
  85. recce/state/local.py +56 -0
  86. recce/state/state.py +119 -0
  87. recce/state/state_loader.py +174 -0
  88. recce/summary.py +188 -143
  89. recce/tasks/__init__.py +19 -3
  90. recce/tasks/core.py +11 -13
  91. recce/tasks/dataframe.py +82 -18
  92. recce/tasks/histogram.py +69 -34
  93. recce/tasks/lineage.py +2 -2
  94. recce/tasks/profile.py +152 -86
  95. recce/tasks/query.py +139 -87
  96. recce/tasks/rowcount.py +37 -31
  97. recce/tasks/schema.py +18 -15
  98. recce/tasks/top_k.py +35 -35
  99. recce/tasks/valuediff.py +216 -152
  100. recce/util/__init__.py +3 -0
  101. recce/util/api_token.py +80 -0
  102. recce/util/breaking.py +87 -85
  103. recce/util/cll.py +274 -219
  104. recce/util/io.py +22 -17
  105. recce/util/lineage.py +65 -16
  106. recce/util/logger.py +1 -1
  107. recce/util/onboarding_state.py +45 -0
  108. recce/util/perf_tracking.py +85 -0
  109. recce/util/recce_cloud.py +322 -72
  110. recce/util/singleton.py +4 -4
  111. recce/yaml/__init__.py +7 -10
  112. recce_cloud/__init__.py +24 -0
  113. recce_cloud/api/__init__.py +17 -0
  114. recce_cloud/api/base.py +111 -0
  115. recce_cloud/api/client.py +150 -0
  116. recce_cloud/api/exceptions.py +26 -0
  117. recce_cloud/api/factory.py +63 -0
  118. recce_cloud/api/github.py +76 -0
  119. recce_cloud/api/gitlab.py +82 -0
  120. recce_cloud/artifact.py +57 -0
  121. recce_cloud/ci_providers/__init__.py +9 -0
  122. recce_cloud/ci_providers/base.py +82 -0
  123. recce_cloud/ci_providers/detector.py +147 -0
  124. recce_cloud/ci_providers/github_actions.py +136 -0
  125. recce_cloud/ci_providers/gitlab_ci.py +130 -0
  126. recce_cloud/cli.py +245 -0
  127. recce_cloud/upload.py +214 -0
  128. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/METADATA +68 -37
  129. recce_nightly-1.26.0.20251124.dist-info/RECORD +180 -0
  130. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/WHEEL +1 -1
  131. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/top_level.txt +1 -0
  132. tests/adapter/dbt_adapter/conftest.py +9 -5
  133. tests/adapter/dbt_adapter/dbt_test_helper.py +37 -22
  134. tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -15
  135. tests/adapter/dbt_adapter/test_dbt_cll.py +656 -41
  136. tests/adapter/dbt_adapter/test_selector.py +22 -21
  137. tests/recce_cloud/__init__.py +0 -0
  138. tests/recce_cloud/test_ci_providers.py +351 -0
  139. tests/recce_cloud/test_cli.py +372 -0
  140. tests/recce_cloud/test_client.py +273 -0
  141. tests/recce_cloud/test_platform_clients.py +333 -0
  142. tests/tasks/conftest.py +1 -1
  143. tests/tasks/test_histogram.py +58 -66
  144. tests/tasks/test_lineage.py +36 -23
  145. tests/tasks/test_preset_checks.py +45 -31
  146. tests/tasks/test_profile.py +339 -15
  147. tests/tasks/test_query.py +46 -46
  148. tests/tasks/test_row_count.py +65 -46
  149. tests/tasks/test_schema.py +65 -42
  150. tests/tasks/test_top_k.py +22 -18
  151. tests/tasks/test_valuediff.py +43 -32
  152. tests/test_cli.py +174 -60
  153. tests/test_cli_mcp_optional.py +45 -0
  154. tests/test_cloud_listing_cli.py +324 -0
  155. tests/test_config.py +7 -9
  156. tests/test_connect_to_cloud.py +82 -0
  157. tests/test_core.py +151 -4
  158. tests/test_dbt.py +7 -7
  159. tests/test_mcp_server.py +332 -0
  160. tests/test_pull_request.py +1 -1
  161. tests/test_server.py +25 -19
  162. tests/test_summary.py +29 -17
  163. recce/data/_next/static/Kcbs3GEIyH2LxgLYat0es/_buildManifest.js +0 -1
  164. recce/data/_next/static/chunks/1f229bf6-d9fe92e56db8d93b.js +0 -1
  165. recce/data/_next/static/chunks/29e3cc0d-8c150e37dff9631b.js +0 -1
  166. recce/data/_next/static/chunks/368-7587b306577df275.js +0 -65
  167. recce/data/_next/static/chunks/36e1c10d-bb0210cbd6573a8d.js +0 -1
  168. recce/data/_next/static/chunks/3998a672-eaad84bdd88cc73e.js +0 -1
  169. recce/data/_next/static/chunks/3a92ee20-3b5d922d4157af5e.js +0 -1
  170. recce/data/_next/static/chunks/450c323b-1bb5db526e54435a.js +0 -1
  171. recce/data/_next/static/chunks/47d8844f-79a1b53c66a7d7ec.js +0 -1
  172. recce/data/_next/static/chunks/6dc81886-c94b9b91bc2c3caf.js +0 -1
  173. recce/data/_next/static/chunks/6ef81909-694dc38134099299.js +0 -1
  174. recce/data/_next/static/chunks/700-3b65fc3666820d00.js +0 -2
  175. recce/data/_next/static/chunks/7a8a3e83-d7fa409d97b38b2b.js +0 -1
  176. recce/data/_next/static/chunks/7f27ae6c-413f6b869a04183a.js +0 -1
  177. recce/data/_next/static/chunks/8d700b6a-f0b1f6b9e0d97ce2.js +0 -1
  178. recce/data/_next/static/chunks/9746af58-d74bef4d03eea6ab.js +0 -1
  179. recce/data/_next/static/chunks/a30376cd-7d806e1602f2dc3a.js +0 -1
  180. recce/data/_next/static/chunks/app/_not-found/page-8a886fa0855c3105.js +0 -1
  181. recce/data/_next/static/chunks/app/layout-9102e22cb73f74d6.js +0 -1
  182. recce/data/_next/static/chunks/app/page-cee661090afbd6aa.js +0 -1
  183. recce/data/_next/static/chunks/b63b1b3f-7395c74e11a14e95.js +0 -1
  184. recce/data/_next/static/chunks/c132bf7d-8102037f9ccf372a.js +0 -1
  185. recce/data/_next/static/chunks/c1ceaa8b-a1e442154d23515e.js +0 -1
  186. recce/data/_next/static/chunks/cd9f8d63-cf0d5a7b0f7a92e8.js +0 -54
  187. recce/data/_next/static/chunks/ce84277d-f42c2c58049cea2d.js +0 -1
  188. recce/data/_next/static/chunks/e24bf851-0f8cbc99656833e7.js +0 -1
  189. recce/data/_next/static/chunks/fee69bc6-f17d36c080742e74.js +0 -1
  190. recce/data/_next/static/chunks/framework-ded83d71b51ce901.js +0 -1
  191. recce/data/_next/static/chunks/main-a0859f1f36d0aa6c.js +0 -1
  192. recce/data/_next/static/chunks/main-app-0225a2255968e566.js +0 -1
  193. recce/data/_next/static/chunks/pages/_app-d5672bf3d8b6371b.js +0 -1
  194. recce/data/_next/static/chunks/pages/_error-ed75be3f25588548.js +0 -1
  195. recce/data/_next/static/chunks/webpack-567d72f0bc0820d5.js +0 -1
  196. recce/data/_next/static/css/c9ecb46a4b21c126.css +0 -14
  197. recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2 +0 -0
  198. recce/data/_next/static/media/montserrat-cyrillic-800-normal.31d693bb.woff +0 -0
  199. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.7e2c1e62.woff +0 -0
  200. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.94a63aea.woff2 +0 -0
  201. recce/data/_next/static/media/montserrat-latin-800-normal.6f8fa298.woff2 +0 -0
  202. recce/data/_next/static/media/montserrat-latin-800-normal.97e20d5e.woff +0 -0
  203. recce/data/_next/static/media/montserrat-latin-ext-800-normal.013b84f9.woff2 +0 -0
  204. recce/data/_next/static/media/montserrat-latin-ext-800-normal.aff52ab0.woff +0 -0
  205. recce/data/_next/static/media/montserrat-vietnamese-800-normal.5f21869b.woff +0 -0
  206. recce/data/_next/static/media/montserrat-vietnamese-800-normal.c0035377.woff2 +0 -0
  207. recce/state.py +0 -753
  208. recce_nightly-1.2.0.20250506.dist-info/RECORD +0 -142
  209. tests/test_state.py +0 -123
  210. /recce/data/_next/static/{Kcbs3GEIyH2LxgLYat0es → 52aV_JrNUZU6dMFgvTQEO}/_ssgManifest.js +0 -0
  211. /recce/data/_next/static/chunks/{polyfills-42372ed130431b0a.js → a6dad97d9634a72d.js} +0 -0
  212. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/entry_points.txt +0 -0
  213. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/licenses/LICENSE +0 -0
@@ -4,8 +4,18 @@ import uuid
4
4
  from datetime import datetime
5
5
  from io import StringIO
6
6
 
7
- from dbt.contracts.graph.nodes import ModelNode, SnapshotNode, SeedNode, SourceDefinition
8
- from dbt.contracts.results import CatalogArtifact, ColumnMetadata, CatalogTable, TableMetadata
7
+ from dbt.contracts.graph.nodes import (
8
+ ModelNode,
9
+ SeedNode,
10
+ SnapshotNode,
11
+ SourceDefinition,
12
+ )
13
+ from dbt.contracts.results import (
14
+ CatalogArtifact,
15
+ CatalogTable,
16
+ ColumnMetadata,
17
+ TableMetadata,
18
+ )
9
19
 
10
20
  from recce.adapter.dbt_adapter import DbtAdapter, as_manifest, load_manifest
11
21
  from recce.core import RecceContext
@@ -19,9 +29,9 @@ class DbtTestHelper:
19
29
  self.curr_schema = f"{schema_prefix}_curr"
20
30
 
21
31
  current_dir = os.path.dirname(os.path.abspath(__file__))
22
- project_dir = os.path.join(current_dir, 'test_proj')
32
+ project_dir = os.path.join(current_dir, "test_proj")
23
33
  profiles_dir = project_dir
24
- manifest_path = os.path.join(project_dir, 'manifest.json')
34
+ manifest_path = os.path.join(project_dir, "manifest.json")
25
35
 
26
36
  dbt_adapter = DbtAdapter.load(
27
37
  no_artifacts=True,
@@ -30,7 +40,7 @@ class DbtTestHelper:
30
40
  )
31
41
 
32
42
  context = RecceContext()
33
- context.adapter_type = 'dbt'
43
+ context.adapter_type = "dbt"
34
44
  context.adapter = dbt_adapter
35
45
  context.schema_prefix = schema_prefix
36
46
  self.adapter = dbt_adapter
@@ -108,16 +118,19 @@ class DbtTestHelper:
108
118
  if csv:
109
119
  dbt_adapter = self.adapter
110
120
  csv = textwrap.dedent(csv)
111
- with dbt_adapter.connection_named('create model'):
121
+ with dbt_adapter.connection_named("create model"):
112
122
  import pandas as pd
113
- df = pd.read_csv(StringIO(csv))
123
+
124
+ df = pd.read_csv(StringIO(csv)) # noqa: F841
125
+ # DuckDB disables python_scan_all_frames by default after 1.1,
126
+ # ref: https://github.com/duckdb/duckdb/pull/13896
127
+ dbt_adapter.execute("SET python_scan_all_frames=true")
114
128
  dbt_adapter.execute(f"CREATE TABLE {schema}.{model_name} AS SELECT * FROM df")
115
129
  raw_code = sql if sql else csv
116
130
 
117
131
  if columns:
118
132
  index = 1
119
- table = CatalogTable(
120
- TableMetadata(type="BASE TABLE", schema=schema, name=model_name), {}, {})
133
+ table = CatalogTable(TableMetadata(type="BASE TABLE", schema=schema, name=model_name), {}, {})
121
134
  catalog.nodes[unique_id] = table
122
135
  for column, column_type in columns.items():
123
136
  col_data = ColumnMetadata(type=column_type, index=index, name=column)
@@ -147,9 +160,7 @@ class DbtTestHelper:
147
160
  "tags": ["test_tag"],
148
161
  },
149
162
  "tags": ["test_tag"],
150
- "depends_on": {
151
- "nodes": depends_on
152
- },
163
+ "depends_on": {"nodes": depends_on},
153
164
  }
154
165
  if patch_func:
155
166
  patch_func(node_dict)
@@ -179,11 +190,12 @@ class DbtTestHelper:
179
190
  self.curr_manifest,
180
191
  self.base_manifest,
181
192
  self.base_catalog,
182
- self.curr_catalog)
193
+ self.curr_catalog,
194
+ )
183
195
 
184
196
  def remove_model(self, model_name):
185
197
  dbt_adapter = self.adapter
186
- with dbt_adapter.connection_named('cleanup'):
198
+ with dbt_adapter.connection_named("cleanup"):
187
199
  dbt_adapter.execute(f"DROP TABLE IF EXISTS {self.base_schema}.{model_name}")
188
200
  dbt_adapter.execute(f"DROP TABLE IF EXISTS {self.curr_schema}.{model_name} ")
189
201
 
@@ -199,8 +211,7 @@ class DbtTestHelper:
199
211
  curr_columns: dict[str, str] = None,
200
212
  patch_func=None,
201
213
  ):
202
- # unique_id = f"model.{package_name}.{model_name}"
203
- unique_id = unique_id if unique_id else f"{source_name}.{table_name}"
214
+ unique_id = unique_id if unique_id else f"source.{package_name}.{source_name}.{table_name}"
204
215
 
205
216
  def _add_source_to_manifest(base):
206
217
  if base:
@@ -219,15 +230,18 @@ class DbtTestHelper:
219
230
  if csv:
220
231
  dbt_adapter = self.adapter
221
232
  csv = textwrap.dedent(csv)
222
- with dbt_adapter.connection_named('create source'):
233
+ with dbt_adapter.connection_named("create source"):
223
234
  import pandas as pd
224
- df = pd.read_csv(StringIO(csv))
235
+
236
+ df = pd.read_csv(StringIO(csv)) # noqa: F841
237
+ # DuckDB disables python_scan_all_frames by default after 1.1,
238
+ # ref: https://github.com/duckdb/duckdb/pull/13896
239
+ dbt_adapter.execute("SET python_scan_all_frames=true")
225
240
  dbt_adapter.execute(f"CREATE TABLE {schema}.{table_name} AS SELECT * FROM df")
226
241
 
227
242
  if columns:
228
243
  index = 1
229
- table = CatalogTable(
230
- TableMetadata(type="BASE TABLE", schema=schema, name=table_name), {}, {})
244
+ table = CatalogTable(TableMetadata(type="BASE TABLE", schema=schema, name=table_name), {}, {})
231
245
  catalog.sources[unique_id] = table
232
246
  for column, column_type in columns.items():
233
247
  col_data = ColumnMetadata(type=column_type, index=index, name=column)
@@ -271,11 +285,12 @@ class DbtTestHelper:
271
285
  self.curr_manifest,
272
286
  self.base_manifest,
273
287
  self.base_catalog,
274
- self.curr_catalog)
288
+ self.curr_catalog,
289
+ )
275
290
 
276
291
  def cleanup(self):
277
292
  dbt_adapter = self.adapter
278
- with dbt_adapter.connection_named('cleanup'):
293
+ with dbt_adapter.connection_named("cleanup"):
279
294
  dbt_adapter.execute(f"DROP SCHEMA IF EXISTS {self.base_schema} CASCADE")
280
295
  dbt_adapter.execute(f"DROP SCHEMA IF EXISTS {self.curr_schema} CASCADE")
281
296
 
@@ -1,15 +1,9 @@
1
1
  from recce.adapter.dbt_adapter import DbtAdapter, dbt_supported_registry
2
- from recce.models import RunType
3
2
 
4
3
 
5
4
  def test_dbt_adapter_support_tasks(dbt_test_helper):
6
5
  adapter: DbtAdapter = dbt_test_helper.context.adapter
7
6
 
8
- # Test dbt package name
9
- supported_dbt_packages = set([package.package_name for package in adapter.manifest.macros.values()])
10
- assert 'audit_helper' in supported_dbt_packages
11
- assert 'dbt_profiler' in supported_dbt_packages
12
-
13
7
  # Test dbt task support
14
8
  support_tasks = adapter.support_tasks()
15
9
 
@@ -29,12 +23,3 @@ def test_dbt_adapter_support_tasks_without_required_dbt_package(dbt_test_helper)
29
23
  for task_type in dbt_supported_registry:
30
24
  task = task_type.value
31
25
  assert task in support_tasks
32
- if task == RunType.PROFILE_DIFF.value:
33
- assert support_tasks[task] is False
34
- elif task == RunType.VALUE_DIFF.value:
35
- assert support_tasks[task] is False
36
- elif task == RunType.VALUE_DIFF_DETAIL.value:
37
- assert support_tasks[task] is False
38
-
39
- # Check the query_diff_with_primary_key is not supported
40
- assert support_tasks["query_diff_with_primary_key"] is False