diff --git a/src/Nirum/Targets/Python.hs b/src/Nirum/Targets/Python.hs index 5bf6abf..d0fd5e9 100644 --- a/src/Nirum/Targets/Python.hs +++ b/src/Nirum/Targets/Python.hs @@ -258,6 +258,17 @@ renameMP Python { renames = table } = renameModulePath table thd3 :: (a, b, c) -> c thd3 (_, _, v) = v +mangleVar :: Code -> T.Text -> Code +mangleVar expr arbitrarySideName = T.concat + [ "__nirum_" + , (`T.map` expr) $ \ c -> if 'A' <= c && c <= 'Z' || + 'a' <= c && c <= 'z' || c == '_' + then c else '_' + , "__" + , arbitrarySideName + , "__" + ] + -- | The set of Python reserved keywords. -- See also: https://docs.python.org/3/reference/lexical_analysis.html#keywords keywords :: S.Set T.Text @@ -648,14 +659,25 @@ compileSerializer' mod' (OptionModifier typeExpr) pythonVar = compileSerializer' mod' (SetModifier typeExpr) pythonVar = compileSerializer' mod' (ListModifier typeExpr) pythonVar compileSerializer' mod' (ListModifier typeExpr) pythonVar = - [qq|[($serializer) for __{pythonVar}__elem__ in ($pythonVar)]|] + [qq|list(($serializer) for $elemVar in ($pythonVar))|] where + elemVar :: Code + elemVar = mangleVar pythonVar "elem" serializer :: Code - serializer = compileSerializer' mod' typeExpr [qq|__{pythonVar}__elem__|] + serializer = compileSerializer' mod' typeExpr elemVar compileSerializer' mod' (MapModifier kt vt) pythonVar = - [qq|\{({compileSerializer' mod' kt $ T.concat ["__", pythonVar, "__k__"]}): - ({compileSerializer' mod' vt $ T.concat ["__", pythonVar, "__v__"]}) - for __{pythonVar}__k__, __{pythonVar}__v__ in ($pythonVar).items()\}|] + [qq|list( + \{ + 'key': ({compileSerializer' mod' kt kVar}), + 'value': ({compileSerializer' mod' vt vVar}), + \} + for $kVar, $vVar in ($pythonVar).items() + )|] + where + kVar :: Code + kVar = mangleVar pythonVar "key" + vVar :: Code + vVar = mangleVar pythonVar "value" compileSerializer' mod' (TypeIdentifier typeId) pythonVar = case lookupType typeId mod' of Missing -> "None" -- must never happen diff --git a/test/nirum_fixture/fixture/foo.nrm b/test/nirum_fixture/fixture/foo.nrm index 9807636..a673869 100644 --- a/test/nirum_fixture/fixture/foo.nrm +++ b/test/nirum_fixture/fixture/foo.nrm @@ -129,3 +129,7 @@ service sample-service ( sample-method (animal a, product b/bb, gender c, way d/dd, uuid e, binary f/ff, bigint g, text h/hh), ); + +record record-with-map ( + {text: text} text-to-text, +); diff --git a/test/python/primitive_test.py b/test/python/primitive_test.py index 40ebd8a..638e5dd 100644 --- a/test/python/primitive_test.py +++ b/test/python/primitive_test.py @@ -5,14 +5,16 @@ from nirum.service import Service from six import PY3 -from fixture.foo import (CultureAgnosticName, Dog, +from fixture.foo import (Album, CultureAgnosticName, Dog, EastAsianName, EvaChar, FloatUnbox, Gender, ImportedTypeUnbox, Irum, Line, MixedName, Mro, Music, NoMro, NullService, + Person, People, Point1, Point2, Point3d, Pop, PingService, Product, - RecordWithOptionalRecordField, + RecordWithMap, RecordWithOptionalRecordField, ReservedKeywordEnum, ReservedKeywordUnion, - Rnb, RpcError, Run, Status, Stop, Way, WesternName) + Rnb, RpcError, Run, Song, Status, Stop, Way, + WesternName) from fixture.foo.bar import PathUnbox, IntUnbox, Point from fixture.qux import Path, Name @@ -351,3 +353,43 @@ def test_nirum_tag_classes(): Status.Tag.run: Run, Status.Tag.stop: Stop, } + + +def test_list_serializer(): + album = Album(name=u'Album title', tracks=[Song(name=u'Song title')]) + assert album.__nirum_serialize__() == { + '_type': 'album', + 'name': u'Album title', + 'tracks': [ + {'_type': 'song', 'name': u'Song title'}, + ], + } + + +def test_set_serializer(): + people = People(people={ + Person(first_name=Name(u'First'), last_name=Name(u'Last')), + }) + assert people.__nirum_serialize__() == { + '_type': 'people', + 'people': [ + { + '_type': 'person', + 'first_name': u'First', + 'last_name': u'Last', + }, + ] + } + + +def test_map_serializer(): + record = RecordWithMap(text_to_text={u'key': u'value'}) + assert record.__nirum_serialize__() == { + '_type': 'record_with_map', + 'text_to_text': [ + { + 'key': u'key', + 'value': u'value', + }, + ], + }