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 CHANGED
@@ -1 +1 @@
1
- 1.4.0.20250518
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, cll
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,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;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\":\"jV5FXBTZB_ybwhM-KEJpR\",\"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>
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,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;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\":\"jV5FXBTZB_ybwhM-KEJpR\",\"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>
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:["jV5FXBTZB_ybwhM-KEJpR",[[["",{"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]]]]
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
- chanage = scope_changes_map[source]
78
- if chanage.category == "breaking":
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
- def _cll_expression(expression, table_alias_map) -> ColumnLevelDependencyColumn:
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
- if alias is None:
103
- table = next(iter(table_alias_map.values()))
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
- table = table_alias_map.get(alias, alias)
106
-
107
- return ColumnLevelDependencyColumn(type="passthrough", depends_on=[ColumnLevelDependsOn(table, column.name)])
108
- elif isinstance(expression, Paren):
109
- return _cll_expression(expression.this, table_alias_map)
110
- elif isinstance(expression, Binary):
111
- depends_on = []
112
- if expression.left:
113
- depends_on_left = _cll_expression(expression.left, table_alias_map).depends_on
114
- depends_on.extend(depends_on_left)
115
- if expression.right:
116
- depends_on_right = _cll_expression(expression.right, table_alias_map).depends_on
117
- depends_on.extend(depends_on_right)
118
- type = "derived" if depends_on else "source"
119
- return ColumnLevelDependencyColumn(type=type, depends_on=depends_on)
120
- elif isinstance(expression, Case):
121
- ifs = expression.args["ifs"]
122
- default = expression.args["default"]
123
- depends_on = []
124
- for expr in ifs:
125
- depends_on_one = _cll_expression(expr, table_alias_map).depends_on
126
- depends_on.extend(depends_on_one)
127
- if default is not None:
128
- depends_on.extend(_cll_expression(default, table_alias_map).depends_on)
129
- type = "derived" if depends_on else "source"
130
- return ColumnLevelDependencyColumn(type=type, depends_on=depends_on)
131
- elif isinstance(expression, If):
132
- depends_on = []
133
- if expression.this:
134
- depends_on_one = _cll_expression(expression.this, table_alias_map).depends_on
135
- depends_on.extend(depends_on_one)
136
- if expression.args.get("true"):
137
- depends_on_one = _cll_expression(expression.args.get("true"), table_alias_map).depends_on
138
- depends_on.extend(depends_on_one)
139
- if expression.args.get("false"):
140
- depends_on_one = _cll_expression(expression.args.get("false"), table_alias_map).depends_on
141
- depends_on.extend(depends_on_one)
142
- type = "derived" if depends_on else "source"
143
- return ColumnLevelDependencyColumn(type=type, depends_on=depends_on)
144
- elif isinstance(expression, Func):
145
- if expression.expressions:
146
- depends_on = []
147
- for expr in expression.expressions:
148
- depends_on_one = _cll_expression(expr, table_alias_map).depends_on
149
- depends_on.extend(depends_on_one)
150
- type = "derived" if depends_on else "source"
151
- return ColumnLevelDependencyColumn(type=type, depends_on=depends_on)
152
- if expression.this:
153
- depends_on = _cll_expression(expression.this, table_alias_map).depends_on
154
- type = "derived" if depends_on else "source"
155
- return ColumnLevelDependencyColumn(type=type, depends_on=depends_on)
156
-
157
- return ColumnLevelDependencyColumn(type="source", depends_on=[])
158
- elif expression.this and isinstance(expression.this, Expression):
159
- depends_on = _cll_expression(expression.this, table_alias_map).depends_on
160
- type = "derived" if depends_on else "source"
161
- return ColumnLevelDependencyColumn(type=type, depends_on=depends_on)
162
- elif expression.expressions:
163
- depends_on = []
164
- for expr in expression.expressions:
165
- depends_on_one = _cll_expression(expr, table_alias_map).depends_on
166
- depends_on.extend(depends_on_one)
167
- type = "derived" if depends_on else "source"
168
- return ColumnLevelDependencyColumn(type=type, depends_on=depends_on)
169
- else:
170
- depends_on = []
171
- return ColumnLevelDependencyColumn(type="source", depends_on=depends_on)
172
-
173
-
174
- def cll(sql, schema=None, dialect=None) -> Dict[str, ColumnLevelDependencyColumn]:
175
- # given a sql, return the columns depends on
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
- # 'column1': {
178
- # 'transformation_type': 'transform' or 'original',
179
- # 'depends_on': {
180
- # {node: model_id, column: column}, ...]
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
- global_lineage = {}
323
+ result = CllResult(depends_on=[], columns={})
324
+ scope_cll_map = {}
199
325
  for scope in traverse_scope(expression):
200
- scope_lineage = {}
201
-
202
- table_alias_map = {t.alias_or_name: t.name for t in scope.tables}
203
-
204
- if isinstance(scope.expression, Union) or isinstance(scope.expression, Intersect):
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
- for select in scope.expression.selects:
214
- # instance of Column
215
- if isinstance(select, Column):
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: recce-nightly
3
- Version: 1.4.0.20250518
3
+ Version: 1.4.0.20250520
4
4
  Summary: Environment diff tool for dbt
5
5
  Home-page: https://github.com/InfuseAI/recce
6
6
  Author: InfuseAI Dev Team
@@ -1,4 +1,4 @@
1
- recce/VERSION,sha256=Kt7eX-LJ14jv6OsKcl7a1_oHlYm0LPlZ9T5Pm-_AecQ,15
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=21FBwx6ovGO-oOxLcsZWVejlD35NT_r2v3vtApnWfTU,54384
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=0lH4SW2l6Dt44Ru3qvxCzwWbrv0ecMOl5WJOOgmylB4,6554
26
+ recce/data/404.html,sha256=ESxAPakccS9Akrleo2oa9oMUn71fzPrKWayZKq6NdB0,6554
27
27
  recce/data/favicon.ico,sha256=B2mBumUOnzvUrXrqNkrc5QfdDXjzEXRcWkWur0fJ6sM,2565
28
- recce/data/index.html,sha256=o1YUZN0Vpi1rEdsSsT6lqd8D5Sb8B-cdASEs_Un2rg8,40259
29
- recce/data/index.txt,sha256=atdaq-Y0ZAHysIJWSsVqlDC2Xmdc4VKpcnd9Ap-RkT8,3514
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=_63SJhEqYVIsIp7SqXA9Muh2fDcvgjm9RhfZ3nTNJFQ,12593
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=eg32KNz4Ec-FkOLSgMwP8TrW_TTUydI7xTb_UAbt-oI,12164
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.20250518.dist-info/licenses/LICENSE,sha256=CQjjMy9aYPhfe8xG_bcpIfKtNkdxLZ5IOb8oPygtUhY,11343
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.20250518.dist-info/METADATA,sha256=eShSGzdH8k3udWlLGWqE176wx9TTXiQIQbHOKibnJhs,9299
140
- recce_nightly-1.4.0.20250518.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
141
- recce_nightly-1.4.0.20250518.dist-info/entry_points.txt,sha256=oqoY_IiwIqXbgrIsPnlqUqao2eiIeP2dprowkOlmeyg,40
142
- recce_nightly-1.4.0.20250518.dist-info/top_level.txt,sha256=6PKGVpf75idP0C6KEaldDzzZUauIxNu1ZDstau1pI4I,12
143
- recce_nightly-1.4.0.20250518.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5