Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type hints and clean up ABI code #253

Merged
merged 30 commits into from
Nov 24, 2021
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4cab7a8
Start ABI JSON interaction
algochoi Oct 27, 2021
223b05e
Add static annoation
algochoi Oct 27, 2021
bad480d
Fix Method argument parsing
algochoi Oct 27, 2021
3b6f40c
Add ABI Typing to Method arguments
algochoi Oct 29, 2021
7b732a6
Merge remote-tracking branch 'origin/develop' into algochoi/abi-inter…
algochoi Oct 29, 2021
7cf0608
[WIP] Add AtomicTransactionComposer build functions
algochoi Oct 29, 2021
58cef31
[WIP] Sign and send atomic transaction groups
algochoi Nov 1, 2021
43874b2
Add unit tests for object parsing
algochoi Nov 1, 2021
d3fe73d
Clean up method calls
algochoi Nov 3, 2021
c7f4e14
Address PR comments on JSON objects
algochoi Nov 8, 2021
72d172d
Refactor ABI Type to ABIType so it can be exposed to outside world
algochoi Nov 10, 2021
e96b740
Add cucumber steps for ABI tests and update existing implementation s…
algochoi Nov 10, 2021
e052fa7
Refactor TransactionSigner to Abstract class and merge signatures whe…
algochoi Nov 12, 2021
d55f9a6
Update testing to reflect json unit tests and composer tests
algochoi Nov 16, 2021
a748f7b
Formatting and docstring fixes
algochoi Nov 16, 2021
23f63bb
Clean up imports
algochoi Nov 16, 2021
f21ec5d
Fix unit test for appId
algochoi Nov 17, 2021
d63b4d1
Refactor some names and add txn as an arg type
algochoi Nov 18, 2021
5c9d28e
Partially address PR comments
algochoi Nov 19, 2021
9fa591a
Add some additional checks for safety
algochoi Nov 19, 2021
351099a
Fix a step so we check for empty string instead of None
algochoi Nov 19, 2021
155fc90
MInclude returns tests and check for a valid returns from a ABI call
algochoi Nov 22, 2021
2a3e6c9
Addressing PR comments about type hints and returning self
algochoi Nov 23, 2021
02a1bb0
Ensure group ids are zero when adding transactions
algochoi Nov 23, 2021
008b09a
Add type hints and clean up ABI types
algochoi Nov 24, 2021
ab72fab
Merge branch 'develop' into algochoi/abi-type-hints
algochoi Nov 24, 2021
d088d2c
Change relative imports to absolute imports
algochoi Nov 24, 2021
049d09c
Add type hints for ABI objects
algochoi Nov 24, 2021
e27e0df
Refactor composer with type hints
algochoi Nov 24, 2021
9b9de57
Address PR comments, change list type hints, and move type_from_strin…
algochoi Nov 24, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions algosdk/abi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from .util import type_from_string
from .uint_type import UintType
from .ufixed_type import UfixedType
from .base_type import ABIType
from .bool_type import BoolType
from .byte_type import ByteType
from .address_type import AddressType
from .string_type import StringType
from .array_dynamic_type import ArrayDynamicType
from .array_static_type import ArrayStaticType
from .tuple_type import TupleType
from algosdk.abi.uint_type import UintType
algochoi marked this conversation as resolved.
Show resolved Hide resolved
from algosdk.abi.ufixed_type import UfixedType
from algosdk.abi.base_type import ABIType
from algosdk.abi.bool_type import BoolType
from algosdk.abi.byte_type import ByteType
from algosdk.abi.address_type import AddressType
from algosdk.abi.string_type import StringType
from algosdk.abi.array_dynamic_type import ArrayDynamicType
from algosdk.abi.array_static_type import ArrayStaticType
from algosdk.abi.tuple_type import TupleType
from .method import Method, Argument, Returns
from .interface import Interface
from .contract import Contract
Expand Down
22 changes: 12 additions & 10 deletions algosdk/abi/address_type.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from .base_type import ABIType
algochoi marked this conversation as resolved.
Show resolved Hide resolved
from .byte_type import ByteType
from .tuple_type import TupleType
from .. import error
from typing import Union

from algosdk.abi.base_type import ABIType
from algosdk.abi.byte_type import ByteType
from algosdk.abi.tuple_type import TupleType
from algosdk import error

from algosdk import encoding

Expand All @@ -14,18 +16,18 @@ class AddressType(ABIType):
def __init__(self) -> None:
super().__init__()

def __eq__(self, other) -> bool:
def __eq__(self, other: object) -> bool:
if not isinstance(other, AddressType):
return False
return True

