modelstudio-sdk 0.0.0.dev0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/CLAUDE.md +65 -36
  2. modelstudio_sdk-0.2.0/PKG-INFO +341 -0
  3. modelstudio_sdk-0.2.0/README.md +321 -0
  4. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/gl-sast-report.json +7 -7
  5. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/gl-secret-detection-report.json +6 -6
  6. modelstudio_sdk-0.2.0/src/modelstudio/_version.py +1 -0
  7. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/client.py +47 -7
  8. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/__init__.py +32 -0
  9. modelstudio_sdk-0.2.0/src/modelstudio/models/experiments.py +39 -0
  10. modelstudio_sdk-0.2.0/src/modelstudio/models/projects.py +38 -0
  11. modelstudio_sdk-0.2.0/src/modelstudio/models/runs.py +95 -0
  12. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/resources/dataset.py +11 -69
  13. modelstudio_sdk-0.2.0/src/modelstudio/resources/experiment.py +102 -0
  14. modelstudio_sdk-0.2.0/src/modelstudio/resources/project.py +144 -0
  15. modelstudio_sdk-0.2.0/src/modelstudio/resources/run.py +129 -0
  16. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/resources/split.py +25 -26
  17. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/helpers.py +3 -0
  18. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/integration/conftest.py +39 -15
  19. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/integration/test_connectivity.py +4 -4
  20. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/integration/test_mutations.py +21 -20
  21. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/integration/test_read_only.py +10 -6
  22. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/test_client.py +26 -0
  23. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/test_pandas.py +22 -20
  24. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/test_resources/test_dataset.py +2 -41
  25. modelstudio_sdk-0.2.0/tests/test_resources/test_experiment.py +71 -0
  26. modelstudio_sdk-0.2.0/tests/test_resources/test_project.py +117 -0
  27. modelstudio_sdk-0.2.0/tests/test_resources/test_run.py +145 -0
  28. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/test_resources/test_split.py +21 -6
  29. modelstudio_sdk-0.0.0.dev0/PKG-INFO +0 -513
  30. modelstudio_sdk-0.0.0.dev0/README.md +0 -493
  31. modelstudio_sdk-0.0.0.dev0/src/modelstudio/_version.py +0 -1
  32. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/.claude/commands/agent-os/discover-standards.md +0 -0
  33. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/.claude/commands/agent-os/index-standards.md +0 -0
  34. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/.claude/commands/agent-os/inject-standards.md +0 -0
  35. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/.claude/commands/agent-os/plan-product.md +0 -0
  36. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/.claude/commands/agent-os/shape-spec.md +0 -0
  37. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/.gitignore +0 -0
  38. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/.gitlab-ci.yml +0 -0
  39. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/LICENSE +0 -0
  40. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/Makefile +0 -0
  41. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-06-sdk-phase2-pandas-integration/plan.md +0 -0
  42. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-06-sdk-phase2-pandas-integration/references.md +0 -0
  43. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-06-sdk-phase2-pandas-integration/shape.md +0 -0
  44. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-06-sdk-phase2-pandas-integration/standards.md +0 -0
  45. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-10-integration-testing-sdk/plan.md +0 -0
  46. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-10-integration-testing-sdk/references.md +0 -0
  47. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-10-integration-testing-sdk/shape.md +0 -0
  48. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-10-integration-testing-sdk/standards.md +0 -0
  49. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-11-1500-sdk-deploy-and-notebooks/plan.md +0 -0
  50. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-11-1500-sdk-deploy-and-notebooks/references.md +0 -0
  51. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-11-1500-sdk-deploy-and-notebooks/shape.md +0 -0
  52. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-11-1500-sdk-deploy-and-notebooks/standards.md +0 -0
  53. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-11-1900-custom-notebook-ui/plan.md +0 -0
  54. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-11-1900-custom-notebook-ui/references.md +0 -0
  55. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-11-1900-custom-notebook-ui/shape.md +0 -0
  56. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-11-1900-custom-notebook-ui/standards.md +0 -0
  57. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-12-sdk-api-realignment/plan.md +0 -0
  58. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-12-sdk-api-realignment/references.md +0 -0
  59. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-12-sdk-api-realignment/shape.md +0 -0
  60. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-12-sdk-api-realignment/standards.md +0 -0
  61. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-12-sdk-tutorials/plan.md +0 -0
  62. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/specs/2026-03-12-sdk-tutorials/shape.md +0 -0
  63. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/agent-os/standards/index.yml +0 -0
  64. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/develop.sh +0 -0
  65. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/docker/.env.example +0 -0
  66. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/docker/Dockerfile.dev +0 -0
  67. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/docker/docker-compose.yml +0 -0
  68. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/docker/requirements.txt +0 -0
  69. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/pyproject.toml +0 -0
  70. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/scripts/get-token.sh +0 -0
  71. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/scripts/smoke_test.py +0 -0
  72. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/__init__.py +0 -0
  73. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/_http.py +0 -0
  74. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/_pandas.py +0 -0
  75. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/_polling.py +0 -0
  76. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/exceptions.py +0 -0
  77. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/annotations.py +0 -0
  78. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/categories.py +0 -0
  79. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/common.py +0 -0
  80. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/datasets.py +0 -0
  81. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/deletion.py +0 -0
  82. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/exports.py +0 -0
  83. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/few_shot.py +0 -0
  84. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/filters.py +0 -0
  85. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/history.py +0 -0
  86. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/images.py +0 -0
  87. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/imports.py +0 -0
  88. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/media.py +0 -0
  89. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/merge.py +0 -0
  90. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/metrics.py +0 -0
  91. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/oversample.py +0 -0
  92. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/splits.py +0 -0
  93. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/models/validation.py +0 -0
  94. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/src/modelstudio/resources/__init__.py +0 -0
  95. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/__init__.py +0 -0
  96. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/conftest.py +0 -0
  97. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/integration/__init__.py +0 -0
  98. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/test_http.py +0 -0
  99. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/test_polling.py +0 -0
  100. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/test_resources/__init__.py +0 -0
  101. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tests/test_resources/conftest.py +0 -0
  102. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tutorials/.ipynb_checkpoints/getting-started-checkpoint.ipynb +0 -0
  103. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tutorials/01-getting-started.ipynb +0 -0
  104. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tutorials/02-exploring-data.ipynb +0 -0
  105. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tutorials/03-category-management.ipynb +0 -0
  106. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tutorials/04-import-export.ipynb +0 -0
  107. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tutorials/05-annotations.ipynb +0 -0
  108. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tutorials/06-advanced-workflows.ipynb +0 -0
  109. {modelstudio_sdk-0.0.0.dev0 → modelstudio_sdk-0.2.0}/tutorials/README.md +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Project Overview
