From d993ac247ca8afaecc72053add022fd8828c47a2 Mon Sep 17 00:00:00 2001 From: Nick Gheorghita Date: Fri, 1 Nov 2019 10:24:34 -0400 Subject: [PATCH] Add type hints to web3.main --- mypy.ini | 13 ++++++++++++ setup.py | 1 + tox.ini | 1 + web3/main.py | 58 ++++++++++++++++++++++++++++++++++------------------ 4 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000000..04cf2e47fa --- /dev/null +++ b/mypy.ini @@ -0,0 +1,13 @@ +[mypy] +warn_unused_ignores = True +ignore_missing_imports = True +strict_optional = False +check_untyped_defs = True +disallow_incomplete_defs = True +disallow_untyped_defs = True +disallow_any_generics = True +; todo: disallow untyped calls after entire web3 codebase has type hints +; disallow_untyped_calls = True +warn_redundant_casts = True +warn_unused_configs = True +strict_equality = True diff --git a/setup.py b/setup.py index bea2079133..a5ccc36057 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,7 @@ 'linter': [ "flake8==3.4.1", "isort>=4.2.15,<4.3.5", + "mypy==0.730", ], 'docs': [ "mock", diff --git a/tox.ini b/tox.ini index 2d538a2e1f..dca0fff869 100644 --- a/tox.ini +++ b/tox.ini @@ -62,3 +62,4 @@ extras=linter commands= flake8 {toxinidir}/web3 {toxinidir}/ens {toxinidir}/ethpm {toxinidir}/tests isort --recursive --check-only --diff {toxinidir}/web3/ {toxinidir}/ens/ {toxinidir}/ethpm/ {toxinidir}/tests/ + mypy -p web3.main --config-file {toxinidir}/mypy.ini diff --git a/web3/main.py b/web3/main.py index 2e30befd9e..ef095d7585 100644 --- a/web3/main.py +++ b/web3/main.py @@ -15,6 +15,10 @@ from hexbytes import ( HexBytes, ) +from typing import Any, Dict, Iterable, List, Union + +from eth_typing import HexStr, Primitives +from eth_typing.abi import TypeStr from ens import ENS from web3._utils.abi import ( @@ -28,6 +32,7 @@ ) from web3._utils.empty import ( empty, + Empty, ) from web3._utils.encoding import ( hex_encode_abi_type, @@ -43,6 +48,9 @@ from web3._utils.normalizers import ( abi_ens_resolver, ) +from web3.datastructures import ( + NamedElementOnion, +) from web3.eth import ( Eth, ) @@ -68,6 +76,10 @@ ParityPersonal, ParityShh, ) +from web3.pm import PM +from web3.providers import ( + BaseProvider, +) from web3.providers.eth_tester import ( EthereumTesterProvider, ) @@ -88,7 +100,7 @@ ) -def get_default_modules(): +def get_default_modules() -> Dict[str, Iterable[Any]]: return { "eth": (Eth,), "net": (Net,), @@ -137,7 +149,13 @@ class Web3: isChecksumAddress = staticmethod(is_checksum_address) toChecksumAddress = staticmethod(to_checksum_address) - def __init__(self, provider=None, middlewares=None, modules=None, ens=empty): + def __init__( + self, + provider: BaseProvider=None, + middlewares: List[Any]=None, + modules: Dict[str, Iterable[Any]]=None, + ens: Union[ENS, Empty]=empty + ) -> None: self.manager = self.RequestManager(self, provider, middlewares) if modules is None: @@ -150,35 +168,35 @@ def __init__(self, provider=None, middlewares=None, modules=None, ens=empty): self.ens = ens @property - def middleware_onion(self): + def middleware_onion(self) -> NamedElementOnion: return self.manager.middleware_onion @property - def provider(self): + def provider(self) -> BaseProvider: return self.manager.provider @provider.setter - def provider(self, provider): + def provider(self, provider: BaseProvider) -> None: self.manager.provider = provider @property - def clientVersion(self): + def clientVersion(self) -> int: return self.manager.request_blocking("web3_clientVersion", []) @property - def api(self): + def api(self) -> str: from web3 import __version__ return __version__ @staticmethod @deprecated_for("keccak") @apply_to_return_value(HexBytes) - def sha3(primitive=None, text=None, hexstr=None): + def sha3(primitive: Primitives=None, text: str=None, hexstr: HexStr=None) -> bytes: return Web3.keccak(primitive, text, hexstr) @staticmethod @apply_to_return_value(HexBytes) - def keccak(primitive=None, text=None, hexstr=None): + def keccak(primitive: Primitives=None, text: str=None, hexstr: HexStr=None) -> bytes: if isinstance(primitive, (bytes, int, type(None))): input_bytes = to_bytes(primitive, hexstr=hexstr, text=text) return eth_utils_keccak(input_bytes) @@ -194,11 +212,11 @@ def keccak(primitive=None, text=None, hexstr=None): @combomethod @deprecated_for("solidityKeccak") - def soliditySha3(cls, abi_types, values): + def soliditySha3(cls, abi_types: List[TypeStr], values: List[Any]) -> bytes: return cls.solidityKeccak(abi_types, values) @combomethod - def solidityKeccak(cls, abi_types, values): + def solidityKeccak(cls, abi_types: List[TypeStr], values: List[Any]) -> bytes: """ Executes keccak256 exactly as Solidity does. Takes list of abi_types as inputs -- `[uint24, int8[], bool]` @@ -223,27 +241,28 @@ def solidityKeccak(cls, abi_types, values): )) return cls.keccak(hexstr=hex_string) - def isConnected(self): + def isConnected(self) -> bool: return self.provider.isConnected() - def is_encodable(self, _type, value): + def is_encodable(self, _type: TypeStr, value: Any) -> bool: return self.codec.is_encodable(_type, value) @property - def ens(self): + def ens(self) -> Union[ENS, Empty]: if self._ens is empty: return ENS.fromWeb3(self) else: return self._ens @ens.setter - def ens(self, new_ens): + def ens(self, new_ens: Union[ENS, Empty]) -> None: self._ens = new_ens @property - def pm(self): + def pm(self) -> PM: if hasattr(self, '_pm'): - return self._pm + # ignored b/c property is dynamically set via enable_unstable_package_management_api + return self._pm # type: ignore else: raise AttributeError( "The Package Management feature is disabled by default until " @@ -251,10 +270,9 @@ def pm(self): "`w3.enable_unstable_package_management_api()` and try again." ) - def enable_unstable_package_management_api(self): - from web3.pm import PM + def enable_unstable_package_management_api(self) -> None: if not hasattr(self, '_pm'): PM.attach(self, '_pm') - def enable_strict_bytes_type_checking(self): + def enable_strict_bytes_type_checking(self) -> None: self.codec = ABICodec(build_strict_registry())