Skip to main content

aip_sdk.Project

aip_sdk.Project(id: str, name: str, schema_name: str, dimensions: list[Dimension], schema_capability: dict[str, Any] | None, created_at: datetime, updated_at: datetime, workspace_id: str | None = None, task_type: str | None = None, embedding_config_id: str | None = None, embedding_config_name: str | None = None, required_quality_checks: list[str] | None = None, test_plan: TestPlanBinding | None = None, client: APIClient | None = None)

A project is the top-level organizational unit in AIP v2.

Projects belong to a workspace, declare a GDI schema, and have stratification dimensions that drive coverage analysis and run-level score breakdowns.

A project created from a test plan reports the binding it was given, as six read-only attributes over one TestPlanBinding. All six read None/False on a project that declared its own contract, and on one whose plan was dropped by a move to another workspace.

Attributes

  • test_plan_id str | None: The published plan version this project was created from, or None when unbound. The pin never moves: a newer version of the same plan does not change what this project was bound to.
  • test_plan_name str | None: The bound plan's name. Reads the same from Project.list as from Project.get; None on an unbound project, and on one whose pin no longer resolves to a plan.
  • test_plan_version int | None: The bound plan version's number, with the same caveat as test_plan_name.
  • is_metrics_locked bool: Whether the plan fixed the project's evaluation config — runs on a locked project must omit metrics, metric_configs and metric_config_refs and score with the plan's values.
  • is_quality_checks_locked bool: Whether the plan fixed the project's required_quality_checks — the checks a dataset version must have produced a verdict for before promote_to_golden will accept it. Locked, that set is fixed at creation and cannot be changed.
  • is_dimensions_locked bool: Whether the plan fixed the project's dimension set — update_dimensions refuses every change on a locked project.
  • required_quality_checks list[str]: The checks a dataset version must have a verdict for before promote_to_golden accepts it, by bare operation key; [] means none. Reads the same from Project.list as from Project.get. The project's own set, not the binding's — it survives detach_test_plan.

aip_sdk.Project.analyse_coverage​

aip_sdk.Project.analyse_coverage(df: pd.DataFrame) -> CoverageReport

Perform client-side coverage analysis on a DataFrame.

Checks which dimension values are present/missing/unrecognised without requiring dataset upload.

Parameters

  • df pd.DataFrame: DataFrame to analyze

Returns

  • CoverageReport: CoverageReport with gaps, unrecognised values, and distributions

aip_sdk.Project.attach_test_plan​

aip_sdk.Project.attach_test_plan(test_plan: str | PublishedTestPlan) -> Project

Bring this project under a published test plan version.

The plan's task type, dimensions and every lock are written onto the project and the version is pinned — the same contract create_from_test_plan injects at creation, on a project that already holds its datasets and run history. The plan's dimensions replace the project's own, staging a draft version for each dataset already promoted; a version that is already golden keeps the dimensions it was promoted under, so the plan's dimensions apply from the next quality run and promotion onward. Runs created before this call are not rewritten.

The plan's schema and task type must be the ones this project already has, since neither can change afterwards. A project holding no task type adopts the plan's, and that is permanent — detach_test_plan does not give it back, because every dataset uploaded since is required to match it. So a project that adopted a task type here can only ever be bound to plans declaring that same one, and swapping it for a plan with a different task type is not possible on any path; check task_type before attaching if the project had none.

For that reason the adoption is refused outright when the project already holds a dataset declaring a different task type, naming those datasets: a project with no task type never required its datasets to agree with it, and adopting one would strand them.

Attach a plan to an unbound project only: call detach_test_plan first to swap one plan for another that declares the same schema and task type.

Parameters

  • test_plan str | PublishedTestPlan: The published plan version to attach — its id, or the record publish_test_plan, get_test_plan or list_test_plans returned. Pinned as given: a newer version of the same plan does not move the pin.

Returns

  • Project: This Project instance, updated in place with the contract the plan supplied.

