Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@

# Dependency directories (remove the comment below to include it)
vendor/

# Python
__pycache__/
*.pyc
*.egg-info/
.venv/
.pytest_cache/
.idea
.vscode
.cache
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ validate-examples: ## validate examples in the specification markdown files
.PHONY: test
test:
go test ./...

.PHONY: generate-python-models
generate-python-models: ## generate Python models from JSON schema
python3 tools/generate_python_models.py
58 changes: 58 additions & 0 deletions specs-python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Python ModelPack Types

This directory provides Python data structures for the CNCF ModelPack specification.

The core model types are **auto-generated** from the canonical JSON Schema at `schema/config-schema.json` using [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator), ensuring they stay in sync with the specification automatically.

## Requirements

- Python >= 3.10
- pydantic >= 2
- jsonschema >= 4.20.0

## Installation

```bash
cd specs-python
pip install -e .
```

For development:

```bash
pip install -e ".[dev]"
```

## Usage

```python
from modelpack.v1 import Model, ModelDescriptor, ModelFS, ModelConfig

# Create a model from a JSON payload
model = Model.model_validate_json(json_payload)
print(model.descriptor.name)

# Validate a config dict against the JSON schema
from modelpack.v1 import validate_config
validate_config(config_dict)
```

## Regenerate Models

If the schema changes, regenerate the Pydantic models:

```bash
pip install datamodel-code-generator
make generate-python-models
```

This runs `tools/generate_python_models.py`, which regenerates `specs-python/modelpack/v1/models.py`.

**Do not edit `models.py` manually.** Update the schema and regenerate instead.

## Run Tests

```bash
cd specs-python
pytest
```
Empty file.
97 changes: 97 additions & 0 deletions specs-python/modelpack/v1/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Copyright 2025 The CNCF ModelPack Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""ModelPack Python SDK - CNCF standard for packaging and distributing AI models.

Types are auto-generated from schema/config-schema.json using datamodel-code-generator.
Do not edit models.py manually — regenerate with: make generate-python-models
"""

from modelpack.v1.annotations import (
ANNOTATION_FILE_METADATA,
ANNOTATION_FILEPATH,
ANNOTATION_MEDIA_TYPE_UNTESTED,
FileMetadata,
)
from modelpack.v1.mediatype import (
ARTIFACT_TYPE_MODEL_MANIFEST,
MEDIA_TYPE_MODEL_CODE,
MEDIA_TYPE_MODEL_CODE_GZIP,
MEDIA_TYPE_MODEL_CODE_RAW,
MEDIA_TYPE_MODEL_CODE_ZSTD,
MEDIA_TYPE_MODEL_CONFIG,
MEDIA_TYPE_MODEL_DATASET,
MEDIA_TYPE_MODEL_DATASET_GZIP,
MEDIA_TYPE_MODEL_DATASET_RAW,
MEDIA_TYPE_MODEL_DATASET_ZSTD,
MEDIA_TYPE_MODEL_DOC,
MEDIA_TYPE_MODEL_DOC_GZIP,
MEDIA_TYPE_MODEL_DOC_RAW,
MEDIA_TYPE_MODEL_DOC_ZSTD,
MEDIA_TYPE_MODEL_WEIGHT,
MEDIA_TYPE_MODEL_WEIGHT_CONFIG,
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_GZIP,
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_RAW,
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_ZSTD,
MEDIA_TYPE_MODEL_WEIGHT_GZIP,
MEDIA_TYPE_MODEL_WEIGHT_RAW,
MEDIA_TYPE_MODEL_WEIGHT_ZSTD,
)
from modelpack.v1.models import (
Language,
Modality,
Model,
ModelCapabilities,
ModelConfig,
ModelDescriptor,
ModelFS,
)
from modelpack.v1.validator import validate_config

__all__ = [
"Model",
"ModelCapabilities",
"ModelConfig",
"ModelDescriptor",
"ModelFS",
"Modality",
"Language",
"FileMetadata",
"ANNOTATION_FILEPATH",
"ANNOTATION_FILE_METADATA",
"ANNOTATION_MEDIA_TYPE_UNTESTED",
"ARTIFACT_TYPE_MODEL_MANIFEST",
"MEDIA_TYPE_MODEL_CONFIG",
"MEDIA_TYPE_MODEL_WEIGHT_RAW",
"MEDIA_TYPE_MODEL_WEIGHT",
"MEDIA_TYPE_MODEL_WEIGHT_GZIP",
"MEDIA_TYPE_MODEL_WEIGHT_ZSTD",
"MEDIA_TYPE_MODEL_WEIGHT_CONFIG_RAW",
"MEDIA_TYPE_MODEL_WEIGHT_CONFIG",
"MEDIA_TYPE_MODEL_WEIGHT_CONFIG_GZIP",
"MEDIA_TYPE_MODEL_WEIGHT_CONFIG_ZSTD",
"MEDIA_TYPE_MODEL_DOC_RAW",
"MEDIA_TYPE_MODEL_DOC",
"MEDIA_TYPE_MODEL_DOC_GZIP",
"MEDIA_TYPE_MODEL_DOC_ZSTD",
"MEDIA_TYPE_MODEL_CODE_RAW",
"MEDIA_TYPE_MODEL_CODE",
"MEDIA_TYPE_MODEL_CODE_GZIP",
"MEDIA_TYPE_MODEL_CODE_ZSTD",
"MEDIA_TYPE_MODEL_DATASET_RAW",
"MEDIA_TYPE_MODEL_DATASET",
"MEDIA_TYPE_MODEL_DATASET_GZIP",
"MEDIA_TYPE_MODEL_DATASET_ZSTD",
"validate_config",
]
87 changes: 87 additions & 0 deletions specs-python/modelpack/v1/annotations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Copyright 2025 The CNCF ModelPack Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Annotation constants and types matching specs-go/v1/annotations.go."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime, timezone

# Annotation key for the file path of the layer.
ANNOTATION_FILEPATH = "org.cncf.model.filepath"

# Annotation key for the file metadata of the layer.
ANNOTATION_FILE_METADATA = "org.cncf.model.file.metadata+json"

# Annotation key for file media type untested flag of the layer.
ANNOTATION_MEDIA_TYPE_UNTESTED = "org.cncf.model.file.mediatype.untested"


def _format_datetime(dt: datetime) -> str:
"""Format a datetime as RFC 3339 with 'Z' suffix for UTC, matching Go."""
s = dt.isoformat()
if s.endswith("+00:00"):
s = s[:-6] + "Z"
return s


@dataclass
class FileMetadata:
"""Represents the metadata of a file.

