diff --git a/src/Nirum/Targets/Python.hs b/src/Nirum/Targets/Python.hs index e9af30c..d4fc7f9 100644 --- a/src/Nirum/Targets/Python.hs +++ b/src/Nirum/Targets/Python.hs @@ -21,7 +21,7 @@ module Nirum.Targets.Python import Control.Monad (forM) import qualified Data.List as L -import Data.Maybe (catMaybes, fromMaybe) +import Data.Maybe (catMaybes, fromMaybe, isJust) import GHC.Exts (IsList (toList)) import Text.Printf (printf) @@ -462,13 +462,32 @@ compileTypeDeclaration src d@TypeDeclaration { typename = typename' |] compileTypeDeclaration src d@TypeDeclaration { typename = typename' , type' = UnboxedType itype + , typeAnnotations = annots } = do let className = toClassName' typename' itypeExpr <- compileTypeExpression' src (Just itype) insertStandardImport "typing" insertThirdPartyImports [("nirum.deserialize", ["deserialize_meta"])] pyVer <- getPythonVersion - Validator typePred valueValidators' <- compileValidator' src itype "value" + Validator typePred valueValidatorsProto <- + compileValidator' src itype "value" + valueValidators' <- case A.lookup "numeric-constraints" annots of + Just A.Annotation { A.arguments = args } -> do + let constraintValidators = + [ case name' of + "min" -> Just $ ValueValidator + [qq|value >= ($value)|] + [qq|value is less than $value|] + "max" -> Just $ ValueValidator + [qq|value <= ($value)|] + [qq|value is greater than $value|] + _ -> Nothing + | (name', value) <- toList args + ] + if all isJust constraintValidators + then return $ catMaybes constraintValidators + else fail "Unsupported arguments on @numeric-constraints" + Nothing -> return valueValidatorsProto return $ toStrict $ renderMarkup $ [compileText| class #{className}(object): #{compileDocstring " " d} diff --git a/test/Nirum/Targets/PythonSpec.hs b/test/Nirum/Targets/PythonSpec.hs index c4aaf43..add8362 100644 --- a/test/Nirum/Targets/PythonSpec.hs +++ b/test/Nirum/Targets/PythonSpec.hs @@ -7,8 +7,10 @@ import System.FilePath (()) import Test.Hspec.Meta import Text.InterpolatedString.Perl6 (q) +import qualified Nirum.Constructs.Annotation as A import Nirum.Constructs.Module (Module (Module)) import Nirum.Constructs.Name (Name (Name)) +import Nirum.Constructs.TypeDeclaration import Nirum.Package.Metadata (Target (compilePackage)) import Nirum.Targets.Python ( Source (Source) @@ -169,3 +171,16 @@ spec = do parseModulePath "foo..bar" `shouldBe` Nothing parseModulePath "foo.bar>" `shouldBe` Nothing parseModulePath "foo.bar-" `shouldBe` Nothing + + describe "@numeric-constraints" $ + it "fails if unsupported arguments are present" $ do + let Right annots = A.fromList + [ A.Annotation "numeric-constraints" + [("min", "1"), ("unsupported", "asdf")] + ] + let unboxed = TypeDeclaration "foo" (UnboxedType "int32") annots + let (Source pkg _) = makeDummySource $ Module [unboxed] Nothing + let files = compilePackage pkg + let result = M.lookup ("src" "foo" "__init__.py") files + result `shouldBe` + Just (Left "Unsupported arguments on @numeric-constraints") diff --git a/test/nirum_fixture/fixture/constraints.nrm b/test/nirum_fixture/fixture/constraints.nrm new file mode 100644 index 0000000..376d351 --- /dev/null +++ b/test/nirum_fixture/fixture/constraints.nrm @@ -0,0 +1,2 @@ +@numeric-constraints(min="1", max="12") +unboxed month (int32); diff --git a/test/python/constraints_test.py b/test/python/constraints_test.py new file mode 100644 index 0000000..a46ee1e --- /dev/null +++ b/test/python/constraints_test.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pytest import raises + +from fixture.constraints import Month + + +def test_numeric_constraints(): + month = Month(1) + assert month.value == 1 + + with raises(ValueError): + Month(0) + + with raises(ValueError): + Month(13) diff --git a/test/python/setup_test.py b/test/python/setup_test.py index f09c07f..0a6a4bb 100644 --- a/test/python/setup_test.py +++ b/test/python/setup_test.py @@ -22,7 +22,7 @@ def test_setup_metadata(): assert set(pkg['Provides']) == { 'fixture', 'fixture.foo', 'fixture.foo.bar', 'fixture.qux', 'fixture.reserved_keyword_enum', 'fixture.reserved_keyword_union', - 'fixture.types', 'fixture.alias', + 'fixture.types', 'fixture.alias', 'fixture.constraints', 'renamed', 'renamed.foo', 'renamed.foo.bar', } assert ['0.3.0'] == pkg['Version'] @@ -43,6 +43,7 @@ def test_module_entry_points(): 'fixture.reserved-keyword-enum', 'fixture.reserved-keyword-union', 'fixture.types', 'fixture.alias', + 'fixture.constraints', 'renames.test.foo', 'renames.test.foo.bar', } import fixture.foo