Raises

  • InvalidArgumentError: If test_plan is neither an id nor a published record — an unpublished TestPlan has no id.
  • ConflictError: If this project is already bound to a plan — including this one, which a retried request can meet after the first attempt was committed. Read test_plan_id before deciding: for another version of the plan it already names, and for the retry case, use upgrade_test_plan, which needs no unbinding; call detach_test_plan only when it names a different plan, since detaching leaves the project unbound and every lock off until something binds it again.
  • TestPlanReferenceError: If a reference the plan carries no longer resolves — a metric deregistered since publish, or a pinned config since retired. failures names each one; nothing is written.
  • UnprocessableEntityError: If the plan's schema or task type is not this project's, if adopting the plan's task type would strand a dataset declaring a different one, or if a dimension the plan declares names a column one of this project's datasets does not have. Nothing is written in any of them.
  • NotFoundError: If the project no longer exists, or if no published plan version has that id in this project's workspace. The project is looked up first, so a project deleted since it was read reports this rather than the plan's absence.
  • ForbiddenError: If the caller is not an editor or admin of that workspace.
  • InvalidStateError: If this project was closed.
  • ResponseParseError: If the binding on the updated project does not match the shape this SDK version reads.

aip_sdk.Project.close​

aip_sdk.Project.close() -> None

Close the HTTP client if we own it.

aip_sdk.Project.create​

aip_sdk.Project.create(name: str, schema: str, dimensions: list[Dimension] | None = None, workspace_id: str | None = None, task_type: str | None = None, client: APIClient | None = None) -> Project

Create a new project with stratification dimensions.

Parameters

  • name str: Project name
  • schema str: GDI schema name (e.g., "gdi_text_v1")
  • dimensions list[Dimension] | None: Optional dimension declarations. Omitted or None creates a project with no dimensions (an empty list), mirroring the API default.
  • workspace_id str | None: Workspace this project belongs to. Falls back to client.config.workspace_id (set via init() or the AIP_WORKSPACE_ID env var) when not provided explicitly.
  • task_type str | None: Task discriminator for task-scoped schemas, e.g. "detection" for "gdi_image_v1".
  • client APIClient | None: Optional API client

Returns

Raises

aip_sdk.Project.create_from_test_plan​

aip_sdk.Project.create_from_test_plan(test_plan: str | PublishedTestPlan, *, name: str | None = None, dimensions: list[Dimension] | None = None, workspace_id: str | None = None, client: APIClient | None = None) -> Project

Create a project from a published test plan version.

The plan declares the project's schema and task type, so neither is passed here; the platform copies them, along with the plan's dimensions and every lock, onto the new project and pins the plan version it took them from. Nothing is fetched on the way — pass the id of the version you mean, or a record you already hold. create is the path for a project that declares its own contract.

A plan that leaves its dimensions unlocked accepts dimensions here, which replaces the set the project would otherwise copy. A plan that locks them refuses it, as update_dimensions refuses every later edit.

Parameters

  • test_plan str | PublishedTestPlan: The published plan version to create from — its id, or the record publish_test_plan, get_test_plan or list_test_plans returned.
  • name str | None: Project name. Defaults to the plan's name.
  • dimensions list[Dimension] | None: Dimension declarations to use instead of the plan's. Omit it, or pass None, to take the plan's own set; [] is refused, since the platform reads an empty set as no set at all. Refused too when the plan locks its dimensions — get_test_plan_by_id(id).plan.is_dimensions_locked says whether it does, if you need to know before calling.
  • workspace_id str | None: Workspace to create the project in. Falls back to the session's workspace (set via init() or the AIP_WORKSPACE_ID env var).
  • client APIClient | None: Optional API client.

Returns

  • Project: The new Project, with test_plan_id, test_plan_version and both lock flags set
  • Project: from the plan.

Raises

  • NoWorkspaceSelectedError: If no workspace is given here or configured for the session.
  • InvalidArgumentError: If test_plan is neither an id nor a published record — an unpublished TestPlan has no id — or if dimensions is an empty list.
  • TestPlanReferenceError: If a reference the plan carries no longer resolves — a metric deregistered since publish, or a pinned config since retired. failures names each one; no project is created.
  • DimensionLockViolationError: If dimensions is given and the plan locks its dimension set. Retrying the same call will not succeed; no project is created.
  • NotFoundError: If no published plan version has that id in the workspace.
  • UnprocessableEntityError: If the request fails validation for a reason other than the plan's references or its dimension lock, e.g. a malformed name.
  • ResponseParseError: If the platform's refusal detail, or the binding on the created project, does not match the shape this SDK version reads.

