diff options
| author | Ben Sima <ben@bsima.me> | 2025-11-13 18:24:15 -0500 |
|---|---|---|
| committer | Ben Sima <ben@bsima.me> | 2025-11-13 18:24:15 -0500 |
| commit | 34b55f96e1befe7b453a86bc4896d93ecb206be2 (patch) | |
| tree | 5c4b8b8e15af78ea81020ba9d3a80e8c64cd04a0 /Omni/Bild.hs | |
| parent | 989a1a5de2419373e4932b11c2f2f5877a2fb959 (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/Bild.hs')
| -rwxr-xr-x | Omni/Bild.hs | 54 |
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 ] |
