nbparts-0.1.0.0: src/Nbparts/Unpack/Outputs.hs
module Nbparts.Unpack.Outputs where
import Control.Monad.Error.Class (MonadError, throwError)
import Control.Monad.State.Strict (MonadState)
import Control.Monad.State.Strict qualified as State
import Data.ByteString (ByteString)
import Data.Ipynb qualified as Ipynb
import Data.List qualified as List
import Data.Map qualified as Map
import Data.Maybe qualified as Maybe
import Data.Text (Text)
import Nbparts.Types
( UnembeddedCellOutput (DisplayData, Err, ExecuteResult, Stream),
UnembeddedNotebookOutputs (UnembeddedNotebookOutputs),
UnpackError (UnpackMissingCellIdError),
)
import Nbparts.Unpack.Mime (unembedMimeBundle)
collectOutputs ::
FilePath ->
Ipynb.Notebook a ->
Either UnpackError (UnembeddedNotebookOutputs, [(FilePath, ByteString)])
collectOutputs subdir (Ipynb.Notebook _meta _format cells) = State.runStateT nbOutputsState []
where
nbOutputsState ::
( MonadState [(FilePath, ByteString)] m,
MonadError UnpackError m
) =>
m UnembeddedNotebookOutputs
nbOutputsState = do
let codeOutputs = Maybe.mapMaybe extractCodeOutputs cells
entries <- traverse (uncurry (unembedCodeOutputs subdir)) codeOutputs
pure (UnembeddedNotebookOutputs $ Map.fromList entries)
extractCodeOutputs :: Ipynb.Cell a -> Maybe (Maybe Text, [Ipynb.Output a])
extractCodeOutputs (Ipynb.Cell (Ipynb.Code _ outputs) maybeCellId _ _ _)
| List.null outputs = Nothing -- Filter out cells with empty outputs to avoid serialising empty lists.
| otherwise = Just (maybeCellId, outputs)
extractCodeOutputs _ = Nothing
unembedCodeOutputs ::
(MonadState [(FilePath, ByteString)] m, MonadError UnpackError m) =>
FilePath ->
Maybe Text ->
[Ipynb.Output a] ->
m (Text, [UnembeddedCellOutput])
unembedCodeOutputs subdir (Just cellId) outputs = (cellId,) <$> traverse (unembedOutput subdir) outputs
unembedCodeOutputs _ Nothing _ = throwError UnpackMissingCellIdError
unembedOutput :: (MonadState [(FilePath, ByteString)] m) => FilePath -> Ipynb.Output a -> m UnembeddedCellOutput
unembedOutput _ (Ipynb.Stream streamName (Ipynb.Source streamText)) = pure $ Stream streamName streamText
unembedOutput subdir (Ipynb.DisplayData displayData metadata) = do
uDisplayData <- unembedMimeBundle subdir displayData
pure $ DisplayData uDisplayData metadata
unembedOutput subdir (Ipynb.ExecuteResult executeCount executeData metadata) = do
uExData <- unembedMimeBundle subdir executeData
pure $ ExecuteResult executeCount uExData metadata
unembedOutput _ (Ipynb.Err errName errValue errTraceback) = pure $ Err errName errValue errTraceback