Connectors
Import datasets from V7 (Darwin) and Roboflow into Pictograph. Annotations are converted to canonical Pictograph JSON automatically.
Import remote datasets in two steps: validate the source API key → kick off the import. The import runs as an async job; the SDK polls until terminal status by default.
from pictograph import Client
client = Client()
Supported providers
provider | Source | Notes |
|---|---|---|
v7 | V7 Darwin | Polygon paths, bboxes, polylines, keypoints, tags |
roboflow | Roboflow | COCO export → Pictograph JSON |
validate
Verify the source API key and list available remote datasets. No quota consumed; the API key is sent only on this call.
result = client.connectors.validate(
provider="v7",
api_key="v7_api_token_…",
)
if result.valid:
for ds in result.datasets:
print(ds.id, ds.name, ds.image_count)
else:
print("invalid:", result.error)
Returns ValidationResult — inspect .valid first; .datasets is
populated only on success.
check_limits
Pre-flight tier-cap check before kicking off an import.
check = client.connectors.check_limits(
total_images=12500,
estimated_size_bytes=4_000_000_000, # 4 GB
)
if not check.allowed:
print("blocked by:", check.exceeded) # "images" / "storage" / "both"
import_
Kick off the import. Trailing underscore avoids shadowing the Python
import keyword.
job = client.connectors.import_(
provider="v7",
api_key="v7_api_token_…",
datasets=[
{"id": "ds_abc", "name": "Road signs", "slug": "road-signs"},
# OR pass RemoteDataset instances from validate():
# *result.datasets[:2],
],
wait=True,
poll_interval=3.0,
timeout=3600.0, # 1h default
)
print(job.import_id, job.status)
for ds in job.datasets:
print(ds.dataset_name, ds.images_imported, "/", ds.total_images)
| Arg | Type | Default | Notes |
|---|---|---|---|
provider | ConnectorProvider | required | "v7" / "roboflow" |
api_key | str | required | Sent only to fetch source data |
datasets | Sequence[RemoteDataset | dict] | required | RemoteDataset instances or raw dicts |
wait | bool | True | Poll until terminal |
poll_interval | float | 3.0 | seconds |
timeout | float | 3600.0 | Max poll seconds (V7 large exports take 30+ min) |
Returns ImportJob.
get_import / wait_for_import / cancel_import
job = client.connectors.get_import(import_id)
job = client.connectors.wait_for_import(import_id, timeout=600.0)
job = client.connectors.cancel_import(import_id)
Annotation conversion
| V7 / COCO | Pictograph |
|---|---|
V7 polygon.paths | polygon.paths (passthrough) |
V7 bounding_box (no polygon) | bounding_box |
V7 line.path | polyline.path |
V7 keypoint | keypoint |
V7 tag / ellipse / mask | skipped (no Pictograph equivalent) |
COCO segmentation (flat array) | polygon.paths (paired into points) |
COCO bbox (no segmentation) | bounding_box |
COCO keypoints triplets | keypoint (skips v=0) |
Tier caps
Imports are charged against your storage + image-count tier caps. See Credits and your plan in the web app.
Common errors
| Status | Exception | Cause |
|---|---|---|
| 401 | AuthError | Source provider API key rejected |
| 402 | PaymentRequiredError | Tier cap exceeded |
| 404 | NotFoundError | import_id missing |
| 408 | PollTimeoutError | wait=True exceeded timeout (job keeps running) |
| 422 | ValidationError | Invalid provider, empty datasets list |