aipmodel 0.2.63__tar.gz → 0.2.65__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.
- {aipmodel-0.2.63 → aipmodel-0.2.65}/PKG-INFO +1 -8
- aipmodel-0.2.65/README.md +326 -0
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel/CephS3Manager.py +170 -51
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel/__init__.py +2 -4
- aipmodel-0.2.65/aipmodel/acl_manager.py +228 -0
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel/model_registry.py +395 -130
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel/template.py +45 -8
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel.egg-info/PKG-INFO +1 -8
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel.egg-info/SOURCES.txt +1 -0
- aipmodel-0.2.65/aipmodel.egg-info/requires.txt +5 -0
- aipmodel-0.2.65/requirements.txt +5 -0
- {aipmodel-0.2.63 → aipmodel-0.2.65}/setup.py +1 -1
- aipmodel-0.2.63/README.md +0 -204
- aipmodel-0.2.63/aipmodel.egg-info/requires.txt +0 -12
- aipmodel-0.2.63/requirements.txt +0 -12
- {aipmodel-0.2.63 → aipmodel-0.2.65}/MANIFEST.in +0 -0
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel/update_checker.py +0 -0
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel.egg-info/dependency_links.txt +0 -0
- {aipmodel-0.2.63 → aipmodel-0.2.65}/aipmodel.egg-info/top_level.txt +0 -0
- {aipmodel-0.2.63 → aipmodel-0.2.65}/setup.cfg +0 -0
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aipmodel
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.65
|
|
4
4
|
Summary: SDK for model registration, versioning, and storage
|
|
5
5
|
Home-page: https://github.com/AIP-MLOPS/model-registry
|
|
6
6
|
Author: AIP MLOPS Team
|
|
7
7
|
Author-email: mohmmadweb@gmail.com
|
|
8
8
|
Requires-Python: >=3.6
|
|
9
9
|
Requires-Dist: boto3==1.34.0
|
|
10
|
-
Requires-Dist: clearml==2.0.2
|
|
11
|
-
Requires-Dist: fastapi==0.128.2
|
|
12
|
-
Requires-Dist: hf_xet==1.2.0
|
|
13
10
|
Requires-Dist: huggingface-hub==0.36.2
|
|
14
|
-
Requires-Dist: pydantic==2.12.5
|
|
15
11
|
Requires-Dist: python-dotenv==1.2.1
|
|
16
12
|
Requires-Dist: requests==2.32.5
|
|
17
|
-
Requires-Dist: tabulate==0.9.0
|
|
18
13
|
Requires-Dist: tqdm==4.67.1
|
|
19
|
-
Requires-Dist: ruff==0.14.7
|
|
20
|
-
Requires-Dist: uvicorn[standard]==0.38.0
|
|
21
14
|
Dynamic: author
|
|
22
15
|
Dynamic: author-email
|
|
23
16
|
Dynamic: home-page
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# AIP Model SDK
|
|
2
|
+
|
|
3
|
+
This SDK provides a robust interface for registering, uploading, downloading, listing, and deleting machine learning models using ClearML and S3 (Ceph) as storage. It supports **automatic versioning**, **categorization**, **tagging**, **metadata transparency**, **web link generation**, and fail-fast connectivity checks.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Install from PyPI:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install aipmodel
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Configuration & Authentication
|
|
19
|
+
|
|
20
|
+
To use the SDK, you must set up your environment variables. You can create a `.env` file in your project root:
|
|
21
|
+
|
|
22
|
+
```env
|
|
23
|
+
# ClearML API Credentials
|
|
24
|
+
CLEARML_API_HOST="http://your-clearml-server:8008"
|
|
25
|
+
CLEARML_WEB_HOST="http://your-clearml-web-ui:8080" # Required for generating model web links
|
|
26
|
+
CLEARML_ACCESS_KEY="your_access_key"
|
|
27
|
+
CLEARML_SECRET_KEY="your_secret_key"
|
|
28
|
+
|
|
29
|
+
# Ceph / S3 Storage
|
|
30
|
+
CEPH_ENDPOINT_URL="https://your-ceph-endpoint.com"
|
|
31
|
+
|
|
32
|
+
# User Management (Internal)
|
|
33
|
+
USER_MANAGEMENT_API="http://your-user-manager:30009"
|
|
34
|
+
USER_TOKEN="your_bearer_token" # Or pass explicitly in code
|
|
35
|
+
|
|
36
|
+
# Public bucket (used by public=True / set_model_public)
|
|
37
|
+
CEPH_PUBLIC_BUCKET_NAME="aip-public"
|
|
38
|
+
CEPH_ADMIN_ACCESS_KEY="your_public_bucket_access_key"
|
|
39
|
+
CEPH_ADMIN_SECRET_KEY="your_public_bucket_secret_key"
|
|
40
|
+
|
|
41
|
+
# ACL (Access Control) - optional, see "Access Control (ACL)" below
|
|
42
|
+
ACL_ENABLED="false"
|
|
43
|
+
ACL_API_HOST="http://your-acl-server:30011"
|
|
44
|
+
|
|
45
|
+
# Optional overrides (all have sane defaults if omitted)
|
|
46
|
+
SDK_REQUEST_TIMEOUT="30"
|
|
47
|
+
MODEL_ALLOWED_CATEGORIES="Text Generation,Image Classification"
|
|
48
|
+
S3_MULTIPART_THRESHOLD_MB="64"
|
|
49
|
+
S3_MULTIPART_CHUNKSIZE_MB="16"
|
|
50
|
+
S3_MAX_CONCURRENCY="10"
|
|
51
|
+
S3_UPLOAD_WORKERS="4"
|
|
52
|
+
S3_DOWNLOAD_WORKERS="4"
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> **Note:** `CLEARML_WEB_HOST` is new. If not provided, the SDK will default to the API host, which might result in incorrect clickable links in the output.
|
|
57
|
+
|
|
58
|
+
> Every constant the SDK relies on (timeouts, categories, transfer tuning, ACL) is overridable via `.env` — nothing important is hardcoded.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Logging Verbosity
|
|
63
|
+
|
|
64
|
+
`MLOpsManager(..., verbose=False)` — **`False` is the default.**
|
|
65
|
+
|
|
66
|
+
- `verbose=False`: only essential output is printed — operation start/result, successes, failures, and warnings that affect state (e.g. overwriting a version, falling back to a new "latest" version).
|
|
67
|
+
- `verbose=True`: every internal step is also printed (`[SDK_DEBUG]`/`[SDK_INFO]` narration), including the full raw metadata for transparency.
|
|
68
|
+
|
|
69
|
+
Nothing is ever logged to a file or hidden — all output goes to stdout via `print()`, so it's visible wherever the process runs.
|
|
70
|
+
|
|
71
|
+
## Access Control (ACL)
|
|
72
|
+
|
|
73
|
+
ACL is **off by default** and fully optional. Toggle it with one env var:
|
|
74
|
+
|
|
75
|
+
```env
|
|
76
|
+
ACL_ENABLED="true"
|
|
77
|
+
ACL_API_HOST="http://your-acl-server:30011"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- `ACL_ENABLED=false` (default): identical behavior to a build with no ACL at all — every call bypasses permission checks.
|
|
81
|
+
- `ACL_ENABLED=true`: `add_model`, `get_model`, `get_model_info`, `delete_model`, `set_model_public`, `set_latest_version`, and `list_models` all enforce permission checks against the ACL service, and `add_model`/`delete_model`/`set_model_public` keep the ACL service's record of each model in sync.
|
|
82
|
+
|
|
83
|
+
### Sharing a model
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
manager.share_model(model_name="demo_model_local", target_user="colleague@example.com", access_level="write")
|
|
87
|
+
# access_level: "read" | "write" | "delete" | "admin" | "owner"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Requires `ACL_ENABLED=true` and that you have `admin`-level access on the model. **Note:** the underlying ACL endpoint contract for sharing was inferred from the existing ACL client conventions and hasn't been verified against the live ACL service — confirm the request shape before relying on it in production.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Cross-User Visibility (Public Models)
|
|
95
|
+
|
|
96
|
+
Every model lives in its owner's own ClearML project (`project_<owner_username>`) — that part hasn't changed. What changed is **how `list_models`/`get_model_id_by_name`/`get_model_info`/`get_model` look things up**:
|
|
97
|
+
|
|
98
|
+
- **`list_models()`** (default `include_public=True`): returns your own models (private + public) **plus** every other user's model that is marked `public=True`. Other users' **private** models are never returned, under any setting. Each entry's `owner` field is resolved from the model's actual project, so models from other users show their real owner, not yours.
|
|
99
|
+
- Pass `include_public=False` to get the exact pre-existing behavior: your own project only, nothing from other users.
|
|
100
|
+
- `public_only=True` / `private_only=True` now filter across this combined set too.
|
|
101
|
+
- **`get_model_id_by_name(name, owner=None)`**, **`get_model(model_name, local_dest, version=None, owner=None)`**, **`get_model_info(identifier, owner=None)`**: all gained an optional `owner` argument. Omit it and behavior is identical to before (your own project only). Pass `owner="some_username"` to resolve a model by name from *that* user's project — useful once `list_models()` has shown you a public model that isn't yours.
|
|
102
|
+
- **`get_model_link`** now resolves the link using the model's *actual* owning project (previously it always used your own project ID, which silently produced a wrong link for any model you didn't own — this never came up before because nothing could return another user's model anyway).
|
|
103
|
+
- Write operations (`add_model`, `delete_model`, `set_model_public`, `set_latest_version`) are **unchanged** — they still only ever operate within your own project by name. To act on a model you don't own (e.g. as an ACL-granted admin), pass its `model_id` directly (already supported) rather than its name.
|
|
104
|
+
|
|
105
|
+
**Performance note:** when `include_public=True` (the default), `list_models()` makes one extra unscoped ClearML query (`models.get_all` with no project filter) to find other users' public models — on a very large ClearML deployment this returns every model company-wide before filtering down to public ones. If that ever becomes slow, set `include_public=False` and only fetch other users' models on demand via `owner=`.
|
|
106
|
+
|
|
107
|
+
**Backward compatibility:** `get_model_id_by_name`, `get_model`, `get_model_info` keep their exact old signatures plus one new optional trailing argument — no existing call site breaks. `list_models()`'s default *output* now includes more rows than before (other users' public models) since that was the explicit point of this change; pass `include_public=False` if your code depends on the exact old row set.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Example Usage
|
|
112
|
+
|
|
113
|
+
This example demonstrates how to use the new features: **Auto-Versioning**, **Categories**, **Tags**, and **Web Links**.
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
import os
|
|
117
|
+
from dotenv import load_dotenv
|
|
118
|
+
from aipmodel.model_registry import MLOpsManager
|
|
119
|
+
|
|
120
|
+
load_dotenv()
|
|
121
|
+
|
|
122
|
+
# --- STEP 1: Initialize MLOps Manager ---
|
|
123
|
+
print("\n[STEP 1] Initialize MLOps Manager")
|
|
124
|
+
# verbose=True enables detailed logging and transparency mode.
|
|
125
|
+
manager = MLOpsManager(
|
|
126
|
+
user_token=os.getenv("USER_TOKEN"),
|
|
127
|
+
CLEARML_API_HOST=os.getenv("CLEARML_API_HOST"),
|
|
128
|
+
CLEARML_WEB_HOST=os.getenv("CLEARML_WEB_HOST"), # For generating UI links
|
|
129
|
+
CEPH_ENDPOINT_URL=os.getenv("CEPH_ENDPOINT_URL"),
|
|
130
|
+
USER_MANAGEMENT_API=os.getenv("USER_MANAGEMENT_API"),
|
|
131
|
+
verbose=True
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# --- STEP 2: Add Private Local Model (Explicit Version) ---
|
|
135
|
+
print("\n[STEP 2] Add Private Model (Explicit Version + Metadata)")
|
|
136
|
+
local_model_id = manager.add_model(
|
|
137
|
+
source_type="local",
|
|
138
|
+
model_name="demo_model_local",
|
|
139
|
+
version="v1.0",
|
|
140
|
+
source_path="./my_models/v1",
|
|
141
|
+
code_path="./my_models/train.py",
|
|
142
|
+
category="Text Generation",
|
|
143
|
+
tags=["production", "base-model"],
|
|
144
|
+
public=False # Default is False (Private Bucket)
|
|
145
|
+
)
|
|
146
|
+
print(f" -> Registered ID: {local_model_id}")
|
|
147
|
+
|
|
148
|
+
# --- STEP 3: Add Auto-Versioned Model ---
|
|
149
|
+
print("\n[STEP 3] Add Local Model (Auto-Versioning)")
|
|
150
|
+
# Passing version=None triggers auto-generation (e.g., _v2, _v3 based on history)
|
|
151
|
+
auto_ver_id = manager.add_model(
|
|
152
|
+
source_type="local",
|
|
153
|
+
model_name="demo_model_local",
|
|
154
|
+
version=None,
|
|
155
|
+
source_path="./my_models/v2_finetuned",
|
|
156
|
+
tags=["experimental", "auto-versioned"]
|
|
157
|
+
)
|
|
158
|
+
print(f" -> Registered ID: {auto_ver_id}")
|
|
159
|
+
|
|
160
|
+
# --- STEP 4: Add Public Model (Direct to Public Bucket) ---
|
|
161
|
+
print("\n[STEP 4] Add Public Model")
|
|
162
|
+
# Setting public=True uploads directly to the shared/public bucket
|
|
163
|
+
public_model_id = manager.add_model(
|
|
164
|
+
source_type="local",
|
|
165
|
+
model_name="demo_model_public",
|
|
166
|
+
version="v1.0",
|
|
167
|
+
source_path="./my_models/public_release",
|
|
168
|
+
tags=["community", "public"],
|
|
169
|
+
public=True
|
|
170
|
+
)
|
|
171
|
+
print(f" -> Registered ID: {public_model_id}")
|
|
172
|
+
|
|
173
|
+
# --- STEP 5: Add Hugging Face Model ---
|
|
174
|
+
print("\n[STEP 5] Add Model from Hugging Face")
|
|
175
|
+
hf_model_id = manager.add_model(
|
|
176
|
+
source_type="hf",
|
|
177
|
+
model_name="demo_model_hf",
|
|
178
|
+
version="v1",
|
|
179
|
+
source_path="facebook/wav2vec2-base-960h",
|
|
180
|
+
category="Image Classification",
|
|
181
|
+
tags=["imported", "audio"]
|
|
182
|
+
)
|
|
183
|
+
print(f" -> Registered ID: {hf_model_id}")
|
|
184
|
+
|
|
185
|
+
# --- STEP 6: Get Detailed Info ---
|
|
186
|
+
print("\n[STEP 6] Get Detailed Model Info")
|
|
187
|
+
# Displays ID, Public status, Total Versions, Size, and ClearML Web Link
|
|
188
|
+
manager.get_model_info("demo_model_local")
|
|
189
|
+
|
|
190
|
+
# --- STEP 7: List All Models ---
|
|
191
|
+
print("\n[STEP 7] List All Models")
|
|
192
|
+
# Check the 'Public' column (T/F) and 'Latest' version column.
|
|
193
|
+
# By default this also includes OTHER users' public models (each tagged with
|
|
194
|
+
# its real 'owner') - pass include_public=False to see only your own, like before.
|
|
195
|
+
manager.list_models(verbose=False)
|
|
196
|
+
manager.list_models(category="Text Generation") # filter by category
|
|
197
|
+
manager.list_models(tag="production") # filter by tag
|
|
198
|
+
manager.list_models(public_only=True) # only public models (yours + others')
|
|
199
|
+
manager.list_models(include_public=False) # only your own project, old behavior
|
|
200
|
+
|
|
201
|
+
# --- STEP 7B: Look Up a Model You Don't Own ---
|
|
202
|
+
print("\n[STEP 7B] Inspect/Download a Public Model From Another User")
|
|
203
|
+
# Suppose list_models() above showed a public model named "shared_model" owned by "colleague_username"
|
|
204
|
+
# other_info = manager.get_model_info("shared_model", owner="colleague_username")
|
|
205
|
+
# manager.get_model(model_name="shared_model", local_dest="./downloads/shared", owner="colleague_username")
|
|
206
|
+
|
|
207
|
+
# --- STEP 8: Management & Visibility Operations ---
|
|
208
|
+
print("\n[STEP 8] Management Operations")
|
|
209
|
+
|
|
210
|
+
# A. Change Visibility (Private -> Public)
|
|
211
|
+
# Moves files physically from User Bucket to Public Bucket
|
|
212
|
+
manager.set_model_public("demo_model_local", public=True)
|
|
213
|
+
|
|
214
|
+
# B. Get Latest Version Name
|
|
215
|
+
# Returns the string tag of the latest version (e.g., "_v2")
|
|
216
|
+
latest_ver = manager.get_latest_version("demo_model_local")
|
|
217
|
+
print(f"Latest version is: {latest_ver}")
|
|
218
|
+
|
|
219
|
+
# C. Set Manual Latest Version
|
|
220
|
+
# Points the 'latest' tag to a specific version
|
|
221
|
+
manager.set_latest_version(model_name="demo_model_local", version="v1.0")
|
|
222
|
+
|
|
223
|
+
# --- STEP 9: Download Operations ---
|
|
224
|
+
print("\n[STEP 9] Download Model")
|
|
225
|
+
|
|
226
|
+
# Download latest version
|
|
227
|
+
# NOTE: The SDK automatically appends the Model ID to the path.
|
|
228
|
+
# Destination will be: ./downloads/latest/<MODEL_ID>/<VERSION_NAME>/
|
|
229
|
+
manager.get_model(
|
|
230
|
+
model_name="demo_model_local",
|
|
231
|
+
local_dest="./downloads/latest"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# --- STEP 10: Deletion ---
|
|
235
|
+
print("\n[STEP 10] Deletion")
|
|
236
|
+
|
|
237
|
+
# Delete a specific version (Removes files + Metadata entry)
|
|
238
|
+
manager.delete_model(model_name="demo_model_local", version="v1.0")
|
|
239
|
+
|
|
240
|
+
# Delete the entire model (Removes all versions + ClearML ID)
|
|
241
|
+
manager.delete_model(model_name="demo_model_hf")
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## API Reference
|
|
248
|
+
|
|
249
|
+
### `MLOpsManager` Methods
|
|
250
|
+
|
|
251
|
+
| Function | Input Arguments | Description |
|
|
252
|
+
| --- | --- | --- |
|
|
253
|
+
| **`__init__`** | `user_token`, `CLEARML_API_HOST`, `CLEARML_WEB_HOST`, `CEPH_ENDPOINT_URL`, `USER_MANAGEMENT_API`, `verbose`, `ACL_API_HOST`, `ACL_ENABLED` | Initializes connections. Performs fail-fast health checks. `ACL_*` args (or env vars) toggle ACL enforcement (default: disabled). |
|
|
254
|
+
| **`add_model`** | `source_type`, `model_name`, `version`, `source_path`, `code_path`, `category`, `tags`, `external_ceph_*`, `model_folder_name` | Uploads a model. `version`: if `None`, generates `_v{n}` automatically. `category`: must be one of `get_allowed_categories()` (defaults to "Text Generation"/"Image Classification", overridable via `MODEL_ALLOWED_CATEGORIES`). `tags`: list of strings. `model_folder_name`: optional explicit folder name for the uploaded model; if omitted, it's derived automatically as before (backward compatible). |
|
|
255
|
+
| **`get_model`** | `model_name`, `local_dest`, `version`, `owner` | Downloads model files. If `version` is omitted, downloads the version marked as 'latest'. `owner` (optional): resolve `model_name` from another user's project, e.g. to download a public model that isn't yours. |
|
|
256
|
+
| **`get_model_info`** | `identifier` (Name or ID), `owner` | Prints detailed info including **Owner**, **Web Link**, Tags, Category, and Version History. `owner` (optional): resolve a name-based `identifier` from another user's project. |
|
|
257
|
+
| **`get_allowed_categories`** | *(none)* | Returns the list of valid `category` values for `add_model`. |
|
|
258
|
+
| **`list_models`** | `verbose`, `category`, `tag`, `public_only`, `private_only`, `include_public` | Lists your own models **plus** (by default, `include_public=True`) every other user's `public=True` model — never another user's private model. Each entry includes a real `owner` field. `verbose=True` shows full JSON metadata. `category`/`tag` filter by exact match; `public_only`/`private_only` filter by visibility, applied across the combined set. `include_public=False` restores the pre-existing own-project-only behavior. When ACL is enabled, results are additionally filtered to models you can access (plus public ones). See "Cross-User Visibility" above. |
|
|
259
|
+
| **`get_model_id_by_name`** | `name`, `owner` | Resolves a model name to its ClearML ID. `owner` (optional): look it up in another user's project instead of your own. |
|
|
260
|
+
| **`get_model_name_by_id`** | `model_id` | Resolves a ClearML ID back to its model name (works for any model, regardless of owner). |
|
|
261
|
+
| **`get_latest_version`** | `model_identifier` (Name or ID) | Returns the version tag currently marked 'latest'. |
|
|
262
|
+
| **`set_latest_version`** | `model_name`, `version` | Updates the 'latest' pointer to a specific version without modifying files. |
|
|
263
|
+
| **`set_model_public`** | `model_name`, `public` | Moves a model's files between the private and public buckets (transactional, parallel server-side copy). |
|
|
264
|
+
| **`share_model`** | `model_name`, `target_user`, `access_level` | Grants another user access to a model. Requires `ACL_ENABLED=true`. |
|
|
265
|
+
| **`delete_model`** | `model_name`, `version` | If `version` provided: deletes that version (and rolls "latest" back to the next one if it was the latest). If that was the *last* version, the model container is removed too. If `version` is omitted: deletes the entire model in one call — this already is "delete all versions", no need to delete one by one. |
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## HTTP API
|
|
270
|
+
|
|
271
|
+
The SDK ships a companion **HTTP API** service (`api/model-registry-api`) that exposes every SDK operation over HTTP for non-Python clients.
|
|
272
|
+
|
|
273
|
+
Full documentation for that service — endpoints, auth, request/response shapes, ACL toggle, curl examples — lives in its own repo:
|
|
274
|
+
|
|
275
|
+
> **`api/model-registry-api/README.md`**
|
|
276
|
+
|
|
277
|
+
The short version: run `uvicorn main:app --host 0.0.0.0 --port 8080`, pass `Authorization: Bearer <token>` on every call, and toggle ACL with `ACL_ENABLED=true/false` in the API service's `.env`.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Constraints & Validations
|
|
282
|
+
|
|
283
|
+
1. **Model Names:** Cannot start with `tmp_`, `_tmp_`, or `#`.
|
|
284
|
+
2. **Version Names:**
|
|
285
|
+
* Manual versions cannot start with `_` (reserved for auto-generated versions).
|
|
286
|
+
* Auto-generated versions follow the pattern `_v1`, `_v2`, etc.
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
3. **Categories:** Only categories returned by `manager.get_allowed_categories()` are allowed. Defaults to:
|
|
290
|
+
* `Text Generation`
|
|
291
|
+
* `Image Classification`
|
|
292
|
+
|
|
293
|
+
Override the full list via `MODEL_ALLOWED_CATEGORIES` in `.env` (comma-separated).
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Testing
|
|
300
|
+
|
|
301
|
+
- `test_model_registry.py` / `test_ceph_s3_manager.py`: automated unit tests (mock the ClearML/S3 boundary, no live infra needed). Run with:
|
|
302
|
+
```bash
|
|
303
|
+
pip install pytest
|
|
304
|
+
pytest test_model_registry.py test_ceph_s3_manager.py -v
|
|
305
|
+
```
|
|
306
|
+
- `test.py`: a manual/live-integration demo script covering every scenario above against **real** ClearML/Ceph/ACL services — everything is commented out by default; uncomment only what you intend to run.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Admin Instructions: Auto-Publishing to PyPI
|
|
311
|
+
|
|
312
|
+
This SDK uses a GitHub Actions workflow (`.github/workflows/publish.yaml`) for automatic versioning and PyPI publishing.
|
|
313
|
+
|
|
314
|
+
### Trigger Conditions
|
|
315
|
+
|
|
316
|
+
* Push to `main` branch.
|
|
317
|
+
* Commit message contains `pipy commit -push`.
|
|
318
|
+
* GitHub variable `PUBLISH_TO_PYPI` is set to `true`.
|
|
319
|
+
|
|
320
|
+
### Commit Message Format
|
|
321
|
+
|
|
322
|
+
| Keyword | Action |
|
|
323
|
+
| --- | --- |
|
|
324
|
+
| `pipy commit -push major` | Increments **Major** version (e.g., 1.0.0 -> 2.0.0) |
|
|
325
|
+
| `pipy commit -push minor` | Increments **Minor** version (e.g., 0.1.0 -> 0.2.0) |
|
|
326
|
+
| `pipy commit -push` | Increments **Patch** version (e.g., 0.1.1 -> 0.1.2) |
|