Managing Projects
Retrieve one remote project
To inspect a project in Union, initialize Flyte and call the publicly re-exported Project class:
import flyte
from flyte.remote import Project
flyte.init(endpoint="dns:///your-union-endpoint")
project = Project.get("my_project")
print(project.to_dict())
print(project.to_json())
Project is a dataclass whose pb2 attribute contains the returned flyteidl.admin.project_pb2.Project message. It inherits ToJSONMixin, so to_dict() uses protobuf MessageToDict and to_json() uses protobuf MessageToJson for that payload.
Project.get(name, org=None) is implemented in remote/_project.py. It first calls ensure_client(), obtains get_client().project_domain_service, and sends a project_pb2.ProjectGetRequest with id=name to GetProject. The response protobuf is wrapped directly in a new Project instance. Although the method accepts org, the org=org request field is currently commented out; passing org therefore does not change the request sent by flyte-sdk.
The returned object can also be rendered through Rich. Its __rich_repr__() exposes these fields:
nameandidfrom the protobuf messagedescription- the symbolic project state from
Project.ProjectState.Name(...) - labels as a comma-separated
key: valuestring, orNonewhen the protobuf labels field is empty
For example, the CLI's named-project path uses the same method and Rich representation:
from rich.console import Console
from rich.pretty import pretty_repr
from flyte.remote import Project
console = Console()
console.print(pretty_repr(Project.get("my_project")))
The repository's pyflyte get project NAME command initializes its configured client with cfg.init(), calls Project.get(name), and prints pretty_repr(...).
List projects
Use Project.listall() when the goal is to enumerate projects rather than retrieve one by name:
import flyte
from flyte.remote import Project
flyte.init(endpoint="dns:///your-union-endpoint")
for project in Project.listall():
print(project.pb2.name, project.pb2.id)
listall accepts two optional arguments:
Project.listall(
filters=None,
sort_by=None,
)
Pass sorting as a (field, order) tuple. If omitted, flyte-sdk uses ("created_at", "asc"):
for project in Project.listall(sort_by=("created_at", "desc")):
print(project.to_dict())
The implementation converts the tuple to common_pb2.Sort. The exact string "asc" selects common_pb2.Sort.ASCENDING; any other order value follows the descending branch, so callers should use the documented "asc" or "desc" literals. A filters string, when supplied, is copied to the filters field of each project_pb2.ProjectListRequest:
for project in Project.listall(filters="your-project-filter"):
print(project.pb2.name)
The filter expression is passed through to the backend; Project does not parse or transform it.
Pagination behavior
Project.listall is backed by an async generator but is decorated with @syncify. Each request uses limit=100. After yielding every project in the response, it assigns resp.token to the next request's token. It continues making ListProjects calls until the service returns an empty token. Consequently, consuming the iterator can make multiple backend requests, and there is no caller-facing page-size or maximum-result argument.
Every yielded value is a Project wrapping one protobuf project, rather than the raw protobuf message. This makes the same to_dict(), to_json(), and Rich behavior available for list results as for Project.get() results.
Use the async form
Synchronous callers use the ordinary call shown above. In async code, use the .aio() form supplied by syncify:
import flyte
from flyte.remote import Project
await flyte.init.aio(endpoint="dns:///your-union-endpoint")
project = await Project.get.aio("my_project")
async for project in Project.listall.aio(sort_by=("created_at", "asc")):
print(project.pb2.name)
Project.get is an async implementation exposed synchronously by @syncify; its async counterpart returns an awaitable project. Project.listall is an async-generator implementation, so its async counterpart is consumed with async for. Async code should use .aio() rather than invoking the synchronous wrapper from the syncify background-loop thread; the syncify implementation detects that blocking situation and raises an assertion directing the caller to .aio().
How project requests reach Union
Both methods use the current ClientSet obtained through get_client():
Project.get(...)callsClientSet.project_domain_service.GetProject(...).Project.listall(...)callsClientSet.project_domain_service.ListProjects(...).
ClientSet.project_domain_service returns the _admin_client as the ProjectDomainService client. The project methods construct the generated request messages from flyteidl.admin.project_pb2, and construct list ordering with flyteidl.admin.common_pb2.Sort.
Use the built-in CLI listing
The repository already wires both project operations into pyflyte get project:
@get.command()
@click.argument("name", type=str, required=False)
@click.pass_obj
def project(cfg: common.CLIConfig, name: str | None = None):
"""
Get a list of all projects, or details of a specific project by name.
"""
from flyte.remote import Project
cfg.init()
console = Console()
if name:
console.print(pretty_repr(Project.get(name)))
else:
console.print(common.format("Projects", Project.listall(), cfg.output_format))
With a name, the command displays one project using Rich. Without a name, it passes the Project.listall() iterator to common.format. The CLI output format is configured through CLIConfig; the declared formats are table, json, and table-simple.
Troubleshooting and current limitations
Client initialization errors
Call flyte.init(...) with a valid endpoint or API key before calling either project method. ensure_client() checks that a client exists, and get_client() raises InitializationError with a message instructing callers to initialize with an endpoint or API key when it does not. init also supports the configured authentication and transport options, but Project itself reads none of them directly.
Organization is not currently applied
Project.get exposes org, but the request construction contains # org=org, so the argument is ignored. Organization handling is also commented out in listall. The source contains a top-level TODO to add organization support again. Do not rely on org to scope either operation.
Sorting values
Use a two-item tuple such as ("created_at", "asc") or ("created_at", "desc"). The implementation treats only the exact string "asc" as ascending and routes every other value to descending; use the documented literals to avoid surprising ordering.
Large result sets
There is no limit parameter on Project.listall. The method requests 100 projects per RPC and follows continuation tokens internally, so iteration does not stop after the first 100 results. It stops only after a response has no continuation token.
Project state and labels in Rich output
Rich output converts the numeric protobuf state with Project.ProjectState.Name(...) and flattens labels into display text. The Rich representation is intended for presentation; use to_dict() or to_json() when you need the protobuf-backed serialized representation.