-
Notifications
You must be signed in to change notification settings - Fork 163
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
Add support for writing to ERROR_OUTPUT from kernel code #3043
Conversation
file/stream referenced by the ERROR_OUTPUT global variable
Codecov Report
@@ Coverage Diff @@
## master #3043 +/- ##
==========================================
- Coverage 83.78% 83.78% -0.01%
==========================================
Files 685 685
Lines 343377 343389 +12
==========================================
+ Hits 287694 287702 +8
- Misses 55683 55687 +4
|
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.
Thank you! On a first glance, this seems quite sensible to me, but I'd like to think a bit more about. Also, I hope @markuspf and @ChrisJefferson and others will have a look, too :-).
src/error.c
Outdated
/* It may be we already tried and failed to open *errout* above but | ||
* but this is an extreme case so it can't hurt to try again | ||
* anyways */ | ||
if ((ret = OpenOutput("*errout*"))) { |
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.
Please don't assign inside the if
, i.e., first assign, then test.
src/error.c
Outdated
ret = OpenOutput(CONST_CSTR_STRING(ERROR_OUTPUT)); | ||
} | ||
else { | ||
ret = OpenOutputStream(ERROR_OUTPUT); |
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.
We started to add more validation, and here, one could verify that ERROR_OUTPUT actually is a stream; see e.g. PRINT_OR_APPEND_TO_FILE_OR_STREAM
.
On that note, perhaps it would be "better" to put this new function into streams.c
or io.c
...; but I have no strong conviction in either direction, and in any case, it's not hard to move a function to another file later on, should we feel the need for it :-).
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 wanted to check that it was actually a stream, but I couldn't quickly find the "right" way to check that. Is there a TNUM for stream objects? I'll look at those functions you mentioned.
I agree this function might make more sense in a io.c
. I put it in error.c
because that was already loading another global variable from error.g
. I don't know if that entirely matters though: The connection between the C-based modules and the GAP language library modules is one that I haven't deeply explored yet and is unclear to me.
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.
In general, TNUMs only cover a very small, hard-wired list of types with special representations in the GAP kernel (things like integers, booleans, permutations). For things like streams, you want to use the more general IsOutputStream
. As Max mentioned, you can see how to get this GAP level variable, and copy a reference to it into C, in PRINT_OR_APPEND_TO_FILE_OR_STREAM
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, clearly I did not even test my last commit. I'm just going to delete it.
I noticed that the JupyterKernel package already relies on setting I still think it's reasonable behavior that it does that. But if this change is accepted we should either updated the JupyterKernel code, or just keep this variable read/write by default (and in that case, what would be the best way to do that after |
afa635f
to
2949b24
Compare
About the role of ERROR_OUTPUT: There is no particular reason that I introduced it as a GAP-level global variable. Unless there is some reason against it, maybe a better way of protecting it would be to let it be a C-level Obj later and provide a |
It isn't exactly equivalent, since that looks at an arbitrary stream object (in practice it is often the But I could refactor a bit more to eliminate that duplicate code. I don't know how much you all care about moving around GAP kernel internal functions that aren't directly accessible from GAP code, given that there is not officially an "API" as such (outside of the the new one that's being added...) |
Don't worry about |
I think this is in some sense entirely coincidental.
There might even be a point in introducing a setter function for error output (later). It might indeed be a good idea to have I'd just like someone (@ssicha?) to make a matching PR for |
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've tried it with jupyter and got it to work. All other points raised in the discussion can be addressed in different issues and PRs. LGTM 👍
Also I opened a corresponding PR gap-packages/JupyterKernel#85. |
I just merged #78 on |
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.
Fine then, let's merge this once the build queue for master has cleared.
Did we agree to backport this to stable-4.10 branch? |
Backported via de7b9b9 |
#2824 added a global variable called
ERROR_OUTPUT
tolib/error.g
, which can be manipulated to control the file/stream that error output is sent to by the error library. This works for most cases; however, code in the kernel that outputs error messages ought also to write to whateverERROR_OUTPUT
points to, rather than defaulting to `"errout".The one case I found this to be an issue was in printing syntax errors, though there may be other cases.
This is my first attempt to work around it, and my first addition of new code to GAP, so please be kind--I've tried my best to observe and follow local conventions, etc.
One problem with this PR I'm aware of currently is that when using
ImportGVarFromLibrary
, it sets that global variable as read-only by default, which was not previously the case forERROR_OUTPUT
. I'm not exactly sure why it does this, as it is still possible to set the variable read-write afterwards. This may be a good change though. It would prevent accidental clobbering ofERROR_OUTPUT
: In order to change it you really have to mean it. I've seen this pattern in use in a couple of packages when overridingErrorInner
as well, so there is precedent for it. But I don't know whether or not that's considered an anti-pattern.