Skip to content
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ Pass `auth_scheme="Bearer"` to use an OIDC access token instead of an API token.

HTTP errors raise `openconceptlab.APIError`, with `status_code`, `detail` and the parsed response `body`. Network failures raise the httpx exception (`httpx.TimeoutException` or `httpx.TransportError`) once retries run out. A client holds one token, so create one per user.

Each ID, version or key you pass is encoded as one segment of the request path. An empty value, `.`, `..` or a value containing `/` raises `APIError` (`status_code` 0) before anything is sent. So does a request to a URL outside the client's `base_url`, such as one taken from a response.

## Quick Start

### 1. Authenticate
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "openconceptlab"
version = "0.2.0"
version = "0.2.1"
description = "Python client and command-line interface for the Open Concept Lab API"
readme = "README.md"
license = "MPL-2.0"
Expand Down
15 changes: 13 additions & 2 deletions src/ocl_cli/commands/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from ocl_cli.api_client import APIError
from ocl_cli.main import handle_api_error
from openconceptlab.client import _segment

# Regex to detect versioned concept/mapping expressions (e.g. /concepts/100/1/)
VERSIONED_EXPR = re.compile(r"/(concepts|mappings)/\d+/\d+/?$")
Expand Down Expand Up @@ -117,6 +118,12 @@ def _collection_url(org: str | None, collection_id: str) -> str:
return f"/user/collections/{collection_id}/"


def _collection_path(org: str | None, collection_id: str) -> str:
"""The collection's API path, each identifier encoded as one segment."""
owner = f"/orgs/{_segment(org)}" if org else "/user"
return f"{owner}/collections/{_segment(collection_id)}/"


def _build_references(export, org, collection_id, client, callback=None):
"""Build deduplicated, versionless reference lines from export data.

Expand Down Expand Up @@ -238,6 +245,11 @@ def recreate_collection(ctx, input_path, org, name, output_path, dry_run):
if not collection_id:
click.echo("Error: Collection id not found in export and --name not provided.", err=True)
sys.exit(1)
try:
collection_path = _collection_path(org, collection_id)
except APIError as exc:
click.echo(f"Error: {exc}", err=True)
sys.exit(1)

# Default output filename
if not output_path:
Expand Down Expand Up @@ -273,7 +285,6 @@ def recreate_collection(ctx, input_path, org, name, output_path, dry_run):

# Delete and recreate collection
click.echo("Recreating collection and importing references...")
collection_path = _collection_url(org, collection_id)
try:
# Check if collection exists
try:
Expand All @@ -289,7 +300,7 @@ def recreate_collection(ctx, input_path, org, name, output_path, dry_run):
# Create collection
click.echo(f"Creating collection {collection_id}...")
payload = _build_collection_payload(export_data, name)
collections_path = f"/orgs/{org}/collections/" if org else "/user/collections/"
collections_path = f"/orgs/{_segment(org)}/collections/" if org else "/user/collections/"
client.post(collections_path, json=payload)

# Bulk import
Expand Down
Loading
Loading