Permalink
Browse files

Make Python target to generate client w/ transport

  • Loading branch information...
dahlia committed Jun 29, 2017
1 parent 5803b64 commit a773e1000d982bc21a25c4647136b3babd377f8b
Showing with 62 additions and 37 deletions.
  1. +1 −0 src/Nirum/Constructs/Service.hs
  2. +52 −30 src/Nirum/Targets/Python.hs
  3. +6 −4 test/python/primitive_test.py
  4. +3 −3 tox.ini
@@ -1,4 +1,5 @@
module Nirum.Constructs.Service ( Method ( Method
, errorType
, methodAnnotations
, methodName
, parameters
@@ -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 {} =
@@ -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):
View
@@ -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}

0 comments on commit a773e10

Please sign in to comment.