-
Notifications
You must be signed in to change notification settings - Fork 54
python: consider output header w/ expandable width #7053
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
python: consider output header w/ expandable width #7053
Conversation
src/bindings/python/flux/util.py
Outdated
initialmaxwidth = spec.width or 0 | ||
if ( | ||
sentinels[end] in ("maxwidth", "both") | ||
and self.headings | ||
and self.headings[field] | ||
and len(self.headings[field]) > initialmaxwidth | ||
): | ||
initialmaxwidth = len(self.headings[field]) |
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.
Unfortunately, this applies the heading length to maxwidth even if -n, --no-header
is used, which isn't what we want.
Let me ponder the best way to fix this. It may be to just pass args.no_header
into the initializer then zero out the headings (if that works, it may not be so simple for JobInfoFormatter)
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.
Yeah, I did realize that. We seem to always pass headers into OutputFormat.
I did consider it being a possibly separate issue. Notice this commit I just added 0e4a22e. That's just to get a test to pass, checking if headers exist in other parts of OutputFormat probably also warranted.
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.
Yeah, and the design allows headers to be class variables when you subclass so just not passing in headings is not a great solution.
The simplest thing would be just add a no_headers=False
optional argument to the class initializer and use this in the test above. Unfortunately we'll have to update all callers, but I don't really see a cleaner way around it for now.
Finally, to make this code cleaner, the class should start with an empty self.headings
, e.g. self.headings = {}
. Then you can drop the test for self.headings
. Then avoid accessing self.headings[field]
multiple times by doing something like:
if sentinels[end] in ("maxwidth", "both"):
initialmaxwidth = max(spec.width or 0, len(self.headings.get(field, "")))
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 simplest thing would be just add a no_headers=False optional argument to the class initializer and use this in the test above. Unfortunately we'll have to update all callers, but I don't really see a cleaner way around it for now.
Hmmm. Technically I think we only have to do this for JobInfoFormat? B/c w/ OutputFormat we can just pass in or not pass in a headings. For JobInfoFormat we are always setting one. Or are you thinking of doing both for just consistency?
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.
Since the code to set the maxwidth is in the base OutputFormat
class, it should take no_header
in its initializer I'd think.
The initialization of self.headings
in OutputFormat
to and empty dictionary would just seem to make the rest of the code cleaner because you would not have to check for self.headings = None
anywhere.
Let me check if that would mess up any other assumptions though.
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 could be in one PR since it is only required to fix this issue properly.
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.
Hmmmm. I just noticed that the primary user of the filter()
function in OutputFormat
is the print_items()
function, which already has a no_header
flag. So we could get away with adding no_header
to filter()
instead. Any objections? That would take care of the majority of cases, just a few oddball ones (for example flux-jobs
calls filter()
directly).
Edit: As I look at this more, I'm liking this option 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.
Yeah, that is what I was envisioning as the easiest "fix".
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.
ahh, you mentioned passing no_header
in the initializer at first, so that was what I was going with initially.
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.
Oh yeah, I did, didn't I? Sorry, I probably shouldn't mention specifics until actually looking at the implementation again 🤦
f9bf273
to
0743b25
Compare
0743b25
to
ec16919
Compare
0eb078f
to
1f82640
Compare
re-pushed with fixes per discussion above |
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 turned out excellent. Nice work!
Problem: There is no documentation for the args to the OutputFormat filter() function. Add inline documentation.
Problem: In the future the header may be needed in calculations within the OutputFormat filter() function. There is no way to inform the filter() function that the header should not be considered (for example, if the header fill not be output). Add a no_header flag to the filter() function in OutputFormat(). This parameter currently does nothing. Update all callers as needed.
Problem: The expandable field prefix ("+:") does not consider the width of the output header name when calculating output width. If all output entries are less than the size of the output header name, then output will not look as expected. Solution: When calculating maximum output width of a field, take into account the header entry name as long as no_header is not set. Update some tests in python/t0024-util.py for changes. Fixes flux-framework#7030
Problem: Tests already exist for flux-jobs expandable fields ("+:") but do not cover the special case when all outputs are less than the length of the column header. Add a test in t2800-jobs-cmd.t.
Problem: The current OutputFormat python tests always assume output headers used in expandable width tests. Add some tests that set no_headers=True, so that the output headers are not taken into account.
1f82640
to
8c72102
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #7053 +/- ##
=======================================
Coverage 84.08% 84.08%
=======================================
Files 549 549
Lines 92521 92524 +3
=======================================
+ Hits 77796 77802 +6
+ Misses 14725 14722 -3
🚀 New features to boost your workflow:
|
Problem: The expandable field prefix ("+:") does not consider the width of the output header name when calculated output width.
If all output entries are less than the size of the output header name, then output will not look as expected.
Solution: When calculating maximum output width of a field, take into account the header entry name.
Fixes #7030
Edit: Oops, some python tests I forgot to update, working on em :-)