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
recce/util/lineage.py CHANGED
@@ -1,34 +1,83 @@
1
- def find_upstream(node, parent_map):
1
+ from typing import Dict, Iterable, Set, Tuple
2
+
3
+ from recce.models.types import CllColumn, CllNode
4
+
5
+
6
+ def find_upstream(node_ids: Iterable, parent_map):
2
7
  visited = set()
3
8
  upstream = set()
4
9
 
5
- def dfs(current):
10
+ stack = list(node_ids)
11
+ while stack:
12
+ current = stack.pop()
6
13
  if current in visited:
7
- return
14
+ continue
8
15
  visited.add(current)
9
-
10
16
  parents = parent_map.get(current, [])
11
17
  for parent in parents:
12
- upstream.add(parent)
13
- dfs(parent)
14
-
15
- dfs(node)
18
+ if parent not in upstream:
19
+ upstream.add(parent)
20
+ stack.append(parent)
16
21
  return upstream
17
22
 
18
23
 
19
- def find_downstream(node, child_map):
24
+ def find_downstream(node_ids: Iterable, child_map):
20
25
  visited = set()
21
26
  downstream = set()
22
27
 
23
- def dfs(current):
28
+ stack = list(node_ids)
29
+ while stack:
30
+ current = stack.pop()
24
31
  if current in visited:
25
- return
32
+ continue
26
33
  visited.add(current)
27
-
28
34
  children = child_map.get(current, [])
29
35
  for child in children:
30
- downstream.add(child)
31
- dfs(child)
32
-
33
- dfs(node)
36
+ if child not in downstream:
37
+ downstream.add(child)
38
+ stack.append(child)
34
39
  return downstream
40
+
41
+
42
+ def find_column_dependencies(node_column_id: str, parent_map: Dict, child_map: Dict) -> Tuple[Set, Set]:
43
+ upstream_cols = find_upstream([node_column_id], parent_map)
44
+ downstream_cols = find_downstream([node_column_id], child_map)
45
+ return upstream_cols, downstream_cols
46
+
47
+
48
+ def filter_lineage_vertices(
49
+ lineage_nodes: Dict[str, CllNode], lineage_columns: Dict[str, CllColumn], relevant_columns: Set[str]
50
+ ) -> Tuple[Dict[str, CllNode], Dict[str, CllColumn]]:
51
+ nodes = {}
52
+ columns = {}
53
+
54
+ for node_id, node in lineage_nodes.items():
55
+ if node_id in relevant_columns:
56
+ nodes[node_id] = node
57
+
58
+ for col_id, column in lineage_columns.items():
59
+ if col_id in relevant_columns:
60
+ columns[col_id] = column
61
+
62
+ return nodes, columns
63
+
64
+
65
+ def filter_dependency_maps(
66
+ parent_map: Dict, child_map: Dict, relevant_ids: Set
67
+ ) -> Tuple[Dict[str, Set], Dict[str, Set]]:
68
+ p_map = {}
69
+ c_map = {}
70
+ for node_id, parents in parent_map.items():
71
+ if node_id in relevant_ids:
72
+ p_map[node_id] = {p for p in parents if p in relevant_ids}
73
+
74
+ for node_id, children in child_map.items():
75
+ if node_id in relevant_ids:
76
+ c_map[node_id] = {c for c in children if c in relevant_ids}
77
+
78
+ return p_map, c_map
79
+
80
+
81
+ def build_column_key(node_id: str, column_name: str) -> str:
82
+ """Build a unique column key from node name and column name."""
83
+ return f"{node_id}_{column_name}"
recce/util/logger.py CHANGED
@@ -16,7 +16,7 @@ class CustomFormatter(logging.Formatter):
16
16
  logging.INFO: green + format + reset,
17
17
  logging.WARNING: yellow + format + reset,
18
18
  logging.ERROR: red + format + reset,
19
- logging.CRITICAL: bold_red + format + reset
19
+ logging.CRITICAL: bold_red + format + reset,
20
20
  }
21
21
 
22
22
  def format(self, record):