Mirrors the Go FileMetadata struct in specs-go/v1/annotations.go.
"""

name: str = ""
mode: int = 0
uid: int = 0
gid: int = 0
size: int = 0
mod_time: datetime = field(
default_factory=lambda: datetime(1, 1, 1, tzinfo=timezone.utc)
)
typeflag: int = 0

def to_dict(self) -> dict:
"""Serialize to a dict matching the JSON field names.

All fields are always present, matching Go's FileMetadata
which has no omitempty tags.
"""
return {
"name": self.name,
"mode": self.mode,
"uid": self.uid,
"gid": self.gid,
"size": self.size,
"mtime": _format_datetime(self.mod_time),
"typeflag": self.typeflag,
}

@classmethod
def from_dict(cls, data: dict) -> FileMetadata:
"""Deserialize from a dict with JSON field names."""
mod_time = None
if "mtime" in data:
mod_time = datetime.fromisoformat(data["mtime"].replace("Z", "+00:00"))
return cls(
name=data.get("name", ""),
mode=data.get("mode", 0),
uid=data.get("uid", 0),
gid=data.get("gid", 0),
size=data.get("size", 0),
mod_time=mod_time,
typeflag=data.get("typeflag", 0),
)
55 changes: 55 additions & 0 deletions specs-python/modelpack/v1/mediatype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright 2025 The CNCF ModelPack Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Media type constants matching specs-go/v1/mediatype.go."""

# Artifact type for a model manifest.
ARTIFACT_TYPE_MODEL_MANIFEST = "application/vnd.cncf.model.manifest.v1+json"

# Media type for a model configuration.
MEDIA_TYPE_MODEL_CONFIG = "application/vnd.cncf.model.config.v1+json"

# Model weight media types.
MEDIA_TYPE_MODEL_WEIGHT_RAW = "application/vnd.cncf.model.weight.v1.raw"
MEDIA_TYPE_MODEL_WEIGHT = "application/vnd.cncf.model.weight.v1.tar"
MEDIA_TYPE_MODEL_WEIGHT_GZIP = "application/vnd.cncf.model.weight.v1.tar+gzip"
MEDIA_TYPE_MODEL_WEIGHT_ZSTD = "application/vnd.cncf.model.weight.v1.tar+zstd"

# Model weight config media types.
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_RAW = "application/vnd.cncf.model.weight.config.v1.raw"
MEDIA_TYPE_MODEL_WEIGHT_CONFIG = "application/vnd.cncf.model.weight.config.v1.tar"
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_GZIP = (
"application/vnd.cncf.model.weight.config.v1.tar+gzip"
)
MEDIA_TYPE_MODEL_WEIGHT_CONFIG_ZSTD = (
"application/vnd.cncf.model.weight.config.v1.tar+zstd"
)

# Model documentation media types.
MEDIA_TYPE_MODEL_DOC_RAW = "application/vnd.cncf.model.doc.v1.raw"
MEDIA_TYPE_MODEL_DOC = "application/vnd.cncf.model.doc.v1.tar"
MEDIA_TYPE_MODEL_DOC_GZIP = "application/vnd.cncf.model.doc.v1.tar+gzip"
MEDIA_TYPE_MODEL_DOC_ZSTD = "application/vnd.cncf.model.doc.v1.tar+zstd"

# Model code media types.
MEDIA_TYPE_MODEL_CODE_RAW = "application/vnd.cncf.model.code.v1.raw"
MEDIA_TYPE_MODEL_CODE = "application/vnd.cncf.model.code.v1.tar"
MEDIA_TYPE_MODEL_CODE_GZIP = "application/vnd.cncf.model.code.v1.tar+gzip"
MEDIA_TYPE_MODEL_CODE_ZSTD = "application/vnd.cncf.model.code.v1.tar+zstd"

# Model dataset media types.
MEDIA_TYPE_MODEL_DATASET_RAW = "application/vnd.cncf.model.dataset.v1.raw"
MEDIA_TYPE_MODEL_DATASET = "application/vnd.cncf.model.dataset.v1.tar"
MEDIA_TYPE_MODEL_DATASET_GZIP = "application/vnd.cncf.model.dataset.v1.tar+gzip"
MEDIA_TYPE_MODEL_DATASET_ZSTD = "application/vnd.cncf.model.dataset.v1.tar+zstd"
Loading