Skip to content

Commit

Permalink
Change Subroutine Wrapped Callable to a class with call method (algor…
Browse files Browse the repository at this point in the history
…and#171)

Allows for more information (name, return type, has return) about the subroutine extractable from wrapped fnImpl by subroutine
  • Loading branch information
ahangsu authored and algoidurovic committed Mar 23, 2022
1 parent b6b2439 commit 8ccc2fa
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 18 deletions.
1 change: 1 addition & 0 deletions pyteal/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ __all__ = [
"SubroutineDefinition",
"SubroutineDeclaration",
"SubroutineCall",
"SubroutineFnWrapper",
"ScratchSlot",
"ScratchLoad",
"ScratchStore",
Expand Down
2 changes: 2 additions & 0 deletions pyteal/ast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
SubroutineDefinition,
SubroutineDeclaration,
SubroutineCall,
SubroutineFnWrapper,
)
from .while_ import While
from .for_ import For
Expand Down Expand Up @@ -221,6 +222,7 @@
"SubroutineDefinition",
"SubroutineDeclaration",
"SubroutineCall",
"SubroutineFnWrapper",
"ScratchSlot",
"ScratchLoad",
"ScratchStore",
Expand Down
58 changes: 41 additions & 17 deletions pyteal/ast/subroutine.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from typing import Callable, Tuple, List, Optional, cast, TYPE_CHECKING
from typing import Callable, List, Optional, TYPE_CHECKING
from inspect import Parameter, signature
from functools import wraps

from ..types import TealType, require_type
from ..types import TealType
from ..ir import TealOp, Op, TealBlock
from ..errors import TealInputError, verifyTealVersion
from .expr import Expr
Expand Down Expand Up @@ -167,6 +166,39 @@ def has_return(self):
SubroutineCall.__module__ = "pyteal"


class SubroutineFnWrapper:
def __init__(
self,
fnImplementation: Callable[..., Expr],
returnType: TealType,
name: str = None,
) -> None:
self.subroutine = SubroutineDefinition(
fnImplementation, returnType=returnType, nameStr=name
)

def __call__(self, *args: Expr, **kwargs) -> Expr:
if len(kwargs) != 0:
raise TealInputError(
"Subroutine cannot be called with keyword arguments. Received keyword arguments: {}".format(
",".join(kwargs.keys())
)
)
return self.subroutine.invoke(list(args))

def name(self) -> str:
return self.subroutine.name()

def type_of(self):
return self.subroutine.getDeclaration().type_of()

def has_return(self):
return self.subroutine.getDeclaration().has_return()


SubroutineFnWrapper.__module__ = "pyteal"


class Subroutine:
"""Used to create a PyTeal subroutine from a Python function.
Expand Down Expand Up @@ -194,20 +226,12 @@ def __init__(self, returnType: TealType, name: str = None) -> None:
self.returnType = returnType
self.name = name

def __call__(self, fnImplementation: Callable[..., Expr]) -> Callable[..., Expr]:
subroutine = SubroutineDefinition(fnImplementation, self.returnType, self.name)

@wraps(fnImplementation)
def subroutineCall(*args: Expr, **kwargs) -> Expr:
if len(kwargs) != 0:
raise TealInputError(
"Subroutine cannot be called with keyword arguments. Received keyword arguments: {}".format(
",".join(kwargs.keys())
)
)
return subroutine.invoke(list(args))

return subroutineCall
def __call__(self, fnImplementation: Callable[..., Expr]) -> SubroutineFnWrapper:
return SubroutineFnWrapper(
fnImplementation=fnImplementation,
returnType=self.returnType,
name=self.name,
)


Subroutine.__module__ = "pyteal"
Expand Down
2 changes: 1 addition & 1 deletion pyteal/ast/subroutine_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def test_decorator():
def mySubroutine(a):
return Return()

assert callable(mySubroutine)
assert isinstance(mySubroutine, SubroutineFnWrapper)

invocation = mySubroutine(Int(1))
assert isinstance(invocation, SubroutineCall)
Expand Down

0 comments on commit 8ccc2fa

Please sign in to comment.