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

Existing linters, type-checker configuration or other tooling to identify unused Results? #45

Closed
WasabiFan opened this issue Jul 29, 2021 · 7 comments

Comments

@WasabiFan
Copy link

I'm rather fond of the promise of this library in my type-annotated codebase. I already type-check it with Pyright. However, it seems easy to accidentally miss a returned Result if the method otherwise returns None. i.e., if I care about the value in case of success, I'll surely get a type error in the case that I fail to check for error variants; if I don't, then I might not be warned about the Result being there at all.

This seems like it would be a common problem for projects using this crate. Is there a well-understood solution already? Perhaps other type-checkers can catch unused return values (like Rust does with #[must_use]), or linters/linter plugins which would provide such functionality. I see issues considering adding this to mypy but they remain open and unimplemented.

What do others do? Is the best solution solution to only use Result when I have a value to return in the success case?

@francium
Copy link
Member

francium commented Jul 29, 2021

Good questions. I don't have any good answers for you (unfortunately I don't use Python day-to-day). But we can leave this open to see if anyone else has any good ideas.

The only comparison I can think of to what I believe you're experiencing is with TypeScript. Which provides strict null checks and non-strict null checks -- ie null | undefined | T values can be freely mixed. So you can have a function that says it returns T but can actually return either one of those and type checker is happy. But with strict null checks, you can't do this. So similar to Python's None being returned from some functions which claim to return Result but really end up actually returning None.

Does the sound accurate to what you're seeing? Does mypy or pyright offter strict checks like that?

Quick search shows me this bit which seems related,
https://mypy.readthedocs.io/en/stable/kinds_of_types.html#disabling-strict-optional-checking

def inc(x: int) -> int:
    return x + 1

x = inc(None)  # No error reported by mypy if strict optional mode disabled!

@WasabiFan
Copy link
Author

WasabiFan commented Jul 30, 2021

Thanks for the response.

The particular case I'm worried about is:

def go_do_something_which_might_error() -> Result[None, str]:
    return Err("ahhhh")


if __name__ == "__main__":
    go_do_something_which_might_error()
    do_something_assuming_the_above_succeeded()

In the above, go_do_something_which_might_error might have returned an error; we don't know. The programmer forgot to check. Since the programmer doesn't expect a returned value from that function anyway, they might never notice they forgot to use the returned value.

In Rust, Results are marked with #[must_use], which means you must do something with a returned Result -- you can't forget (it emits a warning).

What I'm hoping for is suggestions on Python tooling that might detect this case.

@francium
Copy link
Member

Relevant mypy issue (funny enough it reference right back to this very library :) )
python/mypy#6936

From TypeScript experience, I know this is definitely possible with typecheckers/linters...whether the Python ecosystem has something in place, I don't know.

@francium
Copy link
Member

francium commented Jul 30, 2021

Wait, found something promising,

python/mypy#8951 (comment)

If prior art helps at all, pyright added this in 1.1.89 with a reportUnusedCallResult rule (off by default). It works well based on some local testing.

reportUnusedCallResult [boolean or string, optional]: Generate or suppress diagnostics for call statements whose return value is not used in any way and is not None. The default value for this setting is 'none'.

from https://github.com/microsoft/pyright/blob/main/docs/configuration.md

@WasabiFan
Copy link
Author

That's exactly what I was looking for; evidently, my Ctrl+F attempt was very poorly executed! I saw the mypy thread but missed the reference to Pyright, and I guess didn't use the right terms in their actual docs. It works great.

Thank you!

@francium
Copy link
Member

We'd welcome your feedback and experience if you end up playing around with that. Let us know so we can possibly update the README here for overall better user experience with this library.

@Corwinpro
Copy link

Just to document this somewhere, I think I've came across the very same issue as the TS reported. It would be super nice if this question / feature request was kept in a roadmap of some sort, so that if this gets implemented in mypy, result would add that. Thank you!

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

No branches or pull requests

3 participants