4
4
 
5
- **Model Studio SDK** is a Python package that wraps the Model Studio REST API, providing typed access to dataset management, annotation tooling, and ML workflow operations. This repo also hosts the **Jupyter Server Docker infrastructure** for the custom notebook UI.
5
+ **Model Studio SDK** is a Python package that wraps the Model Studio REST API, providing typed access to projects, datasets, experiments, runs, annotations, and ML workflow operations. This repo also hosts the **Jupyter Server Docker infrastructure** for the custom notebook UI.
6
6
 
7
7
  **Tech Stack**: Python 3.10+, httpx (HTTP client), pydantic v2 (response models), pandas (optional DataFrame helpers)
8
8
 
@@ -22,24 +22,48 @@
22
22
  ### Package Layout (`src/modelstudio/`)
23
23
 
24
24
  ```
25
- client.py # ModelStudioClient entry point (from_env, dataset, datasets)
25
+ client.py # ModelStudioClient entry point (from_env, projects, project, dataset)
26
26
  _http.py # HttpTransport - httpx wrapper with auth + error mapping
27
27
  _polling.py # OperationPoller - wait on async ops (clone, import, finalize)
28
28
  _pandas.py # Optional pandas helpers (guarded import)
29
29
  exceptions.py # Typed exception hierarchy (BadRequestError, NotFoundError, etc.)
30
30
  models/ # Pydantic v2 response/request DTOs (match API snake_case)
31
+ projects.py # ProjectModel, CreateProjectRequest, UpdateProjectRequest
32
+ experiments.py # ExperimentModel, CreateExperimentRequest, UpdateExperimentRequest
33
+ runs.py # RunModel, CreateRunRequest, UpdateRunRequest, CloneRunRequest, etc.
34
+ datasets.py # DatasetModel
35
+ annotations.py # AnnotationModel, CreateAnnotationRequest, etc.
36
+ ... # categories, images, imports, exports, metrics, filters, etc.
31
37
  resources/
32
- dataset.py # DatasetsCollection + Dataset (~50 methods)
33
- split.py # Split sub-resource (~20 methods)
38
+ project.py # ProjectsCollection + Project (datasets, experiments access)
39
+ experiment.py # ExperimentsCollection + Experiment (runs access)
40
+ run.py # RunsCollection + Run (CRUD, submit, cancel, metrics, stages)
41
+ dataset.py # Dataset (~50 methods for per-dataset operations)
42
+ split.py # Split sub-resource (images, annotations, import, export)
34
43
  ```
