diff --git a/examples/pdf-service.nrm b/examples/pdf-service.nrm index ebf5ac9..421fd8d 100644 --- a/examples/pdf-service.nrm +++ b/examples/pdf-service.nrm @@ -1,3 +1,5 @@ +@error +union markdown-parse-error = symbol-error | syntax-error (text reason); type html = text; @@ -13,4 +15,9 @@ service pdf-service ( # Renders a PDF from the given HTML text. html html, ), + + binary render-md ( + # Renders a PDF from the given HTML text. + text md, + ) throws markdown-parse-error, ); diff --git a/src/Nirum/Targets/Python.hs b/src/Nirum/Targets/Python.hs index caa9b93..c46d46f 100644 --- a/src/Nirum/Targets/Python.hs +++ b/src/Nirum/Targets/Python.hs @@ -46,7 +46,7 @@ module Nirum.Targets.Python ( Code import qualified Control.Monad.State as ST import qualified Data.List as L -import Data.Maybe (fromMaybe) +import Data.Maybe (catMaybes, fromMaybe) import Data.Typeable (Typeable) import GHC.Exts (IsList (toList)) import Text.Printf (printf) @@ -63,9 +63,10 @@ import Text.InterpolatedString.Perl6 (q, qq) import qualified Nirum.CodeGen as C import Nirum.CodeGen (Failure) -import Nirum.Constructs.Declaration (Documented (docsBlock)) +import qualified Nirum.Constructs.Annotation as A import qualified Nirum.Constructs.DeclarationSet as DS import qualified Nirum.Constructs.Identifier as I +import Nirum.Constructs.Declaration (Documented (docsBlock)) import Nirum.Constructs.ModulePath ( ModulePath , fromIdentifiers , hierarchy @@ -693,9 +694,11 @@ class $className(object): def __hash__(self){ret "int"}: return hash(($hashText,)) |] -compileTypeDeclaration src d@TypeDeclaration { typename = typename' - , type' = UnionType tags - } = do +compileTypeDeclaration src + d@TypeDeclaration { typename = typename' + , type' = UnionType tags + , typeAnnotations = annotations + } = do tagCodes <- mapM (compileUnionTag src typename') $ toList tags let className = toClassName' typename' tagCodes' = T.intercalate "\n\n" tagCodes @@ -711,7 +714,7 @@ compileTypeDeclaration src d@TypeDeclaration { typename = typename' ret <- returnCompiler arg <- parameterCompiler return [qq| -class $className(object): +class $className({T.intercalate "," $ compileExtendClasses annotations}): {compileDocstring " " d} __nirum_union_behind_name__ = '{I.toSnakeCaseText $ N.behindName typename'}' @@ -753,6 +756,19 @@ $tagCodes' toNamePair [name' | Tag name' _ _ <- toList tags] ",\n " + compileExtendClasses :: A.AnnotationSet -> [Code] + compileExtendClasses annotations' = + if null extendClasses + then ["object"] + else extendClasses + where + extendsClassMap :: M.Map I.Identifier Code + extendsClassMap = [("error", "Exception")] + extendClasses :: [Code] + extendClasses = catMaybes + [ M.lookup annotationName extendsClassMap + | (A.Annotation annotationName _) <- A.toList annotations' + ] compileTypeDeclaration src@Source { sourcePackage = Package { metadata = metadata' } } d@ServiceDeclaration { serviceName = name' @@ -763,8 +779,11 @@ compileTypeDeclaration let methodMetadata' = commaNl methodMetadata dummyMethods <- mapM compileMethod methods' clientMethods <- mapM compileClientMethod methods' + methodErrorTypes <- mapM compileErrorType methods' let dummyMethods' = T.intercalate "\n\n" dummyMethods clientMethods' = T.intercalate "\n\n" clientMethods + methodErrorTypes' = + T.intercalate "," $ catMaybes methodErrorTypes insertStandardImport "json" insertThirdPartyImports [ ("nirum.constructs", ["name_dict_type"]) , ("nirum.deserialize", ["deserialize_meta"]) @@ -783,6 +802,7 @@ class $className(service_type): __nirum_method_names__ = name_dict_type([ $methodNameMap ]) + __nirum_method_error_types__ = dict([$methodErrorTypes']) {dummyMethods'} @@ -798,6 +818,13 @@ class {className}_Client(client_type, $className): className = toClassName' name' commaNl :: [T.Text] -> T.Text commaNl = T.intercalate ",\n" + compileErrorType :: Method -> CodeGen (Maybe Code) + compileErrorType (Method mn _ _ me _) = + case me of + Just errorTypeExpression -> do + et <- compileTypeExpression src errorTypeExpression + return $ Just [qq|('{toAttributeName' mn}', $et)|] + Nothing -> return Nothing compileMethod :: Method -> CodeGen Code compileMethod m@(Method mName params rtype _etype _anno) = do let mName' = toAttributeName' mName diff --git a/test/nirum_fixture/fixture/foo.nrm b/test/nirum_fixture/fixture/foo.nrm index 1415075..b847dfb 100644 --- a/test/nirum_fixture/fixture/foo.nrm +++ b/test/nirum_fixture/fixture/foo.nrm @@ -69,11 +69,16 @@ union status = run service null-service (); +@error +union rpc-error = connection-lose-error + | not-found-error (text message,) + ; + service ping-service ( # Service docs. bool ping ( # Method docs. text nonce, # Parameter docs. - ), + ) throws rpc-error, ); diff --git a/test/python/annotation_test.py b/test/python/annotation_test.py new file mode 100644 index 0000000..531c83f --- /dev/null +++ b/test/python/annotation_test.py @@ -0,0 +1,5 @@ +from fixture.foo import RpcError + + +def test_annotation_as_error(): + assert issubclass(RpcError, Exception) diff --git a/test/python/service_test.py b/test/python/service_test.py new file mode 100644 index 0000000..2786f67 --- /dev/null +++ b/test/python/service_test.py @@ -0,0 +1,5 @@ +from fixture.foo import PingService, RpcError + + +def test_throws_error(): + assert PingService.__nirum_method_error_types__ == {'ping': RpcError}