Skip to content

[CLI] Add Flow360 CLI foundation commands#2022

Open
maciej-flexcompute wants to merge 12 commits intomainfrom
maciej/codex/flow360-cli-pr1-foundation
Open

[CLI] Add Flow360 CLI foundation commands#2022
maciej-flexcompute wants to merge 12 commits intomainfrom
maciej/codex/flow360-cli-pr1-foundation

Conversation

@maciej-flexcompute
Copy link
Copy Markdown
Collaborator

@maciej-flexcompute maciej-flexcompute commented Apr 27, 2026

Summary

This is PR 1 of the Flow360 CLI split. It adds the lightweight foundation and discovery surface without including resource inspection, mutation, draft execution, logs, or results handling.

Changes included:

  • Add lazy root Click command loading for SDK-backed command groups.
  • Add shared CLI context and JSON/text output helpers.
  • Add flow360 project list/info/tree/items/path with lightweight webAPI-backed reads.
  • Add flow360 project list --format text and reuse the formatter for legacy show_projects.
  • Add flow360 folder get/tree.
  • Add thin ProjectWebApi, ProjectTree, and FolderWebApi helpers for these read paths.
  • Add focused tests for lazy imports, project/folder CLI behavior, and endpoint selection.

Validation

Result: 39 passed in 3.75s.

CLI command smoke timings

Real E2E smoke run against the Flow360 API using the locally installed PR checkout after removing the hidden project get alias. Times are single-run wall-clock measurements from the CLI process and include authentication lookup, API latency, JSON parsing, and terminal formatting.

Real data used:

  • Project: Simple Airplane (prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0), with geometry, surface mesh, two volume meshes, and two cases.
  • Case path target: case-7b77792d-ed36-4760-921a-a7b9614a867d.
  • Folder: Codex Perf Folder 153737 (folder-7629a9ed-c3de-4d38-b48b-c9fef25ddb71).
Command Real data Time Exit
flow360 project list --limit 3 workspace projects, limit 3 3.136s 0
flow360 project list --limit 1 --format text workspace projects, limit 1 2.479s 0
flow360 project info prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0 Simple Airplane project 2.587s 0
flow360 project tree prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0 Simple Airplane project hierarchy 2.514s 0
flow360 project items prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0 Simple Airplane project items 2.471s 0
flow360 project path prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0 --item-id case-7b77792d-ed36-4760-921a-a7b9614a867d --item-type Case Simple Airplane Case path 2.733s 0
flow360 folder get folder-7629a9ed-c3de-4d38-b48b-c9fef25ddb71 Codex Perf Folder 153737 2.971s 0
flow360 folder tree workspace folder tree 2.459s 0

Example responses:
flow360 project list --limit 3

{
  "records": [
    {
      "id": "prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0",
      "name": "Simple Airplane",
      "root_item_type": "Geometry",
      "solver_version": "release-25.8",
      "statistics": {
        "case": {
          "count": 2,
          "diverged_count": 0,
          "error_count": 0,
          "running_count": 0,
          "success_count": 2
        },
        "geometry": {
          "count": 1,
          "diverged_count": 0,
          "error_count": 0,
          "running_count": 0,
          "success_count": 1
        },
        "surface_mesh": {
          "count": 1,
          "diverged_count": 0,
          "error_count": 0,
          "running_count": 0,
          "success_count": 1
        },
        "volume_mesh": {
          "count": 2,
          "diverged_count": 0,
          "error_count": 0,
          "running_count": 0,
          "success_count": 2
        }
      }
    },
    {
      "id": "prj-68627738-e399-4720-ba1b-27714c156807",
      "name": "Codex Perf Temp 153737",
      "root_item_type": "Geometry",
      "solver_version": "release-25.9",
      "statistics": {
        "case": null,
        "geometry": {
          "count": 1,
          "diverged_count": 0,
          "error_count": 0,
          "running_count": 0,
          "success_count": 1
        },
        "surface_mesh": null,
        "volume_mesh": null
      }
    }
  ],
  "note": "2 of 3 returned projects shown"
}

flow360 project list --limit 1 --format text

>>> Projects sorted by creation time:
 Name:         Simple Airplane
 Created at:   2026-04-24 15:41 CEST
 Created with: Geometry
 Solver:       release-25.8
 ID:           prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0
 Link:         https://flow360.simulation.cloud/workbench/prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0
 Tags:         ['SA', 'Steady']
 Geometry count:     1
 Surface Mesh count: 1
 Volume Mesh count:  2
 Case count:         2

