Skip to content
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

feat(framework) Add JSON formatting to flwr ls output #4610

Merged
merged 44 commits into from
Dec 4, 2024
Merged
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5b59496
Init
chongshenng Nov 28, 2024
28e8c5a
Suppress stdout and stderr
chongshenng Nov 29, 2024
9d7af73
Update json
chongshenng Dec 2, 2024
6192d77
Redirect captured output
chongshenng Dec 2, 2024
ae09cf5
Merge branch 'main' into add-json-to-flwr-ls
chongshenng Dec 2, 2024
ab64a3f
Format
chongshenng Dec 2, 2024
f9e13fa
feat(framework) Refactor flwr ls table formatter
chongshenng Dec 2, 2024
6a96dfe
Introduce try-except block to print JSON-formatted errors
chongshenng Dec 2, 2024
bc761b5
Introduce JSON formatting function
chongshenng Dec 2, 2024
97b9a70
Format
chongshenng Dec 2, 2024
5de9505
Add missing import
chongshenng Dec 2, 2024
de1fb19
Rename
chongshenng Dec 2, 2024
28cf26c
Update docstring
chongshenng Dec 2, 2024
fd77e44
Update
chongshenng Dec 2, 2024
985af69
Merge branch 'main' into add-json-to-flwr-ls
chongshenng Dec 3, 2024
a7f02a7
Refactor
chongshenng Dec 3, 2024
bd1c86a
Add output formats to constants
chongshenng Dec 3, 2024
1c501a1
Merge branch 'main' into introduce-json-format
chongshenng Dec 3, 2024
392b9c3
Revert
chongshenng Dec 3, 2024
605d576
Break arg lines
chongshenng Dec 3, 2024
3d22e45
Address comments
chongshenng Dec 3, 2024
4885ba3
Merge branch 'main' into refactor-ls-table-format
chongshenng Dec 3, 2024
8490c95
Update
chongshenng Dec 3, 2024
066dfcf
Remove SystemExit
chongshenng Dec 3, 2024
ca0dd00
Update
chongshenng Dec 3, 2024
c1905c8
Update
chongshenng Dec 3, 2024
69336ad
Address comment
chongshenng Dec 3, 2024
07bc030
Address comments
chongshenng Dec 3, 2024
c8259e4
Address comments
chongshenng Dec 3, 2024
6831f70
Fix
chongshenng Dec 3, 2024
ab8e4d5
Fix
chongshenng Dec 3, 2024
3c1808c
Move fn to utils
chongshenng Dec 4, 2024
4a09f95
Use Python bool
chongshenng Dec 4, 2024
65288bf
Merge main
chongshenng Dec 4, 2024
ba8f8fb
Merge branch 'print-errors-as-json' into introduce-json-format
chongshenng Dec 4, 2024
e6eae95
Merge main
chongshenng Dec 4, 2024
0cc5ed6
Merge branch 'main' into introduce-json-format
danieljanes Dec 4, 2024
51c5c1c
Lint
chongshenng Dec 4, 2024
a65f7af
Update
chongshenng Dec 4, 2024
52838e5
Remove bbcode function, move format
chongshenng Dec 4, 2024
014fcc0
Merge branch 'introduce-json-format' into add-json-to-flwr-ls
chongshenng Dec 4, 2024
5d123fa
Merge main
chongshenng Dec 4, 2024
4631cc0
Remove unused typehint
chongshenng Dec 4, 2024
bb93935
Merge branch 'main' into add-json-to-flwr-ls
danieljanes Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 46 additions & 9 deletions src/py/flwr/cli/ls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@
"""Flower command line interface `ls` command."""


import io
import json
from datetime import datetime, timedelta
from logging import DEBUG
from pathlib import Path
from typing import Annotated, Any, Optional
from typing import Annotated, Any, Optional, Union

import grpc
import typer
from rich.console import Console
from rich.table import Table
from rich.text import Text
from typer import Exit

from flwr.cli.config_utils import (
load_and_validate,
Expand All @@ -36,7 +38,7 @@
from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat, SubStatus
from flwr.common.date import format_timedelta, isoformat8601_utc
from flwr.common.grpc import GRPC_MAX_MESSAGE_LENGTH, create_channel
from flwr.common.logger import log
from flwr.common.logger import log, redirect_output, remove_emojis, restore_output
from flwr.common.serde import run_from_proto
from flwr.common.typing import Run
from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
Expand All @@ -48,7 +50,7 @@
_RunListType = tuple[int, str, str, str, str, str, str, str, str]


def ls(
def ls( # pylint: disable=too-many-locals, too-many-branches
app: Annotated[
Path,
typer.Argument(help="Path of the Flower project"),
Expand All @@ -71,9 +73,22 @@ def ls(
help="Specific run ID to display",
),
] = None,
output_format: Annotated[
str,
typer.Option(
"--format",
case_sensitive=False,
help="Format output using 'default' view or 'json'",
),
] = CliOutputFormat.DEFAULT,
) -> None:
"""List runs."""
suppress_output = output_format == CliOutputFormat.JSON
captured_output = io.StringIO()
try:
if suppress_output:
redirect_output(captured_output)

# Load and validate federation config
typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)

Expand Down Expand Up @@ -105,11 +120,13 @@ def ls(
# Display information about a specific run ID
if run_id is not None:
typer.echo(f"🔍 Displaying information for run ID {run_id}...")
_display_one_run(stub, run_id)
restore_output()
panh99 marked this conversation as resolved.
Show resolved Hide resolved
_display_one_run(stub, run_id, output_format)
# By default, list all runs
else:
typer.echo("📄 Listing all runs...")
_list_runs(stub)
restore_output()
panh99 marked this conversation as resolved.
Show resolved Hide resolved
_list_runs(stub, output_format)

except ValueError as err:
typer.secho(
Expand All @@ -120,9 +137,21 @@ def ls(
raise typer.Exit(code=1) from err
finally:
channel.close()
# pylint: disable=broad-except
except (typer.Exit, Exception):
_print_json_error()
except (typer.Exit, Exception) as err: # pylint: disable=broad-except
if suppress_output:
restore_output()
panh99 marked this conversation as resolved.
Show resolved Hide resolved
e_message = captured_output.getvalue()
_print_json_error(e_message, err)
else:
typer.secho(
f"{err}",
fg=typer.colors.RED,
bold=True,
)
finally:
if suppress_output:
restore_output()
captured_output.close()


def on_channel_state_change(channel_connectivity: str) -> None:
Expand Down Expand Up @@ -313,5 +342,13 @@ def _display_one_run(
Console().print(_to_table(formatted_runs))


def _print_json_error() -> None:
def _print_json_error(msg: str, e: Union[Exit, Exception]) -> None:
"""Print error message as JSON."""
Console().print_json(
json.dumps(
{
"success": False,
"error-message": remove_emojis(str(msg) + "\n" + str(e)),
}
)
)