-
Notifications
You must be signed in to change notification settings - Fork 3
mypy: upgrade to 1.10.0 #156
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
Signed-off-by: Achille Roussel <[email protected]>
Signed-off-by: Achille Roussel <[email protected]>
Signed-off-by: Achille Roussel <[email protected]>
|
|
||
| primitive_func.__qualname__ = f"{name}_primitive" | ||
| primitive_func = durable(primitive_func) | ||
| durable_primitive_func = durable(primitive_func) |
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.
mypy complained here that the type of primitive_func didn't match after being wrapped by durable.
| max_age = timedelta(minutes=5) | ||
| try: | ||
| verify_request(signed_request, verification_key, max_age) | ||
| verify_request(signed_request, self.verification_key, max_age) |
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 was an actual bug.
|
|
||
|
|
||
| def status_for_error(error: Exception) -> Status: | ||
| def status_for_error(error: BaseException) -> Status: |
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.
Turned out KeyboardInterrupt is not a subclass of Exception.
| self.roundtrips: OrderedDict[DispatchID, List[RoundTrip]] = OrderedDict() | ||
| self.collect_roundtrips = collect_roundtrips |
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 simplifies call sites where we accessed the roundtrips field since it cannot be None anymore.
| assert isinstance(verification_key, Ed25519PublicKey) | ||
| assert verification_key.public_bytes_raw(), public_key2_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.
Using assert instead of the methods helped mypy understand that verification_key couldn't be None.
|
|
||
| error = Error.from_exception(original_exception) | ||
| error.traceback = "" | ||
| error.traceback = b"" |
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 was an actual bug.
| resp = self.client.post( | ||
| f"{self.endpoint}/dispatch.sdk.v1.FunctionService/Run", | ||
| data=b"a" * 16_000_001, | ||
| data={"msg": "a" * 16_000_001}, |
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.
The post method apparently expected data to be an object.
| for i, (is_null, value) in enumerate(stack if stack is not None else []): | ||
| if is_null: | ||
| print(f"stack[{i}] = NULL") | ||
| else: | ||
| print(f"stack[{i}] = {value}") | ||
| print(f"BP = {bp}") | ||
| for i, block in enumerate(blocks): | ||
| for i, block in enumerate(blocks if blocks is not None else []): |
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 would have broken in the case where stack and blocks were None.
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 mypy isn't smart enough to see that these are only None if frame_state >= FRAME_CLEARED, and that we're in a block where frame_state < FRAME_CLEARED.
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 analysis would be pretty difficult to make right? There are no constants in Python, FRAME_CLEARED could be altered concurrently by a thread, potentially in a module that imported this one.
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 don't think there are any points between checks where the GIL would be released and another thread allowed to run? There are calls to the C extension in there, but you have to explicitly release the GIL from C. mypy either assumes that all C extension calls may release the GIL, or it just doesn't propagate constraints across blocks.
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.
Assumptions about when the GIL can be released seem like asking for trouble, the rules are a bit unclear as to when this may happen; I would expect mypy not to try to be that smart because it's a lot of efforts for unclear rewards (false positives make the program safer anyways).
We could verify by pulling the value into a local instead of depending on the global FRAME_CLEARED variable.
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.
Oh but even with a local, it doesn't know that frame_state = ext.get_frame_state(g) will return a value less than FRAME_CLEARED right?
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 just tried with a local and it still complains that the values might be None)
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.
stack and blocks are set to None after frame_state is set, and if and only if frame_state < FRAME_CLEARED. The frame_state variable does not change after they're set to None.
I suspect the issue is that mypy forwards constraints into blocks, but doesn't carry them across blocks, because of potential path explosions. It seems to be smart enough to tighten types as you extend into if blocks, but in this case it doesn't carry the frame_state < FRAME_CLEARED constraint forward to an adjacent block.
No big deal, false positives are expected occasionally 🙂
|
|
||
| typecheck: | ||
| $(PYTHON) -m mypy src tests | ||
| $(PYTHON) -m mypy --check-untyped-defs src tests examples |
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.
We're doing type checks on the examples directory as well now.
Signed-off-by: Achille Roussel <[email protected]>
Signed-off-by: Achille Roussel <[email protected]>
Signed-off-by: Achille Roussel <[email protected]>
Signed-off-by: Achille Roussel <[email protected]>
…om-test-package test: drop FastAPI dependency
This PR upgrade mypy to 1.10.0, and enable
--check-untyped-defswhich does a much stricter pass. I then fixed all the type checks that were newly reported.