-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Print methods(f)
with color like stack traces
#40251
Conversation
This is no doubt subjective, but when I'm calling |
I really like this. However, I feel that the colored package names in your examples stand out most -- they are the first thing I see/read when looking at those images. I feel that's reverse from how it should be. Perhaps one can experiment a bit more with this. Either by deemphasizing the package names, or by emphasizing the method argument types more. Besides colors, one could also experiment with e.g. using bold face -- e.g. how does it look if the argument types are printed in bold? |
More subtle colours would be better, but hard to make things precise. Bold seems to vary from doing nothing to feeling like shouting, here's a very crude attempt: With more fiddling the colour could be moved to apply to the types owned by that package, not the module name. Or (simpler) to highlight the package name in the path, rather than alone. |
To me your last screenshot is by far the best in terms if being able to quickly pick out which methods are there and in particular finding any that I care about |
Really like these! Seems ok if the coloring and emphasis of stack traces and methods lists are a bit different, but ideal to share the common printing logic aside from those details. |
Nice! Any idea why in the ambiguity error the first |
That is nice! I wonder if the module name coloring is helpful at all in this context though. To me, right now, they remain the most visible feature in the list, drawing my eye to them as a kind of semi-noisy "headers" of sorts (and notably, the headers come after the content - this is confuses me in the stack trace printing as well a bit; I'm always finding a "header", then I need to remind myself to look upwards to see its associated content). If the modules were all colored gray, the "where-is-this-method-actually-from" line would serve as a nice and consistent "quasi-whitespace" of sorts between method signatures. |
Probably a bad decision! In looking at examples with a few types & many
The hope is that it's a proxy for the package for whose types a method is being added. How often things will end up monochrome or looking like a rainbow in actual use, will depend... I guess colours will be most useful when there are just a few "foreign" methods, which are either the ones you care about, or the ones you can ignore.
Agreed. There were other proposals in the giant stack trace threads, like highlighting the Here, I worry that highlighting |
methods(f)
much like stack tracesmethods(f)
with color like stack traces
This! |
It would also be nice to unify the code which prints "MethodError: no method matching" with everything else --this PR doesn't change that, but affects "MethodError: ... ambiguous" because that is shared with For this one, I guess we need to decide whether to do this at all. And whether the style here is what's wanted?
I fixed some doctests but there are some more... I'd rather not do that too many times. |
This already looks great, sorry it got forgotten a bit! This seems preferable to #40916 since it is more consistent with stacktrace printing.
Oh, that's smart! Sounds reasonable to me.
Looks good for me, I wouldn't expect this to be a big issue.
Maybe? Although I don't think the more compact printing is bad here either.
Do you have a screenshot of how this looks like for you? This probably isn't a dealbreaker though.
Do you know about #40546 (comment)? You can even pass |
Now I do, thanks! Will try that out.
Yes. This is the error printing with the pre-built Julia 1.6 -- some a long paths, and not useful ones. But perhaps orthogonal to this PR, which just re-uses the same path logic as for stack traces. |
doc/src/manual/methods.md
Outdated
... | ||
[180] +(a, b, c, xs...) in Base at operators.jl:424 | ||
[207] +(a::Any, b::Any, c::Any, xs::Any...) |
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.
Was this change intentional? I think always printing the ::Any
is a bit verbose and I am not sure it adds much information.
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.
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 think it would be fine to omit the ::Any
here, but I don't have any strong opinions on this.
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.
Here are some variants which print the module & path without a new line. (Because the new one above takes up a lot of lines compared to the old. And the types printed here are usually shorter than those in the stack traces.) I think this might be better.
On the left I omit the ::Any
, what I don't like is that suddenly the variable name has to stand on its own, instead of being clearly secondary information to the signature. You can't answer "how many arguments?" by scanning "how many bold things?" anymore.
On the right, I've also added bold to required keywords, shown with cumsum
. Seems like useful information to mark them somehow, hope bold isn't confusing --- all the types are also requirements, after all.
I made #40916 before someone pointed this out to me. I have no idea what's going to happen, but should this be the approach that ends up being used, I'd like to add some thoughts:
|
|
for kw in kwargs | ||
skw = sym_to_string(kw) | ||
if QuoteNode(kw) in m.roots # then it's required | ||
printstyled(io, skw, color=:bold) | ||
else | ||
print(io, skw) |
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.
This is meant to check which keyword arguments are required, and print those in bold.
Will this be robust? I don't know any details of the method struct, but in cases I could think of this appears to work.
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.
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.
This question of whether the check for required keyword arguments is correct, safe, could use a look from someone who knows about things.
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, this is not robust. but quite amusing that you found this
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.
Ok. I just poke around... Is there a robust way to query this?
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 know of one right now. Let's leave that for later work?
|
Yes, it's true we aren't constrained to greyscale. I'm hesitant to touch the error printing, though... would it be weird if they diverge, is the information more or less useful in one than the other? Here's what variables in I quite like this, but perhaps it's too fancy? (This isn't committed yet.) I think the code which is printing the path is in errorshow.jl, this moves it into a function |
Bump, pre-1.8. Pinging @StefanKarpinski maybe? |
for kw in kwargs | ||
skw = sym_to_string(kw) | ||
if QuoteNode(kw) in m.roots # then it's required | ||
printstyled(io, skw, color=:bold) | ||
else | ||
print(io, skw) |
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, this is not robust. but quite amusing that you found this
file, line = updated_methodloc(m) | ||
print(io, " at ", file, ":", line) | ||
|
||
# module & flie, re-using function from errorshow.jl |
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.
# module & flie, re-using function from errorshow.jl | |
# module & file, re-using function from errorshow.jl |
modulecolordict = Dict{Module, Symbol}() | ||
modulecolorcycler = Iterators.Stateful(Iterators.cycle(METHODLIST_MODULECOLORS)) | ||
modulecolordict[parentmodule_before_main(modul)] = :blue |
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 this really our only strategy for this? Global state through a particular list?
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 have no memory of writing this :/ I presume I tried to copy the stack traces.
The list [:cyan, :green, :yellow] is global, but isn't modulecolorcycler
local to this function?
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.
ah, true, seems to be a copy from there. I guess this is okay
@@ -96,7 +96,7 @@ Each statement gets analyzed for its total cost in a function called | |||
as follows: | |||
```jldoctest; filter=r"tuple.jl:\d+" | |||
julia> Base.print_statement_costs(stdout, map, (typeof(sqrt), Tuple{Int},)) # map(sqrt, (2,)) | |||
map(f, t::Tuple{Any}) in Base at tuple.jl:179 | |||
map(f::Any, t::Tuple{Any}) @ Base tuple.jl:218 |
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.
this seems like a regression
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 you explain what you mean?
I just landed here by chasing errors, and have not looked for the code which generates this. I believe that Base.Math.throw_complex_domainerror(:sqrt::Symbol, %2::Float64)::Union{}
just below in this output does not take the path this PR changes, since it does not get printed in bold:
Is there an alternative path that the first line's printing should take? Or should I add some option like fancy=false
(or checking IOContext) to the basic show(method) path, to print this closer to the old style?
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.
The added ::Any
is unnecessary, and seems to be explicitly being added in this PR
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.
Ok, I can surely figure out a way to remove it here.
But the logic of including it in general is this:
On the right you can count the arguments by counting the bold words. On the left the grey f,
is really easy to miss, and seems worse than before.
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 looks like this seems sound. I have mentioned a few places to fix (to not change), but otherwise seems like it successfully shares code, so it quite sane.
From triage: after much discussion, we all came to a different conclusion, that we like having the signature and location on two lines since (1) it's nice to be consistent with stack traces, and (2) the method location is actually always quite important and two lines makes it much easier to scan the locations. We also like omitting Sorry about all the back-and-forth on this; these formatting PRs can be really contentious as you know :) |
Oh I know. One question though is whether the all-important Fixing the code is easy, fixing the tests may take me a while to get to, we'll see. |
Could we add some logic that prints either |
Yes, surely. Will try that out. |
Jeff/Jameson as a fan of making the arg name stand out regardless (as in #40251 (comment)), is there anything you have against that? |
I mildly dislike the extra color, on the basis of being too noisy. |
Note: closes #40913 |
I see. I'd comment that having it be styled the same regardless is good for visual consistency and it isn't unimportant enough to be greyed out, as the naming can often be informative. |
Ah, I forgot to mention that @staticfloat made the point that we shouldn't rely too heavily on colors; the output should be nice even with the colors stripped. That's another reason I prefer leaving out |
Should we re-use something like the new error printing for method lists?
Perhaps the module
which(f)
should be mostly omitted, to highlight only other-module methods?(Edit -- deleted an example. The one above does not yet have types in bold, added below.)
Closes #40913 Closes #30110 Closes #36129