Skip to content

Conversation

chu11
Copy link
Member

@chu11 chu11 commented Sep 12, 2025

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 :-)

Comment on lines 1003 to 1010
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])
Copy link
Contributor

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)

Copy link
Member Author

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.

Copy link
Contributor

@grondo grondo Sep 12, 2025

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, "")))

Copy link
Member Author

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?

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Member Author

@chu11 chu11 Sep 15, 2025

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

Copy link
Contributor

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".

Copy link
Member Author

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.

Copy link
Contributor

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 🤦

@chu11 chu11 force-pushed the issue7030_flux_jobs_column_width branch 2 times, most recently from f9bf273 to 0743b25 Compare September 16, 2025 17:17
@chu11 chu11 force-pushed the issue7030_flux_jobs_column_width branch from 0743b25 to ec16919 Compare September 16, 2025 17:36
@chu11 chu11 force-pushed the issue7030_flux_jobs_column_width branch 2 times, most recently from 0eb078f to 1f82640 Compare September 16, 2025 19:16
@chu11
Copy link
Member Author

chu11 commented Sep 16, 2025

re-pushed with fixes per discussion above

Copy link
Contributor

@grondo grondo left a 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.
@chu11 chu11 force-pushed the issue7030_flux_jobs_column_width branch from 1f82640 to 8c72102 Compare September 16, 2025 22:04
@mergify mergify bot merged commit a29d29d into flux-framework:master Sep 16, 2025
35 checks passed
Copy link

codecov bot commented Sep 16, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.08%. Comparing base (3776faf) to head (8c72102).
⚠️ Report is 7 commits behind head on master.

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     
Files with missing lines Coverage Δ
src/bindings/python/flux/util.py 96.64% <100.00%> (+0.01%) ⬆️
src/cmd/flux-jobs.py 96.68% <100.00%> (ø)
src/cmd/flux-pgrep.py 95.12% <100.00%> (ø)

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@chu11 chu11 deleted the issue7030_flux_jobs_column_width branch September 17, 2025 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

flux jobs -o struggles with right-alignment in certain fields
2 participants