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

2982.elegantly handle known errors #2995

Merged

Conversation

oliver-sanders
Copy link
Member

@oliver-sanders oliver-sanders commented Mar 12, 2019

For Discussion

I've made a quick start at #2982, raising as a PR now to discuss approach before committing to it.

WIP

I've got the tests/validate tests to pass, these changes should give a flavour for what this would look like if fully implemented.

closes #2982

Highlights:

  • Cylc / Parsec exceptions inherit from CylcError and ParsecError respectively.
  • Jinja2 becomes an optional extra to Parsec (like EmPy).
  • Add UserImputError for CLI input.
  • Merge GraphNodeError in with GraphParseError
  • CLI commands catch CylcError, ParsecError errors elegantly but allow anything else to materialise in traceback.
  • Use (minimal) inheritance for exceptions:
    • Excessive nesting causes performance and maintenance issues.
    • Don't catch CylcError exceptions in order to re-raise as a more generic type e.g. GraphParseError being re-raised as a SuiteConfigError
  • Simplify & standardise exceptions.
    • No more def __str__(self): return repr(self.msg).
  • Move exceptions into their own module.
  • Replace inconsistent ERROR prefix with the more informative error class name.
  • Remove redundant information (stuff like this: ItemError: ERROR: error in item).

Example:

before: catch specific exception and re-raise as a generic exception

FileParseError:
Include-file not found: bar.rc via foo.rc from $PWD/suite.rc

after: remove un-necessary Include-file not found text, exception title should suffice

IncludeFileNotFoundError: bar.rc via foo.rc from $PWD/suite.rc

TODO:

  • Isodatetime exceptions should inherit from ISODateTimeError.

Questions

@cylc/core Are we happy with this approach?

Should exceptions multiple-inherit for context (see lib/parsec/exceptions.py for example):

class ItemNotFoundError(ParsecError, KeyError):

@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch 3 times, most recently from f55e5f3 to d96d81d Compare March 12, 2019 15:26
flines = inline(
flines, fdir, fpath, False, viewcfg=viewcfg, for_edit=asedit)
except IncludeFileNotFoundError as exc:
raise FileParseError(str(exc))
Copy link
Member Author

Choose a reason for hiding this comment

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

One example of catching a specific exception then raising a generic one in its place.

return '%s: %s' % (self.__class__.__name__, self.args[0])


class ItemNotFoundError(ParsecError, KeyError):
Copy link
Member Author

Choose a reason for hiding this comment

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

Is this a sensible way to provide more context to the exception or a potential hazard?

Copy link
Member

Choose a reason for hiding this comment

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

I think so, knowing it's due/related to KeyError looks simple and useful.

pass


class CyclerTypeError(CyclingError):
Copy link
Member Author

Choose a reason for hiding this comment

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

Do we need super-specialised exceptions like this?

Copy link
Member

Choose a reason for hiding this comment

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

Presumably a good reason for a "super-specialised exception" is if the calling code needs to catch and respond specifically to that specific exception; otherwise it's pointless.

@hjoliver
Copy link
Member

@cylc/core Are we happy with this approach?

Sounds pretty sensible to me, although I wouldn't say I have a deep understanding of exception handling best practice (if there is such a thing).

@matthewrmshin
Copy link
Contributor

Happy with approach. Key points:

  • So we are able to easily catch known errors and present them to users as intended.
  • So we don't catch unexpected errors that are likely to be bugs in our system.
  • So we don't need extra code for each exception class unless there is a special requirement.

@kinow
Copy link
Member

kinow commented Mar 12, 2019

I like the classes design too! In Java and PHP, normally you have one base exception class, and the children classes are designed per application feature/issue/section/etc. So +1 🎉

As for the decorator cli_function, +1 as well, but not too sure if it won't change later.

From #2972, some libraries that handle command line parsing/arguments also provide ways to intercept and display exceptions, which could be used with or replace the decorator (I think?)

Another possibility, is that in #2802 the current Cylc commands could be re-designed in some simple object structure. Depending on the outcome of that task, we could instead of having each command with a try-catch, or with a decorator, have an entry point that uses the new Python code. aws-cli has an entry point where exception is handled. But not sure if we will go in the same direction.

One benefit of having this approach, is that if we had the logic of cylc run in some class like CylcRun that was fully independent of the command line (no imports related to command line parsing, no exceptions related to that), it would be easier to re-use it from the Web, without having to worry about sending the right parameters to avoid the errors being accidentally suppressed (I think we may need the full traceback in the web and then log to some FileAppender, etc).

@oliver-sanders
Copy link
Member Author

OK, based on this response I'll finish work on this PR, lots of tests to fix!

