packages feed

JuPyTer-notebook-0.1.0.0: src/Data/JuPyTer.hs

{-# LANGUAGE TemplateHaskell     #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RecordWildCards     #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE TypeOperators       #-}
{-# LANGUAGE DeriveGeneric       #-}

module Data.JuPyTer where

import           System.Exit        (exitFailure, exitSuccess)
import           System.IO          (stderr, hPutStrLn)
import qualified Data.ByteString.Lazy.Char8 as BSL
import           System.Environment (getArgs)
import           Control.Monad      (forM_, mzero, join)
import           Control.Applicative
import           Data.Aeson.AutoType.Alternative
import           Data.Aeson(decode, Value(..), FromJSON(..), ToJSON(..),
                            pairs,
                            (.:), (.:?), (.=), object)
import           Data.Monoid
import           Data.Text (Text)
import qualified Data.Text as Text
import qualified GHC.Generics

-- | Workaround for https://github.com/bos/aeson/issues/287.
o .:?? val = fmap join (o .:? val)


data CodemirrorMode = CodemirrorMode { 
    codemirrorModeName :: Text,
    codemirrorModeVersion :: Double
  } deriving (Show,Eq,GHC.Generics.Generic)


instance FromJSON CodemirrorMode where
  parseJSON (Object v) = CodemirrorMode <$> v .:   "name" <*> v .:   "version"
  parseJSON _          = mzero


instance ToJSON CodemirrorMode where
  toJSON     (CodemirrorMode {..}) = object ["name" .= codemirrorModeName, "version" .= codemirrorModeVersion]
  toEncoding (CodemirrorMode {..}) = pairs  ("name" .= codemirrorModeName<>"version" .= codemirrorModeVersion)


data LanguageInfo = LanguageInfo { 
    languageInfoNbconvertExporter :: Text,
    languageInfoFileExtension :: Text,
    languageInfoPygmentsLexer :: Text,
    languageInfoMimetype :: Text,
    languageInfoName :: Text,
    languageInfoVersion :: Text,
    languageInfoCodemirrorMode :: CodemirrorMode
  } deriving (Show,Eq,GHC.Generics.Generic)


instance FromJSON LanguageInfo where
  parseJSON (Object v) = LanguageInfo <$> v .:   "nbconvert_exporter" <*> v .:   "file_extension" <*> v .:   "pygments_lexer" <*> v .:   "mimetype" <*> v .:   "name" <*> v .:   "version" <*> v .:   "codemirror_mode"
  parseJSON _          = mzero


instance ToJSON LanguageInfo where
  toJSON     (LanguageInfo {..}) = object ["nbconvert_exporter" .= languageInfoNbconvertExporter, "file_extension" .= languageInfoFileExtension, "pygments_lexer" .= languageInfoPygmentsLexer, "mimetype" .= languageInfoMimetype, "name" .= languageInfoName, "version" .= languageInfoVersion, "codemirror_mode" .= languageInfoCodemirrorMode]
  toEncoding (LanguageInfo {..}) = pairs  ("nbconvert_exporter" .= languageInfoNbconvertExporter<>"file_extension" .= languageInfoFileExtension<>"pygments_lexer" .= languageInfoPygmentsLexer<>"mimetype" .= languageInfoMimetype<>"name" .= languageInfoName<>"version" .= languageInfoVersion<>"codemirror_mode" .= languageInfoCodemirrorMode)


data Kernelspec = Kernelspec { 
    kernelspecDisplayName :: Text,
    kernelspecName :: Text,
    kernelspecLanguage :: Text
  } deriving (Show,Eq,GHC.Generics.Generic)


instance FromJSON Kernelspec where
  parseJSON (Object v) = Kernelspec <$> v .:   "display_name" <*> v .:   "name" <*> v .:   "language"
  parseJSON _          = mzero


instance ToJSON Kernelspec where
  toJSON     (Kernelspec {..}) = object ["display_name" .= kernelspecDisplayName, "name" .= kernelspecName, "language" .= kernelspecLanguage]
  toEncoding (Kernelspec {..}) = pairs  ("display_name" .= kernelspecDisplayName<>"name" .= kernelspecName<>"language" .= kernelspecLanguage)


data Slideshow = Slideshow { 
    slideshowSlideType :: Text
  } deriving (Show,Eq,GHC.Generics.Generic)


instance FromJSON Slideshow where
  parseJSON (Object v) = Slideshow <$> v .:   "slide_type"
  parseJSON _          = mzero


instance ToJSON Slideshow where
  toJSON     (Slideshow {..}) = object ["slide_type" .= slideshowSlideType]
  toEncoding (Slideshow {..}) = pairs  ("slide_type" .= slideshowSlideType)


data Metadata = Metadata { 
    metadataScrolled :: (Maybe (Bool:|:[(Maybe Value)])),
    metadataCelltoolbar :: (Maybe (Text:|:[(Maybe Value)])),
    metadataLanguageInfo :: (Maybe (LanguageInfo:|:[(Maybe Value)])),
    metadataKernelspec :: (Maybe (Kernelspec:|:[(Maybe Value)])),
    metadataEditable :: (Maybe (Bool:|:[(Maybe Value)])),
    metadataDeletable :: (Maybe (Bool:|:[(Maybe Value)])),
    metadataSlideshow :: (Maybe (Slideshow:|:[(Maybe Value)])),
    metadataCollapsed :: (Maybe (Bool:|:[(Maybe Value)]))
  } deriving (Show,Eq,GHC.Generics.Generic)


instance FromJSON Metadata where
  parseJSON (Object v) = Metadata <$> v .:?? "scrolled" <*> v .:?? "celltoolbar" <*> v .:?? "language_info" <*> v .:?? "kernelspec" <*> v .:?? "editable" <*> v .:?? "deletable" <*> v .:?? "slideshow" <*> v .:?? "collapsed"
  parseJSON _          = mzero


instance ToJSON Metadata where
  toJSON     (Metadata {..}) = object ["scrolled" .= metadataScrolled, "celltoolbar" .= metadataCelltoolbar, "language_info" .= metadataLanguageInfo, "kernelspec" .= metadataKernelspec, "editable" .= metadataEditable, "deletable" .= metadataDeletable, "slideshow" .= metadataSlideshow, "collapsed" .= metadataCollapsed]
  toEncoding (Metadata {..}) = pairs  ("scrolled" .= metadataScrolled<>"celltoolbar" .= metadataCelltoolbar<>"language_info" .= metadataLanguageInfo<>"kernelspec" .= metadataKernelspec<>"editable" .= metadataEditable<>"deletable" .= metadataDeletable<>"slideshow" .= metadataSlideshow<>"collapsed" .= metadataCollapsed)

data CellsElt = CellsElt { 
    cellsEltExecutionCount :: (Maybe (Double:|:[(Maybe Value)])),
    cellsEltOutputs :: (Maybe ([[(Maybe Value)]])),
    cellsEltMetadata :: Metadata,
    cellsEltSource :: [Text:|:[(Maybe Value)]],
    cellsEltCellType :: Text
  } deriving (Show,Eq,GHC.Generics.Generic)


instance FromJSON CellsElt where
  parseJSON (Object v) = CellsElt <$> v .:?? "execution_count" <*> v .:?? "outputs" <*> v .:   "metadata" <*> v .:   "source" <*> v .:   "cell_type"
  parseJSON _          = mzero


instance ToJSON CellsElt where
  toJSON     (CellsElt {..}) = object ["execution_count" .= cellsEltExecutionCount, "outputs" .= cellsEltOutputs, "metadata" .= cellsEltMetadata, "source" .= cellsEltSource, "cell_type" .= cellsEltCellType]
  toEncoding (CellsElt {..}) = pairs  ("execution_count" .= cellsEltExecutionCount<>"outputs" .= cellsEltOutputs<>"metadata" .= cellsEltMetadata<>"source" .= cellsEltSource<>"cell_type" .= cellsEltCellType)

data IPyNb = IPyNb { 
    iPyNbNbformatMinor :: Double,
    iPyNbNbformat :: Double,
    iPyNbCells :: [CellsElt],
    iPyNbMetadata :: Metadata
  } deriving (Show,Eq,GHC.Generics.Generic)


instance FromJSON IPyNb where
  parseJSON (Object v) = IPyNb <$> v .:   "nbformat_minor" <*> v .:   "nbformat" <*> v .:   "cells" <*> v .:   "metadata"
  parseJSON _          = mzero


instance ToJSON IPyNb where
  toJSON     (IPyNb {..}) = object ["nbformat_minor" .= iPyNbNbformatMinor, "nbformat" .= iPyNbNbformat, "cells" .= iPyNbCells, "metadata" .= iPyNbMetadata]
  toEncoding (IPyNb {..}) = pairs  ("nbformat_minor" .= iPyNbNbformatMinor<>"nbformat" .= iPyNbNbformat<>"cells" .= iPyNbCells<>"metadata" .= iPyNbMetadata)




parse :: FilePath -> IO IPyNb
parse filename = do input <- BSL.readFile filename
                    case decode input of
                      Nothing -> fatal $ case (decode input :: Maybe Value) of
                                           Nothing -> "Invalid JSON file: "     ++ filename
                                           Just v  -> "Mismatched JSON value from file: " ++ filename
                      Just r  -> return (r :: IPyNb)
  where
    fatal :: String -> IO a
    fatal msg = do hPutStrLn stderr msg
                   exitFailure

main :: IO ()
main = do
  filenames <- getArgs
  forM_ filenames (\f -> parse f >>= (\p -> p `seq` putStrLn $ "Successfully parsed " ++ f))
  exitSuccess