aip_sdk.Project.created_at​

aip_sdk.Project.created_at = created_at

No docstring is defined in the source.

aip_sdk.Project.detach_test_plan​

aip_sdk.Project.detach_test_plan() -> Project

Release this project from the test plan it is bound to.

Both locks are cleared, so dimension edits and run metrics are the project's own choices again. The contract itself stays: the project keeps the dimensions the plan gave it, to edit or discard, because its datasets were curated against them.

It keeps the task_type too, including one it adopted at attach because it had none. Datasets uploaded under the plan are required to match it, so it is never cleared, and nothing can set it back — the project stays bound to that task type whether or not it is bound to a plan.

Returns

  • Project: This Project instance, updated in place and bound to no plan.

Raises

aip_sdk.Project.dimensions​

aip_sdk.Project.dimensions = dimensions

No docstring is defined in the source.

aip_sdk.Project.embedding_config_id​

aip_sdk.Project.embedding_config_id = embedding_config_id

No docstring is defined in the source.

aip_sdk.Project.embedding_config_name​

aip_sdk.Project.embedding_config_name = embedding_config_name

No docstring is defined in the source.

aip_sdk.Project.get​

aip_sdk.Project.get(project_id: str, client: APIClient | None = None) -> Project

Fetch an existing project by ID.

Parameters

  • project_id str: Project ID
  • client APIClient | None: Optional API client

Returns

Raises

aip_sdk.Project.get_coverage​

aip_sdk.Project.get_coverage() -> CoverageReport

Get server-side coverage analysis for the project's active golden dataset.

This queries the actual golden dataset stored in MinIO (via DuckDB).

Returns

Raises

aip_sdk.Project.get_or_create​

aip_sdk.Project.get_or_create(name: str, schema: str, dimensions: list[Dimension] | None = None, workspace_id: str | None = None, task_type: str | None = None, client: APIClient | None = None) -> tuple[Project, bool]

Get an existing project by name or create it.

Parameters

  • name str: Project name to look up or create.
  • schema str: GDI schema name (used only when creating).
  • dimensions list[Dimension] | None: Desired dimension declarations. When reusing a project, declarations that differ from its current dimensions replace the existing configuration and prepare recovery drafts for datasets that were previously promoted. Dimension order and vocabulary order do not count as changes. Omit or pass None to leave an existing project's dimensions unchanged; a new project then has no dimensions.
  • workspace_id str | None: Workspace to scope the lookup. Falls back to client.config.workspace_id when not provided.
  • task_type str | None: Task discriminator for task-scoped schemas.
  • client APIClient | None: Optional API client.

Returns

  • Project: (project, created) — the Project instance and True when
  • bool: freshly created, False when an existing project was found.

Raises

  • NoWorkspaceSelectedError: If no workspace is given here or configured for the session. The lookup is always workspace-scoped, so that a name match cannot resolve to a project in a workspace the caller did not choose.
  • ForbiddenError: If an existing project's dimensions need updating and the caller cannot edit the project.
  • NotFoundError: If an existing project is deleted while it is being resolved.
  • DimensionLockViolationError: If an existing project's dimensions are locked by the test plan it was created from. Passing dimensions that differ from a locked project's will fail on every call; pass the project's own dimensions, or none, to reuse it.
  • UnprocessableEntityError: If dimensions are malformed or reference columns unavailable in an existing dataset.

Example:

project, created = aip.Project.get_or_create(
name="My Project",
schema="gdi_text_v1",
dimensions=[aip.Dimension(name="intent", column="intent", values=["complaint", "enquiry"])],
workspace_id=ws.id,
)
print("Created" if created else "Reusing", project.id)

aip_sdk.Project.id​

aip_sdk.Project.id = id

No docstring is defined in the source.

aip_sdk.Project.is_dimensions_locked​

aip_sdk.Project.is_dimensions_locked: bool

Return whether dimensions are locked in the associated test plan.

aip_sdk.Project.is_metrics_locked​

aip_sdk.Project.is_metrics_locked: bool

Return whether metrics are locked in the associated test plan.

aip_sdk.Project.is_quality_checks_locked​

aip_sdk.Project.is_quality_checks_locked: bool

