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
DM-9846: Improve handling of error messages #4
Conversation
src/base.cc
Outdated
// Construct ErrorHandler once, the first time this function is called. | ||
// This is done to initialize `errorMsgStream` and register `reportError` as the AST error handler. | ||
// See https://isocpp.org/wiki/faq/ctors#static-init-order | ||
static ErrorHandler * errHandler = new ErrorHandler(); |
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.
EDIT: Never mind, found https://isocpp.org/wiki/faq/ctors#construct-on-first-use-v2.
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.
Perhaps I should change the link to https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use (which is the solution, and comes right before the discussion about why to use new
.
Also, it may not be safe just rely on a link, as it may go stale. @jonathansick do we have a way to archive a useful page so we're sure we always have access to it? I'd hate to copy all that information to this note.
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 don't think you need to copy all that information. The static initialization order issue is fairly well known (e.g., there's an item devoted to it in Effective C++), so a brief mention should be all the justification you need. The static de-initialization issue is not one I was familiar with, but it's exactly the same principle and so can probably be explained in one line.
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.
@r-owen We don't have a formal system for that, but it's an interesting concept. Probably combining ls.st with an auto-archive service that fails over if the original link 404s. I'll put that in my idea bucket. Something probably exists off-the-shelf for this. In the meantime, webarchive.org can save us if the link goes stale.
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.
No major problems, just some style nitpicks.
Longer term desires: | ||
- Support AST regions | ||
- Add support for building with cmake. | ||
- Add doc strings to python wrapped objects. |
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.
Did you mean to remove the "longer-term" bit as well?
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.
Yes. The current code will probably suffice for LSST and it's not clear to me which, if any, additional AST features we will want to add. Much as I would like python doc strings I suspect it is not practical unless we come up with an automated way to add them.
ErrorHandler() { | ||
astSetPutErr(reportError); | ||
} | ||
|
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.
Is astshim
bound by RFC-209? I'm not clear on its relationship to the Stack.
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.
It is not bound but I have been doing that for most classes. It seems fussy for such a tiny class, but I'll add it.
src/base.cc
Outdated
astSetPutErr(reportError); | ||
} | ||
|
||
std::string getErrMsg() { |
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.
Can getErrMsg()
be made static?
src/base.cc
Outdated
std::string getErrMsg() { | ||
std::string errMsg = errorMsgStream.str(); | ||
errorMsgStream.clear(); | ||
if (errMsg.empty()) { |
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.
Should clear()
be called even if errMsg
is empty?
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 believe so. clear
clears state flags, such as the error bit, so it is probably always best to call that. To empty the buffer requires calling str("")
and I think I will do that only if a string was read. I added a test to test_object.py
that makes sure the buffer is properly cleared.
Does this change make the AST error code itself available to the code that is catching the exception? It seems a bit lossy to end up with a RuntimeError that can not be used to work out what really went wrong without looking at the text of the error message. |
That would be a nice feature, but I think it would require a custom exception. Perhaps as a separate ticket? |
Something that's pretty easy in Python but I don't know how to do it in C++ so I'll leave the decision on that to the experts. I think it would be something that we should definitely have in the future though. |
384f04f
to
228e0b7
Compare
@timj Including the error code as a value in the exception would be a lot more work and I consider it out of scope for this ticket. We could easily print the AST status as part of the error message but I'm reluctant to do so without a demonstrated need; so far I have found the error messages perfectly clear by themselves. |
Using the new AST function `astSetPutErr` write AST error messages to an ostringstream and have `assertOK` use the contents of that stream as the error message when it raises an exception.
python/astshim/keyMap.cc was moved into a subdirectory, but somehow the original was still present (though ignored).
test_object.py was trying to call methods that were no longer publicly available. This passed because it was checking for errors (just not the ones being raised). Improve test_channel.py and test_normMap.py to test for a more explicit exception when using assertRaises. I checked the usage in other tests and concluded it was best to leave them as is because in some cases it wasn't clear which C++ exception would be mapped to the Python exception that was raised, and in others it was unclear if AST or C++ code would catch the problem, thus which Python exception would be raised.
...about comparing unsigned int to int
Ok. I just feel uncomfortable throwing a runtime error for every possible AST problem. In pyast we go the other extreme and have a special exception for every AST error: https://github.com/timj/starlink-pyast/blob/master/tools/make_exceptions.py but it's probably the case that there should be groups of related error types triggering ValueError vs TypeError etc. I don't want to derail this PR but please consider in the future how you are catching exceptions and whether more granularity would lead to cleaner code. |
The source of truth is at https://github.com/Starlink/ast/blob/master/ast_err.msg I concur that the API document does not actually say which error codes are relevant for which method. Things like Most of the error codes are fatal, so I guess that a program will not need to care about specifics in those cases and the error message is fine. Some of them are recoverable (such as |
"Which error codes are relevant" is actually ill-defined on a method by method basis, because all methods share the same error flag. My question was more along the lines of "If I find out the error code was 42, what does that actually tell me?" |
I'm not sure I understand you. If you ask for an attribute from an AST object that does not exist AST will trigger |
astshim attempts to raise appropriate exceptions. The python wrapper needs a bit of work on that, but the C++ is probably OK. |
No description provided.