Skip to content

Commit 44e3464

Browse files
committed
feat: add Python SDK for ModelPack spec types and validation
Signed-off-by: pradhyum6144 <pradhyum314@gmail.com>
1 parent 5196234 commit 44e3464

14 files changed

Lines changed: 1934 additions & 0 deletions

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010

1111
# Dependency directories (remove the comment below to include it)
1212
vendor/
13+
14+
# Python
15+
__pycache__/
16+
*.pyc
17+
*.egg-info/
18+
.venv/
19+
.pytest_cache/
1320
.idea
1421
.vscode
1522
.cache

specs-python/modelpack/__init__.py

Whitespace-only changes.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Copyright 2025 The CNCF ModelPack Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""ModelPack Python SDK - CNCF standard for packaging and distributing AI models."""
16+
17+
from modelpack.v1.config import (
18+
Model,
19+
ModelCapabilities,
20+
ModelConfig,
21+
ModelDescriptor,
22+
ModelFS,
23+
Modality,
24+
)
25+
from modelpack.v1.annotations import (
26+
ANNOTATION_FILEPATH,
27+
ANNOTATION_FILE_METADATA,
28+
ANNOTATION_MEDIA_TYPE_UNTESTED,
29+
FileMetadata,
30+
)
31+
from modelpack.v1.mediatype import (
32+
ARTIFACT_TYPE_MODEL_MANIFEST,
33+
MEDIA_TYPE_MODEL_CONFIG,
34+
MEDIA_TYPE_MODEL_WEIGHT_RAW,
35+
MEDIA_TYPE_MODEL_WEIGHT,
36+
MEDIA_TYPE_MODEL_WEIGHT_GZIP,
37+
MEDIA_TYPE_MODEL_WEIGHT_ZSTD,
38+
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_RAW,
39+
MEDIA_TYPE_MODEL_WEIGHT_CONFIG,
40+
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_GZIP,
41+
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_ZSTD,
42+
MEDIA_TYPE_MODEL_DOC_RAW,
43+
MEDIA_TYPE_MODEL_DOC,
44+
MEDIA_TYPE_MODEL_DOC_GZIP,
45+
MEDIA_TYPE_MODEL_DOC_ZSTD,
46+
MEDIA_TYPE_MODEL_CODE_RAW,
47+
MEDIA_TYPE_MODEL_CODE,
48+
MEDIA_TYPE_MODEL_CODE_GZIP,
49+
MEDIA_TYPE_MODEL_CODE_ZSTD,
50+
MEDIA_TYPE_MODEL_DATASET_RAW,
51+
MEDIA_TYPE_MODEL_DATASET,
52+
MEDIA_TYPE_MODEL_DATASET_GZIP,
53+
MEDIA_TYPE_MODEL_DATASET_ZSTD,
54+
)
55+
from modelpack.v1.validator import validate_config
56+
57+
__all__ = [
58+
"Model",
59+
"ModelCapabilities",
60+
"ModelConfig",
61+
"ModelDescriptor",
62+
"ModelFS",
63+
"Modality",
64+
"FileMetadata",
65+
"ANNOTATION_FILEPATH",
66+
"ANNOTATION_FILE_METADATA",
67+
"ANNOTATION_MEDIA_TYPE_UNTESTED",
68+
"ARTIFACT_TYPE_MODEL_MANIFEST",
69+
"MEDIA_TYPE_MODEL_CONFIG",
70+
"MEDIA_TYPE_MODEL_WEIGHT_RAW",
71+
"MEDIA_TYPE_MODEL_WEIGHT",
72+
"MEDIA_TYPE_MODEL_WEIGHT_GZIP",
73+
"MEDIA_TYPE_MODEL_WEIGHT_ZSTD",
74+
"MEDIA_TYPE_MODEL_WEIGHT_CONFIG_RAW",
75+
"MEDIA_TYPE_MODEL_WEIGHT_CONFIG",
76+
"MEDIA_TYPE_MODEL_WEIGHT_CONFIG_GZIP",
77+
"MEDIA_TYPE_MODEL_WEIGHT_CONFIG_ZSTD",
78+
"MEDIA_TYPE_MODEL_DOC_RAW",
79+
"MEDIA_TYPE_MODEL_DOC",
80+
"MEDIA_TYPE_MODEL_DOC_GZIP",
81+
"MEDIA_TYPE_MODEL_DOC_ZSTD",
82+
"MEDIA_TYPE_MODEL_CODE_RAW",
83+
"MEDIA_TYPE_MODEL_CODE",
84+
"MEDIA_TYPE_MODEL_CODE_GZIP",
85+
"MEDIA_TYPE_MODEL_CODE_ZSTD",
86+
"MEDIA_TYPE_MODEL_DATASET_RAW",
87+
"MEDIA_TYPE_MODEL_DATASET",
88+
"MEDIA_TYPE_MODEL_DATASET_GZIP",
89+
"MEDIA_TYPE_MODEL_DATASET_ZSTD",
90+
"validate_config",
91+
]
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Copyright 2025 The CNCF ModelPack Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Annotation constants and types matching specs-go/v1/annotations.go."""
16+
17+
from __future__ import annotations
18+
19+
from dataclasses import dataclass
20+
from datetime import datetime
21+
22+
# Annotation key for the file path of the layer.
23+
ANNOTATION_FILEPATH = "org.cncf.model.filepath"
24+
25+
# Annotation key for the file metadata of the layer.
26+
ANNOTATION_FILE_METADATA = "org.cncf.model.file.metadata+json"
27+
28+
# Annotation key for file media type untested flag of the layer.
29+
ANNOTATION_MEDIA_TYPE_UNTESTED = "org.cncf.model.file.mediatype.untested"
30+
31+
32+
@dataclass
33+
class FileMetadata:
34+
"""Represents the metadata of a file.
35+
36+
Mirrors the Go FileMetadata struct in specs-go/v1/annotations.go.
37+
"""
38+
39+
name: str = ""
40+
mode: int = 0
41+
uid: int = 0
42+
gid: int = 0
43+
size: int = 0
44+
mod_time: datetime | None = None
45+
typeflag: int = 0
46+
47+
def to_dict(self) -> dict:
48+
"""Serialize to a dict matching the JSON field names."""
49+
d: dict = {
50+
"name": self.name,
51+
"mode": self.mode,
52+
"uid": self.uid,
53+
"gid": self.gid,
54+
"size": self.size,
55+
"typeflag": self.typeflag,
56+
}
57+
if self.mod_time is not None:
58+
d["mtime"] = self.mod_time.isoformat()
59+
return d
60+
61+
@classmethod
62+
def from_dict(cls, data: dict) -> FileMetadata:
63+
"""Deserialize from a dict with JSON field names."""
64+
mod_time = None
65+
if "mtime" in data:
66+
mod_time = datetime.fromisoformat(
67+
data["mtime"].replace("Z", "+00:00")
68+
)
69+
return cls(
70+
name=data.get("name", ""),
71+
mode=data.get("mode", 0),
72+
uid=data.get("uid", 0),
73+
gid=data.get("gid", 0),
74+
size=data.get("size", 0),
75+
mod_time=mod_time,
76+
typeflag=data.get("typeflag", 0),
77+
)
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
{
2+
"description": "Model Artifact Configuration Schema",
3+
"$schema": "http://json-schema.org/draft-04/schema#",
4+
"$id": "https://github.com/modelpack/model-spec/config",
5+
"type": "object",
6+
"properties": {
7+
"descriptor": {
8+
"$ref": "#/$defs/ModelDescriptor"
9+
},
10+
"modelfs": {
11+
"$ref": "#/$defs/ModelFS"
12+
},
13+
"config": {
14+
"$ref": "#/$defs/ModelConfig"
15+
}
16+
},
17+
"additionalProperties": false,
18+
"required": [
19+
"descriptor",
20+
"config",
21+
"modelfs"
22+
],
23+
"$defs": {
24+
"ModelConfig": {
25+
"type": "object",
26+
"properties": {
27+
"architecture": {
28+
"type": "string"
29+
},
30+
"format": {
31+
"type": "string"
32+
},
33+
"paramSize": {
34+
"type": "string"
35+
},
36+
"precision": {
37+
"type": "string"
38+
},
39+
"quantization": {
40+
"type": "string"
41+
},
42+
"capabilities": {
43+
"$ref": "#/$defs/ModelCapabilities"
44+
}
45+
},
46+
"additionalProperties": false
47+
},
48+
"ModelDescriptor": {
49+
"type": "object",
50+
"properties": {
51+
"createdAt": {
52+
"type": "string",
53+
"format": "date-time"
54+
},
55+
"authors": {
56+
"type": "array",
57+
"items": {
58+
"type": "string"
59+
}
60+
},
61+
"family": {
62+
"type": "string"
63+
},
64+
"name": {
65+
"type": "string",
66+
"minLength": 1
67+
},
68+
"docURL": {
69+
"type": "string"
70+
},
71+
"sourceURL": {
72+
"type": "string"
73+
},
74+
"datasetsURL": {
75+
"type": "array",
76+
"items": {
77+
"type": "string"
78+
}
79+
},
80+
"version": {
81+
"type": "string"
82+
},
83+
"revision": {
84+
"type": "string"
85+
},
86+
"vendor": {
87+
"type": "string"
88+
},
89+
"licenses": {
90+
"type": "array",
91+
"items": {
92+
"type": "string"
93+
}
94+
},
95+
"title": {
96+
"type": "string"
97+
},
98+
"description": {
99+
"type": "string"
100+
}
101+
},
102+
"additionalProperties": false
103+
},
104+
"ModelFS": {
105+
"type": "object",
106+
"properties": {
107+
"type": {
108+
"type": "string",
109+
"enum": ["layers"]
110+
},
111+
"diffIds": {
112+
"type": "array",
113+
"items": {
114+
"type": "string"
115+
},
116+
"minItems": 1
117+
}
118+
},
119+
"additionalProperties": false,
120+
"required": [
121+
"type",
122+
"diffIds"
123+
]
124+
},
125+
"ModelCapabilities": {
126+
"type": "object",
127+
"properties": {
128+
"inputTypes": {
129+
"type": "array",
130+
"items": {
131+
"$ref": "#/$defs/Modality"
132+
}
133+
},
134+
"outputTypes": {
135+
"type": "array",
136+
"items": {
137+
"$ref": "#/$defs/Modality"
138+
}
139+
},
140+
"knowledgeCutoff": {
141+
"type": "string",
142+
"format": "date-time"
143+
},
144+
"reasoning": {
145+
"type": "boolean"
146+
},
147+
"toolUsage": {
148+
"type": "boolean"
149+
},
150+
"reward": {
151+
"type": "boolean"
152+
},
153+
"languages": {
154+
"type": "array",
155+
"items": {
156+
"type": "string",
157+
"pattern": "^[a-z]{2}$"
158+
}
159+
}
160+
},
161+
"additionalProperties": false
162+
},
163+
"Modality": {
164+
"type": "string",
165+
"enum": ["text", "image", "audio", "video", "embedding", "other"]
166+
}
167+
}
168+
}

0 commit comments

Comments
 (0)