Return whether required quality checks are locked in the associated test plan.

aip_sdk.Project.list​

aip_sdk.Project.list(schema_name: str | None = None, workspace_id: str | None = None, client: APIClient | None = None, *, all_workspaces: bool = False) -> list[Project]

List all projects.

Reads your session's workspace unless you name one, and raises if none is set. Pass all_workspaces=True to read across every workspace you can access.

Parameters

  • schema_name str | None: Optional filter by schema name
  • workspace_id str | None: Optional filter by workspace ID
  • all_workspaces bool: Read across every workspace you can access.
  • client APIClient | None: Optional API client

Returns

  • list[Project]: List of Project instances

Raises

aip_sdk.Project.local​

aip_sdk.Project.local(schema_name: str, dimensions: list[Dimension] | None = None, name: str = 'local', task_type: str | None = None) -> Project

Create a local-only project stub for offline operations.

No API call is made. Use this when you only need client-side operations such as analyse_coverage() and do not need to upload anything.

Parameters

  • schema_name str: GDI schema name (e.g. "gdi_text_v1").
  • dimensions list[Dimension] | None: Optional dimension declarations for coverage analysis.
  • name str: Display name (informational only).
  • task_type str | None: Optional task discriminator for task-scoped schemas.

Returns

  • Project: A Project instance that is not registered on the server.

Example:

import aip_sdk as aip

project = aip.Project.local(
"gdi_text_v1",
dimensions=[
aip.Dimension(name="intent", column="intent", values=["complaint", "enquiry"]),
],
)
coverage = project.analyse_coverage(df) # local — no network call

aip_sdk.Project.move_to_workspace​

aip_sdk.Project.move_to_workspace(target_workspace_id: str) -> Project

Move this project — and everything under it — to another workspace.

Datasets, runs, and eval configs move with the project. A workspace-level SUT the project's runs use is copied or reused in the target instead of moved, so it stays available to any other project still using it in the source workspace; a SUT scoped directly to this project moves with it.

Requires workspace_admin/workspace_editor on both the source and target workspace (a platform admin bypasses both checks).

A project created from a test plan does not keep it across a move: the plan belongs to the source workspace and cannot follow, so the moved project keeps its dimensions and metrics but is no longer bound to the plan, and neither tier stays locked. Its past runs lose their test_plan_id for the same reason — the stamp is cleared, not repointed, so a moved run no longer names the plan version that scored it.

Parameters

  • target_workspace_id str: The workspace to move this project into. Must be a shared (non-personal) workspace different from the project's current one.

Returns

  • Project: This project instance, updated in place with the new workspace_id.

Raises

  • NotFoundError: If the target workspace doesn't exist, or the project belongs to a workspace the caller is not a member of.
  • UnprocessableEntityError: If the target is a personal workspace, the project already belongs to it, or the project isn't associated with a workspace.
  • ForbiddenError: If the caller lacks an editor or admin role on the project's workspace, or is not an editor or admin of the target workspace.
  • ConflictError: If a project with the same name already exists in the target workspace, or a run is still pending/claimed/running for this project.

Example:

project.move_to_workspace(team_workspace.id)
print(project.workspace_id) # now the team workspace

aip_sdk.Project.name​

aip_sdk.Project.name = name

No docstring is defined in the source.

aip_sdk.Project.required_quality_checks​

aip_sdk.Project.required_quality_checks: list[str] = list(required_quality_checks or [])

No docstring is defined in the source.

aip_sdk.Project.schema_capability​

aip_sdk.Project.schema_capability = schema_capability

No docstring is defined in the source.

aip_sdk.Project.schema_name​

aip_sdk.Project.schema_name = schema_name

No docstring is defined in the source.

aip_sdk.Project.set_embedding_config​

aip_sdk.Project.set_embedding_config(name: str | None) -> Project

Set, opt out of, or unset this project's embedding config.

Resolution order. A hosted scoring run's embedding config is resolved by walking three tiers and taking the first one with an opinion:

run ──unset──▶ project ──unset──▶ workspace ──unset──▶ no embeddings
│ │ │
└─ config or ─────┴─ config or ───────┴─ config or opt-out (stops the chain)