Showing 1 of 446 matching projects.

flow360 project info prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0

{
  "id": "prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0",
  "name": "Simple Airplane",
  "root_item": {
    "id": "geo-55cf9c04-02e2-4584-870d-9352d397a789",
    "type": "Geometry"
  },
  "solver_version": "release-25.8",
  "tags": [
    "SA",
    "Steady"
  ]
}

flow360 project tree prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0

{
  "root": {
    "id": "geo-55cf9c04-02e2-4584-870d-9352d397a789",
    "name": "Simple Airplane",
    "type": "Geometry",
    "children": [
      {
        "id": "sm-1a308cad-f76d-4ef7-a908-9b4cc5be50e0",
        "name": "Simple Airplane",
        "type": "SurfaceMesh",
        "child_count": 2
      }
    ]
  }
}

flow360 project items prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0

{
  "items": [
    {
      "id": "geo-55cf9c04-02e2-4584-870d-9352d397a789",
      "name": "Simple Airplane",
      "parent_id": null,
      "type": "Geometry"
    },
    {
      "id": "sm-1a308cad-f76d-4ef7-a908-9b4cc5be50e0",
      "name": "Simple Airplane",
      "parent_id": "geo-55cf9c04-02e2-4584-870d-9352d397a789",
      "type": "SurfaceMesh"
    },
    {
      "id": "vm-2ba578a0-c17b-4c61-ae47-f8d7ea2dcced",
      "name": "Simple Airplane (copy)",
      "parent_id": "sm-1a308cad-f76d-4ef7-a908-9b4cc5be50e0",
      "type": "VolumeMesh"
    },
    {
      "id": "vm-e84a7911-2370-406f-99a8-fc0a35a9b87a",
      "name": "Simple Airplane",
      "parent_id": "sm-1a308cad-f76d-4ef7-a908-9b4cc5be50e0",
      "type": "VolumeMesh"
    },
    {
      "id": "case-7b77792d-ed36-4760-921a-a7b9614a867d",
      "name": "Simple Airplane",
      "parent_id": "vm-e84a7911-2370-406f-99a8-fc0a35a9b87a",
      "type": "Case"
    },
    {
      "id": "case-1a0fd2c2-5908-4910-a2ed-a4e6927e47e6",
      "name": "Simple Airplane (copy)",
      "parent_id": "vm-2ba578a0-c17b-4c61-ae47-f8d7ea2dcced",
      "type": "Case"
    }
  ]
}

flow360 project path prj-7cd91cca-3049-47cd-a5c8-d7cf0ad1cbc0 --item-id case-7b77792d-ed36-4760-921a-a7b9614a867d --item-type Case

{
  "items": [
    {
      "id": "geo-55cf9c04-02e2-4584-870d-9352d397a789",
      "name": "Simple Airplane",
      "parent_id": null,
      "status": "processed",
      "type": "Geometry",
      "updated_at": "2026-04-24T13:41:26.114Z"
    },
    {
      "id": "sm-1a308cad-f76d-4ef7-a908-9b4cc5be50e0",
      "name": "Simple Airplane",
      "parent_id": "geo-55cf9c04-02e2-4584-870d-9352d397a789",
      "status": "processed",
      "type": "SurfaceMesh",
      "updated_at": "2026-04-24T13:48:50.02Z"
    },
    {
      "id": "vm-e84a7911-2370-406f-99a8-fc0a35a9b87a",
      "name": "Simple Airplane",
      "parent_id": "sm-1a308cad-f76d-4ef7-a908-9b4cc5be50e0",
      "status": "completed",
      "type": "VolumeMesh",
      "updated_at": "2026-04-24T13:41:32.716Z"
    },
    {
      "id": "case-7b77792d-ed36-4760-921a-a7b9614a867d",
      "name": "Simple Airplane",
      "parent_id": "vm-e84a7911-2370-406f-99a8-fc0a35a9b87a",
      "status": "completed",
      "type": "Case",
      "updated_at": "2026-04-24T13:41:35.088Z"
    }
  ]
}

flow360 folder get folder-7629a9ed-c3de-4d38-b48b-c9fef25ddb71

{
  "created_at": "2026-04-24T13:39:48.658518301Z",
  "id": "folder-7629a9ed-c3de-4d38-b48b-c9fef25ddb71",
  "name": "Codex Perf Folder 153737",
  "parent_folders": [
    {
      "id": "ROOT.FLOW360",
      "name": "ROOT.FLOW360"
    },
    {
      "id": "folder-7629a9ed-c3de-4d38-b48b-c9fef25ddb71",
      "name": "Codex Perf Folder 153737"
    }
  ],
  "parent_id": "ROOT.FLOW360",
  "tags": [],
  "type": "Folder",
  "updated_at": "2026-04-24T13:39:48.658518301Z"
}

