{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module CPython.Simple where

import CPython.Simple.Instances

import Control.Exception (catch, SomeException)
import Data.Semigroup ((<>))
import Data.Text (Text)
import qualified Data.Text as T

import qualified CPython as Py
import qualified CPython.Protocols.Object as Py
import qualified CPython.Types as Py
import qualified CPython.Types.Module as Py
import qualified CPython.Types.Tuple as Py (toTuple)
import qualified CPython.Types.Dictionary as PyDict

data Arg = forall a. ToPy a => Arg a

instance ToPy Arg where
  toPy :: Arg -> IO SomeObject
toPy (Arg a :: a
a) = a -> IO SomeObject
forall a. ToPy a => a -> IO SomeObject
toPy a
a

arg :: ToPy a => a -> Arg
arg :: a -> Arg
arg = a -> Arg
forall a. ToPy a => a -> Arg
Arg

initialize :: IO ()
initialize :: IO ()
initialize = IO ()
Py.initialize

importModule :: Text -> IO Py.Module
importModule :: Text -> IO Module
importModule module_ :: Text
module_ = Text -> IO Module
Py.importModule Text
module_

call
  :: FromPy a
  => Text -- ^ module name
  -> Text -- ^ function name
  -> [Arg] -- ^ args
  -> [(Text, Arg)] -- ^ kwargs
  -> IO a
call :: Text -> Text -> [Arg] -> [(Text, Arg)] -> IO a
call moduleName :: Text
moduleName func :: Text
func args :: [Arg]
args kwargs :: [(Text, Arg)]
kwargs = do
  Module
module_ <- Text -> IO Module
importModule Text
moduleName
  SomeObject
pyFunc <- Module -> Unicode -> IO SomeObject
forall self. Object self => self -> Unicode -> IO SomeObject
Py.getAttribute Module
module_ (Unicode -> IO SomeObject) -> IO Unicode -> IO SomeObject
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Text -> IO Unicode
Py.toUnicode Text
func
  [SomeObject]
pyArgs <- (Arg -> IO SomeObject) -> [Arg] -> IO [SomeObject]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Arg -> IO SomeObject
forall a. ToPy a => a -> IO SomeObject
toPy [Arg]
args
  Tuple
pyArgsTuple <- [SomeObject] -> IO Tuple
Py.toTuple [SomeObject]
pyArgs
  Dictionary
pyKwargs <- [(Text, Arg)] -> IO Dictionary
toPyKwargs [(Text, Arg)]
kwargs
  SomeObject
result <- SomeObject -> Tuple -> Dictionary -> IO SomeObject
forall self.
Object self =>
self -> Tuple -> Dictionary -> IO SomeObject
Py.call SomeObject
pyFunc Tuple
pyArgsTuple Dictionary
pyKwargs
  SomeObject -> IO a
forall a. FromPy a => SomeObject -> IO a
fromPy SomeObject
result
  where
    toPyKwargs :: [(Text, Arg)] -> IO Py.Dictionary
    toPyKwargs :: [(Text, Arg)] -> IO Dictionary
toPyKwargs dict :: [(Text, Arg)]
dict = do
      Dictionary
myDict <- IO Dictionary
PyDict.new
      ((Text, Arg) -> IO ()) -> [(Text, Arg)] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_
        (\(k :: Text
k, v :: Arg
v) -> do
          SomeObject
pyKey <- Text -> IO SomeObject
forall a. ToPy a => a -> IO SomeObject
toPy Text
k
          SomeObject
pyVal <- Arg -> IO SomeObject
forall a. ToPy a => a -> IO SomeObject
toPy Arg
v
          Dictionary -> SomeObject -> SomeObject -> IO ()
forall key value.
(Object key, Object value) =>
Dictionary -> key -> value -> IO ()
PyDict.setItem Dictionary
myDict SomeObject
pyKey SomeObject
pyVal)
        [(Text, Arg)]
dict
      Dictionary -> IO Dictionary
forall (f :: * -> *) a. Applicative f => a -> f a
pure Dictionary
myDict

setAttribute
  :: ToPy a
  => Text -- ^ module name
  -> Text -- ^ attribute name
  -> a -- ^ value to set attribute to
  -> IO ()
setAttribute :: Text -> Text -> a -> IO ()
setAttribute moduleName :: Text
moduleName name :: Text
name value :: a
value = do
  Module
module_ <- Text -> IO Module
importModule Text
moduleName
  Unicode
pyName <- Text -> IO Unicode
Py.toUnicode Text
name
  SomeObject
pyValue <- a -> IO SomeObject
forall a. ToPy a => a -> IO SomeObject
toPy a
value
  Module -> Unicode -> SomeObject -> IO ()
forall self v.
(Object self, Object v) =>
self -> Unicode -> v -> IO ()
Py.setAttribute Module
module_ Unicode
pyName SomeObject
pyValue

getAttribute
  :: FromPy a
  => Text -- ^ module name
  -> Text -- ^ attribute name
  -> IO a
getAttribute :: Text -> Text -> IO a
getAttribute moduleName :: Text
moduleName name :: Text
name = do
  Module
module_ <- Text -> IO Module
importModule Text
moduleName
  SomeObject
attr <- Module -> Unicode -> IO SomeObject
forall self. Object self => self -> Unicode -> IO SomeObject
Py.getAttribute Module
module_ (Unicode -> IO SomeObject) -> IO Unicode -> IO SomeObject
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Text -> IO Unicode
Py.toUnicode Text
name
  SomeObject -> IO a
forall a. FromPy a => SomeObject -> IO a
fromPy SomeObject
attr