summaryrefslogtreecommitdiff
path: root/Omni
diff options
context:
space:
mode:
authorBen Sima <ben@bsima.me>2025-11-13 18:24:15 -0500
committerBen Sima <ben@bsima.me>2025-11-13 18:24:15 -0500
commit34b55f96e1befe7b453a86bc4896d93ecb206be2 (patch)
tree5c4b8b8e15af78ea81020ba9d3a80e8c64cd04a0 /Omni
parent989a1a5de2419373e4932b11c2f2f5877a2fb959 (diff)
Fix Python import detection to handle transitive dependencies
detectPythonImports now recursively analyzes imported modules to find transitive dependencies, matching the behavior of detectHaskellImports. Previously it only detected direct imports, which caused build failures when Python modules had nested dependencies. - Changed signature from [Text] -> IO (Set FilePath) to Analysis -> [Text] -> IO (Set FilePath) - Added filepaths, findDeps, and onlyPython helper functions - Recursively calls analyze() on imported modules to find transitive deps - Updated tests to pass empty Analysis map
Diffstat (limited to 'Omni')
-rwxr-xr-xOmni/Bild.hs54
1 files changed, 38 insertions, 16 deletions
diff --git a/Omni/Bild.hs b/Omni/Bild.hs
index 967d143..c1c4210 100755
--- a/Omni/Bild.hs
+++ b/Omni/Bild.hs
@@ -540,7 +540,7 @@ analyze hmap ns = case Map.lookup ns hmap of
contentLines
|> Meta.detectAll "#"
|> \Meta.Parsed {..} ->
- detectPythonImports contentLines +> \srcs ->
+ detectPythonImports hmap contentLines +> \srcs ->
Target
{ builder = "python",
wrapper = Nothing,
@@ -818,19 +818,23 @@ detectLispImports contentLines =
|> Set.fromList
|> pure
--- | Finds local imports. Does not recurse to find transitive imports like
--- 'detectHaskellImports' does. Someday I will refactor these detection
--- functions and have a common, well-performing, complete solution.
-detectPythonImports :: [Text] -> IO (Set FilePath)
-detectPythonImports contentLines =
- contentLines
- /> Text.unpack
- /> Regex.match pythonImport
- |> catMaybes
- /> Namespace.fromPythonModule
- /> Namespace.toPath
- |> filterM Dir.doesPathExist
- /> Set.fromList
+-- | Finds local imports and recursively finds transitive imports, similar to
+-- 'detectHaskellImports'.
+detectPythonImports :: Analysis -> [Text] -> IO (Set FilePath)
+detectPythonImports pmap contentLines =
+ Env.getEnv "CODEROOT" +> \root ->
+ contentLines
+ /> Text.unpack
+ /> Regex.match pythonImport
+ |> catMaybes
+ |> \imports ->
+ filepaths imports
+ +> \files ->
+ findDeps root files
+ +> \deps ->
+ (map (stripRoot root) files <> Set.toList deps)
+ |> Set.fromList
+ |> pure
where
-- only detects 'import x' because I don't like 'from'
pythonImport :: Regex.RE Char String
@@ -839,16 +843,34 @@ detectPythonImports contentLines =
*> Regex.some (Regex.psym Char.isSpace)
*> Regex.many (Regex.psym isModuleChar)
<* Regex.many Regex.anySym
+ filepaths :: [String] -> IO [FilePath]
+ filepaths imports =
+ imports
+ |> map Namespace.fromPythonModule
+ |> map Namespace.toPath
+ |> traverse Dir.makeAbsolute
+ +> filterM Dir.doesFileExist
+ findDeps :: String -> [FilePath] -> IO (Set FilePath)
+ findDeps root fps =
+ fps
+ |> traverse (pure <. Namespace.fromPath root)
+ /> catMaybes
+ +> foldM analyze (onlyPython pmap)
+ /> Map.elems
+ /> map srcs
+ /> mconcat
+ onlyPython :: Analysis -> Analysis
+ onlyPython = Map.filterWithKey (\ns _ -> ext ns == Namespace.Py)
test_detectPythonImports :: Test.Tree
test_detectPythonImports =
Test.group
"detectPythonImports"
[ Test.unit "matches import statements" <| do
- set <- detectPythonImports ["import Omni.Log"]
+ set <- detectPythonImports mempty ["import Omni.Log"]
Set.fromList ["Omni/Log.py"] @=? set,
Test.unit "matches import as statements" <| do
- set <- detectPythonImports ["import Omni.Log as Log"]
+ set <- detectPythonImports mempty ["import Omni.Log as Log"]
Set.fromList ["Omni/Log.py"] @=? set
]