recce-nightly 1.4.0.20250518__py3-none-any.whl → 1.4.0.20250520__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.
- recce/VERSION +1 -1
- recce/adapter/dbt_adapter/__init__.py +2 -1
- recce/data/404.html +1 -1
- recce/data/index.html +1 -1
- recce/data/index.txt +1 -1
- recce/util/breaking.py +2 -2
- recce/util/cll.py +231 -199
- {recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/METADATA +1 -1
- {recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/RECORD +15 -15
- {recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/WHEEL +1 -1
- /recce/data/_next/static/{jV5FXBTZB_ybwhM-KEJpR → POqJHyxRZAKc5Vb7Bi6Gz}/_buildManifest.js +0 -0
- /recce/data/_next/static/{jV5FXBTZB_ybwhM-KEJpR → POqJHyxRZAKc5Vb7Bi6Gz}/_ssgManifest.js +0 -0
- {recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/entry_points.txt +0 -0
- {recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/licenses/LICENSE +0 -0
- {recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/top_level.txt +0 -0
recce/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.4.0.
|
|
1
|
+
1.4.0.20250520
|
|
@@ -24,7 +24,8 @@ from typing import (
|
|
|
24
24
|
|
|
25
25
|
from recce.event import log_performance
|
|
26
26
|
from recce.exceptions import RecceException
|
|
27
|
-
from recce.util.cll import CLLPerformanceTracking
|
|
27
|
+
from recce.util.cll import CLLPerformanceTracking
|
|
28
|
+
from recce.util.cll import cll_old as cll
|
|
28
29
|
from recce.util.lineage import find_downstream, find_upstream
|
|
29
30
|
|
|
30
31
|
from ...tasks.profile import ProfileTask
|
recce/data/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/88b8abc134cfd59a.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-b787cb1a4f2293de.js"/><script src="/_next/static/chunks/1f229bf6-d9fe92e56db8d93b.js" async=""></script><script src="/_next/static/chunks/700-3b65fc3666820d00.js" async=""></script><script src="/_next/static/chunks/main-app-0225a2255968e566.js" async=""></script><meta name="robots" content="noindex"/><title>404: This page could not be found.</title><title>recce</title><meta name="description" content="Recce: Data validation toolkit for comprehensive PR review"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-b787cb1a4f2293de.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/88b8abc134cfd59a.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[37194,[],\"\"]\n4:I[79137,[],\"\"]\n5:I[63846,[],\"\"]\nb:I[67160,[],\"\"]\n6:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n7:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n8:{\"display\":\"inline-block\"}\n9:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nc:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"
|
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/88b8abc134cfd59a.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-b787cb1a4f2293de.js"/><script src="/_next/static/chunks/1f229bf6-d9fe92e56db8d93b.js" async=""></script><script src="/_next/static/chunks/700-3b65fc3666820d00.js" async=""></script><script src="/_next/static/chunks/main-app-0225a2255968e566.js" async=""></script><meta name="robots" content="noindex"/><title>404: This page could not be found.</title><title>recce</title><meta name="description" content="Recce: Data validation toolkit for comprehensive PR review"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-b787cb1a4f2293de.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/88b8abc134cfd59a.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[37194,[],\"\"]\n4:I[79137,[],\"\"]\n5:I[63846,[],\"\"]\nb:I[67160,[],\"\"]\n6:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n7:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n8:{\"display\":\"inline-block\"}\n9:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nc:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"POqJHyxRZAKc5Vb7Bi6Gz\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"_not-found\"],\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null],null],null]},[null,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/88b8abc134cfd59a.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"suppressHydrationWarning\":true,\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$6\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$7\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$8\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$9\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$La\"],\"globalErrorComponent\":\"$b\",\"missingSlots\":\"$Wc\"}]\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"recce\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Recce: Data validation toolkit for comprehensive PR review\"}]]\n3:null\n"])</script></body></html>
|
recce/data/index.html
CHANGED
|
@@ -24,4 +24,4 @@
|
|
|
24
24
|
transparent 0%,
|
|
25
25
|
#3182ce 50%,
|
|
26
26
|
transparent 100%
|
|
27
|
-
);position:absolute;will-change:left;min-width:50%;-webkit-animation:animation-11lmxjq 1s ease infinite normal none running;animation:animation-11lmxjq 1s ease infinite normal none running;}@-webkit-keyframes animation-11lmxjq{0%{left:-40%;}100%{left:100%;}}@keyframes animation-11lmxjq{0%{left:-40%;}100%{left:100%;}}</style><div style="width:0%" data-indeterminate="" aria-valuemax="100" aria-valuemin="0" role="progressbar" class="css-h5ends"></div></div></div><div class="css-0"></div></div></div></div><span></span><span id="__chakra_env" hidden=""></span><script src="/_next/static/chunks/webpack-b787cb1a4f2293de.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/88b8abc134cfd59a.css\",\"style\"]\n2:HL[\"/_next/static/css/c9ecb46a4b21c126.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"3:I[37194,[],\"\"]\n5:I[86822,[],\"ClientPageRoot\"]\n6:I[1996,[\"266\",\"static/chunks/e24bf851-0f8cbc99656833e7.js\",\"517\",\"static/chunks/c1ceaa8b-a1e442154d23515e.js\",\"376\",\"static/chunks/3a92ee20-3b5d922d4157af5e.js\",\"455\",\"static/chunks/6ef81909-694dc38134099299.js\",\"678\",\"static/chunks/3998a672-eaad84bdd88cc73e.js\",\"509\",\"static/chunks/9746af58-d74bef4d03eea6ab.js\",\"648\",\"static/chunks/ce84277d-f42c2c58049cea2d.js\",\"989\",\"static/chunks/47d8844f-79a1b53c66a7d7ec.js\",\"147\",\"static/chunks/a30376cd-7d806e1602f2dc3a.js\",\"995\",\"static/chunks/fee69bc6-f17d36c080742e74.js\",\"739\",\"static/chunks/7a8a3e83-d7fa409d97b38b2b.js\",\"283\",\"static/chunks/450c323b-1bb5db526e54435a.js\",\"303\",\"static/chunks/36e1c10d-bb0210cbd6573a8d.js\",\"22\",\"static/chunks/29e3cc0d-8c150e37dff9631b.js\",\"25\",\"static/chunks/b63b1b3f-7395c74e11a14e95.js\",\"355\",\"static/chunks/7f27ae6c-413f6b869a04183a.js\",\"495\",\"static/chunks/6dc81886-c94b9b91bc2c3caf.js\",\"599\",\"static/chunks/c132bf7d-8102037f9ccf372a.js\",\"971\",\"static/chunks/cd9f8d63-e020f408095ed77c.js\",\"778\",\"static/chunks/778-aef312bffb4c0312.js\",\"931\",\"static/chunks/app/page-7086764277331fcb.js\"],\"default\",1]\n7:I[79137,[],\"\"]\n8:I[63846,[],\"\"]\na:I[67160,[],\"\"]\nb:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L3\",null,{\"buildId\":\"
|
|
27
|
+
);position:absolute;will-change:left;min-width:50%;-webkit-animation:animation-11lmxjq 1s ease infinite normal none running;animation:animation-11lmxjq 1s ease infinite normal none running;}@-webkit-keyframes animation-11lmxjq{0%{left:-40%;}100%{left:100%;}}@keyframes animation-11lmxjq{0%{left:-40%;}100%{left:100%;}}</style><div style="width:0%" data-indeterminate="" aria-valuemax="100" aria-valuemin="0" role="progressbar" class="css-h5ends"></div></div></div><div class="css-0"></div></div></div></div><span></span><span id="__chakra_env" hidden=""></span><script src="/_next/static/chunks/webpack-b787cb1a4f2293de.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/88b8abc134cfd59a.css\",\"style\"]\n2:HL[\"/_next/static/css/c9ecb46a4b21c126.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"3:I[37194,[],\"\"]\n5:I[86822,[],\"ClientPageRoot\"]\n6:I[1996,[\"266\",\"static/chunks/e24bf851-0f8cbc99656833e7.js\",\"517\",\"static/chunks/c1ceaa8b-a1e442154d23515e.js\",\"376\",\"static/chunks/3a92ee20-3b5d922d4157af5e.js\",\"455\",\"static/chunks/6ef81909-694dc38134099299.js\",\"678\",\"static/chunks/3998a672-eaad84bdd88cc73e.js\",\"509\",\"static/chunks/9746af58-d74bef4d03eea6ab.js\",\"648\",\"static/chunks/ce84277d-f42c2c58049cea2d.js\",\"989\",\"static/chunks/47d8844f-79a1b53c66a7d7ec.js\",\"147\",\"static/chunks/a30376cd-7d806e1602f2dc3a.js\",\"995\",\"static/chunks/fee69bc6-f17d36c080742e74.js\",\"739\",\"static/chunks/7a8a3e83-d7fa409d97b38b2b.js\",\"283\",\"static/chunks/450c323b-1bb5db526e54435a.js\",\"303\",\"static/chunks/36e1c10d-bb0210cbd6573a8d.js\",\"22\",\"static/chunks/29e3cc0d-8c150e37dff9631b.js\",\"25\",\"static/chunks/b63b1b3f-7395c74e11a14e95.js\",\"355\",\"static/chunks/7f27ae6c-413f6b869a04183a.js\",\"495\",\"static/chunks/6dc81886-c94b9b91bc2c3caf.js\",\"599\",\"static/chunks/c132bf7d-8102037f9ccf372a.js\",\"971\",\"static/chunks/cd9f8d63-e020f408095ed77c.js\",\"778\",\"static/chunks/778-aef312bffb4c0312.js\",\"931\",\"static/chunks/app/page-7086764277331fcb.js\"],\"default\",1]\n7:I[79137,[],\"\"]\n8:I[63846,[],\"\"]\na:I[67160,[],\"\"]\nb:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L3\",null,{\"buildId\":\"POqJHyxRZAKc5Vb7Bi6Gz\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"\"],\"initialTree\":[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"__PAGE__\",{},[[\"$L4\",[\"$\",\"$L5\",null,{\"props\":{\"params\":{},\"searchParams\":{}},\"Component\":\"$6\"}],[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/c9ecb46a4b21c126.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]]],null],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/88b8abc134cfd59a.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"suppressHydrationWarning\":true,\"children\":[\"$\",\"$L7\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L8\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[null,\"$L9\"],\"globalErrorComponent\":\"$a\",\"missingSlots\":\"$Wb\"}]\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"recce\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Recce: Data validation toolkit for comprehensive PR review\"}],[\"$\",\"link\",\"4\",{\"rel\":\"icon\",\"href\":\"/favicon.ico\",\"type\":\"image/x-icon\",\"sizes\":\"32x32\"}]]\n4:null\n"])</script></body></html>
|
recce/data/index.txt
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
3:I[1996,["266","static/chunks/e24bf851-0f8cbc99656833e7.js","517","static/chunks/c1ceaa8b-a1e442154d23515e.js","376","static/chunks/3a92ee20-3b5d922d4157af5e.js","455","static/chunks/6ef81909-694dc38134099299.js","678","static/chunks/3998a672-eaad84bdd88cc73e.js","509","static/chunks/9746af58-d74bef4d03eea6ab.js","648","static/chunks/ce84277d-f42c2c58049cea2d.js","989","static/chunks/47d8844f-79a1b53c66a7d7ec.js","147","static/chunks/a30376cd-7d806e1602f2dc3a.js","995","static/chunks/fee69bc6-f17d36c080742e74.js","739","static/chunks/7a8a3e83-d7fa409d97b38b2b.js","283","static/chunks/450c323b-1bb5db526e54435a.js","303","static/chunks/36e1c10d-bb0210cbd6573a8d.js","22","static/chunks/29e3cc0d-8c150e37dff9631b.js","25","static/chunks/b63b1b3f-7395c74e11a14e95.js","355","static/chunks/7f27ae6c-413f6b869a04183a.js","495","static/chunks/6dc81886-c94b9b91bc2c3caf.js","599","static/chunks/c132bf7d-8102037f9ccf372a.js","971","static/chunks/cd9f8d63-e020f408095ed77c.js","778","static/chunks/778-aef312bffb4c0312.js","931","static/chunks/app/page-7086764277331fcb.js"],"default",1]
|
|
3
3
|
4:I[79137,[],""]
|
|
4
4
|
5:I[63846,[],""]
|
|
5
|
-
0:["
|
|
5
|
+
0:["POqJHyxRZAKc5Vb7Bi6Gz",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/c9ecb46a4b21c126.css","precedence":"next","crossOrigin":"$undefined"}]]],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/88b8abc134cfd59a.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"suppressHydrationWarning":true,"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
|
|
6
6
|
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"recce"}],["$","meta","3",{"name":"description","content":"Recce: Data validation toolkit for comprehensive PR review"}],["$","link","4",{"rel":"icon","href":"/favicon.ico","type":"image/x-icon","sizes":"32x32"}]]
|
|
7
7
|
1:null
|
recce/util/breaking.py
CHANGED
|
@@ -74,8 +74,8 @@ def _diff_select_scope(old_scope: Scope, new_scope: Scope, scope_changes_map: di
|
|
|
74
74
|
# check if the upstream scopes is not breaking
|
|
75
75
|
for source_name, source in new_scope.sources.items():
|
|
76
76
|
if scope_changes_map.get(source) is not None:
|
|
77
|
-
|
|
78
|
-
if
|
|
77
|
+
change = scope_changes_map[source]
|
|
78
|
+
if change.category == "breaking":
|
|
79
79
|
change_category = "breaking"
|
|
80
80
|
|
|
81
81
|
# check if non-select expressions are the same
|
recce/util/cll.py
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
import time
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
-
from typing import Dict, List, Literal
|
|
3
|
+
from typing import Dict, List, Literal, Optional
|
|
4
4
|
|
|
5
|
+
import sqlglot.expressions as exp
|
|
5
6
|
from sqlglot import Dialect, parse_one
|
|
6
7
|
from sqlglot.errors import OptimizeError, SqlglotError
|
|
7
|
-
from sqlglot.expressions import (
|
|
8
|
-
Alias,
|
|
9
|
-
Binary,
|
|
10
|
-
Case,
|
|
11
|
-
Column,
|
|
12
|
-
Expression,
|
|
13
|
-
Func,
|
|
14
|
-
If,
|
|
15
|
-
Intersect,
|
|
16
|
-
Paren,
|
|
17
|
-
Union,
|
|
18
|
-
)
|
|
19
8
|
from sqlglot.optimizer import Scope, traverse_scope
|
|
20
9
|
from sqlglot.optimizer.qualify import qualify
|
|
21
10
|
|
|
@@ -91,94 +80,231 @@ class ColumnLevelDependencyColumn:
|
|
|
91
80
|
depends_on: List[ColumnLevelDependsOn]
|
|
92
81
|
|
|
93
82
|
|
|
94
|
-
|
|
83
|
+
@dataclass()
|
|
84
|
+
class CllResult:
|
|
85
|
+
# Model to column dependencies
|
|
86
|
+
depends_on: List[ColumnLevelDependsOn]
|
|
87
|
+
|
|
88
|
+
# Column to column dependencies
|
|
89
|
+
columns: Dict[str, ColumnLevelDependencyColumn]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _cll_column(proj, table_alias_map) -> ColumnLevelDependencyColumn:
|
|
95
93
|
# given an expression, return the columns depends on
|
|
96
94
|
# [{node: table, column: column}, ...]
|
|
95
|
+
type = "source"
|
|
96
|
+
depends_on: List[ColumnLevelDependsOn] = []
|
|
97
|
+
|
|
98
|
+
# instance of Column
|
|
99
|
+
if isinstance(proj, exp.Alias):
|
|
100
|
+
# 'select a as b'
|
|
101
|
+
# 'select CURRENT_TIMESTAMP() as create_at'
|
|
102
|
+
root = proj.this
|
|
103
|
+
|
|
104
|
+
for expression in root.walk(bfs=False):
|
|
105
|
+
if isinstance(expression, exp.Column):
|
|
106
|
+
column = expression
|
|
107
|
+
alias = column.table
|
|
108
|
+
|
|
109
|
+
if alias is None:
|
|
110
|
+
table = next(iter(table_alias_map.values()))
|
|
111
|
+
else:
|
|
112
|
+
table = table_alias_map.get(alias, alias)
|
|
113
|
+
depends_on.append(ColumnLevelDependsOn(table, column.name))
|
|
114
|
+
if type == "source":
|
|
115
|
+
type = "passthrough"
|
|
116
|
+
elif isinstance(expression, (exp.Paren, exp.Identifier)):
|
|
117
|
+
pass
|
|
118
|
+
else:
|
|
119
|
+
type = "derived"
|
|
120
|
+
|
|
121
|
+
depends_on = _dedeup_depends_on(depends_on)
|
|
122
|
+
|
|
123
|
+
if len(depends_on) == 0:
|
|
124
|
+
type = "source"
|
|
125
|
+
|
|
126
|
+
if isinstance(proj, exp.Alias):
|
|
127
|
+
alias = proj
|
|
128
|
+
if type == "passthrough" and depends_on[0].column != alias.alias_or_name:
|
|
129
|
+
type = "renamed"
|
|
130
|
+
|
|
131
|
+
return ColumnLevelDependencyColumn(type=type, depends_on=depends_on)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def cll_old(sql, schema=None, dialect=None) -> Dict[str, ColumnLevelDependencyColumn]:
|
|
135
|
+
result = cll(sql, schema=schema, dialect=dialect)
|
|
136
|
+
return result.columns
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _dedeup_depends_on(depends_on: List[ColumnLevelDependsOn]) -> List[ColumnLevelDependsOn]:
|
|
140
|
+
# deduplicate the depends_on list
|
|
141
|
+
dedup_set = set()
|
|
142
|
+
dedup_list = []
|
|
143
|
+
for col_dep in depends_on:
|
|
144
|
+
node_col = col_dep.node + "." + col_dep.column
|
|
145
|
+
if node_col not in dedup_set:
|
|
146
|
+
dedup_list.append(col_dep)
|
|
147
|
+
dedup_set.add(node_col)
|
|
148
|
+
return dedup_list
|
|
97
149
|
|
|
98
|
-
if isinstance(expression, Column):
|
|
99
|
-
column = expression
|
|
100
|
-
alias = column.table
|
|
101
150
|
|
|
102
|
-
|
|
103
|
-
|
|
151
|
+
def _dedeup_cll_result(cll_result: CllResult):
|
|
152
|
+
cll_result.depends_on = _dedeup_depends_on(cll_result.depends_on)
|
|
153
|
+
for column in cll_result.columns.values():
|
|
154
|
+
column.depends_on = _dedeup_depends_on(column.depends_on)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _cll_set_scope(scope: Scope, scope_cll_map: dict[Scope, CllResult]) -> CllResult:
|
|
158
|
+
result = CllResult(depends_on=[], columns={})
|
|
159
|
+
scope_lineage = result.columns
|
|
160
|
+
|
|
161
|
+
for union_scope in scope.union_scopes:
|
|
162
|
+
sub_scope_result = scope_cll_map.get(union_scope)
|
|
163
|
+
|
|
164
|
+
for k, v in sub_scope_result.columns.items():
|
|
165
|
+
if k not in result.columns:
|
|
166
|
+
scope_lineage[k] = v
|
|
167
|
+
else:
|
|
168
|
+
scope_lineage[k].depends_on.extend(v.depends_on)
|
|
169
|
+
scope_lineage[k].type = "derived"
|
|
170
|
+
|
|
171
|
+
result.depends_on.extend(sub_scope_result.depends_on)
|
|
172
|
+
return result
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _cll_select_scope(scope: Scope, scope_cll_map: dict[Scope, CllResult]) -> CllResult:
|
|
176
|
+
assert scope.expression.key == "select"
|
|
177
|
+
|
|
178
|
+
column_dep_map = {}
|
|
179
|
+
model_depends_on = []
|
|
180
|
+
table_alias_map = {t.alias_or_name: t.name for t in scope.tables}
|
|
181
|
+
select = scope.expression
|
|
182
|
+
|
|
183
|
+
def source_column_dependency(ref_column: exp.Column) -> Optional[ColumnLevelDependencyColumn]:
|
|
184
|
+
column_name = ref_column.name
|
|
185
|
+
table_name = ref_column.table if ref_column.table != "" else next(iter(table_alias_map.values()))
|
|
186
|
+
source = scope.sources.get(table_name, None) # type: exp.Table | Scope
|
|
187
|
+
if isinstance(source, Scope):
|
|
188
|
+
ref_cll = scope_cll_map.get(source)
|
|
189
|
+
if ref_cll is None:
|
|
190
|
+
return None
|
|
191
|
+
return ref_cll.columns.get(column_name)
|
|
192
|
+
elif isinstance(source, exp.Table):
|
|
193
|
+
return ColumnLevelDependencyColumn(
|
|
194
|
+
type="passthrough", depends_on=[ColumnLevelDependsOn(source.name, column_name)]
|
|
195
|
+
)
|
|
104
196
|
else:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
#
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
for proj in scope.expression.selects:
|
|
200
|
+
type = "source"
|
|
201
|
+
column_depends_on: List[ColumnLevelDependsOn] = []
|
|
202
|
+
root = proj.this if isinstance(proj, exp.Alias) else proj
|
|
203
|
+
for expression in root.walk(bfs=False):
|
|
204
|
+
if isinstance(expression, exp.Column):
|
|
205
|
+
ref_column_dependency = source_column_dependency(expression)
|
|
206
|
+
if ref_column_dependency is not None:
|
|
207
|
+
column_depends_on.extend(ref_column_dependency.depends_on)
|
|
208
|
+
if ref_column_dependency.type == "derived":
|
|
209
|
+
type = "derived"
|
|
210
|
+
elif ref_column_dependency.type == "renamed":
|
|
211
|
+
if type == "source" or type == "passthrough":
|
|
212
|
+
type = "renamed"
|
|
213
|
+
elif ref_column_dependency.type == "passthrough":
|
|
214
|
+
if type == "source":
|
|
215
|
+
type = "passthrough"
|
|
216
|
+
else:
|
|
217
|
+
column_depends_on.append(ColumnLevelDependsOn(expression.table, expression.name))
|
|
218
|
+
if type == "source":
|
|
219
|
+
type = "passthrough"
|
|
220
|
+
|
|
221
|
+
elif isinstance(expression, (exp.Paren, exp.Identifier)):
|
|
222
|
+
pass
|
|
223
|
+
else:
|
|
224
|
+
type = "derived"
|
|
225
|
+
|
|
226
|
+
column_depends_on = _dedeup_depends_on(column_depends_on)
|
|
227
|
+
|
|
228
|
+
if len(column_depends_on) == 0 and type != "source":
|
|
229
|
+
type = "source"
|
|
230
|
+
|
|
231
|
+
if isinstance(proj, exp.Alias):
|
|
232
|
+
alias = proj
|
|
233
|
+
if type == "passthrough" and column_depends_on[0].column != alias.alias_or_name:
|
|
234
|
+
type = "renamed"
|
|
235
|
+
|
|
236
|
+
column_dep_map[proj.alias_or_name] = ColumnLevelDependencyColumn(type=type, depends_on=column_depends_on)
|
|
237
|
+
|
|
238
|
+
def selected_column_dependency(ref_column: exp.Column) -> Optional[ColumnLevelDependencyColumn]:
|
|
239
|
+
column_name = ref_column.name
|
|
240
|
+
return column_dep_map.get(column_name)
|
|
241
|
+
|
|
242
|
+
# joins clause: Reference the source columns
|
|
243
|
+
if select.args.get("joins"):
|
|
244
|
+
joins = select.args.get("joins")
|
|
245
|
+
for join in joins:
|
|
246
|
+
if isinstance(join, exp.Join):
|
|
247
|
+
for ref_column in join.find_all(exp.Column):
|
|
248
|
+
if source_column_dependency(ref_column) is not None:
|
|
249
|
+
model_depends_on.extend(source_column_dependency(ref_column).depends_on)
|
|
250
|
+
|
|
251
|
+
# where clauses: Reference the source columns
|
|
252
|
+
if select.args.get("where"):
|
|
253
|
+
where = select.args.get("where")
|
|
254
|
+
if isinstance(where, exp.Where):
|
|
255
|
+
for ref_column in where.find_all(exp.Column):
|
|
256
|
+
if source_column_dependency(ref_column) is not None:
|
|
257
|
+
model_depends_on.extend(source_column_dependency(ref_column).depends_on)
|
|
258
|
+
|
|
259
|
+
# group by clause: Reference the source columns, column index
|
|
260
|
+
if select.args.get("group"):
|
|
261
|
+
group = select.args.get("group")
|
|
262
|
+
if isinstance(group, exp.Group):
|
|
263
|
+
for ref_column in group.find_all(exp.Column):
|
|
264
|
+
if source_column_dependency(ref_column) is not None:
|
|
265
|
+
model_depends_on.extend(source_column_dependency(ref_column).depends_on)
|
|
266
|
+
|
|
267
|
+
# having clause: Reference the source columns, selected columns
|
|
268
|
+
if select.args.get("having"):
|
|
269
|
+
having = select.args.get("having")
|
|
270
|
+
if isinstance(having, exp.Having):
|
|
271
|
+
for ref_column in having.find_all(exp.Column):
|
|
272
|
+
if source_column_dependency(ref_column) is not None:
|
|
273
|
+
model_depends_on.extend(source_column_dependency(ref_column).depends_on)
|
|
274
|
+
elif selected_column_dependency(ref_column) is not None:
|
|
275
|
+
model_depends_on.extend(selected_column_dependency(ref_column).depends_on)
|
|
276
|
+
|
|
277
|
+
# order by clause: Reference the source columns, selected columns, column index
|
|
278
|
+
if select.args.get("order"):
|
|
279
|
+
order = select.args.get("order")
|
|
280
|
+
if isinstance(order, exp.Order):
|
|
281
|
+
for ref_column in order.find_all(exp.Column):
|
|
282
|
+
if source_column_dependency(ref_column) is not None:
|
|
283
|
+
model_depends_on.extend(source_column_dependency(ref_column).depends_on)
|
|
284
|
+
elif selected_column_dependency(ref_column) is not None:
|
|
285
|
+
model_depends_on.extend(selected_column_dependency(ref_column).depends_on)
|
|
286
|
+
|
|
287
|
+
for source in scope.sources.values():
|
|
288
|
+
scope_result = scope_cll_map.get(source)
|
|
289
|
+
if scope_result is not None:
|
|
290
|
+
model_depends_on.extend(scope_result.depends_on)
|
|
291
|
+
|
|
292
|
+
model_depends_on = _dedeup_depends_on(model_depends_on)
|
|
293
|
+
|
|
294
|
+
return CllResult(columns=column_dep_map, depends_on=model_depends_on)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def cll(sql, schema=None, dialect=None) -> CllResult:
|
|
298
|
+
# given a sql, return the cll for the sql
|
|
176
299
|
# {
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
#
|
|
180
|
-
#
|
|
181
|
-
#
|
|
300
|
+
# 'depends_on': [{'node': 'model_id', 'column': 'column'}],
|
|
301
|
+
# 'columns': {
|
|
302
|
+
# 'column1': {
|
|
303
|
+
# 'type': 'derived',
|
|
304
|
+
# 'depends_on': [{'node': 'model_id', 'column': 'column'}],
|
|
305
|
+
# }
|
|
306
|
+
# }
|
|
307
|
+
# }
|
|
182
308
|
|
|
183
309
|
dialect = Dialect.get(dialect) if dialect is not None else None
|
|
184
310
|
|
|
@@ -194,111 +320,17 @@ def cll(sql, schema=None, dialect=None) -> Dict[str, ColumnLevelDependencyColumn
|
|
|
194
320
|
except SqlglotError as e:
|
|
195
321
|
raise RecceException(f"Failed to qualify SQL: {str(e)}")
|
|
196
322
|
|
|
197
|
-
result = {}
|
|
198
|
-
|
|
323
|
+
result = CllResult(depends_on=[], columns={})
|
|
324
|
+
scope_cll_map = {}
|
|
199
325
|
for scope in traverse_scope(expression):
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
for union_scope in scope.union_scopes:
|
|
206
|
-
for k, v in global_lineage[union_scope].items():
|
|
207
|
-
if k not in scope_lineage:
|
|
208
|
-
scope_lineage[k] = v
|
|
209
|
-
else:
|
|
210
|
-
scope_lineage[k].depends_on.extend(v.depends_on)
|
|
211
|
-
scope_lineage[k].type = "derived"
|
|
326
|
+
scope_type = scope.expression.key
|
|
327
|
+
if scope_type == "union" or scope_type == "intersect" or scope_type == "except":
|
|
328
|
+
result = _cll_set_scope(scope, scope_cll_map)
|
|
329
|
+
elif scope_type == "select":
|
|
330
|
+
result = _cll_select_scope(scope, scope_cll_map)
|
|
212
331
|
else:
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
# 'select a'
|
|
217
|
-
column = select
|
|
218
|
-
column_cll = _cll_expression(column, table_alias_map)
|
|
219
|
-
elif isinstance(select, Alias):
|
|
220
|
-
# 'select a as b'
|
|
221
|
-
# 'select CURRENT_TIMESTAMP() as create_at'
|
|
222
|
-
alias = select
|
|
223
|
-
col_expression = alias.this
|
|
224
|
-
column_cll = _cll_expression(col_expression, table_alias_map)
|
|
225
|
-
if (
|
|
226
|
-
column_cll
|
|
227
|
-
and column_cll.type == "passthrough"
|
|
228
|
-
and column_cll.depends_on[0].column != alias.alias_or_name
|
|
229
|
-
):
|
|
230
|
-
column_cll.type = "renamed"
|
|
231
|
-
else:
|
|
232
|
-
# 'select 1'
|
|
233
|
-
column_cll = ColumnLevelDependencyColumn(type="source", depends_on=[])
|
|
234
|
-
|
|
235
|
-
cte_type = None
|
|
236
|
-
flatten_col_depends_on = []
|
|
237
|
-
for col_dep in column_cll.depends_on:
|
|
238
|
-
col_dep_node = col_dep.node
|
|
239
|
-
col_dep_column = col_dep.column
|
|
240
|
-
# cte
|
|
241
|
-
cte_scope = scope.cte_sources.get(col_dep_node)
|
|
242
|
-
# inline derived table
|
|
243
|
-
source_scope = None
|
|
244
|
-
if isinstance(scope.sources.get(col_dep_node), Scope):
|
|
245
|
-
source_scope = scope.sources.get(col_dep_node)
|
|
246
|
-
|
|
247
|
-
if cte_scope is not None:
|
|
248
|
-
cte_cll = global_lineage[cte_scope]
|
|
249
|
-
if cte_cll is None or cte_cll.get(col_dep_column) is None:
|
|
250
|
-
# In dbt-duckdb, the external source is compiled as `read_csv('..') rather than a table.
|
|
251
|
-
continue
|
|
252
|
-
cte_type = cte_cll.get(col_dep_column).type
|
|
253
|
-
flatten_col_depends_on.extend(cte_cll.get(col_dep_column).depends_on)
|
|
254
|
-
elif source_scope is not None:
|
|
255
|
-
source_cll = global_lineage[source_scope]
|
|
256
|
-
if source_cll is None or source_cll.get(col_dep_column) is None:
|
|
257
|
-
continue
|
|
258
|
-
flatten_col_depends_on.extend(source_cll.get(col_dep_column).depends_on)
|
|
259
|
-
else:
|
|
260
|
-
flatten_col_depends_on.append(col_dep)
|
|
261
|
-
|
|
262
|
-
# deduplicate
|
|
263
|
-
dedup_col_depends_on = []
|
|
264
|
-
dedup_set = set()
|
|
265
|
-
for col_dep in flatten_col_depends_on:
|
|
266
|
-
node_col = col_dep.node + "." + col_dep.column
|
|
267
|
-
if node_col not in dedup_set:
|
|
268
|
-
dedup_col_depends_on.append(col_dep)
|
|
269
|
-
dedup_set.add(node_col)
|
|
270
|
-
|
|
271
|
-
# transformation type
|
|
272
|
-
type = column_cll.type
|
|
273
|
-
if type == "derived":
|
|
274
|
-
if len(dedup_col_depends_on) == 0:
|
|
275
|
-
type = "source"
|
|
276
|
-
else:
|
|
277
|
-
# keep current scope type
|
|
278
|
-
pass
|
|
279
|
-
elif cte_type is not None:
|
|
280
|
-
if len(dedup_col_depends_on) > 1:
|
|
281
|
-
type = "derived"
|
|
282
|
-
elif len(dedup_col_depends_on) == 0:
|
|
283
|
-
type = "source"
|
|
284
|
-
else:
|
|
285
|
-
if isinstance(select, Column):
|
|
286
|
-
type = cte_type
|
|
287
|
-
elif isinstance(select, Alias):
|
|
288
|
-
alias = select
|
|
289
|
-
if column_cll.depends_on[0].column == alias.alias_or_name:
|
|
290
|
-
type = cte_type
|
|
291
|
-
else:
|
|
292
|
-
type = "renamed" if cte_type == "passthrough" else cte_type
|
|
293
|
-
else:
|
|
294
|
-
type = "source"
|
|
295
|
-
|
|
296
|
-
scope_lineage[select.alias_or_name] = ColumnLevelDependencyColumn(
|
|
297
|
-
type=type, depends_on=dedup_col_depends_on
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
global_lineage[scope] = scope_lineage
|
|
301
|
-
if not scope.is_cte:
|
|
302
|
-
result = scope_lineage
|
|
332
|
+
continue
|
|
333
|
+
|
|
334
|
+
scope_cll_map[scope] = result
|
|
303
335
|
|
|
304
336
|
return result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
recce/VERSION,sha256=
|
|
1
|
+
recce/VERSION,sha256=nzNc5MSbZy5vU3A_AaSf535vMGZjYwiqQi4GX2x_Wkk,15
|
|
2
2
|
recce/__init__.py,sha256=yNb0QT-yoStex0VZALNJvUwtPLommoVCStcow31guqo,2392
|
|
3
3
|
recce/artifact.py,sha256=tKQAHSrLRjiR3ppOI4sym8SxYiiLTuD3DPMYh4DWQdA,6506
|
|
4
4
|
recce/cli.py,sha256=OqIUMkQSm1XgpGawm_j1XURAMK9ijlBQrWTuakPP6S0,35388
|
|
@@ -16,17 +16,19 @@ recce/summary.py,sha256=Mbxvxr9KazR5o9icqhhjiGHsoAiWxQU4PdN7HytBJ1c,19154
|
|
|
16
16
|
recce/adapter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
recce/adapter/base.py,sha256=T_JNeLHgiHSaegw-DbrvHOaYjMyZcjj2Qtg5cWh_fco,3548
|
|
18
18
|
recce/adapter/sqlmesh_adapter.py,sha256=IU3N-F6ToDoO7_bV5vsG8pmTuDcbFtewTIuCxedTaRM,5046
|
|
19
|
-
recce/adapter/dbt_adapter/__init__.py,sha256=
|
|
19
|
+
recce/adapter/dbt_adapter/__init__.py,sha256=tVrGZ6Nd5xEHpE7RFPiA3ZVzDif1FwdHSTEwbGZ66RM,54421
|
|
20
20
|
recce/adapter/dbt_adapter/dbt_version.py,sha256=M7aedZIWslXnJsryK8Ki4OL_t2oAKxy4uE2pRwfWIkk,1228
|
|
21
21
|
recce/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
recce/apis/check_api.py,sha256=KMCXSMl1qqzx2jQgRqCrD4j_cY3EHBbM3H2-t-6saAU,6227
|
|
23
23
|
recce/apis/check_func.py,sha256=gktbCcyk3WGvWRJJ-wDnwv7NrIny2nTHWLl1-kdiVRo,4183
|
|
24
24
|
recce/apis/run_api.py,sha256=eOaxOxXDkH59uqGCd4blld7edavUx7JU_DCd2WAYrL8,3416
|
|
25
25
|
recce/apis/run_func.py,sha256=6wC8TDU-h7TLr2VZH7HNsWaUVlQ9HBN5N_dwqfi4lMY,7440
|
|
26
|
-
recce/data/404.html,sha256=
|
|
26
|
+
recce/data/404.html,sha256=ESxAPakccS9Akrleo2oa9oMUn71fzPrKWayZKq6NdB0,6554
|
|
27
27
|
recce/data/favicon.ico,sha256=B2mBumUOnzvUrXrqNkrc5QfdDXjzEXRcWkWur0fJ6sM,2565
|
|
28
|
-
recce/data/index.html,sha256=
|
|
29
|
-
recce/data/index.txt,sha256=
|
|
28
|
+
recce/data/index.html,sha256=2AKakSTZnNxu5VKaqzz0z_kP2O6e8AA7tVGCrPL78dQ,40259
|
|
29
|
+
recce/data/index.txt,sha256=C2KkXwCZRkjt5V59X7QBauByQHFbJH0pz3yhM7zr0t0,3514
|
|
30
|
+
recce/data/_next/static/POqJHyxRZAKc5Vb7Bi6Gz/_buildManifest.js,sha256=gZrGHi2LPMw1gkjYWs13MYkJyb5aOtihBRSJ1w0E6QA,224
|
|
31
|
+
recce/data/_next/static/POqJHyxRZAKc5Vb7Bi6Gz/_ssgManifest.js,sha256=Z49s4suAsf5y_GfnQSvm4qtq2ggxEbZPfEDTXjy6XgA,80
|
|
30
32
|
recce/data/_next/static/chunks/1f229bf6-d9fe92e56db8d93b.js,sha256=NvhILR-yLwIu-WlvwD9Hkr2H_I7ZK64vwYvR6c84wC0,172836
|
|
31
33
|
recce/data/_next/static/chunks/29e3cc0d-8c150e37dff9631b.js,sha256=4ZQR-OYMhGWnYPNwUjG5FpsTVzVTPEAf6T0v0E5g-4o,700
|
|
32
34
|
recce/data/_next/static/chunks/36e1c10d-bb0210cbd6573a8d.js,sha256=SkfIoUJXsrjEoql4hRRcWKtW2vMfHOAHUm4NE6eaho4,7797
|
|
@@ -62,8 +64,6 @@ recce/data/_next/static/chunks/pages/_app-d5672bf3d8b6371b.js,sha256=UcYdHJMmCNf
|
|
|
62
64
|
recce/data/_next/static/chunks/pages/_error-ed75be3f25588548.js,sha256=o_MwN3cYfszhI-hy_wkB0XAyTgcEcXt43rrzk-oKIe0,250
|
|
63
65
|
recce/data/_next/static/css/88b8abc134cfd59a.css,sha256=Tb97QjWxV5rOawZojbeD9SSETGsG2p9iaOrENjzAjYM,7235
|
|
64
66
|
recce/data/_next/static/css/c9ecb46a4b21c126.css,sha256=JbGypR8aDNuZavNvH6dhPtSbMVSCsy0ycPrz_6XkiVc,21925
|
|
65
|
-
recce/data/_next/static/jV5FXBTZB_ybwhM-KEJpR/_buildManifest.js,sha256=gZrGHi2LPMw1gkjYWs13MYkJyb5aOtihBRSJ1w0E6QA,224
|
|
66
|
-
recce/data/_next/static/jV5FXBTZB_ybwhM-KEJpR/_ssgManifest.js,sha256=Z49s4suAsf5y_GfnQSvm4qtq2ggxEbZPfEDTXjy6XgA,80
|
|
67
67
|
recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2,sha256=P5Sx5PNkdTlDYzAdulW_OPRfMokDLi6XTpmS8KJSRoI,11148
|
|
68
68
|
recce/data/_next/static/media/montserrat-cyrillic-800-normal.31d693bb.woff,sha256=ITxULbMzWscxwUi_v3GpzTSYVWlwq_z9fpEvAkEvHJw,11020
|
|
69
69
|
recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.7e2c1e62.woff,sha256=6J3PqBk_hOFVM8PpfZeSfwZQumQd6LTPPjnaVha2KQ0,12672
|
|
@@ -98,9 +98,9 @@ recce/tasks/schema.py,sha256=HHrSvhd_ZJdrNj2QKi9W8vmig0NuYci5cgsKFvp2bu4,2274
|
|
|
98
98
|
recce/tasks/top_k.py,sha256=vY3VCBmg61E8I4V-9-hJOv5RCYCmhxl6sHiKR9Zv7eE,5521
|
|
99
99
|
recce/tasks/valuediff.py,sha256=XJWkA307B5qTerT87fJRhJxPCqjmXn5eILYCXDfPtSQ,16439
|
|
100
100
|
recce/util/__init__.py,sha256=0lcJectK7Z7k9h0EaYCcv4Bgw2PN03OdJoxb3tbV5j8,37
|
|
101
|
-
recce/util/breaking.py,sha256=
|
|
101
|
+
recce/util/breaking.py,sha256=evT-xlDWMgIbuPQH6w5yNoDjOqopKzBXnCF9_xTn1S0,12591
|
|
102
102
|
recce/util/cache.py,sha256=QB6wzxe0M3jNTwP0M27Ys8F2hF-oda4-LyXXG9THuZQ,646
|
|
103
|
-
recce/util/cll.py,sha256=
|
|
103
|
+
recce/util/cll.py,sha256=78A7bCuxRhOVJWE5uj6jJgPyAkFBHVydg4sU5rR3e9A,12363
|
|
104
104
|
recce/util/io.py,sha256=53s4uDFT6ftpI-12MBxfv-RiBkWvPXMvdxPO9lJrjJM,3374
|
|
105
105
|
recce/util/lineage.py,sha256=C-jNqRARgwAEQoicO5t7D0XGBkcVs6SyxLzfzCAqkPQ,707
|
|
106
106
|
recce/util/logger.py,sha256=6UgLFkRiur9jJfu2ZRdo4LUvMw4f75V-l-1HT1-sgKo,747
|
|
@@ -108,7 +108,7 @@ recce/util/pydantic_model.py,sha256=KumKuyCjbTzEMsKLE4-b-eZfp0gLhYDdmVtw1-hxiJw,
|
|
|
108
108
|
recce/util/recce_cloud.py,sha256=F9Y4zqUVqQAzbLrWnccJdSjGPHzhGCVBfN4mOGVwpL8,6822
|
|
109
109
|
recce/util/singleton.py,sha256=1cU99I0f9tjuMQLMJyLsK1oK3fZJMsO5-TbRHAMXqds,627
|
|
110
110
|
recce/yaml/__init__.py,sha256=EgXYlFeJZchatUClRDXbIC5Oqb2_nBvB2NqItYVihio,1292
|
|
111
|
-
recce_nightly-1.4.0.
|
|
111
|
+
recce_nightly-1.4.0.20250520.dist-info/licenses/LICENSE,sha256=CQjjMy9aYPhfe8xG_bcpIfKtNkdxLZ5IOb8oPygtUhY,11343
|
|
112
112
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
113
113
|
tests/test_cli.py,sha256=f0n15QNVAyCqkygwIUp2aaoNAQau1zZp-nXpK4yyf1E,5444
|
|
114
114
|
tests/test_config.py,sha256=ODDFe_XF6gphmSmmc422dGLBaCCmG-IjDzTkD5SJsJE,1557
|
|
@@ -136,8 +136,8 @@ tests/tasks/test_row_count.py,sha256=21PaP2aq-x8-pqwzWHRT1sixhQ8g3CQNRWOZTTmbK0s
|
|
|
136
136
|
tests/tasks/test_schema.py,sha256=7ds4Vx8ixaiIWDR49Lvjem4xlPkRP1cXazDRY3roUak,3121
|
|
137
137
|
tests/tasks/test_top_k.py,sha256=YR_GS__DJsbDlQVaEEdJvNQ3fh1VmV5Nb3G7lb0r6YM,1779
|
|
138
138
|
tests/tasks/test_valuediff.py,sha256=_xQJGgxsXoy2NYk_Z6Hsw2FlVh6zk2nN_iUueyRN1e8,2046
|
|
139
|
-
recce_nightly-1.4.0.
|
|
140
|
-
recce_nightly-1.4.0.
|
|
141
|
-
recce_nightly-1.4.0.
|
|
142
|
-
recce_nightly-1.4.0.
|
|
143
|
-
recce_nightly-1.4.0.
|
|
139
|
+
recce_nightly-1.4.0.20250520.dist-info/METADATA,sha256=Wa5oNsuy7gbk-zHJ3MmIRt6WXLwV0CG6cRInE3j0ssg,9299
|
|
140
|
+
recce_nightly-1.4.0.20250520.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
141
|
+
recce_nightly-1.4.0.20250520.dist-info/entry_points.txt,sha256=oqoY_IiwIqXbgrIsPnlqUqao2eiIeP2dprowkOlmeyg,40
|
|
142
|
+
recce_nightly-1.4.0.20250520.dist-info/top_level.txt,sha256=6PKGVpf75idP0C6KEaldDzzZUauIxNu1ZDstau1pI4I,12
|
|
143
|
+
recce_nightly-1.4.0.20250520.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{recce_nightly-1.4.0.20250518.dist-info → recce_nightly-1.4.0.20250520.dist-info}/top_level.txt
RENAMED
|
File without changes
|