packages feed

nbparts-0.1.0.0: src/Nbparts/Pack/Outputs.hs

module Nbparts.Pack.Outputs where

import Control.Monad.Error.Class (MonadError, liftEither)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Coerce (coerce)
import Data.Ipynb qualified as Ipynb
import Data.Map qualified as Map
import Data.Maybe qualified as Maybe
import Nbparts.Pack.Mime (embedMimeBundle)
import Nbparts.Types
  ( NotebookOutputs (NotebookOutputs),
    PackError (PackMissingCellIdError),
    UnembeddedCellOutput (DisplayData, Err, ExecuteResult, Stream),
    UnembeddedNotebookOutputs (UnembeddedNotebookOutputs),
  )

fillOutputs ::
  (MonadError PackError m, MonadIO m) =>
  FilePath ->
  UnembeddedNotebookOutputs ->
  Ipynb.Notebook a ->
  m (Ipynb.Notebook a)
fillOutputs readDir unembeddedOutputs (Ipynb.Notebook meta format cells) = do
  outputs <- liftIO $ embedOutputs readDir unembeddedOutputs
  filledCells <- liftEither $ traverse (fillCellOutputs outputs) cells
  return $ Ipynb.Notebook meta format filledCells

fillCellOutputs :: NotebookOutputs a -> Ipynb.Cell a -> Either PackError (Ipynb.Cell a)
fillCellOutputs (NotebookOutputs outputs) (Ipynb.Cell (Ipynb.Code codeExecutionCount _) maybeCellId source meta attachments) = do
  cellId <- case maybeCellId of
    Just cellId -> Right cellId
    Nothing -> Left PackMissingCellIdError

  -- If we can't find the outputs, assume that there are no outputs.
  let cellOutputs = Maybe.fromMaybe [] $ Map.lookup cellId outputs

  return $ Ipynb.Cell (Ipynb.Code codeExecutionCount cellOutputs) (Just cellId) source meta attachments
fillCellOutputs _ cell = pure cell

embedOutputs :: FilePath -> UnembeddedNotebookOutputs -> IO (NotebookOutputs a)
embedOutputs readDir = coerce $ fmap NotebookOutputs . traverse (mapM $ embedOutput readDir)

embedOutput :: FilePath -> UnembeddedCellOutput -> IO (Ipynb.Output a)
embedOutput _ (Stream streamName streamText) = pure $ Ipynb.Stream {streamName, streamText = Ipynb.Source streamText}
embedOutput readDir (DisplayData unembeddedDisplayData displayMetadata) = do
  displayData <- embedMimeBundle readDir unembeddedDisplayData
  return
    Ipynb.DisplayData
      { displayData = displayData,
        displayMetadata
      }
embedOutput readDir (ExecuteResult executeCount unembeddedExecuteData executeMetadata) = do
  executeData <- embedMimeBundle readDir unembeddedExecuteData
  return
    Ipynb.ExecuteResult
      { executeCount,
        executeData = executeData,
        executeMetadata
      }
embedOutput _ (Err errName errValue errTraceback) = pure $ Ipynb.Err {errName, errValue, errTraceback}