-
Notifications
You must be signed in to change notification settings - Fork 685
Add type hints For eth/utils module #1404
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
Conversation
@cburgdorf I have done the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great start! Main problem seems that you silenced a bunch of errors in tox.ini
which are caused by these changes. Also left some inline comments.
tox.ini
Outdated
@@ -104,7 +104,8 @@ commands= | |||
{[common-lint]commands} | |||
flake8 {toxinidir}/tests --exclude="trinity,p2p" | |||
# TODO: Drop --ignore-missing-imports once we have type annotations for eth_utils, coincurve and cytoolz | |||
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional --check-untyped-defs --disallow-incomplete-defs -p eth | |||
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional --check-untyped-defs --disallow-incomplete-defs --disallow-untyped-defs --disallow-any-generics eth/utils |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This silences all type errors in the eth
module except those that are in eth.utils
. The tox.ini
setup should continue to be what it is today. As soon as you have finished one of the bigger chunks (eth.tools
, eth.vm
) you can add an additional check for those. This will essentially result in slightly increased type checking time as it means we are checking the entire eth
module with less restrictive checks and then eth.tools
(or eth.vm
) again but with stricter checks. That's why I consider it impractical to add additional checks for each and every submodule now.
In the ideal case, it will just be a short period of days where type checks are less strict in CI compared to the actual type hints being used. Then, once the entire library has been properly typed, we activate the stricter checks for the entire eth
module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cburgdorf how about just two mypy runs? one that has the current config and one that we slowly expand to cover only the modules which have been updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pipermerriam yes, that's my plan. I just think we do not need to do it for each and every submodule (hence,eth.tools
, eth.vm
, then the rest) especially if we consider this whole thing to be finished over the course of the next, say, two weeks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cburgdorf got it. But since I have started on eth.utils
first unfortunately, how about we have one mypy for the normal configuration that we see today, one for the eth.utils
submodule and one for the presently working submodule (eth.tools
and eth.vm
)? Please correct me if I am missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool with me!
eth/utils/bls.py
Outdated
final_exponentiation = final_exponentiate( | ||
pairing(decompress_G2(sig), G1, False) * | ||
pairing(hash_to_G2(m), neg(decompress_G1(pub)), False) | ||
) | ||
return final_exponentiation == FQ12.one() | ||
|
||
|
||
def aggregate_sigs(sigs): | ||
def aggregate_sigs(sigs: List[Tuple[int, int]]) -> Tuple[int, int]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be def aggregate_sigs(sigs: Iterable[Tuple[int, int]]) -> Tuple[int, int]:
eth/utils/bls.py
Outdated
o = Z2 | ||
for s in sigs: | ||
o = add(o, decompress_G2(s)) | ||
return compress_G2(o) | ||
|
||
|
||
def aggregate_pubs(pubs): | ||
def aggregate_pubs(pubs: List[int]) -> int: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, can be Iterable[int]
eth/utils/db.py
Outdated
for account, account_data in state_dict.items(): | ||
assert isinstance(account_data["balance"], int) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These assert
statements may be problematic as they involve a runtime cost. This may not be a big problem for this particular piece of code but I think we could get rid of them if we used something like a TypedDict
here. /cc @pipermerriam @carver
@@ -69,12 +72,13 @@ def is_odd(value: int) -> bool: | |||
return value % 2 == 1 | |||
|
|||
|
|||
def get_highest_bit_index(value): | |||
def get_highest_bit_index(value: int) -> int: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the preferred way is:
def get_highest_bit_index(value: int) -> int:
value >>= 1
for bit_length in itertools.count():
if not value:
return bit_length
value >>= 1
raise Exception("Invariant: unreachable code path")
eth/utils/rlp.py
Outdated
BaseBlock, | ||
) | ||
|
||
DiffObjectType = Union[None, Iterable[Tuple[str, str, str]]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Union[None, Something]
should be equivalent to Optional[Something]
but the latter reads more naturally
eth/utils/state.py
Outdated
for account, account_data in sorted(expected_state.items()): | ||
assert isinstance(account_data['balance'], int) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here about the assert
statements. TypedDict
should help.
I added the mypy-extensions module to |
@Bhargavasomu it comes with py-evm/trinity/protocol/common/handlers.py Lines 59 to 69 in e68e7c3
|
# 'balance', 'nonce' -> int | ||
# 'code' -> bytes | ||
# 'storage' -> Dict[int, int] | ||
AccountDetails = TypedDict('AccountDetails', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️
tox.ini
Outdated
@@ -104,7 +104,9 @@ commands= | |||
{[common-lint]commands} | |||
flake8 {toxinidir}/tests --exclude="trinity,p2p" | |||
# TODO: Drop --ignore-missing-imports once we have type annotations for eth_utils, coincurve and cytoolz | |||
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional --check-untyped-defs --disallow-incomplete-defs -p eth | |||
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional --check-untyped-defs --disallow-incomplete-defs -p eth |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you accidentally used tabs instead of four spaces here.
@cburgdorf, since the whole of |
@Bhargavasomu The type hinting command that is currently already used should stay in place until it is fully converted. We can incrementally add additional checks but should not lower the already existing checks. |
|
a.) something in This is why, even if you aim to just add type hints for module
The rules are:
To elaborate on the second point. If we decided to merge a PR that fails CI, even if it is only for type hints, it becomes hard / impossible to spot any other CI failures as |
4cf7e18
to
64030b8
Compare
@cburgdorf I have made the necessary changes so that the present |
Right, I guess
Lines 7 to 19 in e68e7c3
py-evm/trinity/protocol/common/handlers.py Lines 58 to 59 in e68e7c3
Honestly, I have no preference. Since we already use Feel free to try and pick any of both options. Chances are @carver or @pipermerriam have a stronger preference for one or the other way but it will be trivial to move back and forth so whatever moves this forward is fine by me for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking better and better! Just a couple of minor things left! 👍
eth/utils/rlp.py
Outdated
|
||
@to_tuple | ||
def diff_rlp_object(left, right): | ||
def diff_rlp_object(left: BaseBlock, right: BaseBlock) -> DiffObjectType: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is only being used once, I'd prefer to use the type in it longer form and just reformat as:
def diff_rlp_object(left: BaseBlock,
right: BaseBlock) -> Optional[Iterable[Tuple[str, str, str]]]
...
Union, | ||
) | ||
|
||
from mypy_extensions import ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on what you choose from the stated options you may need to add an if TYPECHECKING
here to only do that import under mypy
runs.
from eth_utils import ( | ||
to_tuple, | ||
) | ||
|
||
from eth_typing import ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: eth_typing
should be above eth_utils
(alphabetical order within 3rd party libraries)
eth/utils/state.py
Outdated
) | ||
|
||
|
||
# Mapping from address to account state. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can get rid of this comment now that we are using a TypedDict
eth/utils/state.py
Outdated
}) | ||
AccountState = Dict[Address, AccountDetails] | ||
|
||
DiffType = Iterable[Tuple[Address, str, Union[int, bytes], Union[int, bytes]]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rename this to AccountDiff
.
tox.ini
Outdated
@@ -105,6 +105,9 @@ commands= | |||
flake8 {toxinidir}/tests --exclude="trinity,p2p" | |||
# TODO: Drop --ignore-missing-imports once we have type annotations for eth_utils, coincurve and cytoolz | |||
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional --check-untyped-defs --disallow-incomplete-defs -p eth | |||
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional --check-untyped-defs --disallow-incomplete-defs --disallow-untyped-defs --disallow-any-generics eth/utils |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than using eth/utils
and eth/tools/builder
can you use -p eth.utils
and -p eth.tools.builder
@cburgdorf sorry for pinging you a lot, but these errors don't seem to be related to the |
The reason you are see these is because you (accidentally) changed the fixed commit of the These newer test cases do fail unless you rebase your branch against latest |
@Bhargavasomu have a look at #1412
|
@Bhargavasomu I'm going to drive this home in #1412 and apply some fine tuning on top of it. You can consider this done and move on adding type hints to other parts. Thank you for pushing this forward. Great work! 👍 I guess the learnings from this PR will make the upcoming PR chunks easier. One thing regarding commit history. I'm quite keen on getting clean semantic commits, which means if there are many wip commits, I'll squash them all together into one semantic commit. You can avoid this by cutting semantic commits yourself and force pushing into the PR. |
@cburgdorf sorry for bugging you a lot through this PR. I definitely learnt a lot which would help me type hinting the rest of the parts. Thankyou |
No problem! I know that adding types can be quite challenging in the beginning. Especially in |
What was wrong?
The
eth
module was nottype hinted
till now. This needs to be fixed and also thetox.ini
file needs to be updated.Issue : #1398
How was it fixed?
Adding
type hints
to the arguments and the function. The phase of adding the type hints is as followsCute Animal Picture