35
44
 
36
45
  ### Resource Pattern
37
46
 
38
47
  ```python
39
48
  client = ModelStudioClient.from_env()
40
- client.datasets.list() # DatasetsCollection methods
41
- client.dataset("uuid").overview() # Dataset-bound methods
42
- client.dataset("uuid").split("sid").list_images() # Split sub-resource
49
+
50
+ # Projects & datasets (project-scoped)
51
+ client.projects.list() # List projects
52
+ client.project("pid").datasets() # List datasets in project
53
+ client.project("pid").create_dataset(name="...") # Create dataset in project
54
+
55
+ # Per-dataset operations (by dataset ID)
56
+ client.dataset("did").overview() # Dataset-bound methods
57
+ client.dataset("did").split("sid").list_images() # Split sub-resource
58
+
59
+ # Experiments & runs (nested under project)
60
+ client.project("pid").experiments.list()
61
+ client.project("pid").experiment("eid").runs.list()
62
+ client.project("pid").experiment("eid").run("rid").submit()
63
+
64
+ # Merge (global, not project-scoped)
65
+ client.merge_datasets_analyze(["ds-1", "ds-2"])
66
+ client.merge_datasets(request)
43
67
  ```
44
68
 
45
69
  ---
@@ -47,6 +71,7 @@ client.dataset("uuid").split("sid").list_images() # Split sub-resource
47
71
  ## Code Conventions
48
72
 
49
73
  - **Pydantic v2** models with snake_case fields (matches API JSON directly)
74
+ - **`model_dump(mode="json")`** for request bodies — ensures UUIDs serialize to strings
50
75
  - **Typed exceptions** mapped from API error envelope `{"error": "...", "message": "..."}`
51
76
  - **Guarded pandas import** in `_pandas.py` - raises helpful error if not installed
52
77
  - **`from_env()` contract**: reads `MODEL_STUDIO_API_URL`, `MODEL_STUDIO_JWT`, `MODEL_STUDIO_ORG`
@@ -58,20 +83,34 @@ client.dataset("uuid").split("sid").list_images() # Split sub-resource
58
83
  ## Key Design Decisions
59
84
 
60
85
  - Resource pattern over flat methods for discoverability
86
+ - Dataset operations are ID-based (`client.dataset(id)`), not project-scoped, since the API supports direct dataset access
87
+ - Project-scoped operations for listing and creating datasets (`client.project(id).datasets()`)
61
88
  - Pollers return immediately; call `.wait()` to block
62
89
  - Models use `| None` for optional fields with defaults
63
- - `model_dump(exclude_none=True)` for request bodies to avoid sending null fields
90
+ - `model_dump(mode="json", exclude_none=True)` for request bodies to avoid sending null fields and ensure UUID serialization
64
91
 