flow360 folder tree

{
  "root": {
    "id": "ROOT.FLOW360",
    "name": "My workspace",
    "subfolders": [
      {
        "id": "folder-080e2fcd-79cc-4880-94ca-c550098de351",
        "name": "my design",
        "subfolder_count": 0
      },
      {
        "id": "folder-0a315ae2-5635-461b-b9a5-b6cd069038c2",
        "name": "assignment",
        "subfolder_count": 0
      },
      {
        "id": "folder-169ed19e-1bd8-460b-90bf-9784329b35bc",
        "name": "customers",
        "subfolder_count": 8
      },
      {
        "id": "folder-1a8efb93-08ad-4dc1-bcef-f32a6ec9feec",
        "name": "ahmed",
        "subfolder_count": 0
      },
      {
        "id": "folder-28079d66-7676-404f-a155-110dacfd8819",
        "name": "test_folder",
        "subfolder_count": 0
      }
    ],
    "note": "showing 5 of 24 root subfolders"
  }
}

Notes

This intentionally excludes later CLI work: geometry/surface-mesh/volume-mesh/case inspection, draft commands, open/wait/logs, project/folder mutations, results handling, and local flow360-schema path wiring.


Note

Medium Risk
Primarily additive, but it changes CLI command loading and global env/profile handling for existing commands, which could alter runtime behavior or error handling in authentication/config flows.

Overview
Introduces a lazy-loading Click CLI foundation that defers importing SDK-backed command groups until invoked, and centralizes global --profile/--dev/--uat/--env handling via a shared CliContext.

Adds new read-only CLI surfaces for cloud discovery: flow360 project list/info/tree/items/path (with optional --format text) and flow360 folder get/tree, plus shared JSON/text output helpers and presentation-only project list formatting.

Refactors existing commands to use the new context resolution (including prompting for API key only when needed), updates show_projects to reuse the new project list formatter, adds thin /v2 web API wrappers for projects/folders, and expands tests (including lazy-import guarantees and endpoint selection) alongside mock server support for the new /v2/folders list endpoint.

Reviewed by Cursor Bugbot for commit 40ee7a9. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

Coverage report (flow360)

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  flow360
  __init__.py
  exceptions.py
  flow360/cli
  app.py 58, 85, 95-98, 126, 137-138, 193, 317-318, 344-346, 363
  context.py
  folder.py 64
  output.py 27
  project.py 135-137
  project_formatters.py 10, 15-16, 37
  flow360/component/simulation/web
  folder_webapi.py 68
  project_records.py 94
  project_webapi.py
Project Total  

This report was generated by python-coverage-comment-action

@maciej-flexcompute maciej-flexcompute changed the title [codex] Add Flow360 CLI foundation commands [CLI] Add Flow360 CLI foundation commands Apr 29, 2026
@maciej-flexcompute maciej-flexcompute marked this pull request as ready for review April 29, 2026 11:41
Comment thread flow360/component/geometry.py Outdated
Comment thread flow360/cli/project.py Outdated
Comment thread flow360/component/geometry.py Outdated
Comment thread flow360/component/simulation/web/project_tree.py Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit bf5f3a0. Configure here.

Comment thread flow360/cli/project.py
Comment thread flow360/cli/project.py
"id": info["id"],
"name": info["name"],
"solver_version": info.get("solverVersion"),
"tags": list(info.get("tags") or []),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

So the schema for tags is actually list of list?

ROOT_FOLDER_NAME = "My workspace"


class FolderWebApi:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Any plan to unify the API call site for the class Folder and class FodlerWebAPI? Like the _build_folder_tree() looks very similar with the _build_tree() function below.

Comment thread flow360/__init__.py
from flow360_schema.models.functions import math
from flow360_schema.models.variables import solution

from flow360 import component
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What is this for?

Comment thread flow360/__init__.py
_warn_prerelease()


def __getattr__(name):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What is this for?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this implementing the lazy load?

Comment thread flow360/exceptions.py
Flow360Error = _schema_exceptions.Flow360Error
Flow360ValueError = _schema_exceptions.Flow360ValueError

Flow360ErrorWithLocation = getattr(_schema_exceptions, "Flow360ErrorWithLocation", Flow360Error)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is the fallback to Flow360Error needed? If we have correct schema dependency specified this (missing module) should not be a problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants