-
Notifications
You must be signed in to change notification settings - Fork 275
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
Enable mypy for ngclient #1489
Enable mypy for ngclient #1489
Conversation
I think there's a few cases here:
First two-three can be fixed now. The last one we can discuss... In any case this is useful work as it shows how much (or little) the lack of signed typing affects us... The download related the changes should maybe only be done after the cleanup is done in #1448 (also the SlowRetrievalError change looks a bit fishy -- I would expect it's used in the legacy code as well?) |
It's debatable whether this simplifies things for humans reading the code (edit: though, apart from the variable name ugliness and possibility for confusion of # locally scoped variable that is definitely a string, even if empty
tgt_base_url: str = self._target_base_url or ""
if target_base_url is not None:
tgt_base_url = _ensure_trailing_slash(target_base_url)
# move the check for a base URL being set to after the locally scoped
# variable assignment logic is bottomed out.
if not tgt_base_url:
raise ValueError(
"target_base_url must be set in either download_target() or "
"constructor"
) see the full diff here. |
this should also work -- the issue for mypy is two branches that seem unrelated (even if they aren't) so making the branches actually same should make the intent clear to computer...
|
e4109a0
to
89facc6
Compare
Rebased on latest changes in develop and fixed all issues but the Metadata.Signed typing ones. |
Actually
|
Right. We could reasonably silence those warnings, as we are only suggesting use of asserts to help mypy determine the expected type. But I think this further reinforces the 'code smell' of using asserts to solve this problem. |
In this case we use assert as the recommended way to deal with |
1b951fb
to
871f68c
Compare
I used the part of #1457 that makes Metadata 'Generic' to resolve the type checking issues related to the 'signed' 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.
Thanks Teodora. This is looking good. I have a minor comment on the change to the root property, and a slight pushback on the type hinting for IDE's that I would appreciate your thoughts on before we merge.
871f68c
to
ba6c672
Compare
Seems like the CI won't be triggered until I rebase and resolve the conflicts. |
4dc28d6
to
8c172af
Compare
If you researched this can you document why? looking in urllib3 git the annotations seem to be there but is that just for some future 2.0 release?
Could we add the required stub packages to test requirements instead? |
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 it looks good (but obviously the last commits depend on a commit from generics PR #1457 so I'm not approving).
This PR isn't using the whole Generics branch though: if it did then it could just remove all of the checks of type if new_root.signed.type != "root"
since the constructor would do that already
The last commit is IMO not great since it has so much code in the try-block: it's not clear that the KeyError should only happen in self.root
... I think the original code is better. Maybe the real alternative would be to not call update_root()
from init but instead do the required steps in init itself -- that seems ok to me as well as I think there aren't that many steps here.
Hmm ... I wouldn't say directly depending, I didn't cherry-pick the commit from the other PR but created a new one and added you as a co-author.
This was done intentionally but I guess I should've tried to explain my intentions somewhere in written form. The "Generics" branch tries to achieve two things simultaneously: correct type annotations of Signed and a runtime check ensuring content and type are really what we expect. Since there seems to be an agreement already on the use of Generics and an ongoing discussion around the runtime check part, I decided to include only the first part here, the one directly related to type annotations and mypy. This way we can leave the rest of the discussion for #1457 which will also make it simpler because it will try to solve only one problem. I hope you agree :) |
I tried this alternative since @joshuagl expressed some concerns about not using the 'root' property consistently inside the class. The three options, none of them perfect, would be:
There is a forth one where we keep root optional as the rest of the properties and add asserts in the code but I tried and this means asserts at 4-5 places which seems to rule out this option. |
Yeah I think the generics change is major enough that we can't just hide it in a PR titled "enable mypy for ngclient" :) We can definitely split the PR if that makes it easier to swallow though. |
Ack, let's do it. |
8c172af
to
7c3c025
Compare
Yes, the latest release is 1.26 which does not include the type annotations. I updated the commit description.
Done: d306370 |
7c3c025
to
e4a21f4
Compare
Ok, I've made the #1457 PR into a "minimal generics" PR -- this PR could be based off of that one I believe. |
e4a21f4
to
6a624f1
Compare
Rebased on #1457 and I believe I have addressed all comments so waiting for another review. |
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 good, updater.py in VSCode is much nicer now. I think this is good to go... except this will definitely clash with #1514 which I was about to merge...
@@ -348,6 +345,7 @@ def _load_snapshot(self) -> None: | |||
# Local snapshot does not exist or is invalid: update from remote | |||
logger.debug("Failed to load local snapshot %s", e) | |||
|
|||
assert self._trusted_set.timestamp is not None # nosec |
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 unfortunate... I don't have any better ideas but it looks so strange in this code.
This seems to only be needed in Updater for getting meta-info -- which is also a sort of duplicate piece of code here and in _load_targets()
... so there's probably some sort of refactoring possibility here but let's not do that in this PR.
Extend mypy to include all files under ngclient. Signed-off-by: Teodora Sechkova <[email protected]>
Add the stub for the requests package (types-requests) to requirements-tests.txt. Add urllib3 to the ignored imports. The project seems to have added type annotations already but has not released a version including them yet. Signed-off-by: Teodora Sechkova <[email protected]>
Needed in order to be compatible with the return type of download_file (TemporaryFile is typed as IO[bytes]). BinaryIO is a subclass of IO[bytes]. Signed-off-by: Teodora Sechkova <[email protected]>
Add missing annotations and partially resolve mypy errors in updater.py and trusted_metadata_set.py Signed-off-by: Teodora Sechkova <[email protected]>
This is done only for hinting 'mypy' that we have ensured these values cannot be None. 'Bandit' raises warnings for assert usage in the code but we are disabling them since we do not rely upon 'asserts' for any runtime checks but only for type checking. Signed-off-by: Teodora Sechkova <[email protected]>
The 'root' property is guaranteed to be set after init. Signed-off-by: Teodora Sechkova <[email protected]>
SlowRetrievalError is raised from RequestsFetcher where average_download_speed is not calculated. Signed-off-by: Teodora Sechkova <[email protected]>
By explicitly denoting the expected type of Metadata.signed we help mypy understand our intentions and correctly figure out types. This is entirely a typing feature and has no runtime effect. Modify the return type of Metadata.from_dict to match the other factory methods (from_*). Signed-off-by: Teodora Sechkova <[email protected]>
Add an additional private method for loading the initial trusted root metadata. The public method update_root() is now used only externally for updating the intiial root. The 'root' property is used only after its initialization in the constructor and is not longer optional which makes mypy happy. This split results in cleaner code and the ability to annotate the 'root' property as non-optional at the cost of some code duplication. Signed-off-by: Teodora Sechkova <[email protected]>
6a624f1
to
6ada96c
Compare
Rebased on latest changes in develop. |
Fixes #1409
Description of the changes being introduced by the pull request:
Enable static type checking for ngclient.
Please verify and check that the pull request fulfills the following
requirements: