Redirecting stdout to avoid banners while `import`ing

I have a silly problem:
We’re using a few packages that insist on printing their banners upon importing (consider this as something beyond me:). This results in a “barrage of banners” situation.
I tried to redirect output as follows:

module TestModule
Libc.flush_cstdio()
Base.flush(stdout)
original_stdout = stdout
out_rd, out_wr = redirect_stdout()
import Nemo
import Polymake
Libc.flush_cstdio()
Base.flush(out_wr)
close(out_wr)
redirect_stdout(original_stdout)
str = read(out_rd, String); @show(str)
end

this works well in REPL, but somehow doesn’t work if module is precompiled. Any idea why and how to make it so?

The reason why is that this code is not run when the module is loaded from a precompiled file. The way precompilation of packages work is to deserialize the state of the module to a file during precompilation and when loading, the state is simply deserialized and then the __init__ function of the module is run. No top-level code is run when the module is loaded.

I’m not really sure how to “hook” into the __init__ function of dependent packages though.

Unconditional printing of banners and such on package load is really user-hostile behavior…

2 Likes

yes, I know and I would agree with the no banner policy; however, these are decisions beyond my will and I have to play along;


Btw. thanks for the explanation on precompilation etc.; this should have been obvious to me after reading the documentation, but somehow wasn’t.

If you could spare a moment, I came up with the following solution hack to to detect if package has been imported from other module (and then suppress banner) or from Main/module inside Main (and display it then).

__is_root_module() = haskey(Base.package_locks, Base.PkgId(@__MODULE__))

is it even remotely close to being correct? (I know that Base.package_locks is private and is not intended for this use)

I think Nemo banner is conditional
https://github.com/Nemocas/Nemo.jl/issues/817
Nemo banner
But I have no idea how to implement this in the __init__ function.
I would also like to remove exactly those two banners, did you, @abulak, succed with __is_root_module()?
How do you use it?

No; please consider opening an issue in those packages

The same trick as in __is_root_module is precisely what is used in Nemo to not print the banner when it’s loaded from a hardcoded list of packages, I don’t think it’s possible to extend this list. As mentioned in the issue you linked to, you could set the environment variable ENV["NEMO_PRINT_BANNER"] = false (but it’s not documented and might not be supported in the future).

I submitted a PR to remove the banner message, but it was rejected: remove banner message by stevengj · Pull Request #828 · Nemocas/Nemo.jl · GitHub

1 Like

Setting this environment variable works on REPL, but I do not know how to do it in a module definition…?

1 Like

Wouldn’t it work, if you just add this:
ENV["NEMO_PRINT_BANNER"] = false as the first thing in your Module?

1 Like

With the following code, the banner is shown.

module NemoPolymake

ENV["NEMO_PRINT_BANNER"] = false
using Nemo
using Polymake

end

I guess it is related to https://discourse.julialang.org/t/redirecting-stdout-to-avoid-banners-while-import-ing/37633/2?u=bmo

1 Like

(The environment is then only set during precompilation—this is when top-level code in the module is executed—and will no longer be set when the user imports the module at a later time.)

4 Likes

Thanks for the clear explanation. (I just wonder, why didn’t I understand this earlier from other answers.)

1 Like