@@ -0,0 +1,45 @@
1
+ from enum import Enum
2
+ from typing import Union
3
+
4
+ from recce.util.recce_cloud import (
5
+ get_recce_cloud_onboarding_state,
6
+ set_recce_cloud_onboarding_state,
7
+ )
8
+
9
+
10
+ class OnboardingState(Enum):
11
+ SIGNUP_SUCCESSFUL = "signup_successful"
12
+ LAUNCHED_WITH_TOKEN = "launched_with_token"
13
+ CONFIGURE_TWO_ENV = "configure_two_env"
14
+
15
+
16
+ def update_onboarding_state(api_token: Union[str, bool, None], is_single_env: bool) -> OnboardingState:
17
+ if api_token:
18
+ # existing onboarding_state values -> new, launched, launched_with_two_envs
19
+ # new -> launched
20
+ # new -> launched_with_two_envs
21
+ # launched -> launched_with_two_envs
22
+ cloud_onboarding_state = get_recce_cloud_onboarding_state(api_token)
23
+
24
+ if cloud_onboarding_state == OnboardingState.SIGNUP_SUCCESSFUL.value:
25
+ # User has an API Token and is a "new" user
26
+ if is_single_env:
27
+ # Mark the onboarding state as "launched" if the user is new
28
+ set_recce_cloud_onboarding_state(api_token, OnboardingState.LAUNCHED_WITH_TOKEN.value)
29
+ return OnboardingState.LAUNCHED_WITH_TOKEN
30
+ else:
31
+ set_recce_cloud_onboarding_state(api_token, OnboardingState.CONFIGURE_TWO_ENV.value)
32
+ return OnboardingState.CONFIGURE_TWO_ENV
33
+ elif cloud_onboarding_state == OnboardingState.LAUNCHED_WITH_TOKEN.value:
34
+ # User has an API Token and has Two Environments
35
+ if is_single_env:
36
+ # Just return the current state
37
+ return OnboardingState.LAUNCHED_WITH_TOKEN
38
+ else:
39
+ set_recce_cloud_onboarding_state(api_token, OnboardingState.CONFIGURE_TWO_ENV.value)
40
+ return OnboardingState.CONFIGURE_TWO_ENV
41
+ elif cloud_onboarding_state == OnboardingState.CONFIGURE_TWO_ENV.value:
42
+ # Just return the current state
43
+ return OnboardingState.CONFIGURE_TWO_ENV
44
+
45
+ return OnboardingState.SIGNUP_SUCCESSFUL
@@ -0,0 +1,85 @@
1
+ import time
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass
6
+ class LineagePerfTracker:
7
+ lineage_start = None
8
+ lineage_elapsed = None
9
+ column_lineage_start = None
10
+ column_lineage_elapsed = None
11
+
12
+ total_nodes = None
13
+ init_nodes = None
14
+ cll_nodes = 0
15
+ change_analysis_nodes = 0
16
+ anchor_nodes = None
17
+
18
+ params = None
19
+
20
+ def start_lineage(self):
21
+ self.lineage_start = time.perf_counter_ns()
22
+
23
+ def end_lineage(self):
24
+ if self.lineage_start is None:
25
+ return
26
+ self.lineage_elapsed = (time.perf_counter_ns() - self.lineage_start) / 1000000
27
+
28
+ def start_column_lineage(self):
29
+ self.column_lineage_start = time.perf_counter_ns()
30
+
31
+ def end_column_lineage(self):
32
+ if self.column_lineage_start is None:
33
+ return
34
+ self.column_lineage_elapsed = (time.perf_counter_ns() - self.column_lineage_start) / 1000000
35
+
36
+ def set_total_nodes(self, total_nodes):
37
+ self.total_nodes = total_nodes
38
+
39
+ def set_init_nodes(self, init_nodes):
40
+ self.init_nodes = init_nodes
41
+
42
+ def set_anchor_nodes(self, anchor_nodes):
43
+ self.anchor_nodes = anchor_nodes
44
+
45
+ def increment_cll_nodes(self):
46
+ self.cll_nodes += 1
47
+
48
+ def increment_change_analysis_nodes(self):
49
+ self.change_analysis_nodes += 1
50
+
51
+ def set_params(self, has_node, has_column, change_analysis, no_cll, no_upstream, no_downstream):
52
+ self.params = {
53
+ "has_node": has_node,
54
+ "has_column": has_column,
55
+ "change_analysis": change_analysis,
56
+ "no_cll": no_cll,
57
+ "no_upstream": no_upstream,
58
+ "no_downstream": no_downstream,
59
+ }
60
+
61
+ def to_dict(self):
62
+ return {
63
+ "lineage_elapsed_ms": self.lineage_elapsed,
64
+ "column_lineage_elapsed_ms": self.column_lineage_elapsed,
65
+ "total_nodes": self.total_nodes,
66
+ "init_nodes": self.init_nodes,
67
+ "cll_nodes": self.cll_nodes,
68
+ "change_analysis_nodes": self.change_analysis_nodes,
69
+ "anchor_nodes": self.anchor_nodes,
70
+ "params": self.params,
71
+ }
72
+
73
+ def reset(self):
74
+ self.lineage_start = None
75
+ self.lineage_elapsed = None
76
+ self.column_lineage_start = None
77
+ self.column_lineage_elapsed = None
78
+
79
+ self.total_nodes = None
80
+ self.init_nodes = None
81
+ self.change_analysis_nodes = 0
82
+ self.cll_nodes = 0
83
+ self.anchor_nodes = 0
84
+
85
+ self.params = None