-
-
Notifications
You must be signed in to change notification settings - Fork 362
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
Even more mypy type checking #1238
Even more mypy type checking #1238
Conversation
This is amazing! There are some module import errors which I can help track down and fix. Thank you! |
) -> FinalResult[Result]: | ||
task_queue: queue.Queue[Task] = queue.Queue() | ||
result_queue: queue.Queue[WorkerResult] = queue.Queue() | ||
result_queue: queue.Queue[WorkerResult[Result]] = queue.Queue() |
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'm a bit surprised -- is FinalResult / WorkerResult a generic 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.
WorkerResult is defined a little further up, it's basically an Either from Haskell, or std::variant from C++.
@overload | ||
def _enc_str(node: str, for_attribute: Literal[True]) -> str: | ||
... | ||
|
||
@overload | ||
def _enc_str( | ||
node: str, for_attribute: Literal[False] | ||
) -> Union[RawValue, Container]: | ||
... | ||
|
||
@overload | ||
def _enc_str(node: str) -> Union[RawValue, Container]: | ||
... | ||
|
||
def _enc_str( | ||
node: str, for_attribute: bool = False | ||
) -> Union[str, RawValue, Container]: |
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'm curious to try this overall PR without the Literal
import, given that it's only used in two places. If that works, we can merge the rest and make this it's own PR and figure out if/how python does dependency management.
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.
Yea, I'd kinda prefer separate functions with it clear in the name what they do/return, rather than relying on a special parameter, but the pattern was present in a variety of places and I don't know if there are calls to this stuff (particularly the logged_exec
calls/wrappers) outside of this code base, so was hesitant to change function names.
If we can refactor and do away with all the Literal
junk without also adding a bunch of cast
s, I think that'd be a win.
An alternative implementation of NixOS#1238 from GitHub user doshitan which used Literal[...] as a sort of dependent type: + @overload + def run_command( + self, + command: Command, + flags: List[str] = ..., + timeout: Optional[int] = ..., + logged: bool = ..., + allow_ssh_args: bool = ..., + user: Optional[str] = ..., + *, + capture_stdout: Literal[False], + **kwargs: Any + ) -> int: + ... + + @overload + def run_command( + self, + command: Command, + flags: List[str] = ..., + timeout: Optional[int] = ..., + logged: bool = ..., + allow_ssh_args: bool = ..., + user: Optional[str] = ..., + *, + capture_stdout: Literal[True], + **kwargs: Any + ) -> str: + ... + + @overload + def run_command( + self, + command: Command, + flags: List[str] = [], + timeout: Optional[int] = None, + logged: bool = True, + allow_ssh_args: bool = False, + user: Optional[str] = None, + **kwargs: Any + ) -> Union[str, int]: + ... however, I think this option is much simpler and improves the API. Possibly in the future we will add this more complex type.
An alternative implementation of #1238 from GitHub user doshitan which used Literal[...] as a sort of dependent type: + @overload + def run_command( + self, + command: Command, + flags: List[str] = ..., + timeout: Optional[int] = ..., + logged: bool = ..., + allow_ssh_args: bool = ..., + user: Optional[str] = ..., + *, + capture_stdout: Literal[False], + **kwargs: Any + ) -> int: + ... + + @overload + def run_command( + self, + command: Command, + flags: List[str] = ..., + timeout: Optional[int] = ..., + logged: bool = ..., + allow_ssh_args: bool = ..., + user: Optional[str] = ..., + *, + capture_stdout: Literal[True], + **kwargs: Any + ) -> str: + ... + + @overload + def run_command( + self, + command: Command, + flags: List[str] = [], + timeout: Optional[int] = None, + logged: bool = True, + allow_ssh_args: bool = False, + user: Optional[str] = None, + **kwargs: Any + ) -> Union[str, int]: + ... however, I think this option is much simpler and improves the API. Possibly in the future we will add this more complex 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.
There is definitely good stuff in here, though it became a bit tricky to merge the later commits, for sure. I picked out some of the easy-to-check, easy to break-out changes and merged those. I'm hoping to merge more from this PR, too.
return " " * level + self.value | ||
|
||
def __repr__(self): | ||
def __repr__(self) -> str: |
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'm a bit unsure about this -- we say we're returning a str, but above we accept an Any in the constructor. What do you think?
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.
My understanding of Python is that __repr__
should always return a string (and typeshed seems to agree). But yea, strange that it just returns the raw value and I don't know if the behavior is relied on somewhere :/
It'll take more types to handle things like `{("a", "b"): 1, "a": 2}` properly, for now, loosen types/go back to more like it was before.
For Literal support in Python 3.7 (though we could also just drop usage of Literal)
…start-with-types * origin/start-with-types: ssh_util: typed run_command wrapper ssh_util.py logger.py nixops: make the op required
Welp, down to just one coverage test error (due to more import cycle shenanigans). |
I don't know why this was done back in 2015 or how it's used, but it fixes the coverage tests locally.
I'm remiss to close this, but it is a bit out of date from master and the remaining commits are tricky to merge. Maybe the work here could be broken up in to a few smaller and related chunks? |
Yea, I've not had a chance to get back to this lately, if you've already lifted what useful bits you could then feel free to close! I may have time this weekend to rebase/pick out any standalone chunks, but can't promise anything. |
If you rebase, go ahead and reopen? Thank you! |
It started out a little more disciplined then became a big ball of changes, apologies.
Also some of this might be overkill.
Included the stricter mypy config that this passes for reference, but it's maybe we don't want to require it yet.
Running mypy (with stricter config):

The mypy report part errors out early, but what it does get to:
Tests:

@grahamc saw your tweet about working on this and having some experience hitting python over the head with mypy, figured I'd make a pass (^_^)