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?

1 Like

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