Each tier expresses one of three states:

  • a config — that config is used, and no later tier is consulted;
  • an explicit opt-out — no embeddings are computed, and no later tier is consulted. At the run tier that is aip.run(..., embeddings=None); here and at the workspace tier it is set_embedding_config(aip.embeddings.NO_EMBEDDINGS);
  • unset (None) — this tier defers to the next one.

So a project opt-out is not the same as a project with no config: the first stops the walk, the second falls through to the workspace default.

Only hosted evaluate_sut_hosted runs resolve embeddings at all; other pipelines and external runs never inherit, since nothing in them computes a projection.

Parameters

  • name str | None: A registered config name in this project's workspace, aip.embeddings.NO_EMBEDDINGS to opt out (the reserved config meaning "compute nothing", present in every workspace), or None to unset the tier and defer to the workspace.

Returns

  • Project: This project instance, updated in place.

Raises

aip_sdk.Project.task_type​

aip_sdk.Project.task_type = task_type

No docstring is defined in the source.

aip_sdk.Project.test_plan_id​

aip_sdk.Project.test_plan_id: str | None

Return the test plan ID if one is associated with this project.

aip_sdk.Project.test_plan_name​

aip_sdk.Project.test_plan_name: str | None

Return the test plan name if one is associated with this project.

aip_sdk.Project.test_plan_version​

aip_sdk.Project.test_plan_version: int | None

Return the test plan version if one is associated with this project.

aip_sdk.Project.trend​

aip_sdk.Project.trend(metric: str, run_ids: list[str] | None = None, last_n: int = 10, group_by: str | None = None) -> pd.DataFrame

Return metric trend across runs as a DataFrame.

Queries POST /projects/{id}/trend. Each row in the returned DataFrame represents one run (or one run x dimension-group pair when group_by is set).

Parameters

  • metric str: Scorer column name to trend (e.g. "bleu", "correctness").
  • run_ids list[str] | None: Explicit list of run IDs to include. When None, the last last_n completed runs for this project are fetched automatically.
  • last_n int: Number of recent completed runs to fetch when run_ids is not supplied (default 10).
  • group_by str | None: Optional dimension column name (e.g. "scenario") to stratify each run's data. When set, the DataFrame includes a group column and one row per run x group combination.

Returns

  • pd.DataFrame: DataFrame with columns: run_id, mean, std, p50,
  • pd.DataFrame: below_threshold, created_at, tags — plus min /
  • pd.DataFrame: max (ungrouped only) and group (when group_by is set).
  • pd.DataFrame: Returns an empty DataFrame if no completed runs are found.

Raises

  • APIError: On network or server errors.

aip_sdk.Project.update_dimensions​

aip_sdk.Project.update_dimensions(dimensions: list[Dimension] | None) -> Project

Replace the project's stratification dimensions.

Triggers server-side staged minting: for each dataset that has been promoted at least once, the server either mints a new pending draft version (if none exists) or marks the existing draft STALE. Datasets that have never been promoted are unaffected. When recovery drafts are returned, the SDK logs their dataset and version identifiers with the required next step.

Parameters

  • dimensions list[Dimension] | None: New dimension declarations. Pass [] to clear all dimensions. Must not be None.

Returns

  • Project: This project instance, updated in place.

Raises

  • ValueError: If dimensions is None.
  • DimensionLockViolationError: If the project's dimensions are locked by the test plan it was created from. A locked contract refuses every change to the set, clearing it included, so retrying the same call will not succeed.
  • UnprocessableEntityError: If any dimension is malformed.
  • ForbiddenError: If the caller lacks permission to edit this project.

aip_sdk.Project.update_required_quality_checks​

aip_sdk.Project.update_required_quality_checks(checks: list[str]) -> Project

Replace the checks a dataset version must have a verdict for to be promoted to golden.

A requirement, not a selection: naming a check does not make it run, and promote_to_golden refuses a version unless every name reported. Grading is untouched — a required WARN still promotes under force=True, a required check with no verdict never does.

Example:

project.update_required_quality_checks(["row_count", "duplicate_ids"])
project.update_required_quality_checks([]) # promote on the aggregate verdict alone

Parameters

  • checks list[str]: The checks to require, by bare operation key — the names quality_verdict reports. Replaces the current set; [] requires none.

