-
Notifications
You must be signed in to change notification settings - Fork 192
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
Bump mypy version to ~=1.13.0 #6630
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #6630 +/- ##
==========================================
+ Coverage 77.51% 77.90% +0.40%
==========================================
Files 560 567 +7
Lines 41444 42147 +703
==========================================
+ Hits 32120 32831 +711
+ Misses 9324 9316 -8 ☔ View full report in Codecov by Sentry. 🚨 Try these New Features:
|
I suspect that the sudden pre-commit failures are due to a new pydantic version 2.10 which was released yesterday. |
Right, but the pydantic type errors didn't show up with the new mypy, so I think we just bump mypy and solve the new issues here. |
It's not because of mypy, they actually released a patch version 2.10.1 that appear to fix some of the issues. But I agree that we might as well bump mypy. |
Here are all errors fixed:
|
It seems last commit change fail the test. |
@@ -41,7 +41,7 @@ class Model(BaseModel): | |||
field_info = Field(default, **kwargs) | |||
|
|||
for key, value in (('priority', priority), ('short_name', short_name), ('option_cls', option_cls)): | |||
if value is not None: | |||
if value is not None and field_info is not 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.
Field
seems can return None, if so the field_info
won't have metadata
attribute.
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.
Nice fix. cc @edan-bainglass for visibility
@@ -1062,7 +1062,7 @@ def presubmit(self, folder: Folder) -> CalcInfo: | |||
|
|||
def encoder(obj): | |||
if dataclasses.is_dataclass(obj): | |||
return dataclasses.asdict(obj) | |||
return dataclasses.asdict(obj) # type: ignore[arg-type] |
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.
Not sure I should cast the type here, for the readability, I ignore the error.
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.
Would try to solve this in a subsequent PR
@@ -17,7 +17,7 @@ class Model(BaseModel): | |||
union_type: t.Union[int, float] = Field(title='Union type') | |||
without_default: str = Field(title='Without default') | |||
with_default: str = Field(title='With default', default='default') | |||
with_default_factory: str = Field(title='With default factory', default_factory=lambda: True) | |||
with_default_factory: str = Field(title='With default factory', default_factory=lambda: True) # type: ignore[assignment] |
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.
It is test, so I just ignore it.
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.
Actually, when I run mypy 1.13 on this, the # type: ignore[assignment]
is not necessary?
@@ -278,7 +278,7 @@ def array_list_checker(array_list, array_name, orb_length): | |||
raise exceptions.ValidationError('Tags must set a list of strings') | |||
self.base.attributes.set('tags', tags) | |||
|
|||
def set_orbitals(self, **kwargs): | |||
def set_orbitals(self, **kwargs): # type: ignore[override] |
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'll just leave kwargs
as it is and ignore type checking.
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.
Can you add a TODO comment with the error? The mypy error suggests that this is an actual error? Or do you think it's a false positive?
projection.py:281: error: Signature of "set_orbitals" incompatible with supertype "OrbitalData" [override]
projection.py:281: note: Superclass:
projection.py:281: note: def set_orbitals(self, orbitals: Any) -> Any
projection.py:281: note: Subclass:
projection.py:281: note: def set_orbitals(self, **kwargs: Any) -> Any
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.
Neither, I think it is a design issue to use inheritance everywhere in the code base. Here it makes sense that the ProjectionData is only inheritant from ArrayData
. For reduce the code duplication, can move the shared methods to dedicate functions or classes. It requires the actual use case of ProjectionData
which I think it is in aiida-quantumespresso.
But since this method is just to override and block the method, so the type in the function call doesn't matter. Just ignore to skip the checker.
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.
Can we just merge it and if this is a problem make an issue out of it?
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.
Yes, I move this change to #6635, so let's continue the discussion there.
ea70514
to
ac5473e
Compare
@@ -116,7 +116,7 @@ def test(submit_and_await): | |||
from aiida.engine import ProcessState | |||
|
|||
def factory( | |||
submittable: 'Process' | 'ProcessBuilder' | 'ProcessNode', | |||
submittable: type[Process] | 'ProcessBuilder' | 'ProcessNode' | t.Any, |
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.
Why is t.Any
needed here? This makes the type checking weaker, would be nice if we could avoid it.
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.
Because there is an else branch otherwise the branch is unreachable.
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.
Yes, makes sense, sorry I originally missed your comment with the errors.
I think the correct fix here is to add type ignores on those branches, since those essentially represent runtime type checking, which we need to enforce. At the same time we don't want to make static type checking weaker.
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 may not fully agree. I think types in the function signature plays two functionalities. On the one hand, it partially is the hint for the function behavior, like in this case in the function body it requires to explicitly deal with three types and raise if it doesn't know what to do with certain type. On the other hand, the type in the function signature is for other function to know what should be passed to the function when it is called.
Ideally the # type: ignore
should all be addressed.
If we just rely on runtime type check, then the type should be t.Any
. Here I still think it is better to have types as I changed.
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.
Ideally the # type: ignore should all be addressed.
I agree with this sentiment, but introducing Any
is just another way to silence type checking. :-) I would argue that in this case Any
is worse, since it "turns off" type checking of this parameter for the whole function, whereas the "type: ignore" would only target a specific part of the code. In this case, there is a real tension between static and runtime type checking: the else branches that are "unreachable" to the static type checker, but static types are not enforce at runtime in Python, and we can't enforce users to use mypy (e.g. in plugins that use this fixture), hence the additional runtime check.
If we just rely on runtime type check, then the type should be t.Any
But we don't want to rely on runtime checks only. If we can catch it statically that's certainly better, no?
Sorry if I am being terse, I am teaching now, am happy to write more later today if needed.
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 correct thing to do here is to NOT change the type annotation, since it was correct.
add type: ignore to the else branch, where the error originates.
The error is not really about type annotation, but about unreachable code. But we already know that branch is unreachable, unless the user screws up and passes a wrong type.
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.
Process
-> type[Process]
should be a correct change, in this function, it expect both workchain and calcjob which are subclass of Process
. If it is just Process, then the issubclass(submittable, Process)
part is useless because and
shortcut the condition.
We can have a zoom chat if you like, can be easier.
I agree that the t.Any
is not necessary since we won't expect the function is used besides those three types. But after change to type[Process]
which I think it is correct, there is not need to add ignore anywhere to make mypy work.
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.
Again, I personally don't like the way how subclass of Process
implemented here. I think this is a place where the duck typing should used. Then with using python protocol, the generic submit
function can just expect the class it calls has a submit method.
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.
In mega office, we decide to merge this one and continue the discussion here to not block other PRs. @danielhollas hope you don't mind.
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.
Sure, go ahead
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.
Thanks @unkcpz! Can you revert the changes to src/aiida/orm/nodes/data/list.py
and only add type: ignore, so we can merge this, and make a separate PR for those changes? Otherwise LGTM
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.
LGTM. Thanks for taking the time to look into this, @unkcpz!
@@ -17,7 +17,7 @@ class Model(BaseModel): | |||
union_type: t.Union[int, float] = Field(title='Union type') | |||
without_default: str = Field(title='Without default') | |||
with_default: str = Field(title='With default', default='default') | |||
with_default_factory: str = Field(title='With default factory', default_factory=lambda: True) | |||
with_default_factory: str = Field(title='With default factory', default_factory=lambda: True) # type: ignore[assignment] |
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.
Actually, when I run mypy 1.13 on this, the # type: ignore[assignment]
is not necessary?
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.
LGTM. Thanks for taking the time to look into this, @unkcpz!
This is the one required by the new pydantic. If you update the pydantic to 2.10.1 you can probably see this. |
[pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci
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.
Please merge because it is blocking all PRs, we can put another PR to fix the remaining small issues.
@@ -278,7 +278,7 @@ def array_list_checker(array_list, array_name, orb_length): | |||
raise exceptions.ValidationError('Tags must set a list of strings') | |||
self.base.attributes.set('tags', tags) | |||
|
|||
def set_orbitals(self, **kwargs): | |||
def set_orbitals(self, **kwargs): # type: ignore[override] |
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.
Can we just merge it and if this is a problem make an issue out of it?
@@ -1062,7 +1062,7 @@ def presubmit(self, folder: Folder) -> CalcInfo: | |||
|
|||
def encoder(obj): | |||
if dataclasses.is_dataclass(obj): | |||
return dataclasses.asdict(obj) | |||
return dataclasses.asdict(obj) # type: ignore[arg-type] |
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.
Would try to solve this in a subsequent PR
@@ -38,7 +38,7 @@ def __init__(self): | |||
def logger(self) -> Logger: | |||
return self._logger | |||
|
|||
def get_version_info(self, plugin: str | type) -> dict[t.Any, dict[t.Any, t.Any]]: |
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.
@unkcpz FYI I think this has a similar issue that we discussed, I don't think adding Any here is correct. Let's discuss on the other PR, but just flagging it here as well so we don't forget.
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 original error was:
src/aiida/plugins/utils.py:67: error: Subclass of "str" and "FunctionType" cannot exist: "FunctionType" is final [unreachable]
src/aiida/plugins/utils.py:67: error: Subclass of "type" and "FunctionType" cannot exist: "FunctionType" is final [unreachable]
Still struggling to understand, will need to experiment a bit.
~=1.13.0