-
Notifications
You must be signed in to change notification settings - Fork 79
Handle traceback when executed command is not found #480
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
Conversation
|
Can one of the admins verify this patch? |
leapp/libraries/stdlib/call.py
Outdated
| raise ValueError('poll_timeout parameter has to be integer greater than zero') | ||
| if not isinstance(read_buffer_size, int) or isinstance(read_buffer_size, bool) or read_buffer_size <= 0: | ||
| raise ValueError('read_buffer_size parameter has to be integer greater than zero') | ||
| if find_executable(command[0]) is 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.
Why are we doing this? I would like to veto this part - the error you are raising is not because the command actually failed but because it does not exist
This is a different kind of error and if you are not happy with handling OSErrors like subprocess and all other to me known apis raise then replace it something that is distinguishable.
Besides if the path exist and it is not executable IIRC you would actually get a different kind of error.
You are trying to reinvent the wheel here for something that already is properly handled on a lower layer of this code. So rather handle and transform the exception than trying make your own checks that properly not even cover everything
|
@shaded-enmity @pirat89 if you think that my opinion is wrong feel free to overrule my review. |
|
@vojtechsokol +1 on what @vinzenz said, the much cleaner solution here is to inspect the result of Note that besides the already mentioned points, this wouldn't work as expected once #481 is merged since the check for executable is done in the parent process. So if I |
|
Note _call actually still raises anythin that exec functions are raising and no error object is returned for this by _call |
a8a1305 to
35ad1bb
Compare
35ad1bb to
3f235f7
Compare
|
@shaded-enmity
And regarding #481 - yes, that was expected, but not unsolvable, therefeore the WIP label. Yes, I'm raising exception not because the command failed, but because it's missing, as can be seen from Regarding the case when path exists but is not executable - yes, I'm aware of that, buth that was first shot, therefeore the WIP label. So what would you recommend then? Taking any action in |
|
Just looking into the original |
Which are all derived from OSError https://docs.python.org/3/library/exceptions.html#exception-hierarchy
I actually prefer if the exception is separate, as one is representing the side of the child process and the other one all things before that. |
|
@vinzenz I just wonder if the parent/child separation is important enough to complicate the failure modes when |
@shaded-enmity try:
run()
except OSError as e:
# report the user that the app is not there or even if there's a workaround like trying to use a different program then go this route
except CalledProcessError as e:
# Report stderr of the command (Or whatever)If we would have a unified way one would end up with something like: try:
run()
except CalledProcessError as e:
if e.exit_code is None: # Or whatever the moniker will be for this
# hmm ok what was going on now? OSError will be stored inside?
else:
# Report stderr of the command (Or whatever)Well, I am not sure why we actually need to do anything about this exception, you can use OSError and should be covered (from what I have seen but I am ok to be proven wrong) For whose convenience is this? If you want to make a convenience you can make a tuple available that contains all the exceptions and people should catch that if they do not care about the specifics. I don't want to make the life harder for anyone who does actually care about the difference. from leapp.libraries.stdlib import run, LEAPP_RUN_ERRORS
...
try:
run()
except LEAPP_RUN_ERRORS:
passAnd for everybody else, you can keep CalledProcessError and OSError this way you don't break anything for anyone and allow people to catch what they need. And about check=False, since this was supposed to be about the exit_code, OSError could still be thrown check=False wouldn't make the execution exception free, at least that's what I wouldn't except. If that is wanted there should be rather a 'noexcept' or whatever. |
2bd1585 to
3a322fc
Compare
It doesn't need to. It would end up with something like: And in case they do not care about difference between those two errors, they still can use just |
That would be solution as well. Even when I would like to go more with Python3 exceptions. But that's just preference. I have not so big problem with that solution as well. But in such case we will have to refactor all caches in leapp-repository. In the unified way, we do not have to do any changes and it's quite easy to work with that as well, without problems. |
|
@shaded-enmity just to keep you on the board :) |
The point is that you don't have to refactor anything at this point, it's a can be updated by someone touching the actor. If you start introducing new Exceptions however that's a different story. Then you have to refactor everything also it's not so easy to make our exception + a builtin exception. I don't really see why you feel like we have to do anything at all. The only thing you can introduce is that tuple that has OSError and CalledProcessError and it should catch all the possible exceptions from run() - Theres no difference right now. Already everyone should be catching OSError at this point, if they don't then their code didn't handle the exceptions properly already.
In the unified way you have to refactor every code, that actually handles them separately already. |
f970b92 to
2f0a710
Compare
|
@vinzenz Now the code should properly handle the cases when the path exists but is not executable, and when environment variable with |
|
@vinzenz man, I am not getting your answer. I see that in completely opossite way, when we will have to change something and when not. What are you writting, looks to me like you missed something in my answer or I am missing something in your answer. If you have: Why I need to touch every call that catches Additionally, generated OSErrors, etc. in this solution will point more to a bug in leapp stdlib instead of problem in command itself. That would be beneficial for us as well. I think we are desynced here. Additional discussion through comments would be too slow, so I would prefer mtg to discuss it in case of need. EDIT: fixed copy&paste error in the pseudocode |
2f0a710 to
7d59ef4
Compare
|
The actual cause of the Traceback is handled now by #533 |
When command is executed using stdlib.run function and it fails due to a missing or mistyped command, traceback with CalledProcessError (A Leapp Command Error occurred.) and OSError ([Errno 2] No such file or directory) occurs.
However if even both of these exceptions are caught, there is still a traceback:
Click for the traceback
The problem is in the _call function which executes the command in forked process.
This PR handles the traceback by raising a CalledProcessError exception (if the command is missing) before the command is executed.
Requires leapp-repository PR: oamg/leapp-repository#123