Returns

  • Project: This project instance, updated in place.

Raises

aip_sdk.Project.updated_at​

aip_sdk.Project.updated_at = updated_at

No docstring is defined in the source.

aip_sdk.Project.upgrade_test_plan​

aip_sdk.Project.upgrade_test_plan(test_plan: str | PublishedTestPlan) -> Project

Move this project onto another version of the test plan it is bound to.

The target version's dimensions and every lock are written onto the project and its version pinned, so the project enforces exactly what that version declares — the same contract attach_test_plan injects. Publishing a version never moves a project by itself; this is how a bound project takes one up.

The target's dimensions replace the project's own, staging a draft version for each dataset already promoted and warning about each, as update_dimensions does. A target declaring the dimensions the project already holds stages nothing and still rewrites every lock. Passing the version this project is already on re-asserts the contract, which restores the target's dimensions on a project that edited them under an unlocked plan.

The columns the target's dimensions name are checked against this project's datasets, but an already-golden version's rows are not: it keeps the dimensions it was promoted under, and one the target would no longer admit is refused at its next promotion rather than here, so a corrected methodology stays adoptable by the projects whose data is the reason it was corrected. Runs created before this call keep the plan version they were scored under.

Parameters

  • test_plan str | PublishedTestPlan: The published plan version to move onto — its id, or the record publish_test_plan, get_test_plan or list_test_plans returned. It must be a version of the plan this project is bound to, and not an older one.

Returns

  • Project: This Project instance, updated in place with the contract the target version
  • Project: supplied.

Raises

  • InvalidArgumentError: If test_plan is neither an id nor a published record — an unpublished TestPlan has no id.
  • ConflictError: If this project is bound to no plan, so there is no version to move from. Bind one with attach_test_plan first.
  • TestPlanReferenceError: If a reference the target version carries no longer resolves — a metric deregistered since publish, or a pinned config since retired. failures names each one; nothing is written.
  • UnprocessableEntityError: If the target is a version of a different plan or an older version of this one, if its schema or task type is not this project's, or if a dimension it declares names a column one of this project's datasets does not have. Nothing is written in any of them.
  • NotFoundError: If the project no longer exists, or if no published plan version has that id in this project's workspace. The project is looked up first, so a project deleted since it was read reports this rather than the plan's absence.
  • ForbiddenError: If the caller is not an editor or admin of that workspace.
  • InvalidStateError: If this project was closed.
  • ResponseParseError: If the binding on the updated project does not match the shape this SDK version reads.

Example:

# An edit is a new version of the same plan, which is what this call moves onto.
current = aip.get_test_plan("toxicity-baseline", version=1)
plan_v2 = aip.publish_test_plan_version(revised_plan, ref=current.id, base_version=current.version)
project.upgrade_test_plan(plan_v2)
print(project.test_plan_version)

aip_sdk.Project.upload_dataset​

aip_sdk.Project.upload_dataset(df: pd.DataFrame, name: str, poll_interval: float = 2.0, timeout: float = 300.0, *, predecessor_dataset_id: str | None = None) -> Dataset

Upload a dataset and poll until it is active or failed.

Parameters

  • df pd.DataFrame: DataFrame to upload (must match project schema)
  • name str: Dataset name
  • poll_interval float: Seconds between status checks
  • timeout float: Maximum seconds to wait
  • predecessor_dataset_id str | None: The dataset this one was derived from, recorded as its lineage parent. Must be a dataset in the same workspace as this project. Omit it when the dataset has no predecessor.

Returns

Raises

  • UnprocessableEntityError: If validation fails
  • InvalidArgumentError: If predecessor_dataset_id is given but blank, or a supplied local image_path cannot be read. Relative paths are resolved from the current working directory.
  • NotFoundError: If this project no longer exists, or if predecessor_dataset_id names no dataset in its workspace.
  • DatasetValidationError: If the dataset fails server-side validation during upload.
  • TimeoutError: If dataset does not become active within timeout

Example:

base = project.upload_dataset(df, name="golden-v1")
refreshed = project.upload_dataset(df_v2, name="golden-v2", predecessor_dataset_id=base.id)

aip_sdk.Project.workspace_id​

aip_sdk.Project.workspace_id = workspace_id

No docstring is defined in the source.