def __str__(self):
def __str__(self) -> str:
return "address"

def byte_len(self):
def byte_len(self) -> int:
return 32

def is_dynamic(self):
def is_dynamic(self) -> bool:
return False

def _to_tuple_type(self):
Expand All @@ -34,7 +36,7 @@ def _to_tuple_type(self):
child_type_array.append(ByteType())
return TupleType(child_type_array)

def encode(self, value):
def encode(self, value: Union[str, bytes]) -> bytes:
"""
Encode an address string or a 32-byte public key into a Address ABI bytestring.

Expand Down Expand Up @@ -62,7 +64,7 @@ def encode(self, value):
)
return bytes(value)

def decode(self, bytestring):
def decode(self, bytestring: Union[bytearray, bytes]) -> bytes:
algochoi marked this conversation as resolved.
Show resolved Hide resolved
"""
Decodes a bytestring to a base32 encoded address string.

Expand Down
30 changes: 16 additions & 14 deletions algosdk/abi/array_dynamic_type.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,47 @@
from .base_type import ABI_LENGTH_SIZE, ABIType
from .byte_type import ByteType
from .tuple_type import TupleType
from .. import error
from typing import NoReturn, Union

from algosdk.abi.base_type import ABI_LENGTH_SIZE, ABIType
from algosdk.abi.byte_type import ByteType
from algosdk.abi.tuple_type import TupleType
from algosdk import error


class ArrayDynamicType(ABIType):
"""
Represents a ArrayDynamic ABI Type for encoding.

Args:
child_type (Type): the type of the dynamic array.
child_type (ABIType): the type of the dynamic array.

Attributes:
child_type (Type)
child_type (ABIType)
"""

def __init__(self, arg_type) -> None:
def __init__(self, arg_type: ABIType) -> None:
super().__init__()
self.child_type = arg_type

def __eq__(self, other) -> bool:
def __eq__(self, other: object) -> bool:
if not isinstance(other, ArrayDynamicType):
return False
return self.child_type == other.child_type

def __str__(self):
def __str__(self) -> str:
return "{}[]".format(self.child_type)

def byte_len(self):
def byte_len(self) -> NoReturn:
algochoi marked this conversation as resolved.
Show resolved Hide resolved
raise error.ABITypeError(
"cannot get length of a dynamic type: {}".format(self)
)

def is_dynamic(self):
def is_dynamic(self) -> bool:
return True

def _to_tuple_type(self, length):
def _to_tuple_type(self, length: int) -> TupleType:
child_type_array = [self.child_type] * length
return TupleType(child_type_array)

def encode(self, value_array):
def encode(self, value_array: Union[list, bytes, bytearray]) -> bytes:
"""
Encodes a list of values into a ArrayDynamic ABI bytestring.

Expand Down Expand Up @@ -67,7 +69,7 @@ def encode(self, value_array):
encoded = converted_tuple.encode(value_array)
return bytes(length_to_encode) + encoded

def decode(self, array_bytes):
def decode(self, array_bytes: Union[bytes, bytearray]) -> list:
"""
Decodes a bytestring to a dynamic list.

Expand Down
35 changes: 18 additions & 17 deletions algosdk/abi/array_static_type.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,63 @@
import math
from typing import Union

from .base_type import ABIType
from .bool_type import BoolType
from .byte_type import ByteType
from .tuple_type import TupleType
from .. import error
from algosdk.abi.base_type import ABIType
from algosdk.abi.bool_type import BoolType
from algosdk.abi.byte_type import ByteType
from algosdk.abi.tuple_type import TupleType
from algosdk import error


class ArrayStaticType(ABIType):
"""
Represents a ArrayStatic ABI Type for encoding.

Args:
child_type (Type): the type of the child_types array.
static_length (int): length of the static array.
child_type (ABIType): the type of the child_types array.
array_len (int): length of the static array.

Attributes:
child_type (Type)
child_type (ABIType)
static_length (int)
"""

def __init__(self, arg_type, array_len) -> None:
def __init__(self, arg_type: ABIType, array_len: int) -> None:
if array_len < 1:
raise error.ABITypeError(
"static array length must be a positive integer: {}".format(
len(array_len)
algochoi marked this conversation as resolved.
Show resolved Hide resolved
array_len
)
)
super().__init__()
self.child_type = arg_type
self.static_length = array_len

def __eq__(self, other) -> bool:
def __eq__(self, other: object) -> bool:
if not isinstance(other, ArrayStaticType):
return False
return (
self.child_type == other.child_type
and self.static_length == other.static_length
)

def __str__(self):
def __str__(self) -> str:
return "{}[{}]".format(self.child_type, self.static_length)