Note, the parsec tests were pretty easy to fix as they are unittests which only check the exception raised not the full text. Test the interface not the implementation is a good motto.

@matthewrmshin matthewrmshin added this to the cylc-8-alpha-1 milestone Mar 13, 2019
@oliver-sanders oliver-sanders changed the title [discussion] 2982.elegantly handle known errors [wip] 2982.elegantly handle known errors Mar 13, 2019
@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from d96d81d to ce8f8d3 Compare March 15, 2019 12:15
@cylc cylc deleted a comment Mar 15, 2019
@hjoliver
Copy link
Member

(@kinow - in your comment above, I guess you were suggesting possible ways to do even better in future, not changes to this PR?)

@kinow
Copy link
Member

kinow commented Mar 18, 2019

@hjoliver yup, but that would depend on the decision for #2972

@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from ce8f8d3 to 6bfc298 Compare March 18, 2019 17:45
@cylc cylc deleted a comment Mar 18, 2019
@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from 6bfc298 to 4700ff5 Compare March 19, 2019 09:49
@cylc cylc deleted a comment Mar 19, 2019
@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from 4700ff5 to 81b2c0c Compare March 19, 2019 11:16
@cylc cylc deleted a comment Mar 19, 2019
@cylc cylc deleted a comment Mar 19, 2019
@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from 7c00811 to 44517fd Compare March 19, 2019 12:34
@cylc cylc deleted a comment Mar 19, 2019
@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from 44517fd to 9933644 Compare March 19, 2019 13:04
@cylc cylc deleted a comment Mar 19, 2019
@oliver-sanders oliver-sanders changed the title [wip] 2982.elegantly handle known errors 2982.elegantly handle known errors Mar 19, 2019
@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from 9933644 to 3dfff49 Compare March 21, 2019 15:18
@oliver-sanders
Copy link
Member Author

  • Deconflicted
  • Tidied Jinja2 & EmPy exceptions

@oliver-sanders
Copy link
Member Author

@kinow resolved codacy niggles, unified IllegalValueError, ListValueError and IllegalItemError in the process.

@cylc cylc deleted a comment Mar 22, 2019
@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from b8bb531 to 6a3a255 Compare March 22, 2019 11:15
@oliver-sanders
Copy link
Member Author

Deconflicted.

@cylc cylc deleted a comment Mar 22, 2019
@matthewrmshin
Copy link
Contributor

All looks good via 👀 with 👓 .

Copy link
Member

@hjoliver hjoliver left a comment

Choose a reason for hiding this comment

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

LGTM so far, but still going through the code. I like the CLI function decorator 😁

@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from 6a3a255 to c8dce24 Compare March 25, 2019 10:22
@cylc cylc deleted a comment Mar 25, 2019
@oliver-sanders
Copy link
Member Author

I like the CLI function decorator 😁

Good! This could pick up other functionality like colour settings/parsing.

Copy link
Member

@hjoliver hjoliver left a comment

Choose a reason for hiding this comment

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

Approve pending minor deconfliction.

Note also #3056 adds more SuiteConfigError.

@oliver-sanders oliver-sanders force-pushed the 2982.elegantly-handle-known-errors branch from c8dce24 to 89d4c88 Compare April 2, 2019 09:43
@cylc cylc deleted a comment Apr 2, 2019
Copy link
Member

@hjoliver hjoliver left a comment

Choose a reason for hiding this comment

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

@oliver-sanders you've rebased onto some recently-merged old-style use of SuiteConfigError (with redundant "ERROR" strings) that need to be made (aesthetically) consistent with your changes here.

$ git status                                                                                                                                                                 
HEAD detached at oliver/2982.elegantly-handle-known-errors

 $ grep -A 1 -B 1 ERROR lib/cylc/config.py                                                                                                                                     

                        raise SuiteConfigError(
                            f"ERROR, "
                            f"xtrigger function not callable: "

                        raise SuiteConfigError(
                            f"ERROR, "
                            f"xtrigger function not found: {xtrig.func_name}")

@cylc cylc deleted a comment Apr 3, 2019
Copy link
Member

@kinow kinow left a comment

Choose a reason for hiding this comment

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

Re-approving!

Copy link
Member

@hjoliver hjoliver left a comment

Choose a reason for hiding this comment

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

🎉

@hjoliver hjoliver merged commit ff62f6a into cylc:master Apr 3, 2019
@oliver-sanders
Copy link
Member Author

🎉

@oliver-sanders oliver-sanders deleted the 2982.elegantly-handle-known-errors branch April 4, 2019 08:14
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.

exceptions: elegantly handle known errors
4 participants