Skip to content

Commit

Permalink
ArtifactBase abstract class to support original artifact implementa…
Browse files Browse the repository at this point in the history
…tion (#103)

- Introduce new customize point for using custom artifact
implementation.
  - This is new feature in Python SDK. Bump up its version to 1.1.0
- Since PyO3 does not support inheriting Python class in Rust side, I
create wrapper classes in Python layer.
PyO3/pyo3#991
  • Loading branch information
termoshtt authored Jul 29, 2024
1 parent 546f82c commit 1fdd2d9
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 11 deletions.
2 changes: 1 addition & 1 deletion python/ommx-python-mip-adapter/docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
copyright = "2024, Jij Inc."
author = "Jij Inc."

version = "1.0.1"
version = "1.1.0"
release = version

# -- General configuration ---------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions python/ommx-python-mip-adapter/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "ommx_python_mip_adapter"
version = "1.0.1"
version = "1.1.0"

description = "An adapter for the Python-MIP from/to OMMX."
authors = [
Expand All @@ -23,7 +23,7 @@ classifiers = [
"License :: OSI Approved :: MIT License",
]
dependencies = [
"ommx >= 1.0.1, < 2.0.0",
"ommx >= 1.1.0, < 2.0.0",

# FIXME: This project requires latest version of Python-MIP (will be 1.16.0?), which does not release yet.
# https://github.com/coin-or/python-mip/issues/384
Expand Down
2 changes: 1 addition & 1 deletion python/ommx/docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
copyright = "2024, Jij Inc."
author = "Jij Inc."

version = "1.0.1"
version = "1.1.0"
release = version

# -- General configuration ---------------------------------------------------
Expand Down
164 changes: 158 additions & 6 deletions python/ommx/ommx/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,107 @@
from dataclasses import dataclass
from pathlib import Path
from dateutil import parser
from abc import ABC, abstractmethod

from ._ommx_rust import (
ArtifactArchive,
ArtifactDir,
ArtifactArchive as _ArtifactArchive,
ArtifactDir as _ArtifactDir,
Descriptor,
ArtifactArchiveBuilder,
ArtifactDirBuilder,
ArtifactArchiveBuilder as _ArtifactArchiveBuilder,
ArtifactDirBuilder as _ArtifactDirBuilder,
)
from .v1 import Instance, Solution


class ArtifactBase(ABC):
@property
@abstractmethod
def image_name(self) -> str | None: ...

@property
@abstractmethod
def annotations(self) -> dict[str, str]: ...

@property
@abstractmethod
def layers(self) -> list[Descriptor]: ...

@abstractmethod
def get_blob(self, digest: str) -> bytes: ...

@abstractmethod
def push(self): ...


# FIXME: This wrapper class should be defined in Rust binding directly,
# but PyO3 does not support inheriting Python class https://github.com/PyO3/pyo3/issues/991
@dataclass
class ArtifactArchive(ArtifactBase):
_base: _ArtifactArchive

@staticmethod
def from_oci_archive(path: str) -> ArtifactArchive:
return ArtifactArchive(_ArtifactArchive.from_oci_archive(path))

@property
def image_name(self) -> str | None:
return self._base.image_name

@property
def annotations(self) -> dict[str, str]:
return self._base.annotations

@property
def layers(self) -> list[Descriptor]:
return self._base.layers

def get_blob(self, digest: str) -> bytes:
return self._base.get_blob(digest)

def push(self):
self._base.push()


# FIXME: This wrapper class should be defined in Rust binding directly,
# but PyO3 does not support inheriting Python class https://github.com/PyO3/pyo3/issues/991
@dataclass
class ArtifactDir(ArtifactBase):
_base: _ArtifactDir

@staticmethod
def from_oci_dir(path: str) -> ArtifactDir:
return ArtifactDir(_ArtifactDir.from_oci_dir(path))

@staticmethod
def from_image_name(image_name: str) -> ArtifactDir:
return ArtifactDir(_ArtifactDir.from_image_name(image_name))

@property
def image_name(self) -> str | None:
return self._base.image_name

@property
def annotations(self) -> dict[str, str]:
return self._base.annotations

@property
def layers(self) -> list[Descriptor]:
return self._base.layers

def get_blob(self, digest: str) -> bytes:
return self._base.get_blob(digest)

def push(self):
self._base.push()


@dataclass
class Artifact:
"""
Reader for OMMX Artifacts.
"""

_base: ArtifactArchive | ArtifactDir
_base: ArtifactBase

@staticmethod
def load_archive(path: str | Path) -> Artifact:
Expand Down Expand Up @@ -206,13 +289,82 @@ def get_dataframe(self, descriptor: Descriptor) -> pandas.DataFrame:
return pandas.read_parquet(io.BytesIO(blob))


class ArtifactBuilderBase(ABC):
@abstractmethod
def add_layer(
self, media_type: str, blob: bytes, annotations: dict[str, str]
) -> Descriptor: ...

@abstractmethod
def add_annotation(self, key: str, value: str): ...

@abstractmethod
def build(self) -> ArtifactBase: ...


# FIXME: This wrapper class should be defined in Rust binding directly,
# but PyO3 does not support inheriting Python class https://github.com/PyO3/pyo3/issues/991
@dataclass
class ArtifactArchiveBuilder(ArtifactBuilderBase):
_base: _ArtifactArchiveBuilder

@staticmethod
def new(path: str, image_name: str) -> ArtifactArchiveBuilder:
return ArtifactArchiveBuilder(_ArtifactArchiveBuilder.new(path, image_name))

@staticmethod
def new_unnamed(path: str) -> ArtifactArchiveBuilder:
return ArtifactArchiveBuilder(_ArtifactArchiveBuilder.new_unnamed(path))

@staticmethod
def temp() -> ArtifactArchiveBuilder:
return ArtifactArchiveBuilder(_ArtifactArchiveBuilder.temp())

def add_layer(
self, media_type: str, blob: bytes, annotations: dict[str, str] = {}
) -> Descriptor:
return self._base.add_layer(media_type, blob, annotations)

def add_annotation(self, key: str, value: str):
self._base.add_annotation(key, value)

def build(self) -> ArtifactArchive:
return ArtifactArchive(self._base.build())


# FIXME: This wrapper class should be defined in Rust binding directly,
# but PyO3 does not support inheriting Python class https://github.com/PyO3/pyo3/issues/991
@dataclass
class ArtifactDirBuilder(ArtifactBuilderBase):
_base: _ArtifactDirBuilder

@staticmethod
def new(image_name: str) -> ArtifactDirBuilder:
return ArtifactDirBuilder(_ArtifactDirBuilder.new(image_name))

@staticmethod
def for_github(org: str, repo: str, name: str, tag: str) -> ArtifactDirBuilder:
return ArtifactDirBuilder(_ArtifactDirBuilder.for_github(org, repo, name, tag))

def add_layer(
self, media_type: str, blob: bytes, annotations: dict[str, str] = {}
) -> Descriptor:
return self._base.add_layer(media_type, blob, annotations)

def add_annotation(self, key: str, value: str):
self._base.add_annotation(key, value)

def build(self) -> ArtifactDir:
return ArtifactDir(self._base.build())


@dataclass(frozen=True)
class ArtifactBuilder:
"""
Builder for OMMX Artifacts.
"""

_base: ArtifactArchiveBuilder | ArtifactDirBuilder
_base: ArtifactBuilderBase

@staticmethod
def new_archive_unnamed(path: str | Path) -> ArtifactBuilder:
Expand Down
2 changes: 1 addition & 1 deletion python/ommx/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "maturin"
[project]
name = "ommx"

version = "1.0.1"
version = "1.1.0"
description = "Open Mathematical prograMming eXchange (OMMX)"
authors = [{ name="Jij Inc.", email="info@j-ij.com" }]
readme = "README.md"
Expand Down

0 comments on commit 1fdd2d9

Please sign in to comment.