Skip to content

Commit

Permalink
Add numeric-constraints annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
earlbread committed Aug 17, 2018
1 parent 9fe340d commit 7f549ca
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 8 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ To be released.

- The `uri` type has completly gone; use `url` instead.
[[#126], [#281] by Jonghun Park]
- Added constraints for numeric unboxed types. [[#206], [#271]]

### Docs target

Expand Down Expand Up @@ -41,6 +42,8 @@ To be released.
(from [spoqa/nirum](https://hub.docker.com/r/spoqa/nirum/)).

[#126]: https://github.com/nirum-lang/nirum/issues/126
[#206]: https://github.com/nirum-lang/nirum/issues/206
[#271]: https://github.com/nirum-lang/nirum/pull/271
[#281]: https://github.com/nirum-lang/nirum/pull/281
[#297]: https://github.com/nirum-lang/nirum/issues/297
[#300]: https://github.com/nirum-lang/nirum/pull/300
Expand Down
25 changes: 23 additions & 2 deletions src/Nirum/Targets/Python.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module Nirum.Targets.Python
import Control.Monad (forM)
import Control.Monad.State (modify)
import qualified Data.List as L
import Data.Maybe (catMaybes, fromMaybe)
import Data.Maybe (catMaybes, fromMaybe, isJust)
import GHC.Exts (IsList (toList))

import qualified Data.ByteString.Lazy
Expand Down Expand Up @@ -685,12 +685,33 @@ 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"
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', value) of
("min", Integer v) ->
Just $ ValueValidator
[qq|value >= ($v)|]
[qq|value is less than $v|]
("max", Integer v) ->
Just $ ValueValidator
[qq|value <= ($v)|]
[qq|value is greater than $v|]
_ -> Nothing
| (name', value) <- toList args
]
if all isJust constraintValidators
then return $ catMaybes constraintValidators
else fail "Unsupported arguments on @numeric-constraints"
Nothing -> return valueValidatorsProto
deserializer <- compileDeserializer' src itype "value" "rv" "on_error"
defaultErrorHandler <- defaultDeserializerErrorHandler
return [compileText|
Expand Down
54 changes: 49 additions & 5 deletions test/Nirum/Targets/PythonSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
module Nirum.Targets.PythonSpec where

import qualified Data.Map.Strict as M
import Data.Either
import System.FilePath ((</>))
import Test.Hspec.Meta

import Nirum.Constructs.Annotation hiding (null)
import Nirum.Constructs.Annotation.Internal
import Nirum.Constructs.Module (Module (Module))
import Nirum.Package.Metadata (Target (compilePackage))
import Nirum.Constructs.TypeDeclaration hiding (Text)
import qualified Nirum.Package.Metadata as M
import Nirum.Targets.Python
( Source (Source)
, parseModulePath
Expand All @@ -19,7 +23,7 @@ spec = do
describe "compilePackage" $ do
it "returns a Map of file paths and their contents to generate" $ do
let (Source pkg _) = makeDummySource $ Module [] Nothing
files = compilePackage pkg
files = M.compilePackage pkg
directoryStructure =
[ "src-py2" </> "foo" </> "__init__.py"
, "src-py2" </> "foo" </> "bar" </> "__init__.py"
Expand All @@ -34,7 +38,7 @@ spec = do
it "creates an emtpy Python package directory if necessary" $ do
let (Source pkg _) = makeDummySource' ["test"] (Module [] Nothing)
[]
files = compilePackage pkg
files = M.compilePackage pkg
directoryStructure =
[ "src-py2" </> "test" </> "__init__.py"
, "src-py2" </> "test" </> "foo" </> "__init__.py"
Expand All @@ -51,7 +55,7 @@ spec = do
it "generates renamed package dirs if renames are configured" $ do
let (Source pkg _) = makeDummySource' [] (Module [] Nothing)
[(["foo"], ["quz"])]
files = compilePackage pkg
files = M.compilePackage pkg
directoryStructure =
[ "src-py2" </> "quz" </> "__init__.py"
, "src-py2" </> "quz" </> "bar" </> "__init__.py"
Expand All @@ -65,7 +69,7 @@ spec = do
M.keysSet files `shouldBe` directoryStructure
let (Source pkg' _) = makeDummySource' [] (Module [] Nothing)
[(["foo", "bar"], ["bar"])]
files' = compilePackage pkg'
files' = M.compilePackage pkg'
directoryStructure' =
[ "src-py2" </> "foo" </> "__init__.py"
, "src-py2" </> "bar" </> "__init__.py"
Expand All @@ -90,3 +94,43 @@ spec = do
parseModulePath "foo..bar" `shouldBe` Nothing
parseModulePath "foo.bar>" `shouldBe` Nothing
parseModulePath "foo.bar-" `shouldBe` Nothing

describe "@numeric-constraints" $ do
it "fails if unsupported arguments are present" $ do
let Right annots = fromList
[ Annotation
"numeric-constraints"
[("min", Integer 1), ("unsupported", Integer 2)]
]
compareErrorMessage annots

it "fails if unsupported arguments type is given" $ do
let Right annots = fromList
[ Annotation
"numeric-constraints"
[("min", Integer 1), ("max", Text "2")]
]
compareErrorMessage annots

it "success" $ do
let Right annots = fromList
[ Annotation
"numeric-constraints"
[("min", Integer 1), ("max", Integer 2)]
]
let Just result = getResult annots
isRight result `shouldBe` True
where
compareErrorMessage annots = do
let Just result = getResult annots
let Left errorMessage = result
errorMessage `shouldBe`
"Unsupported arguments on @numeric-constraints"

getResult annots =
let
unboxed = TypeDeclaration "foo" (UnboxedType "int32") annots
(Source pkg _) = makeDummySource $ Module [unboxed] Nothing
files = M.compilePackage pkg
in
M.lookup ("src" </> "foo" </> "__init__.py") files
2 changes: 2 additions & 0 deletions test/nirum_fixture/fixture/constraints.nrm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@numeric-constraints(min=1, max=12)
unboxed month (int32);
15 changes: 15 additions & 0 deletions test/python/constraints_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- 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)
3 changes: 2 additions & 1 deletion test/python/setup_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
'fixture.datetime',
'fixture.name',
Expand All @@ -46,6 +46,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',
'fixture.datetime',
'fixture.name',
Expand Down

0 comments on commit 7f549ca

Please sign in to comment.