Skip to content
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

Use strict mypy settings globally #613

Merged
merged 8 commits into from
May 3, 2020

Conversation

bhrutledge
Copy link
Contributor

I think this completes the bulk of the work in #231 (comment); I'll follow-up with some more housekeeping PR's..

Changes:

  • Remove module whitelist in mypy.ini
  • Add missing annotations
  • Normalize return type of cli.dispatch to bool

If folks are curious, you can the coverage report at https://twine-mypy.now.sh/. Here's a "before & after" of the current effort:

twine_mypy_coverage

Thanks @deveshks for helping us get here!

twine/cli.py Outdated
@@ -70,4 +69,4 @@ def dispatch(argv: List[str]) -> Any:

main = registered_commands[args.command].load()

return main(args.args)
return bool(main(args.args))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a change in behavior, but I think it results in the same outcome in __main__, where it's used as the argument to sys.exit. It felt cleaner than returning an Optional[bool], which I did in 26357ba.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we just never returned anything? What's returning a bool? Why would we want to return a bool here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I'd like to keep return here to signal the end of execution but ensure that any sub-command we have doesn't return anything

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I could have been clearer there. I added a comment, but register() and upload() returns None, while check() has returned bool since it was added in #395.

def check(dists: List[str], output_stream: IO[str] = sys.stdout) -> bool:

Should that change?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather bring that in-line with everything else. I'm open to being convinced otherwise, but I see no value in returning a bool here

Copy link
Contributor Author

@bhrutledge bhrutledge May 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you suggesting that check() should return None? I think that would break release pipelines that are expecting a non-zero exit code if twine check fails. Since its inception, the bool has indicated "failure", and ends up as the argument to sys.exit().

twine/twine/__main__.py

Lines 23 to 31 in da8d62f

def main():
try:
return cli.dispatch(sys.argv[1:])
except (exceptions.TwineException, requests.HTTPError) as exc:
return "{}: {}".format(exc.__class__.__name__, exc.args[0])
if __name__ == "__main__":
sys.exit(main())

Just to check, I read up on sys.exit, and verified the shell behavior:

$ for result in None 'bool(None)' False True; do
> echo -n "$result: "
> python3 -c "import sys; sys.exit($result)"
> echo $?
> done
None: 0
bool(None): 0
False: 0
True: 1

That said, I'm not married to the bool cast, and depending on where one is reading, it might not be obvious that True means "failure". An alternative is what I did in 26357ba, which is to basically return an Optional[bool]. Or, I could take the original approach, and return Any. Or ???

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not return the actual thing instead of a bool? Yes sys.exit(bool) works but only because True and False have bad default behaviour on most python's of behaving int-ish in certain scenarios. We should be returning 0, 1, or something else and explicitly documenting those error codes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking about this a more, and reading your comment, plus this in sys.exit docs:

The optional argument arg can be an integer giving the exit status (defaulting to zero), or another type of object.... If another type of object is passed, None is equivalent to passing zero, and any other object is printed to stderr and results in an exit code of 1.

I've reverted back to returning Any in 3034635. This feels like the most accurate representation of the current behavior, which I've generally tried to preserve as much as possible in all of the typing work.

If we want to change the return value of check.main and/or cli.dispatch to int, and/or define explicit error codes, I'd rather address that in a separate issue.

@bhrutledge
Copy link
Contributor Author

Once again, I'm assuming the codecov failures are spurious.

@bhrutledge
Copy link
Contributor Author

@sigmavirus24 Is it okay if I merge this?

@sigmavirus24 sigmavirus24 merged commit a0ec139 into pypa:master May 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants