|
25 | 25 |
|
26 | 26 | import grpc |
27 | 27 | import pathspec |
28 | | -import requests |
29 | 28 | import typer |
30 | 29 |
|
31 | 30 | from flwr.common.constant import ( |
|
48 | 47 | create_channel, |
49 | 48 | on_channel_state_change, |
50 | 49 | ) |
51 | | -from flwr.common.version import package_version as flwr_version |
52 | | -from flwr.supercore.constant import APP_ID_PATTERN, APP_VERSION_PATTERN |
53 | 50 |
|
54 | 51 | from .auth_plugin import CliAuthPlugin, get_cli_plugin_class |
55 | 52 | from .cli_account_auth_interceptor import CliAccountAuthInterceptor |
@@ -547,94 +544,6 @@ def flwr_cli_grpc_exc_handler() -> Iterator[None]: # pylint: disable=too-many-b |
547 | 544 | raise |
548 | 545 |
|
549 | 546 |
|
550 | | -def request_download_link( |
551 | | - app_id: str, app_version: str | None, in_url: str, out_url: str |
552 | | -) -> str: |
553 | | - """Request a download link for the given app from the Flower platform API. |
554 | | -
|
555 | | - Parameters |
556 | | - ---------- |
557 | | - app_id : str |
558 | | - The application identifier. |
559 | | - app_version : str | None |
560 | | - The application version, or None for latest. |
561 | | - in_url : str |
562 | | - The API endpoint URL. |
563 | | - out_url : str |
564 | | - The key name for the download URL in the response. |
565 | | -
|
566 | | - Returns |
567 | | - ------- |
568 | | - str |
569 | | - The download URL for the application. |
570 | | -
|
571 | | - Raises |
572 | | - ------ |
573 | | - typer.Exit |
574 | | - If connection fails, app not found, or API request fails. |
575 | | - """ |
576 | | - headers = { |
577 | | - "Content-Type": "application/json", |
578 | | - "Accept": "application/json", |
579 | | - } |
580 | | - body = { |
581 | | - "app_id": app_id, # send raw string of app_id |
582 | | - "app_version": app_version, |
583 | | - "flwr_version": flwr_version, |
584 | | - } |
585 | | - try: |
586 | | - resp = requests.post(in_url, headers=headers, data=json.dumps(body), timeout=20) |
587 | | - except requests.RequestException as e: |
588 | | - typer.secho( |
589 | | - f"Unable to connect to Platform API: {e}", |
590 | | - fg=typer.colors.RED, |
591 | | - err=True, |
592 | | - ) |
593 | | - raise typer.Exit(code=1) from e |
594 | | - |
595 | | - if resp.status_code == 404: |
596 | | - error_message = resp.json()["detail"] |
597 | | - if isinstance(error_message, dict): |
598 | | - available_app_versions = error_message["available_app_versions"] |
599 | | - available_versions_str = ( |
600 | | - ", ".join(map(str, available_app_versions)) |
601 | | - if available_app_versions |
602 | | - else "None" |
603 | | - ) |
604 | | - typer.secho( |
605 | | - f"{app_id}=={app_version} not found in Platform API. " |
606 | | - f"Available app versions for {app_id}: {available_versions_str}", |
607 | | - fg=typer.colors.RED, |
608 | | - err=True, |
609 | | - ) |
610 | | - else: |
611 | | - typer.secho( |
612 | | - f"{app_id} not found in Platform API.", |
613 | | - fg=typer.colors.RED, |
614 | | - err=True, |
615 | | - ) |
616 | | - raise typer.Exit(code=1) |
617 | | - |
618 | | - if not resp.ok: |
619 | | - typer.secho( |
620 | | - f"Platform API request failed with " |
621 | | - f"status {resp.status_code}. Details: {resp.text}", |
622 | | - fg=typer.colors.RED, |
623 | | - err=True, |
624 | | - ) |
625 | | - raise typer.Exit(code=1) |
626 | | - |
627 | | - data = resp.json() |
628 | | - if out_url not in data: |
629 | | - typer.secho( |
630 | | - "Invalid response from Platform API", |
631 | | - fg=typer.colors.RED, |
632 | | - err=True, |
633 | | - ) |
634 | | - raise typer.Exit(code=1) |
635 | | - return str(data[out_url]) |
636 | | - |
637 | | - |
638 | 547 | def build_pathspec(patterns: Iterable[str]) -> pathspec.PathSpec: |
639 | 548 | """Build a PathSpec from a list of GitIgnore-style patterns. |
640 | 549 |
|
@@ -711,49 +620,3 @@ def validate_credentials_content(creds_path: Path) -> str: |
711 | 620 | raise typer.Exit(code=1) |
712 | 621 |
|
713 | 622 | return creds[ACCESS_TOKEN_KEY] |
714 | | - |
715 | | - |
716 | | -def parse_app_spec(app_spec: str) -> tuple[str, str | None]: |
717 | | - """Parse app specification string into app ID and version. |
718 | | -
|
719 | | - Parameters |
720 | | - ---------- |
721 | | - app_spec : str |
722 | | - The app specification string in the format '@account/app' or |
723 | | - '@account/app==x.y.z' (digits only). |
724 | | -
|
725 | | - Returns |
726 | | - ------- |
727 | | - tuple[str, str | None] |
728 | | - A tuple containing the app ID and optional version. |
729 | | -
|
730 | | - Raises |
731 | | - ------ |
732 | | - typer.Exit |
733 | | - If the app specification format is invalid. |
734 | | - """ |
735 | | - if "==" in app_spec: |
736 | | - app_id, app_version = app_spec.split("==") |
737 | | - |
738 | | - # Validate app version format |
739 | | - if not re.match(APP_VERSION_PATTERN, app_version): |
740 | | - typer.secho( |
741 | | - "❌ Invalid app version. Expected format: x.y.z (digits only).", |
742 | | - fg=typer.colors.RED, |
743 | | - err=True, |
744 | | - ) |
745 | | - raise typer.Exit(code=1) |
746 | | - else: |
747 | | - app_id = app_spec |
748 | | - app_version = None |
749 | | - |
750 | | - # Validate app_id format |
751 | | - if not re.match(APP_ID_PATTERN, app_id): |
752 | | - typer.secho( |
753 | | - "❌ Invalid remote app ID. Expected format: '@account/app'.", |
754 | | - fg=typer.colors.RED, |
755 | | - err=True, |
756 | | - ) |
757 | | - raise typer.Exit(code=1) |
758 | | - |
759 | | - return app_id, app_version |
0 commit comments