def byte_len(self):
def byte_len(self) -> int:
if isinstance(self.child_type, BoolType):
# 8 Boolean values can be encoded into 1 byte
return math.ceil(self.static_length / 8)
element_byte_length = self.child_type.byte_len()
return self.static_length * element_byte_length

def is_dynamic(self):
def is_dynamic(self) -> bool:
return self.child_type.is_dynamic()

def _to_tuple_type(self):
def _to_tuple_type(self) -> TupleType:
child_type_array = [self.child_type] * self.static_length
return TupleType(child_type_array)

def encode(self, value_array):
def encode(self, value_array: Union[list, bytes, bytearray]) -> bytes:
"""
Encodes a list of values into a ArrayStatic ABI bytestring.

Expand Down Expand Up @@ -87,7 +88,7 @@ def encode(self, value_array):
converted_tuple = self._to_tuple_type()
return converted_tuple.encode(value_array)

def decode(self, array_bytes):
def decode(self, array_bytes: Union[bytes, bytearray]) -> list:
"""
Decodes a bytestring to a static list.

Expand Down
17 changes: 8 additions & 9 deletions algosdk/abi/base_type.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from abc import ABC, abstractmethod
from typing import Any

# Globals
ABI_LENGTH_SIZE = 2 # We use 2 bytes to encode the length of a dynamic element
Expand All @@ -9,42 +10,40 @@ class ABIType(ABC):
Represents an ABI Type for encoding.
"""

def __init__(
self,
) -> None:
def __init__(self) -> None:
pass

@abstractmethod
def __str__(self):
def __str__(self) -> str:
pass

@abstractmethod
def __eq__(self, other) -> bool:
def __eq__(self, other: object) -> bool:
pass

@abstractmethod
def is_dynamic(self):
def is_dynamic(self) -> bool:
"""
Return whether the ABI type is dynamic.
"""
pass

@abstractmethod
def byte_len(self):
def byte_len(self) -> int:
"""
Return the length in bytes of the ABI type.
"""
pass

@abstractmethod
def encode(self, value):
def encode(self, value: Any) -> bytes:
"""
Serialize the ABI value into a byte string using ABI encoding rules.
"""
pass

@abstractmethod
def decode(self, bytestring):
def decode(self, bytestring: bytes) -> Any:
"""
Deserialize the ABI type and value from a byte string using ABI encoding rules.
"""
Expand Down
18 changes: 10 additions & 8 deletions algosdk/abi/bool_type.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from .base_type import ABIType
from .. import error
from typing import Union

from algosdk.abi.base_type import ABIType
from algosdk import error


class BoolType(ABIType):
Expand All @@ -10,21 +12,21 @@ class BoolType(ABIType):
def __init__(self) -> None:
super().__init__()

def __eq__(self, other) -> bool:
def __eq__(self, other: object) -> bool:
if not isinstance(other, BoolType):
return False
return True

def __str__(self):
def __str__(self) -> str:
return "bool"

def byte_len(self):
def byte_len(self) -> int:
return 1

def is_dynamic(self):
def is_dynamic(self) -> bool:
return False

def encode(self, value):
def encode(self, value: bool) -> bytes:
"""
Encode a boolean value

Expand All @@ -40,7 +42,7 @@ def encode(self, value):
return b"\x80"
return b"\x00"

def decode(self, bytestring):
def decode(self, bytestring: Union[bytes, bytearray]) -> bool:
"""
Decodes a bytestring to a single boolean.

Expand Down
18 changes: 10 additions & 8 deletions algosdk/abi/byte_type.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from .base_type import ABIType
from .. import error
from typing import Union

from algosdk.abi.base_type import ABIType
from algosdk import error


class ByteType(ABIType):
Expand All @@ -10,21 +12,21 @@ class ByteType(ABIType):
def __init__(self) -> None:
super().__init__()

def __eq__(self, other) -> bool:
def __eq__(self, other: object) -> bool:
if not isinstance(other, ByteType):
return False
return True

def __str__(self):
def __str__(self) -> str:
return "byte"

def byte_len(self):
def byte_len(self) -> int:
return 1

def is_dynamic(self):
def is_dynamic(self) -> bool:
return False

def encode(self, value):
def encode(self, value: int) -> bytes:
"""
Encode a single byte or a uint8

Expand All @@ -40,7 +42,7 @@ def encode(self, value):
)
return bytes([value])

def decode(self, bytestring):
def decode(self, bytestring: Union[bytes, bytearray]) -> bytes:
"""
Decodes a bytestring to a single byte.

Expand Down
Loading