Skip to content

🎨 Palette: Human-readable durations & code cleanup#424

Closed
abhimehro wants to merge 1 commit intomainfrom
palette-human-readable-durations-7775783598022719315
Closed

🎨 Palette: Human-readable durations & code cleanup#424
abhimehro wants to merge 1 commit intomainfrom
palette-human-readable-durations-7775783598022719315

Conversation

@abhimehro
Copy link
Owner

💡 What: Added human-readable duration formatting to the CLI summary table and fixed a syntax error.
🎯 Why: Long durations in seconds are hard to parse. The code also contained duplicate table printing logic and a broken validation block.
📸 Before/After: Durations like 125.5s now show as 2m 5.5s.
♿ Accessibility: Improved readability of timing data.


PR created automatically by Jules for task 7775783598022719315 started by @abhimehro

…rror

- Fix critical syntax error in `validate_folder_data` that prevented validation.
- Refactor `print_summary_table` to be a single, robust source of truth.
- Add `format_duration` helper to display times as `1m 30s` instead of raw seconds.
- Remove duplicate inline table printing logic from `main()`.

Co-authored-by: abhimehro <84992105+abhimehro@users.noreply.github.com>
@google-labs-jules
Copy link

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings February 24, 2026 23:01
@trunk-io
Copy link

trunk-io bot commented Feb 24, 2026

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

@github-actions
Copy link

👋 Development Partner is reviewing this PR. Will provide feedback shortly.

@gemini-code-assist
Copy link

Summary of Changes

Hello @abhimehro, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the command-line interface by making duration outputs more user-friendly, which significantly improves the readability of timing data. It also includes important code quality improvements by refactoring duplicated table rendering logic and fixing a critical syntax error in data validation, leading to a more robust and maintainable codebase.

Highlights

  • Human-readable durations: Implemented a new format_duration helper function to convert raw seconds into a more readable format (e.g., '2m 5.5s') for CLI summary tables.
  • Code Cleanup and Refactoring: Consolidated duplicate table printing logic into a single, refactored print_summary_table function, improving modularity and maintainability.
  • Syntax Error Fix: Corrected a syntax error within the validate_folder_data function, ensuring proper validation of rule group structures.
Changelog
  • .Jules/palette.md
    • Added a new learning entry documenting the benefits and action taken for human-readable durations.
  • main.py
    • Introduced a format_duration helper function to convert seconds into a human-readable string format.
    • Removed a redundant print_summary_table function, centralizing table rendering logic.
    • Fixed a syntax error in the validate_folder_data function related to rule group validation.
    • Rewrote the print_summary_table function to be more structured, using dedicated column width variables and incorporating the new format_duration helper.
    • Updated the main execution flow to call the consolidated print_summary_table function, removing inline table rendering logic.
Activity
  • PR created automatically by Jules for task 7775783598022719315, started by @abhimehro.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

**Learning:** Reconstructing command arguments manually for process restarts is brittle and breaks forward compatibility.
**Action:** When restarting a CLI tool with modified flags (e.g., removing `--dry-run`), filter `sys.argv` instead of rebuilding the argument list from parsed args.

## 2025-05-20 - [Human Readable Durations]

Check notice

Code scanning / Remark-lint (reported by Codacy)

Warn when references to undefined definitions are found. Note

[no-undefined-references] Found reference to undefined definition
**Learning:** Reconstructing command arguments manually for process restarts is brittle and breaks forward compatibility.
**Action:** When restarting a CLI tool with modified flags (e.g., removing `--dry-run`), filter `sys.argv` instead of rebuilding the argument list from parsed args.

## 2025-05-20 - [Human Readable Durations]

Check notice

Code scanning / Remark-lint (reported by Codacy)

Warn when shortcut reference links are used. Note

[no-shortcut-reference-link] Use the trailing [] on reference links
if seconds < 60:
return f"{seconds:.1f}s"

m, s = divmod(seconds, 60)

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "s" doesn't conform to snake_case naming style Warning

Variable name "s" doesn't conform to snake_case naming style
if seconds < 60:
return f"{seconds:.1f}s"

m, s = divmod(seconds, 60)

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning

Variable name "m" doesn't conform to snake_case naming style
if m < 60:
return f"{int(m)}m {s:.1f}s"

h, m = divmod(m, 60)

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning

Variable name "m" doesn't conform to snake_case naming style
if m < 60:
return f"{int(m)}m {s:.1f}s"

h, m = divmod(m, 60)

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "h" doesn't conform to snake_case naming style Warning

Variable name "h" doesn't conform to snake_case naming style
table_width = len(dummy_sep)

title_text = " DRY RUN SUMMARY " if dry_run else " SYNC SUMMARY "
title_color = Colors.CYAN if dry_run else Colors.HEADER

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (120/100) Warning

Line too long (120/100)
if seconds < 60:
return f"{seconds:.1f}s"

m, s = divmod(seconds, 60)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "s" doesn't conform to snake_case naming style Warning

Variable name "s" doesn't conform to snake_case naming style
if seconds < 60:
return f"{seconds:.1f}s"

m, s = divmod(seconds, 60)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning

Variable name "m" doesn't conform to snake_case naming style
if m < 60:
return f"{int(m)}m {s:.1f}s"

