From a773e1000d982bc21a25c4647136b3babd377f8b Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Thu, 29 Jun 2017 23:44:36 +0900 Subject: [PATCH 1/5] Make Python target to generate client w/ transport --- src/Nirum/Constructs/Service.hs | 1 + src/Nirum/Targets/Python.hs | 82 +++++++++++++++++++++------------ test/python/primitive_test.py | 10 ++-- tox.ini | 6 +-- 4 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/Nirum/Constructs/Service.hs b/src/Nirum/Constructs/Service.hs index ffe00fd..b4726f9 100644 --- a/src/Nirum/Constructs/Service.hs +++ b/src/Nirum/Constructs/Service.hs @@ -1,4 +1,5 @@ module Nirum.Constructs.Service ( Method ( Method + , errorType , methodAnnotations , methodName , parameters diff --git a/src/Nirum/Targets/Python.hs b/src/Nirum/Targets/Python.hs index 872128d..320660a 100644 --- a/src/Nirum/Targets/Python.hs +++ b/src/Nirum/Targets/Python.hs @@ -79,6 +79,7 @@ import Nirum.Constructs.ModulePath ( ModulePath import Nirum.Constructs.Name (Name (Name)) import qualified Nirum.Constructs.Name as N import Nirum.Constructs.Service ( Method ( Method + , errorType , methodName , parameters , returnType @@ -345,10 +346,6 @@ compileFieldInitializers fields = do attributeName :: Code attributeName = toAttributeName' fieldName' - -quote :: T.Text -> T.Text -quote s = [qq|'{s}'|] - compileDocs :: Documented a => a -> Maybe ReStructuredText compileDocs = fmap render . docsBlock @@ -419,14 +416,16 @@ parameterCompiler = do ver <- getPythonVersion return $ \ n t -> case ver of Python2 -> n - Python3 -> [qq|$n: $t|] + Python3 -> [qq|$n: '{t}'|] returnCompiler :: CodeGen (ReturnType -> Code) returnCompiler = do ver <- getPythonVersion - return $ \ r -> case ver of - Python2 -> "" - Python3 -> [qq| -> $r|] + return $ \ r -> + case (ver, r) of + (Python2, _) -> "" + (Python3, "None") -> [qq| -> None|] + (Python3, _) -> [qq| -> '{r}'|] compileUnionTag :: Source -> Name -> Tag -> CodeGen Code @@ -618,7 +617,7 @@ class $className(object): def __nirum_deserialize__( {arg "cls" "type"}, {arg "value" "typing.Any"} - ){ ret $ quote className }: + ){ ret className }: return deserialize_boxed_type(cls, value) def __repr__(self){ ret "str" }: @@ -660,7 +659,7 @@ $memberNames def __nirum_deserialize__( {arg "cls" "type"}, {arg "value" "str"} - ){ ret $ quote className }: + ){ ret className }: return cls(value.replace('-', '_')) # FIXME: validate input |] compileTypeDeclaration src d@TypeDeclaration { typename = typename' @@ -735,7 +734,7 @@ class $className(object): return serialize_record_type(self) @classmethod - def __nirum_deserialize__($clsType, value){ ret $ quote className }: + def __nirum_deserialize__($clsType, value){ ret className }: return deserialize_record_type(cls, value) def __hash__(self){ret "int"}: @@ -786,7 +785,7 @@ class $className({T.intercalate "," $ compileExtendClasses annotations}): @classmethod def __nirum_deserialize__( {arg "cls" "type"}, value - ){ ret $ quote className }: + ){ ret className }: return deserialize_union_type(cls, value) @@ -832,16 +831,16 @@ compileTypeDeclaration clientMethods' = T.intercalate "\n\n" clientMethods methodErrorTypes' = T.intercalate "," $ catMaybes methodErrorTypes + param <- parameterCompiler + ret <- returnCompiler insertStandardImport "json" insertThirdPartyImports [ ("nirum.deserialize", ["deserialize_meta"]) , ("nirum.serialize", ["serialize_meta"]) ] insertThirdPartyImportsA [ ("nirum.constructs", [("name_dict_type", "NameDict")]) - , ("nirum.rpc", [ ("service_type", "Service") - , ("client_type", "Client") - ] - ) + , ("nirum.rpc", [("service_type", "Service")]) + , ("nirum.transport", [("transport_type", "Transport")]) ] return [qq| class $className(service_type): @@ -865,9 +864,19 @@ class $className(service_type): # FIXME client MUST be generated & saved on diffrent module # where service isn't included. -class {className}_Client(client_type, $className): +class {className}_Client($className): + """The client object of :class:`{className}`.""" + + def __init__(self, + { param "transport" "transport_type" }){ ret "None" }: + if not isinstance(transport, transport_type): + raise TypeError( + 'expected an instance of \{0.__module__\}.\{0.__name__\}, not ' + '\{1!r\}'.format(transport_type, transport) + ) + self.__nirum_transport__ = transport # type: transport_type + {clientMethods'} - pass |] where className :: T.Text @@ -937,30 +946,43 @@ class {className}_Client(client_type, $className): compileClientPayload :: Parameter -> CodeGen Code compileClientPayload (Parameter pName _ _) = do let pName' = toAttributeName' pName - return [qq|meta['_names']['{pName'}']: serialize_meta({pName'})|] + return [qq|'{I.toSnakeCaseText $ N.behindName pName}': + serialize_meta({pName'})|] compileClientMethod :: Method -> CodeGen Code compileClientMethod Method { methodName = mName , parameters = params , returnType = rtype + , errorType = etypeM } = do let clientMethodName' = toAttributeName' mName params' <- mapM compileMethodParameter $ toList params rtypeExpr <- compileTypeExpression src rtype + errorCode <- case etypeM of + Just e -> do + e' <- compileTypeExpression src e + return $ "result_type = " `T.append` e' + Nothing -> + return "raise UnexpectedNirumResponseError(serialized)" payloadArguments <- mapM compileClientPayload $ toList params ret <- returnCompiler return [qq| - def {clientMethodName'}(self, {commaNl params'}){ ret rtypeExpr }: - meta = self.__nirum_service_methods__['{clientMethodName'}'] - rtype = meta['_return']() if meta.get('_v', 1) >= 2 else meta['_return'] - return deserialize_meta( - rtype, - json.loads( - self.remote_call( - self.__nirum_method_names__['{clientMethodName'}'], - payload=\{{commaNl payloadArguments}\} - ) - ) + def {clientMethodName'}(self, {commaNl params'}){ret rtypeExpr}: + successful, serialized = self.__nirum_transport__( + '{I.toSnakeCaseText $ N.behindName mName}', + payload=\{{commaNl payloadArguments}\}, + # FIXME Give annotations. + service_annotations=\{\}, + method_annotations=\{\}, + parameter_annotations=\{\} ) + if successful: + result_type = $rtypeExpr + else: + $errorCode + result = deserialize_meta(result_type, serialized) + if successful: + return result + raise result |] compileTypeDeclaration _ Import {} = diff --git a/test/python/primitive_test.py b/test/python/primitive_test.py index d882d87..c488366 100644 --- a/test/python/primitive_test.py +++ b/test/python/primitive_test.py @@ -3,7 +3,7 @@ from pytest import raises from nirum.rpc import Service -from six import PY3, text_type +from six import PY3 from fixture.foo import (CultureAgnosticName, EastAsianName, EvaChar, FloatUnbox, Gender, ImportedTypeUnbox, Irum, @@ -238,9 +238,11 @@ def test_service(): assert getattr(PingService, '__nirum_schema_version__') == '0.3.0' assert getattr(NullService, '__nirum_schema_version__') == '0.3.0' if PY3: - assert set(PingService.ping.__annotations__) == {'nonce', 'return'} - assert PingService.ping.__annotations__['nonce'] is text_type - assert PingService.ping.__annotations__['return'] is bool + import typing + annots = typing.get_type_hints(PingService.ping) + assert set(annots) == {'nonce', 'return'} + assert annots['nonce'] is str + assert annots['return'] is bool with raises(NotImplementedError): PingService().ping(u'nonce') with raises(NotImplementedError): diff --git a/tox.ini b/tox.ini index 6b5133b..034496c 100644 --- a/tox.ini +++ b/tox.ini @@ -39,9 +39,9 @@ changedir = {envtmpdir} whitelist_externals = mkdir commands = - python -m wget -o master.zip https://github.com/spoqa/nirum-python/archive/master.zip - python -m zipfile -e master.zip . - python -c 'import glob, os.path; [os.rename(f, os.path.join(".", os.path.basename(f))) for f in glob.glob("nirum-python-master/*")]' + python -m wget -o devruntime.zip https://github.com/{env:DEVRUNTIME_REPO:spoqa/nirum-python}/archive/{env:DEVRUNTIME_REF:master}.zip + python -m zipfile -e devruntime.zip . + python -c 'import glob, os.path; [os.rename(f, os.path.join(".", os.path.basename(f))) for f in glob.glob("nirum-python-*/*")]' python setup.py sdist bdist_wheel mkdir {distdir} python -c 'import glob, os, sys; [os.rename(f, os.path.join(sys.argv[1], os.path.basename(f))) for f in glob.glob("dist/nirum-*")]' {distdir} From b8cd0fc92093d6f8e8f4fefbe61dd5910b7ce965 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Mon, 10 Jul 2017 04:20:34 +0900 Subject: [PATCH 2/5] Import Service from nirum.service instead of nirum.rpc --- src/Nirum/Targets/Python.hs | 2 +- test/python/primitive_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nirum/Targets/Python.hs b/src/Nirum/Targets/Python.hs index 320660a..5a3b845 100644 --- a/src/Nirum/Targets/Python.hs +++ b/src/Nirum/Targets/Python.hs @@ -839,7 +839,7 @@ compileTypeDeclaration ] insertThirdPartyImportsA [ ("nirum.constructs", [("name_dict_type", "NameDict")]) - , ("nirum.rpc", [("service_type", "Service")]) + , ("nirum.service", [("service_type", "Service")]) , ("nirum.transport", [("transport_type", "Transport")]) ] return [qq| diff --git a/test/python/primitive_test.py b/test/python/primitive_test.py index c488366..87b5198 100644 --- a/test/python/primitive_test.py +++ b/test/python/primitive_test.py @@ -2,7 +2,7 @@ import enum from pytest import raises -from nirum.rpc import Service +from nirum.service import Service from six import PY3 from fixture.foo import (CultureAgnosticName, EastAsianName, From a9e8a46e4b698db9785c7aae4e2b4f7dbd78f1f4 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Mon, 10 Jul 2017 05:31:59 +0900 Subject: [PATCH 3/5] Link nirum-python-{http,wsgi} --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4cbccf9..3b69f13 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,10 @@ on GitHub! - [nirum-python](https://github.com/spoqa/nirum-python): The official Python runtime library for Nirum. + - [nirim-python-http](https://github.com/spoqa/nirum-python-http): + Nirum HTTP transport for Python. + - [nirum-python-wsgi](https://github.com/spoqa/nirum-python-wsgi): + Adapt Nirum services to WSGI apps. [7]: https://github.com/search?q=topic:nirum+fork:false [8]: https://github.com/blog/2309-introducing-topics From 7a5883a5474000fe33ed57441d14d14b156add92 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Tue, 11 Jul 2017 20:28:53 +0900 Subject: [PATCH 4/5] Disable parallel build on AppVeyor CI See also https://github.com/commercialhaskell/stack/issues/2617 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index afab8a9..a31b696 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -39,7 +39,7 @@ after_build: - ps: ls - ps: upx.exe -9 nirum-win-${env:PLATFORM}.exe test_script: -- stack test +- stack --no-terminal test --jobs 1 - C:\Python36\Scripts\tox -e devruntime - C:\Python36\Scripts\tox artifacts: From aacdfa1bca2f57356de3392174b79ca9a54eece0 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Tue, 11 Jul 2017 01:51:21 +0900 Subject: [PATCH 5/5] Temporarily test using dahlia/nirum-python/transport --- .travis.yml | 3 +++ appveyor.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index a06c552..ed53b30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,9 @@ matrix: - python3.6 - libgmp10 - upx-ucl +env: +# Remove following environment variables after nirum-python 0.6.0 is released. +- DEVRUNTIME_REPO=dahlia/nirum-python DEVRUNTIME_REF=transport cache: directories: - "$HOME/.stack" diff --git a/appveyor.yml b/appveyor.yml index a31b696..9e49cff 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,9 @@ platform: - x64 environment: STACK_ROOT: C:\sr +# Remove following environment variables after nirum-python 0.6.0 is released. + DEVRUNTIME_REPO: dahlia/nirum-python + DEVRUNTIME_REF: transport cache: - '%STACK_ROOT% -> appveyor.yml' - '%LOCALAPPDATA%\Programs\stack -> appveyor.yml'