65
92
  ---
66
93
 
67
94
  ## When Making Changes
68
95
 
69
96
  - DO follow pydantic v2 patterns (BaseModel, model_validate, model_dump)
97
+ - DO use `model_dump(mode="json")` for request bodies (not plain `model_dump()`)
70
98
  - DO keep httpx sync-only
71
99
  - DO map new API error codes to exception classes
100
+ - DO add new resource classes following the existing pattern (Collection + Instance)
72
101
  - DON'T break `from_env()` contract
73
102
  - DON'T add async httpx
74
103
  - DON'T import pandas at module level (always guard behind `_pandas.py`)
104
+ - DON'T use `client.datasets` — that was removed; datasets are listed via projects
105
+
106
+ ---
107
+
108
+ ## API Reference
109
+
110
+ The complete SDK method reference lives in the tutorials repo:
111
+ [model-studio-notebooks/tutorials/api-reference.md](https://gitlab.com/orbitalinsight/elements/model-studio/model-studio-notebooks/-/blob/master/tutorials/api-reference.md)
112
+
113
+ This file is mounted into the notebook environment so users can access it directly.
75
114
 
76
115
  ---
77
116
 
@@ -87,9 +126,16 @@ client.dataset("uuid").split("sid").list_images() # Split sub-resource
87
126
  - `./develop.sh --mode notebook-server` — start headless Jupyter Server (Docker) on port 8889 for custom notebook UI
88
127
  - `./develop.sh --mode docker` — start full JupyterLab (Docker) on port 8888
89
128
  - `scripts/get-token.sh` — standalone Keycloak token fetcher (used by develop.sh)
90
- - Usage: `eval "$(scripts/get-token.sh)"` to export `MODEL_STUDIO_JWT` into the current shell
91
- - Keycloak realm: `elements`, client: `login-direct`
92
- - Credentials are the same as your Model Studio login
129
+
130
+ ### Integration Tests
131
+
132
+ Integration tests run against the live elements-dev API. They expect:
133
+ - **Project**: "SDK Testing"
134
+ - **Datasets**: "sdk-test-read-only" (with splits, images, annotations) and "sdk-test-mutations" (single Train split)
135
+
136
+ ```bash
137
+ ./develop.sh --mode test-integration
138
+ ```
93
139
 
94
140
  ### Custom Notebook UI (cross-repo)
95
141
 
@@ -97,9 +143,8 @@ The notebook UI spans this repo (Jupyter Server backend) and the `frontend` repo
97
143
 
98
144
  1. **This repo**: `docker/docker-compose.yml` defines `jupyter-server` service (headless, CORS for localhost:5173)
99
145
  2. **Frontend**: `vite.config.ts` proxies `/jupyter/*` → `localhost:8889` (includes WebSocket)
100
- 3. **Frontend**: `src/services/jupyter/` — JupyterService (REST), JupyterWebSocketManager (WS), messageBuilder
101
- 4. **Frontend**: `src/store/notebook_store.ts`MobX store for cell state + execution
102
- 5. **Frontend**: `src/pages/ModelStudio/Notebooks/NotebookPanel/` — React UI components
146
+ 3. **Frontend**: `src/api/notebooks/` — auth, API clients, WebSocket manager, MobX store
147
+ 4. **Frontend**: `src/pages/ModelStudio/Notebooks/`React UI components
103
148
 
104
149
  To run locally: `./develop.sh --mode notebook-server` (this repo) + `yarn start` (frontend repo)
105
150
 
@@ -117,31 +162,15 @@ To run locally: `./develop.sh --mode notebook-server` (this repo) + `yarn start`
117
162
 
118
163
  | File | Purpose |
119
164
  |------|---------|
120
- | `src/modelstudio/client.py` | Main entry point |
165
+ | `src/modelstudio/client.py` | Main entry point (projects, project, dataset, merge) |
121
166
  | `src/modelstudio/_http.py` | HTTP transport with auth |
122
167
  | `src/modelstudio/exceptions.py` | Exception hierarchy |
123
- | `src/modelstudio/resources/dataset.py` | All dataset endpoints |
124
- | `src/modelstudio/resources/split.py` | All split endpoints |
125
- | `src/modelstudio/models/metrics.py` | OverviewDto with 11 nested types |
168
+ | `src/modelstudio/resources/project.py` | Project + dataset listing/creation |
169
+ | `src/modelstudio/resources/experiment.py` | Experiment CRUD |
170
+ | `src/modelstudio/resources/run.py` | Run CRUD + submit/cancel/metrics |
171
+ | `src/modelstudio/resources/dataset.py` | All per-dataset operations (~50 methods) |
172
+ | `src/modelstudio/resources/split.py` | Split sub-resource (import, export, images) |
126
173
  | `tests/conftest.py` | MockTransport fixture |
127
174
  | `develop.sh` | Single-command dev setup (conda + deps + auth) |
128
175
  | `scripts/get-token.sh` | Keycloak JWT token fetcher |
129
176
  | `docker/docker-compose.yml` | Docker services (notebook + jupyter-server) |
130
- | `docker/Dockerfile.dev` | Dev image (scipy-notebook + SDK + ML packages) |
131
-
132
- ### Frontend Files (in `../frontend`)
133
-
134
- | File | Purpose |
135
- |------|---------|
136
- | `src/services/jupyter/JupyterService.ts` | REST client for Jupyter Server API |
137
- | `src/services/jupyter/JupyterWebSocketManager.ts` | WebSocket kernel protocol handler |
138
- | `src/services/jupyter/messageBuilder.ts` | Jupyter wire-protocol message builder |
139
- | `src/services/jupyter/types.ts` | Jupyter API + kernel protocol type definitions |
140
- | `src/store/notebook_store.ts` | MobX store for notebook state + execution |
141
- | `src/pages/ModelStudio/Notebooks/NotebookPanel/` | All notebook UI components |
142
- | `src/pages/ModelStudio/Layout/AppBar/AppBar.tsx` | AppBar with Notebook + Agent buttons |
143
- | `vite.config.ts` | Vite proxy: `/jupyter/*` → localhost:8889 |
144
-
145
- ---
146
-
147
- **API Reference**: See `model-studio-api/agent-os/standards/api/` for the API contract standards.
@@ -0,0 +1,341 @@
1
+ Metadata-Version: 2.4
2
+ Name: modelstudio-sdk
3
+ Version: 0.2.0
4
+ Summary: Python SDK for the Model Studio REST API
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: httpx<1.0,>=0.25.0
9
+ Requires-Dist: pydantic<3.0,>=2.0
10
+ Provides-Extra: dev
11
+ Requires-Dist: mypy>=1.8; extra == 'dev'
12
+ Requires-Dist: pandas>=1.5.0; extra == 'dev'
13
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
14
+ Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
15
+ Requires-Dist: pytest>=7.0; extra == 'dev'
16
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
17
+ Provides-Extra: pandas
18
+ Requires-Dist: pandas>=1.5.0; extra == 'pandas'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # Model Studio Python SDK
22
+
23
+ Python SDK for the Model Studio REST API. Provides typed access to projects, datasets, annotations, metrics, and ML workflow operations.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ # From wheel (in notebook containers, pre-installed)
29
+ pip install modelstudio-sdk
30
+
31
+ # Development install
32
+ git clone https://gitlab.com/orbitalinsight/elements/model-studio/modelstudio-sdk.git
33
+ cd modelstudio-sdk
34
+ pip install -e ".[dev]"
35
+
36
+ # With pandas support
37
+ pip install "modelstudio-sdk[pandas]"
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ```python
43
+ from modelstudio import ModelStudioClient
44
+
45
+ # Auto-configured inside notebooks (reads env vars)
46
+ client = ModelStudioClient.from_env()
47
+
48
+ # Or explicit
49
+ client = ModelStudioClient(
50
+ base_url="http://localhost:8081",
51
+ jwt_token="eyJhbG...",
52
+ )
53
+
54
+ # List projects and datasets
55
+ projects = client.projects.list()
56
+ project = client.project(str(projects[0].id))
57
+ for ds in project.datasets():
58
+ print(f"{ds.name} ({ds.dataset_type})")
59
+ ```
60
+
61
+ ## Environment Variables
62
+
63
+ | Variable | Required | Description |
64
+ |----------|----------|-------------|
65
+ | `MODEL_STUDIO_API_URL` | Yes | API base URL |
66
+ | `MODEL_STUDIO_JWT` | No | JWT authentication token |
67
+ | `MODEL_STUDIO_ORG` | No | Organization name |
68
+
69
+ ## Usage Examples
70
+
71
+ ### Projects & Datasets
72
+
73
+ ```python
74
+ # List projects
75
+ projects = client.projects.list()
76
+
77
+ # Create a project
78
+ project = client.projects.create(name="My Project", description="...")
79
+
80
+ # List datasets in a project
81
+ datasets = client.project("project-uuid").datasets()
82
+
83
+ # Create a dataset in a project
84
+ ds_model = client.project("project-uuid").create_dataset(
85
+ name="My Dataset",
86
+ dataset_type="object-detection-coco",
87
+ )
88
+
89
+ # Work with a specific dataset (by ID, independent of project)
90
+ ds = client.dataset("dataset-uuid")
91
+ ```
92
+
93
+ ### Dataset Overview & Metrics
94
+
95
+ ```python
96
+ ds = client.dataset("dataset-uuid")
97
+
98
+ overview = ds.overview()
99
+ print(f"Images: {overview.summary.total_images}")
100
+ print(f"Annotations: {overview.summary.total_annotations}")
101
+
102
+ for split in ds.splits():
103
+ print(f"{split.name} ({split.split_type})")
104
+
105
+ cats = ds.categories()
106
+ for cat in cats.categories:
107
+ print(f"{cat.name}: {cat.annotation_count} annotations")
108
+ ```
109
+
110
+ ### Category Management
111
+
112
+ ```python
113
+ ds.merge_categories(source_categories=[1, 2, 3], target_category="vehicle")
114
+ ds.rename_category(category_id=5, new_name="truck")
115
+ ds.remove_category(category_id=10)
116
+ ds.consolidate_labels({"car": "vehicle", "van": "vehicle"})
117
+
118
+ # Undo any mutation
119
+ ds.undo()
120
+ ```
121
+
122
+ ### Split Operations
123
+
124
+ ```python
125
+ ds.redistribute(ratios={"train": 0.8, "val": 0.1, "test": 0.1}, seed=42)
126
+ ds.class_aware_redistribute(ratios={"train": 0.8, "val": 0.2}, prevent_tile_leakage=True)
127
+ ds.check_leakage()
128
+ ```
129
+
130
+ ### Import & Export
131
+
132
+ ```python
133
+ split = ds.split("split-uuid")
134
+
135
+ # Import from S3
136
+ queued = split.import_from_source("s3", "coco", {
137
+ "connection_id": "conn-uuid",
138
+ "bucket": "my-bucket",
139
+ "prefix": "datasets/coco/",
140
+ })
141
+
142
+ # Export as COCO JSON
143
+ coco = ds.export_coco()
144
+ split_coco = split.export_coco()
145
+ ```
146
+
147
+ ### Cloning & Async Operations
148
+
149
+ ```python
150
+ cloned = ds.clone(name="My Clone")
151
+ poller = ds.clone_poller(interval=2.0, max_wait=300.0)
152
+ result = poller.wait()
153
+ ```
154
+
155
+ ### Annotations
156
+
157
+ ```python
158
+ from modelstudio.models.annotations import CreateAnnotationRequest
159
+
160
+ # Paginated listing
161
+ page = ds.list_annotations(split_id="...", page=0, size=50)
162
+
163
+ # Create
164
+ ds.create_annotation(CreateAnnotationRequest(
165
+ image_id="img-uuid", category_id=1, bbox=[0, 0, 50, 50], area=2500,
166
+ ))
167
+
168
+ # Bulk delete
169
+ ds.delete_annotations(annotation_ids=[1, 2, 3])
170
+ ```
171
+
172
+ ### Few-Shot & Oversampling
173
+
174
+ ```python
175
+ from modelstudio.models.few_shot import FewShotRequest
176
+ from modelstudio.models.oversample import OversampleRequest
177
+
178
+ preview = ds.few_shot_preview(FewShotRequest(num_images=100, method="RANDOM", seed=42))
179
+ result = ds.oversample_execute(OversampleRequest(target_ratio=0.5, strategy="PREFER_ANNOTATED"))
180
+ ```
181
+
182
+ ### Dataset Merge
183
+
184
+ ```python
185
+ from modelstudio.models.merge import MergeDatasetRequest
186
+
187
+ analysis = client.merge_datasets_analyze(["ds-1", "ds-2"])
188
+ result = client.merge_datasets(MergeDatasetRequest(
189
+ source_dataset_ids=["ds-1", "ds-2"],
190
+ target_name="merged-dataset",
191
+ ))
192
+ ```
193
+
194
+ ### Experiments & Runs
195
+
196
+ ```python
197
+ project = client.project("project-uuid")
198
+
199
+ # Create experiment
200
+ exp = project.experiments.create(name="YOLOv8 ablation")
201
+
202
+ # Create and submit a run
203
+ from modelstudio.models.runs import CreateRunRequest
204
+ run_model = project.experiment(str(exp.id)).runs.create(CreateRunRequest(
205
+ name="baseline",
206
+ model_architecture="yolov8",
207
+ dataset_id="dataset-uuid",
208
+ ))
209
+ run = project.experiment(str(exp.id)).run(str(run_model.id))
210
+ run.submit()
211
+
212
+ # Monitor
213
+ run.stages()
214
+ run.metrics()
215
+ run.metrics_data(name="loss")
216
+ ```
217
+
218
+ ### DataFrame Integration
219
+
220
+ ```python
221
+ # Requires: pip install "modelstudio-sdk[pandas]"
222
+ ds.images_df(size=100)
223
+ ds.annotations_df(size=100)
224
+ ds.categories_df()
225
+ ds.class_distribution_df()
226
+ split.images_df()
227
+ split.annotations_df()
228
+ ```
229
+
230
+ ## Error Handling
231
+
232
+ ```python
233
+ from modelstudio.exceptions import NotFoundError, ConflictError, BadRequestError
234
+
235
+ try:
236
+ ds.overview()
237
+ except NotFoundError as e:
238
+ print(f"Not found: {e.message}")
239
+ except BadRequestError as e:
240
+ print(f"Bad request: {e.message}")
241
+ ```
242
+
243
+ ## API Reference
244
+
245
+ For the complete method listing, see the [API Reference](https://gitlab.com/orbitalinsight/elements/model-studio/model-studio-notebooks/-/blob/master/tutorials/api-reference.md) in the tutorials folder (also available in your notebook environment at `tutorials/api-reference.md`).
246
+
247
+ ## Architecture
248
+
249
+ ### Related Repositories
250
+
251
+ | Repo | Purpose |
252
+ |------|---------|
253
+ | [`model-studio-sdk`](https://gitlab.com/orbitalinsight/elements/model-studio/modelstudio-sdk) | This repo — Python SDK + Jupyter Server Docker |
254
+ | [`frontend`](https://gitlab.com/orbitalinsight/frontend-2.0) | Model Studio React frontend (custom notebook UI lives here) |
255
+ | [`model-studio-api`](https://gitlab.com/orbitalinsight/elements/model-studio/model-studio-api) | Backend REST API the SDK wraps |
256
+ | [`model-studio-notebooks`](https://gitlab.com/orbitalinsight/elements/model-studio/model-studio-notebooks) | JupyterHub + KubeSpawner Helm chart (production multi-user) |
257
+ | [`model-studio-agent`](https://gitlab.com/orbitalinsight/elements/model-studio/model-studio-agent) | Agent chat backend |
258
+ | [`keycloak-config`](https://gitlab.com/orbitalinsight/elements/keycloak-config) | Keycloak realm/client configuration |
259
+
260
+ ### Local Development Architecture
261
+
262
+ ```
263
+ ┌─────────────────────────────────────────────────────────────┐
264
+ │ Browser (http://localhost:5173) │
265
+ │ │
266
+ │ ┌───────────────────────────────────────────────────────┐ │
267
+ │ │ Model Studio Frontend (Vite) │ │
268
+ │ │ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │ │
269
+ │ │ │ Dataset Pages │ │ Notebook │ │ Agent Chat │ │ │
270
+ │ │ │ │ │ Panel │ │ Panel │ │ │
271
+ │ │ └──────────────┘ └──────┬───────┘ └─────┬──────┘ │ │
272
+ │ └───────────────────────────┼────────────────┼──────────┘ │
273
+ │ │ │ │
274
+ │ Vite Dev Server Proxies: │ │ │
275
+ │ /jupyter/* ─────────────────┘ │ │
276
+ │ /agent/* ────────────────────────────────────┘ │
277
+ └──────────────────────────────┼────────────────┼─────────────┘
278
+ │ │
279
+ ┌────────────────┘ │
280
+ ▼ ▼
281
+ ┌──────────────────────────┐ ┌──────────────────────────┐
282
+ │ Jupyter Server (Docker) │ │ Agent API │
283
+ │ localhost:8889 │ │ localhost:8080 │
284
+ │ │ │ (model-studio-agent) │
285
+ │ ┌────────────────────┐ │ └──────────────────────────┘
286
+ │ │ Python 3.10 Kernel │ │
287
+ │ │ + Model Studio SDK │ │
288
+ │ └────────┬───────────┘ │
289
+ └───────────┼──────────────┘
290
+
291
+
292
+ ┌──────────────────────────────────────────────────────────┐
293
+ │ Model Studio API │
294
+ │ https://model-studio-api.elements.dev.privateer.com │
295
+ └──────────────────────────────────────────────────────────┘
296
+ ```
297
+
298
+ ## Development
299
+
300
+ ### Prerequisites
301
+
302
+ - [Miniconda](https://docs.conda.io/en/latest/miniconda.html) or Anaconda
303
+ - Docker + Docker Compose (for notebook server)
304
+ - `jq` and `curl` (for Keycloak token fetch)
305
+
306
+ ### Quick Start
307
+
308
+ ```bash
309
+ ./develop.sh --mode setup # Create conda env, install deps
310
+ ./develop.sh --mode test # Run unit tests
311
+ ./develop.sh --mode test-integration # Fetch Keycloak token + run integration tests
312
+ ./develop.sh --mode lint # Run ruff + mypy
313
+ ./develop.sh --mode notebook-server # Start headless Jupyter Server on port 8889
314
+ ```
315
+
316
+ ### Make Targets
317
+
318
+ ```bash
319
+ make install # pip install -e ".[dev]"
320
+ make test # Unit tests with coverage
321
+ make test-unit # Unit tests only (no integration)
322
+ make lint # ruff + mypy
323
+ make build # Build wheel
324
+ make notebook-server # Start headless Jupyter Server (port 8889)
325
+ make docker # Start full JupyterLab (port 8888)
326
+ ```
327
+
328
+ ### Integration Tests
329
+
330
+ ```bash
331
+ ./develop.sh --mode test-integration
332
+ ```
333
+
334
+ Integration tests run against the live API (elements-dev). They expect a project named "SDK Testing" with datasets "sdk-test-read-only" and "sdk-test-mutations".
335
+
336
+ ## Requirements
337
+
338
+ - Python >= 3.10
339
+ - httpx >= 0.25.0
340
+ - pydantic >= 2.0
341
+ - pandas >= 1.5.0 (optional)