From 7848eae4612ed7be11660850c8323823fb20a4aa Mon Sep 17 00:00:00 2001 From: Dag Brattli Date: Sat, 11 Jul 2026 14:59:06 +0200 Subject: [PATCH] fix(python): propagate [] return value as process exit code The generated __main__ guard now calls sys.exit(int(main(...))) instead of discarding main's return value, so a non-zero exit code from an F# entry point (e.g. a failing test runner) is reflected in the process exit status. int(...) coercion is required because fable-library-python's Int32 is not an int subclass. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/Fable.Transforms/Python/Fable2Python.Transforms.fs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Fable.Transforms/Python/Fable2Python.Transforms.fs b/src/Fable.Transforms/Python/Fable2Python.Transforms.fs index 03c7cd96f8..bbf70e0ba3 100644 --- a/src/Fable.Transforms/Python/Fable2Python.Transforms.fs +++ b/src/Fable.Transforms/Python/Fable2Python.Transforms.fs @@ -3216,7 +3216,14 @@ let declareEntryPoint (com: IPythonCompiler) (ctx: Context) (funcExpr: Expressio [ Expression.stringConstant "__main__" ] ) - let main = Expression.call (funcExpr, [ args ]) |> Statement.expr |> List.singleton + let mainCall = Expression.call (funcExpr, [ args ]) + + // Propagate the entry point's return value as the process exit code. + // int(...) coercion is required because fable-library-python's Int32 is not an int subclass. + let main = + emitExpression None "sys.exit(int($0))" [ mainCall ] + |> Statement.expr + |> List.singleton Statement.if' (test, main)