File: Exceptions.hs

package info (click to toggle)
missingpy 0.10.0.2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 464 kB
  • ctags: 42
  • sloc: haskell: 1,433; makefile: 129; ansic: 107
file content (120 lines) | stat: -rw-r--r-- 4,279 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
{- arch-tag: Python low-level exception handling
Copyright (C) 2005 John Goerzen <jgoerzen@complete.org>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-}

{- |
   Module     : Python.Exceptions
   Copyright  : Copyright (C) 2005 John Goerzen
   License    : GNU GPL, version 2 or above

   Maintainer : John Goerzen,
   Maintainer : jgoerzen\@complete.org
   Stability  : provisional
   Portability: portable

Python low-level exception handling

Written by John Goerzen, jgoerzen\@complete.org
-}

module Python.Exceptions (-- * Types
                          PyException(..),
                          -- * General Catching
                          catchPy,
                          handlePy,
                          pyExceptions,
                          -- * Catching of specific Python exceptions
                          catchSpecificPy,
                          -- * Exception Object Operations
                          formatException,
                          doesExceptionMatch,
                          -- * Re-Raising Exceptions
                          exc2ioerror
                         )
where

import Python.Utils
import Foreign.C.Types
import Python.Objects
import Foreign
import Python.Types
import Data.Dynamic
import Data.Typeable
import Control.Exception
import Python.Interpreter
import Python.ForeignImports

{- | Execute the given IO action.

If it raises a 'PyException', then execute the supplied handler and return
its return value.  Otherwise, process as normal. -}
catchPy :: IO a -> (PyException -> IO a) -> IO a
catchPy = catchDyn

{- | Like 'catchPy', with the order of arguments reversed. -}
handlePy :: (PyException -> IO a) -> IO a -> IO a
handlePy = flip catchPy

{- | Like catchPy, but catches only instances of the Python class given
(see 'doesExceptionMatch'). -}
catchSpecificPy :: PyObject -> IO a -> (PyException -> IO a) -> IO a
catchSpecificPy pyo action handlerfunc =
    let handler e = do d <- doesExceptionMatch e pyo
                       if d
                          then handlerfunc e
                          else throwDyn e
        in catchPy action handler

{- | Useful as the first argument to catchJust, tryJust, or handleJust.
Return Nothing if the given exception is not a 'PyException', or 
the exception otherwise. -}
pyExceptions :: Exception -> Maybe PyException
pyExceptions exc = dynExceptions exc >>= fromDynamic

{- | When an exception is thrown, it is not immediately formatted.

This call will format it. -}
formatException :: PyException -> IO PyException
formatException e =
{-
    do fmt <- callByName "traceback.format_exception" 
                [excType e, excValue e, excTraceBack e] [] >>= fromPyObject
-}
    do ename <- strOf (excType e)
       evalue <- strOf (excValue e)
       let fmt = ename ++ ": " ++ evalue
       return $ e  {excFormatted = fmt}

{- | Returns true if the passed 'PyException' matches the given Python
exception class or one of its subclasses.  Standard Python exception classes
are given in 'Python.Exceptions.ExcTypes'. -}
doesExceptionMatch :: PyException -> PyObject -> IO Bool
doesExceptionMatch e pyo =
    withPyObject (excType e) (\ctyp ->
     withPyObject pyo (\cpo ->
      do r <- pyErr_GivenExceptionMatches ctyp cpo >>= checkCInt
         if r == 0
            then return False
            else return True
                      ))

{- | A handler for use in 'catchPy' or 'handlePy'.  Grabs the Python exception,
describes it, and raises the description in the IO monad with 'fail'. -}
exc2ioerror :: PyException -> IO a
exc2ioerror e = do e2 <- formatException e
                   fail $ "Python " ++ show e2