Best Practices for Reporting Errors to Users?
-
Hi,
I've been seeing a lot more usage of code like
raise ValueError("Invalid path selected")
in the Python examples. As I understand it, these errors tend to get surfaced in the Console - which is useful to developers, but less useful to Users.Here's a simple script that asks a user to select an image in a folder containing multiple images.
import c4d def get_images_path(): image_path = c4d.storage.LoadDialog( type=c4d.FILESELECTTYPE_IMAGES, title="Select an image in the folder you want to bulk rename", flags=c4d.FILESELECT_LOAD ) if not image_path: raise ValueError("Valid image path not selected.") return image_path def main(): images_path = get_images_path() c4d.gui.MessageDialog(images_path) if __name__=='__main__': main()
How should I gracefuly accept a user hitting "Cancel"? How should I provide the user with a helpful error if they've selected the wrong filetype (let's for example pretend I'm looking for
.png
files rather than misc image formats)?Should we use popup messages? Status bar updates? Console prints?
Do I need to do something like:
try: images_path = get_images_path() except ValueError as error: c4d.gui.MessageDialog(error)
...every time I call any method that might throw an error? Or is there a way to auto-promote exceptions/errors as alert dialogs/status updates?
Thanks,Donovan
-
Hello,
there is no "official" way of handling or reporting errors in Python scripts. You can do whatever fits your needs or the needs of your user best. Why do you think the console is not useful to users?
The only thing to consider are general best practices regarding software design. E.g. to only show a (modal) dialog when you know that a user is interacting with the software, not in some sub-function.
Another philosophical discussion is, what actually is an error? An error should be returned by a function that failed; but what does that mean? What should happen if an error is detected? (Here is some video about this topic I just recently watched:
)For argument's sake, lets say an error is when something in your code, you are 100% sure should and must work, didn't work. So your program shuts down, if such such an "error" was detected.
In your example, LoadDialog() is a function that - in my opinion - cannot fail. Either the user selects a folder or he presses "Cancel". Both are fine results. And if the user tells you to abort, you can simply exit your program.
Similarly, when the user selects the wrong file type, that's not a program error. Compare that with a user entering a wrong password somewhere - that is not an error, but something to expect. Providing feedback to the user and handling errors are two different things.
def handleError(error): print(error) c4d.gui.MessageDialog(error) def getImagePathFromUserInteraction(): res = c4d.storage.LoadDialog( type=c4d.FILESELECTTYPE_IMAGES, title="Select an image in the folder you want to bulk rename", flags=c4d.FILESELECT_LOAD ) if res == None: return False return res def main(): # UI interaction res = getImagePathFromUserInteraction() if res == False: # nothing to do, lets go home print("script aborted by user") return # do actual work try: doSomething(res) doSomethingElse(res) except ValueError as error: handleError(error) return # show result in the UI c4d.gui.MessageDialog(res)
best wishes,
Sebastian -
Hi,
I assume you are aware of this, but exceptions and errors are a kind of 'problematic' topic for Python in general, because of the fact that it is a typeless language and the resulting constant need of input sanitisation (if you want to play things safe).
I also think that the Google Python style guide [1] is always a good thing to follow (although someone will probably furiously point out that they do not govern the Python language). They have a paragraph on exception and error handling. One thing I could spot in your example is the verbosity problem. Do not throw exceptions or display errors like
"Invalid file path selected."
, use something like"Execution stopped: {} is an invalid file path.".format(some_path)
. Google shows that problem in their examples too.For your actual question: Since Cinema is thankfully rather conservative with throwing error dialogs itself, I would follow this approach and only open a dialog for things that are absolutely critical (so basically never in a plugin) and use the status bar for anything else. Cinema's status bar is somewhat inconspicuous / hard to notice, a feature to let it flash for an error would be nice.
This ultimately ties to the topic of the difference between errors and exceptions, but since you both already covered that subject indirectly, I will leave it at that.
Cheers
zipit[1] https://github.com/google/styleguide/blob/gh-pages/pyguide.md
-
@s_bach & @zipit - Thank you both for the thoughtful replies!
I think I'll opt for the status bar for most user-facing feedback, and console logging for anything bigger. Watching the "What could possibly go wrong?" talk now.