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,283 +0,0 @@
1
- import os
2
- import textwrap
3
- import uuid
4
- from datetime import datetime
5
- from io import StringIO
6
-
7
- from dbt.contracts.graph.nodes import ModelNode, SnapshotNode, SeedNode, SourceDefinition
8
- from dbt.contracts.results import CatalogArtifact, ColumnMetadata, CatalogTable, TableMetadata
9
-
10
- from recce.adapter.dbt_adapter import DbtAdapter, as_manifest, load_manifest
11
- from recce.core import RecceContext
12
-
13
-
14
- class DbtTestHelper:
15
-
16
- def __init__(self):
17
- schema_prefix = "schema_" + uuid.uuid4().hex
18
- self.base_schema = f"{schema_prefix}_base"
19
- self.curr_schema = f"{schema_prefix}_curr"
20
-
21
- current_dir = os.path.dirname(os.path.abspath(__file__))
22
- project_dir = os.path.join(current_dir, 'test_proj')
23
- profiles_dir = project_dir
24
- manifest_path = os.path.join(project_dir, 'manifest.json')
25
-
26
- dbt_adapter = DbtAdapter.load(
27
- no_artifacts=True,
28
- project_dir=project_dir,
29
- profiles_dir=profiles_dir,
30
- )
31
-
32
- context = RecceContext()
33
- context.adapter_type = 'dbt'
34
- context.adapter = dbt_adapter
35
- context.schema_prefix = schema_prefix
36
- self.adapter = dbt_adapter
37
- self.context = context
38
- curr_writable_manifest = load_manifest(manifest_path)
39
- base_writable_manifest = load_manifest(manifest_path)
40
-
41
- self.curr_manifest = as_manifest(curr_writable_manifest)
42
- self.base_manifest = as_manifest(base_writable_manifest)
43
- now = datetime.now()
44
- self.curr_catalog = CatalogArtifact.from_results(
45
- generated_at=now,
46
- nodes={},
47
- sources={},
48
- compile_results=None,
49
- errors=None,
50
- )
51
- self.base_catalog = CatalogArtifact.from_results(
52
- generated_at=now,
53
- nodes={},
54
- sources={},
55
- compile_results=None,
56
- errors=None,
57
- )
58
- self.context = context
59
-
60
- self.adapter.execute(f"CREATE schema IF NOT EXISTS {self.base_schema}")
61
- self.adapter.execute(f"CREATE schema IF NOT EXISTS {self.curr_schema}")
62
- self.adapter.set_artifacts(
63
- base_writable_manifest,
64
- curr_writable_manifest,
65
- self.curr_manifest,
66
- self.base_manifest,
67
- self.base_catalog,
68
- self.curr_catalog,
69
- )
70
-
71
- def create_model(
72
- self,
73
- model_name,
74
- base_csv=None,
75
- curr_csv=None,
76
- base_sql=None,
77
- curr_sql=None,
78
- depends_on=None,
79
- disabled=False,
80
- unique_id=None,
81
- resource_type="model",
82
- package_name="recce_test",
83
- base_columns: dict[str, str] = None,
84
- curr_columns: dict[str, str] = None,
85
- patch_func=None,
86
- ):
87
- # unique_id = f"model.{package_name}.{model_name}"
88
- unique_id = unique_id if unique_id else model_name
89
- if depends_on is None:
90
- depends_on = []
91
-
92
- def _add_model_to_manifest(base):
93
- if base:
94
- schema = self.base_schema
95
- manifest = self.base_manifest
96
- catalog = self.base_catalog
97
- csv = base_csv
98
- sql = base_sql
99
- columns = base_columns
100
- else:
101
- schema = self.curr_schema
102
- manifest = self.curr_manifest
103
- catalog = self.curr_catalog
104
- csv = curr_csv
105
- sql = curr_sql
106
- columns = curr_columns
107
-
108
- if csv:
109
- dbt_adapter = self.adapter
110
- csv = textwrap.dedent(csv)
111
- with dbt_adapter.connection_named('create model'):
112
- import pandas as pd
113
- df = pd.read_csv(StringIO(csv))
114
- dbt_adapter.execute(f"CREATE TABLE {schema}.{model_name} AS SELECT * FROM df")
115
- raw_code = sql if sql else csv
116
-
117
- if columns:
118
- index = 1
119
- table = CatalogTable(
120
- TableMetadata(type="BASE TABLE", schema=schema, name=model_name), {}, {})
121
- catalog.nodes[unique_id] = table
122
- for column, column_type in columns.items():
123
- col_data = ColumnMetadata(type=column_type, index=index, name=column)
124
- catalog.nodes[unique_id].columns[column] = col_data
125
- index = index + 1
126
-
127
- node_dict = {
128
- "resource_type": resource_type,
129
- "name": model_name,
130
- "package_name": package_name,
131
- "path": "",
132
- "original_file_path": "",
133
- "unique_id": unique_id,
134
- "fqn": [
135
- package_name,
136
- model_name,
137
- ],
138
- "schema": schema,
139
- "alias": model_name,
140
- "checksum": {
141
- "name": "sha256",
142
- "checksum": hash(raw_code),
143
- },
144
- "raw_code": raw_code,
145
- "config": {
146
- "materialized": "table",
147
- "tags": ["test_tag"],
148
- },
149
- "tags": ["test_tag"],
150
- "depends_on": {
151
- "nodes": depends_on
152
- },
153
- }
154
- if patch_func:
155
- patch_func(node_dict)
156
-
157
- if resource_type == "snapshot":
158
- node = SnapshotNode.from_dict(node_dict)
159
- elif resource_type == "seed":
160
- node = SeedNode.from_dict(node_dict)
161
- else:
162
- node = ModelNode.from_dict(node_dict)
163
-
164
- if disabled:
165
- manifest.add_disabled_nofile(node)
166
- else:
167
- manifest.add_node_nofile(node)
168
- return node
169
-
170
- if base_csv or base_sql:
171
- _add_model_to_manifest(True)
172
-
173
- if curr_csv or curr_sql:
174
- _add_model_to_manifest(False)
175
-
176
- self.adapter.set_artifacts(
177
- self.base_manifest.writable_manifest(),
178
- self.curr_manifest.writable_manifest(),
179
- self.curr_manifest,
180
- self.base_manifest,
181
- self.base_catalog,
182
- self.curr_catalog)
183
-
184
- def remove_model(self, model_name):
185
- dbt_adapter = self.adapter
186
- with dbt_adapter.connection_named('cleanup'):
187
- dbt_adapter.execute(f"DROP TABLE IF EXISTS {self.base_schema}.{model_name}")
188
- dbt_adapter.execute(f"DROP TABLE IF EXISTS {self.curr_schema}.{model_name} ")
189
-
190
- def create_source(
191
- self,
192
- source_name,
193
- table_name,
194
- base_csv=None,
195
- curr_csv=None,
196
- unique_id=None,
197
- package_name="recce_test",
198
- base_columns: dict[str, str] = None,
199
- curr_columns: dict[str, str] = None,
200
- patch_func=None,
201
- ):
202
- # unique_id = f"model.{package_name}.{model_name}"
203
- unique_id = unique_id if unique_id else f"{source_name}.{table_name}"
204
-
205
- def _add_source_to_manifest(base):
206
- if base:
207
- schema = self.base_schema
208
- manifest = self.base_manifest
209
- catalog = self.base_catalog
210
- csv = base_csv
211
- columns = base_columns
212
- else:
213
- schema = self.curr_schema
214
- manifest = self.curr_manifest
215
- catalog = self.curr_catalog
216
- csv = curr_csv
217
- columns = curr_columns
218
-
219
- if csv:
220
- dbt_adapter = self.adapter
221
- csv = textwrap.dedent(csv)
222
- with dbt_adapter.connection_named('create source'):
223
- import pandas as pd
224
- df = pd.read_csv(StringIO(csv))
225
- dbt_adapter.execute(f"CREATE TABLE {schema}.{table_name} AS SELECT * FROM df")
226
-
227
- if columns:
228
- index = 1
229
- table = CatalogTable(
230
- TableMetadata(type="BASE TABLE", schema=schema, name=table_name), {}, {})
231
- catalog.sources[unique_id] = table
232
- for column, column_type in columns.items():
233
- col_data = ColumnMetadata(type=column_type, index=index, name=column)
234
- catalog.sources[unique_id].columns[column] = col_data
235
- index = index + 1
236
-
237
- node_dict = {
238
- "resource_type": "source",
239
- "source_name": source_name,
240
- "name": table_name,
241
- "identifier": table_name,
242
- "source_description": "test source",
243
- "loader": "",
244
- "package_name": package_name,
245
- "path": "",
246
- "original_file_path": "",
247
- "unique_id": unique_id,
248
- "fqn": [
249
- package_name,
250
- source_name,
251
- table_name,
252
- ],
253
- "schema": schema,
254
- }
255
- if patch_func:
256
- patch_func(node_dict)
257
-
258
- source = SourceDefinition.from_dict(node_dict)
259
- manifest.sources[unique_id] = source
260
- return source
261
-
262
- if base_csv:
263
- _add_source_to_manifest(True)
264
-
265
- if curr_csv:
266
- _add_source_to_manifest(False)
267
-
268
- self.adapter.set_artifacts(
269
- self.base_manifest.writable_manifest(),
270
- self.curr_manifest.writable_manifest(),
271
- self.curr_manifest,
272
- self.base_manifest,
273
- self.base_catalog,
274
- self.curr_catalog)
275
-
276
- def cleanup(self):
277
- dbt_adapter = self.adapter
278
- with dbt_adapter.connection_named('cleanup'):
279
- dbt_adapter.execute(f"DROP SCHEMA IF EXISTS {self.base_schema} CASCADE")
280
- dbt_adapter.execute(f"DROP SCHEMA IF EXISTS {self.curr_schema} CASCADE")
281
-
282
- def create_snapshot(self, sanpshot_name, base_csv, curr_csv, depends_on=[]):
283
- self.create_model(sanpshot_name, base_csv, curr_csv, depends_on=depends_on, resource_type="snapshot")
@@ -1,40 +0,0 @@
1
- from recce.adapter.dbt_adapter import DbtAdapter, dbt_supported_registry
2
- from recce.models import RunType
3
-
4
-
5
- def test_dbt_adapter_support_tasks(dbt_test_helper):
6
- adapter: DbtAdapter = dbt_test_helper.context.adapter
7
-
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
- # Test dbt task support
14
- support_tasks = adapter.support_tasks()
15
-
16
- for task_type in dbt_supported_registry:
17
- task = task_type.value
18
- assert task in support_tasks
19
- assert support_tasks[task] is True
20
-
21
-
22
- def test_dbt_adapter_support_tasks_without_required_dbt_package(dbt_test_helper):
23
- adapter: DbtAdapter = dbt_test_helper.context.adapter
24
- # Mock the macros in manifest to simulate no required dbt package installed
25
- adapter.manifest.macros = {}
26
-
27
- support_tasks = adapter.support_tasks()
28
-
29
- for task_type in dbt_supported_registry:
30
- task = task_type.value
31
- 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
@@ -1,102 +0,0 @@
1
- from recce.adapter.dbt_adapter import DbtAdapter
2
-
3
-
4
- def test_cll_basic(dbt_test_helper):
5
- dbt_test_helper.create_model("model1", curr_sql="select 1 as c", curr_columns={"c": "int"})
6
- dbt_test_helper.create_model("model2", curr_sql='select c from {{ ref("model1") }}', curr_columns={"c": "int"},
7
- depends_on=["model1"])
8
- adapter: DbtAdapter = dbt_test_helper.context.adapter
9
- result = adapter.get_cll_by_node_id("model1")
10
- assert result['nodes']['model2']['columns']['c']['depends_on'][0].column == 'c'
11
- assert result['nodes']['model2']['columns']['c']['depends_on'][0].node == 'model1'
12
-
13
-
14
- def test_cll_table_alisa(dbt_test_helper):
15
- def patch_node(node):
16
- node['alias'] = 'model1_alias'
17
-
18
- dbt_test_helper.create_model("model1", curr_sql="select 1 as c", curr_columns={"c": "int"}, patch_func=patch_node)
19
- dbt_test_helper.create_model("model2", curr_sql='select c from {{ ref("model1") }}', curr_columns={"c": "int"},
20
- depends_on=["model1"])
21
- adapter: DbtAdapter = dbt_test_helper.context.adapter
22
- result = adapter.get_cll_by_node_id("model1")
23
- assert result['nodes']['model2']['columns']['c']['depends_on'][0].column == 'c'
24
- assert result['nodes']['model2']['columns']['c']['depends_on'][0].node == 'model1'
25
-
26
-
27
- def test_seed(dbt_test_helper):
28
- csv_data_curr = """
29
- customer_id,name,age
30
- 1,Alice,30
31
- 2,Bob,25
32
- 3,Charlie,35
33
- """
34
-
35
- dbt_test_helper.create_model("seed1",
36
- curr_csv=csv_data_curr,
37
- curr_columns={"customer_id": "varchar", "name": "varchar", "age": "int"},
38
- resource_type="seed")
39
- adapter: DbtAdapter = dbt_test_helper.context.adapter
40
- result = adapter.get_cll_by_node_id("seed1")
41
-
42
- assert result['nodes']['seed1']['columns']['customer_id']['transformation_type'] == 'source'
43
- assert len(result['nodes']['seed1']['columns']['customer_id']['depends_on']) == 0
44
-
45
-
46
- def test_python_model(dbt_test_helper):
47
- def python_node(node):
48
- node['language'] = 'python'
49
-
50
- csv_data_curr = """
51
- customer_id,name,age
52
- 1,Alice,30
53
- 2,Bob,25
54
- 3,Charlie,35
55
- """
56
- dbt_test_helper.create_model("model1",
57
- curr_csv=csv_data_curr,
58
- curr_columns={"customer_id": "varchar", "name": "varchar", "age": "int"})
59
- dbt_test_helper.create_model("model2",
60
- curr_csv=csv_data_curr,
61
- curr_columns={"customer_id": "varchar", "name": "varchar", "age": "int"},
62
- depends_on=["model1"],
63
- patch_func=python_node)
64
- adapter: DbtAdapter = dbt_test_helper.context.adapter
65
- assert not adapter.is_python_model('model1')
66
- assert adapter.is_python_model('model2')
67
-
68
- result = adapter.get_cll_by_node_id("model1")
69
- assert result['nodes']['model2']['columns']['customer_id']['transformation_type'] == 'unknown'
70
-
71
-
72
- def test_source(dbt_test_helper):
73
- csv_data_curr = """
74
- customer_id,name,age
75
- 1,Alice,30
76
- 2,Bob,25
77
- 3,Charlie,35
78
- """
79
-
80
- dbt_test_helper.create_source(
81
- "source1",
82
- "table1",
83
- curr_csv=csv_data_curr,
84
- curr_columns={"customer_id": "varchar", "name": "varchar", "age": "int"})
85
- adapter: DbtAdapter = dbt_test_helper.context.adapter
86
- result = adapter.get_cll_by_node_id("source1.table1")
87
- assert result['nodes']['source1.table1']['columns']['customer_id']['transformation_type'] == 'source'
88
-
89
-
90
- def test_parse_error(dbt_test_helper):
91
- dbt_test_helper.create_model("model1", curr_sql="select 1 as c", curr_columns={"c": "int"})
92
- dbt_test_helper.create_model("model2", curr_sql='this is not a valid sql', curr_columns={"c": "int"})
93
- adapter: DbtAdapter = dbt_test_helper.context.adapter
94
- result = adapter.get_cll_by_node_id("model2")
95
- assert result['nodes']['model2']['columns']['c']['transformation_type'] == 'unknown'
96
-
97
-
98
- def test_model_without_catalog(dbt_test_helper):
99
- dbt_test_helper.create_model("model1", curr_sql="select 1 as c")
100
- adapter: DbtAdapter = dbt_test_helper.context.adapter
101
- result = adapter.get_cll_by_node_id("model1")
102
- assert not hasattr(result['nodes']['model1'], 'columns')
@@ -1,177 +0,0 @@
1
- from recce.adapter.dbt_adapter import DbtAdapter
2
-
3
-
4
- def test_select(dbt_test_helper):
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
- dbt_test_helper.create_model("customers_1", csv_data_base, csv_data_curr)
20
- dbt_test_helper.create_model("customers_2", csv_data_base, csv_data_base, depends_on=["customers_1"])
21
- adapter: DbtAdapter = dbt_test_helper.context.adapter
22
-
23
- # Test methods
24
- node_ids = adapter.select_nodes('customers_1')
25
- assert len(node_ids) == 1
26
- node_ids = adapter.select_nodes('resource_type:model')
27
- assert len(node_ids) == 2
28
- node_ids = adapter.select_nodes('tag:test_tag')
29
- assert len(node_ids) == 2
30
- node_ids = adapter.select_nodes('tag:test_tag2')
31
- assert len(node_ids) == 0
32
- node_ids = adapter.select_nodes("config.materialized:incremental")
33
- assert len(node_ids) == 0
34
- node_ids = adapter.select_nodes("config.materialized:table")
35
- assert len(node_ids) == 2
36
-
37
- # Test state method
38
- node_ids = adapter.select_nodes("state:modified")
39
- assert len(node_ids) == 1
40
-
41
- # Test set operation
42
- node_ids = adapter.select_nodes("customers_1 customers_2")
43
- assert len(node_ids) == 2
44
- node_ids = adapter.select_nodes("customers_1,customers_2")
45
- assert len(node_ids) == 0
46
- node_ids = adapter.select_nodes("config.materialized:table,tag:test_tag")
47
- assert len(node_ids) == 2
48
- node_ids = adapter.select_nodes("config.materialized:table,tag:test_tag2")
49
- assert len(node_ids) == 0
50
- node_ids = adapter.select_nodes(exclude='customers_1')
51
- assert len(node_ids) == 1
52
- node_ids = adapter.select_nodes('customers_1', exclude='customers_2')
53
- assert len(node_ids) == 1
54
-
55
- # Test graph operation
56
- node_ids = adapter.select_nodes("state:modified+")
57
- assert len(node_ids) == 2
58
- node_ids = adapter.select_nodes("+state:modified")
59
- assert len(node_ids) == 1
60
-
61
- # Test resource type: snapshot
62
- dbt_test_helper.create_snapshot("snapshot_1", csv_data_base, csv_data_curr)
63
- dbt_test_helper.create_model("use_snapshot", csv_data_base, csv_data_base, depends_on=["snapshot_1"])
64
-
65
- node_ids = adapter.select_nodes('resource_type:snapshot')
66
- assert len(node_ids) == 1
67
-
68
- node_ids = adapter.select_nodes('resource_type:snapshot+')
69
- assert len(node_ids) == 2
70
-
71
- node_ids = adapter.select_nodes("state:modified,resource_type:snapshot")
72
- assert len(node_ids) == 1
73
-
74
-
75
- def test_select_removed_by_graph(dbt_test_helper):
76
- csv_data_curr = """
77
- customer_id,name,age
78
- 1,Alice,30
79
- 2,Bob,25
80
- 3,Charlie,35
81
- """
82
-
83
- csv_data_base = """
84
- customer_id,name,age
85
- 1,Alice,35
86
- 2,Bob,25
87
- 3,Charlie,35
88
- """
89
-
90
- dbt_test_helper.create_model("customers_1", csv_data_base, csv_data_curr)
91
- dbt_test_helper.create_model("customers_2", base_csv=csv_data_base, depends_on=["customers_1"])
92
- dbt_test_helper.create_model("customers_3", curr_csv=csv_data_curr, depends_on=["customers_1"])
93
- adapter: DbtAdapter = dbt_test_helper.context.adapter
94
-
95
- # Test graph operation
96
- node_ids = adapter.select_nodes("customers_1+")
97
- assert len(node_ids) == 3
98
- node_ids = adapter.select_nodes("+customers_2")
99
- assert len(node_ids) == 2
100
- node_ids = adapter.select_nodes("+customers_3")
101
- assert len(node_ids) == 2
102
-
103
-
104
- def test_select_with_disabled(dbt_test_helper):
105
- csv_data_curr = """
106
- customer_id,name,age
107
- 1,Alice,30
108
- 2,Bob,25
109
- 3,Charlie,35
110
- """
111
-
112
- csv_data_base = """
113
- customer_id,name,age
114
- 1,Alice,35
115
- 2,Bob,25
116
- 3,Charlie,35
117
- """
118
-
119
- dbt_test_helper.create_model("customers_1", csv_data_base, csv_data_curr)
120
- dbt_test_helper.create_model("customers_2", csv_data_base, csv_data_curr, disabled=True)
121
- adapter: DbtAdapter = dbt_test_helper.context.adapter
122
-
123
- # Test graph operation
124
- node_ids = adapter.select_nodes("customers_1+")
125
- assert len(node_ids) == 1
126
-
127
-
128
- def test_select_with_pacakage_mode_include_exclude(dbt_test_helper):
129
- csv_data_curr = """
130
- customer_id,name,age
131
- 1,Alice,30
132
- 2,Bob,25
133
- 3,Charlie,35
134
- """
135
-
136
- csv_data_base = """
137
- customer_id,name,age
138
- 1,Alice,35
139
- 2,Bob,25
140
- 3,Charlie,35
141
- """
142
-
143
- """
144
- The diagram of the models:
145
- customers_1 ── customers_2 ── customers_3(*) ├── other_package.customers_4
146
- └── customers_5
147
-
148
- Only customers_3 is changed
149
- """
150
- dbt_test_helper.create_model("customers_1", csv_data_base, csv_data_base)
151
- dbt_test_helper.create_model("customers_2", csv_data_base, csv_data_base, depends_on=['customers_1'])
152
- dbt_test_helper.create_model("customers_3", csv_data_base, csv_data_curr, depends_on=['customers_2'])
153
- dbt_test_helper.create_model("customers_4", csv_data_base, csv_data_base, depends_on=['customers_3'],
154
- package_name='other_package')
155
- dbt_test_helper.create_model("customers_5", csv_data_base, csv_data_base, depends_on=['customers_3'])
156
-
157
- adapter: DbtAdapter = dbt_test_helper.context.adapter
158
-
159
- node_ids = adapter.select_nodes(packages=['other_package'])
160
- assert len(node_ids) == 1
161
-
162
- node_ids = adapter.select_nodes(view_mode='changed_models')
163
- assert len(node_ids) == 4
164
-
165
- node_ids = adapter.select_nodes(view_mode='changed_models', packages=['other_package'])
166
- assert len(node_ids) == 1
167
-
168
- node_ids = adapter.select_nodes(view_mode='changed_models', packages=['other_package'], exclude='customers_4')
169
- assert len(node_ids) == 0
170
- node_ids = adapter.select_nodes(view_mode='changed_models', packages=['other_package'], select='customers_1+')
171
- assert len(node_ids) == 1
172
- node_ids = adapter.select_nodes(view_mode='changed_models', select='+customers_5')
173
- assert len(node_ids) == 3
174
- node_ids = adapter.select_nodes(view_mode='all', select='+customers_5')
175
- assert len(node_ids) == 4
176
- node_ids = adapter.select_nodes(select='+customers_5')
177
- assert len(node_ids) == 4
tests/tasks/__init__.py DELETED
File without changes
tests/tasks/conftest.py DELETED
@@ -1,4 +0,0 @@
1
- # Share the fixtures for the tasks tests
2
-
3
- # noinspection PyUnresolvedReferences
4
- from tests.adapter.dbt_adapter.conftest import dbt_test_helper