h, m = divmod(m, 60)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "h" doesn't conform to snake_case naming style Warning

Variable name "h" doesn't conform to snake_case naming style
if m < 60:
return f"{int(m)}m {s:.1f}s"

h, m = divmod(m, 60)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning

Variable name "m" doesn't conform to snake_case naming style
table_width = len(dummy_sep)

title_text = " DRY RUN SUMMARY " if dry_run else " SYNC SUMMARY "
title_color = Colors.CYAN if dry_run else Colors.HEADER

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (120/100) Warning

Line too long (120/100)
dummy_sep = make_col_separator(Box.TL, Box.T, Box.TR, Box.H)
table_width = len(dummy_sep)

title_text = " DRY RUN SUMMARY " if dry_run else " SYNC SUMMARY "

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the CLI user experience by adding human-readable duration formatting and fixes a critical syntax error in validation code. The changes consolidate duplicate table-printing logic into a single function while enhancing readability of timing information.

Changes:

  • Added format_duration() helper function to convert seconds into human-readable format (e.g., "2m 5.5s" instead of "125.5s")
  • Fixed syntax errors in validate_folder_data() where rule validation code had garbled characters and broken formatting
  • Removed duplicate print_summary_table() function definition and consolidated table printing logic into a single reusable function

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
main.py Added format_duration() utility function (lines 274-285), fixed syntax errors in rule validation block (lines 1004-1013), removed duplicate function definition (lines 329-480), refactored print_summary_table() to use new formatting (lines 2303-2404), simplified main() to call consolidated function (lines 2641-2642)
.Jules/palette.md Documented learning about human-readable duration formatting for CLI tools (lines 13-15)

Comment on lines +274 to +284
def format_duration(seconds: float) -> str:
"""Format duration in a human-readable way (e.g. 1m 30s)."""
if seconds < 60:
return f"{seconds:.1f}s"

m, s = divmod(seconds, 60)
if m < 60:
return f"{int(m)}m {s:.1f}s"

h, m = divmod(m, 60)
return f"{int(h)}h {int(m)}m {s:.0f}s"
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new format_duration() function lacks test coverage. Given the comprehensive test suite in this repository (test_main.py and tests/ directory), this utility function should have tests covering:

  • Durations less than 60 seconds (e.g., 45.5s → "45.5s")
  • Durations in minutes (e.g., 125.5s → "2m 5.5s")
  • Durations with hours (e.g., 3661s → "1h 1m 1s")
  • Edge cases like 0.0 seconds and very small values

This is especially important since the function is now used in user-facing summary tables where incorrect formatting would be immediately visible.

Copilot uses AI. Check for mistakes.
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a helper function to format durations into a human-readable format and refactors the summary table printing logic to improve code quality and readability, significantly cleaning up duplicated code. However, a critical Denial of Service vulnerability was identified in the validate_folder_data function due to the use of an undefined variable fil when processing malformed JSON data; this should be fixed by using the correct loop index i. Additionally, there are a couple of suggestions to further improve the consistency and robustness of the new summary table.

return f"{int(m)}m {s:.1f}s"

h, m = divmod(m, 60)
return f"{int(h)}h {int(m)}m {s:.0f}s"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The formatting of seconds is inconsistent across different duration ranges. For durations less than an hour, seconds are displayed with one decimal place (e.g., 59.9s), but for durations of an hour or more, they are rounded to the nearest whole number. This might be intentional, but for a more consistent user experience, consider using one decimal place for seconds in all cases.

Suggested change
return f"{int(h)}h {int(m)}m {s:.0f}s"
return f"{int(h)}h {int(m)}m {s:.1f}s"

Comment on lines +2310 to +2312
w_folders = 10
w_rules = 12
w_duration = 10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The column widths for "Folders", "Rules", and "Duration" are hardcoded. This can cause the table formatting to break if the values for these columns exceed the fixed width (e.g., a very long duration or a large number of rules). To make the table more robust, I suggest calculating these widths dynamically based on the content, similar to how w_profile is handled. Note that for this to work, you'll need to move the total_folders, total_rules, and total_duration calculations to before these width assignments.

Suggested change
w_folders = 10
w_rules = 12
w_duration = 10
w_folders = max(10, len(f"{total_folders:,}"), *(len(f"{r['folders']:,}") for r in sync_results))
w_rules = max(12, len(f"{total_rules:,}"), *(len(f"{r['rules']:,}") for r in sync_results))
w_duration = max(10, len(format_duration(total_duration)), *(len(format_duration(r['duration'])) for r in sync_results))

@abhimehro
Copy link
Owner Author

🤖 Automated PR Review — Closing as duplicate

Duplicate of #417/#420 — human-readable durations and summary table cleanup. The syntax fix is in #425 and unique Palette features are in #427 (ETA) and #437 (countdown timer). Closing as superseded.

@google-labs-jules
Copy link

🤖 Automated PR Review — Closing as duplicate

Duplicate of #417/#420 — human-readable durations and summary table cleanup. The syntax fix is in #425 and unique Palette features are in #427 (ETA) and #437 (countdown timer). Closing as superseded.

Understood. Acknowledging that this work is now obsolete as it has been superseded. Stopping work on this task.

@abhimehro abhimehro deleted the palette-human-readable-durations-7775783598022719315 branch March 1, 2026 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants